Skip to main content
Visitor II
June 3, 2024
Question

How to correctly temporarily abort QSPI memory mapped mode on STM32H750

  • June 3, 2024
  • 2 replies
  • 1729 views

Hello,

I have a project on STM32H750 where the code runs from external qspi flash in memory mapped mode. I need to write the flash occasionally and for that purpose I have some functions in RAM which disable interrupts, disable caching, abort memory mapped mode, do the actual write and then reenable all again.

The described method is working well for me until now when I need DMA for my UART transfers. I found that the DMA somehow collides with my flash writing ending in hardfault.

I don't know why but I suppose that I have to pause the DMA during the flash write process (IRQs disabled?). Can anyone give me an advice what's the correct way to do that? I think I remember I already read something on this topic. some appnote or forum thread, but I cannot find it anymore.

best regards
Jan

    This topic has been closed for replies.

    2 replies

    Technical Moderator
    June 4, 2024

    Hello @JanPohanka and welcome to the Community :),

    Please wait for the end of the transfer before abort the memory mapped mode.

    Also could you please try to pause or disable the DMA transfers before starting the flash write process and then resume them afterward.

    Could you please take a look at these applications notes may help you.

    Quad-SPI interface on STM32 microcontrollers and microprocessors - Application note

    External memory code execution on STM32F7x0 Value line, STM32H750 Value line, STM32H7B0 Value line and STM32H730 Value line MCUs - Application note

    Thank you.

    Kaouthar

     

    Graduate II
    June 4, 2024

    HAL_QSPI_Abort(&hqspi)

    For DMA be aware of cache coherency. Use the ByAddr methods DCache Clean flushes the cache, Invalidate trashes it, loses pending writes, dangerous if done blindly. Cache lines a 32-byte sided/aligned.

    Ensure the QSPI Write Page operation completes

    Visitor II
    June 5, 2024

    Thank you for answer. 

    HAL_QSPI_Abort(&hqspi)

    I know this :), I just don't know how to correctly handle the collision with DMA.

    I have the following logic now, which works well, until I started to need DMA enabled UART. I'd like to solve it in some general way if possible.

    static void __ramfunc qspi_abort()
    {
     SET_BIT(QUADSPI->CR, QUADSPI_CR_ABORT);
    
     while ((QUADSPI->SR & QSPI_FLAG_TC) == 0) ; // TODO timeout
     QUADSPI->FCR |= QSPI_FLAG_TC;
    
     while ((QUADSPI->SR & QSPI_FLAG_BUSY) != 0) ; // TODO timeout
    }
    
    #define RAM_TRAMPOLINE_DISABLE_CACHE
    static uint32_t __qspi_abort_mm(struct flash_qspi_dev_data *devdata)
    {
     __disable_irq();
    
    #if defined(RAM_TRAMPOLINE_DISABLE_CACHE)
     SCB_DisableDCache();
     SCB_DisableICache();
    #endif
    
     uint32_t ccr_backup = QUADSPI->CCR;
    
     qspi_abort();
     devdata->memory_mapped = false;
     devdata->busy = 0;
    
     return ccr_backup;
    }
    
    static void __qspi_start_mm(struct flash_qspi_dev_data *devdata, bool restore, uint32_t ccr_backup)
    {
     if (devdata->busy != 0)
     qspi_abort();
    
     devdata->busy = 1;
    
     // enable memory mapped again
     while ((QUADSPI->SR & QSPI_FLAG_BUSY) != 0) ; // TODO timeout
     QUADSPI->CCR = ccr_backup;
    
    #if defined(RAM_TRAMPOLINE_DISABLE_CACHE)
     SCB_EnableICache();
     SCB_EnableDCache();
    #endif
    
     __enable_irq();
    
     devdata->memory_mapped = true;
    }
    
    __ramfunc static int flash_qspi_write(struct flash_qspi_dev_data *devdata, off_t offset,
     const void *data, size_t size)
    {
     uint32_t ccr_backup;
    
     ccr_backup = __qspi_abort_mm(devdata);
    
     while (size > 0) {
     ...
    
     qspi_cmd(QUAD_PROGRAM_CMD, QUADSPI_CCR_DMODE, ws, QUADSPI_CCR_ADMODE_0,
     QUADSPI_CCR_ADSIZE_1, offset, 0);
     ...
     }
    
     __qspi_start_mm(devdata, true, ccr_backup);
    
     return 0;
    }