STMicroelectronics / stm32h7xx_hal_driver

Provides the STM32Cube MCU Component "hal_driver" of the STM32H7 series.
BSD 3-Clause "New" or "Revised" License
86 stars 36 forks source link

DMA2D_IRQHandler called with empty ISR register #31

Open davidev94 opened 1 year ago

davidev94 commented 1 year ago

I'm using a custom board with STM32H723 (144pin), 5inch display (LTDC), external SRAM (FMC), external NOR flash (OSPI) with Touchgfx and DMA2D (double buffer strategy). No OS.

I experimented random stucks of the touchgfx like described in this thread. After struggling I found out that the problem was caused by DMA2D_IRQHandler called with empty ISR register. In fact, the touchgfx was expecting a call to XferErrorCallback(hdma2d) that never happened and so hanged on.

For what I've seen when this empty call is triggered the _DMA2D_FLAGTC should be HIGH, but actually this sometimes doesn't happens.

I do not know why this happens (silicon bug? touchgfx clean the flag in particular moment?), but for sure the HAL library doesn't manage this case.

So to solve my issue I changed in void HAL_DMA2D_IRQHandler(DMA2D_HandleTypeDef *hdma2d){...} of _stm32h7xx_haldma2d.c the following line: if ((isrflags & DMA2D_FLAG_TC) != 0U) in if ((isrflags & DMA2D_FLAG_TC) != 0U || isrflags == 0U)

taltenbach commented 1 year ago

I am encountering the exact same issue with a STM32H753XL MCU using TouchGFX 4.20.0. After some investigation, it seems that the DMA2D_FLAG_TC interrupt flag is cleared in STM32DMA::tearDown before the ISR is executed:

void tearDown()
{
    /* Wait for DMA2D to finish last run */
    while ((READ_REG(DMA2D->CR) & DMA2D_CR_START) != 0U);

    /* Clear transfer flags */
    WRITE_REG(DMA2D->IFCR, DMA2D_FLAG_TC|DMA2D_FLAG_CE|DMA2D_FLAG_TE);
}

After the while loop is exited, there is no guarantee that the DMA2D ISR is entered before the write to DMA2D_IFCR is performed. I added the following check as a workaround and the issue doesn't seem to happen anymore:

void tearDown()
{
    /* Wait for DMA2D to finish last run */
    while ((READ_REG(DMA2D->CR) & DMA2D_CR_START) != 0U);

    if (DMA2D->CR & DMA2D_CR_TCIE) {
        /* DMA2D interrupt enabled, wait until ISR has been executed, flags are cleared by the ISR */
        while ((DMA2D->ISR & DMA2D_CR_TCIE) != 0u);
    } else {
        /* DMA2D interrupt disabled, manually clear transfer flags */
        WRITE_REG(DMA2D->IFCR, DMA2D_FLAG_TC|DMA2D_FLAG_CE|DMA2D_FLAG_TE);
    }
}

Not sure that's the proper way to fix the issue but hopefully this will be helpful

paulflory commented 7 months ago

@taltenbach Did you override the tearDown() function so this would be overwritten with code generation? I assume you would create another STM32DMA_user.cpp with the overriden tearDown() function right? Would this go in the TouchGFX->target directory above the generated folder with the STM32DMA.cpp function that has the base tearDown() function? Do you have the entire fill you used to share as an example? I'm having a very similar issue on a STM32H743 using TouchGFX 4.20 but only happens occasionally so very difficult to reproduce.

@TOUNSTM Has ST addressed this in a later version of TouchGFX?

cdesjardins commented 5 months ago

Just a note on this patch: while ((DMA2D->ISR & DMA2D_CR_TCIE) != 0u);

appears to be incorrect, I believe the proper bit is: while ((DMA2D->ISR & DMA2D_ISR_TCIF) != 0u);