cancel
Showing results for 
Search instead for 
Did you mean: 

How to correctly temporarily abort QSPI memory mapped mode on STM32H750

JanPohanka
Associate

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

3 REPLIES 3
KDJEM.1
ST Employee

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

 

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

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

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

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;
}