STM32CubeL4 icon indicating copy to clipboard operation
STM32CubeL4 copied to clipboard

SDMMC Data End Interrupt sometimes does not occur

Open by-gnome opened this issue 1 year ago • 1 comments

Describe the set-up The device based on STM32L496VG with high load application. ICCARM v8.32, STM32Cube_FW_L4_V1.18.1.

Describe the bug Writing to an SD memory card using SDMMC+DMA sometimes times out in the SD_write() function. This happens because the DATAEND interrupt does not occur. After some debugging I found that the SD_DMATransmitCplt() function enables the DATAEND interrupt by setting the DATAENDIE bit, but interrupt does not occur, and after the timeout in the SD_write() function the DATAEND bit is set and the DATAENDIE bit is not set.

How To Reproduce SDMMC parameters:

  • Clock source - HSI48 RC
  • Clock transition - Rising
  • Clock divider bypass - Enable
  • Clock power save - Enable
  • HW flow control - Enable
  • Wide bus mode - 4 bit
  • DMA - DMA2 channel 5

The application writes data to the SD card for 12-24 hours, with a data rate of 128 kB/s. After writing several gigabytes of data, a timeout occurs in the SD_write() function.

Additional context Let's consider the SD_DMATransmitCplt() function:

static void SD_DMATransmitCplt(DMA_HandleTypeDef *hdma)
{
  SD_HandleTypeDef* hsd = (SD_HandleTypeDef* )(hdma->Parent);

  /* Enable DATAEND Interrupt */
  __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DATAEND));
}

In case of abnormal operation, before setting DATAENDIE, the SDMMC_STA register has the state 0x00105400: TXDAVL = 1, TXFIFOHE = 1, TXACT = 1, DBCKEND = 1 or 0 (doesn't matter) and SDMMC_MASK register has the state 0x00000000 !!!

After setting DATAENDIE, the SDMMC_STA register has the state 0x00105400: TXDAVL = 1, TXFIFOHE = 1, TXACT = 1, DBCKEND = 1 or 0 (doesn't matter) and SDMMC_MASK register has the state 0x00000100: DATAENDIE = 1

After timeout in SD_write the SDMMC_STA register has the state 0x00000500: DBCKEND = 1, DATAEND = 1 and SDMMC_MASK register has the state 0x0000001A: TXUNDERRIE = 1, DTIMEOUTIE = 1, DCRCFAILIE = 1

The correct values ​​in the SDMMC_MASK register are 0x0000001A and 0x0000011A. Therefore, it can be assumed that in the SD_DMATransmitCplt() function, reading/writing the SDMMC_MASK register is sometimes disrupted.

Possible solution If I set the DATAENDIE bit in the HAL_SD_WriteBlocks_DMA() function, the problem does not occur.

--- a/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_sd.c
+++ b/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_sd.c
@@ -1566,7 +1566,7 @@ HAL_StatusTypeDef HAL_SD_WriteBlocks_DMA(SD_HandleTypeDef *hsd, uint8_t *pData,
       (void)SDMMC_ConfigData(hsd->Instance, &config);
 
       /* Enable SD Error interrupts */
-      __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_TXUNDERR));
+      __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_TXUNDERR | SDMMC_IT_DATAEND));
 #else
       /* Enable transfer interrupts */
       __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_TXUNDERR | SDMMC_IT_DATAEND));
@@ -3225,9 +3225,6 @@ HAL_StatusTypeDef HAL_SD_Abort_IT(SD_HandleTypeDef *hsd)
 static void SD_DMATransmitCplt(DMA_HandleTypeDef *hdma)
 {
   SD_HandleTypeDef* hsd = (SD_HandleTypeDef* )(hdma->Parent);
-
-  /* Enable DATAEND Interrupt */
-  __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DATAEND));
 }

by-gnome avatar Oct 28 '24 14:10 by-gnome

Project configuration

proj_sys_view

Clock configuration

proj_clock_config

by-gnome avatar Oct 31 '24 11:10 by-gnome

Hello @by-gnome,

Thank you for the report.

Regarding the issue, I tested an application with STM32L496G-Disco and work just fine, it's under Projects\32L496GDISCOVERY\Applications\FatFs\FatFs_uSD_DMA_RTOS

However, I will share your proposal to our team in order to analyze it. In the meanwhile, I will try to investigate more and test an example using your config, especially as you mentioned The application writes data to the SD card for 12-24 hours, with a data rate of 128 kB/s. After writing several gigabytes of data, a timeout occurs in the SD_write() function, it's a lot of time and Data.

Just a few questions, if you may:

  • Did you do the test several times, and each time you have this error or timeout?
  • You project with a custom board or ST board?

With regards,

KRASTM avatar Nov 01 '24 14:11 KRASTM

The project runs on a custom board. I tested for several weeks. The problem does not always occur, but quite often. More often with the FAT32 file system than with the exFAT. It might also depend on interrupt priorities and system load. This problem might be similar to STM32CubeL4/pull/35

by-gnome avatar Nov 02 '24 11:11 by-gnome

To localize the problem I modified the SD_DMATransmitCplt() and SD_write() as follows:

static void SD_DMATransmitCplt(DMA_HandleTypeDef *hdma)
{
  SD_HandleTypeDef* hsd = (SD_HandleTypeDef* )(hdma->Parent);
  SdDmaTxCplt1 = SDMMC1->STA | 0x80000000;
  SdDmaTxCplt0 = SDMMC1->MASK | 0x80000000;
  /* Enable DATAEND Interrupt */
  __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DATAEND));
  SdDmaTxCplt3 = hsd->Instance->STA | 0x80000000;
  SdDmaTxCplt2 = hsd->Instance->MASK | 0x80000000;
}
DRESULT SD_write(BYTE lun, const BYTE *buff, DWORD sector, UINT count)
{
  uint32_t tickstart;
  WriteStatus = 0;
  if (BSP_SD_WriteBlocks_DMA((uint32_t*)buff, (uint32_t)(sector), count) == MSD_OK)
  {
    tickstart = HAL_GetTick();
    while ((WriteStatus == 0) && ((HAL_GetTick() - tickstart) < SD_TIMEOUT));
    if (WriteStatus != 0) {
      do {
        if (BSP_SD_GetCardState() == SD_TRANSFER_OK) {
          return RES_OK;
        }
      } while ((HAL_GetTick() - tickstart) < SD_TIMEOUT);
    }
  }
  SdmmcTxCplt3 = hsd1.Instance->STA | 0x80000000;
  SdmmcTxCplt2 = hsd1.Instance->MASK | 0x80000000;
  return RES_ERROR;
}

When timeout, the variables contain the following values:

SdDmaTxCplt1 - 0x80105400
SdDmaTxCplt0 - 0x80000000
SdDmaTxCplt3 - 0x80105400
SdDmaTxCplt2 - 0x80000100
SdmmcTxCplt3 - 0x80000500
SdmmcTxCplt2 - 0x8000001a

It might be a hardware issue with SDMMC_MASK register.

by-gnome avatar Nov 03 '24 15:11 by-gnome

ST Internal Reference: 196054

KRASTM avatar Nov 11 '24 09:11 KRASTM

Hello @by-gnome,

The issue is reported internally. Just if you may, we want to know the type and specification of the SD card used in your project.

With regards,

KRASTM avatar Nov 12 '24 09:11 KRASTM

Hello @KRASTM

32GB ADATA Premier microSDHC UHS-I Class10 (AUSDH32GUICL10-R)

by-gnome avatar Nov 12 '24 12:11 by-gnome

Hello @KRASTM

After 6 months of testing, I can confirm that the proposed patch works well. The following SD cards were used in the tests: 32GB ADATA Premier microSDHC Class10 UHS-I (AUSDH32GUICL10-R) 32GB Transcend microSDHC Class 10 UHS-I (TS32GUSD300S) 32GB Kingston CANVAS Select Plus microSDHC UHS-I (SDCS2/32GBSP)

by-gnome avatar May 13 '25 11:05 by-gnome

Hello @by-gnome,

Thank you for your patience and your feedback, I will pass on your findings to our team. Just for the information #95 was handled internally and it is only a matter of time before the fix is published or shared.

I will keep you posted if there are any updates to this issue.

With regards,

KRASTM avatar May 14 '25 10:05 KRASTM

Hello @by-gnome,

I have checked with our team after sharing your results. It seems that either the approach used in our driver or yours is correct. However, for our driver, we wait for the DMA to enable the DATAEND Interrupt. This is a choice made by our development team and has been implemented in many other IPs.

So, they propose a fix and ask if you could test it with your application and provide feedback.

below the fix:

#if !defined(STM32L4P5xx) && !defined(STM32L4Q5xx) && !defined(STM32L4R5xx) && !defined(STM32L4R7xx) && !defined(STM32L4R9xx) && !defined(STM32L4S5xx) && !defined(STM32L4S7xx) && !defined(STM32L4S9xx)
    /* Enable SDMMC DMA transfer */
-    __HAL_SD_DMA_ENABLE(hsd);

    /* Enable the DMA Channel */
    if(HAL_DMA_Start_IT(hsd->hdmatx, (uint32_t)pData, (uint32_t)&hsd->Instance->FIFO, (uint32_t)(BLOCKSIZE * NumberOfBlocks)/4U) != HAL_OK)
    {
      __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
      hsd->ErrorCode |= HAL_SD_ERROR_DMA;
      hsd->State = HAL_SD_STATE_READY;
      hsd->Context = SD_CONTEXT_NONE;
      return HAL_ERROR;
    }
    else
    {
      /* Configure the SD DPSM (Data Path State Machine) */
      config.DataTimeOut   = SDMMC_DATATIMEOUT;
      config.DataLength    = BLOCKSIZE * NumberOfBlocks;
      config.DataBlockSize = SDMMC_DATABLOCK_SIZE_512B;
      config.TransferDir   = SDMMC_TRANSFER_DIR_TO_CARD;
      config.TransferMode  = SDMMC_TRANSFER_MODE_BLOCK;
      config.DPSM          = SDMMC_DPSM_ENABLE;
      (void)SDMMC_ConfigData(hsd->Instance, &config);


      /* Enable SD Error interrupts */
      __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_TXUNDERR));

+     __HAL_SD_DMA_ENABLE(hsd);
#else
      /* Enable transfer interrupts */
      __HAL_SD_ENABLE_IT(hsd, (SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_TXUNDERR | SDMMC_IT_DATAEND));
#endif /* !STM32L4P5xx && !STM32L4Q5xx && !STM32L4R5xx && !STM32L4R7xx && !STM32L4R9xx && !STM32L4S5xx && !STM32L4S7xx && !STM32L4S9xx */

Thank you, With regards,

KRASTM avatar May 23 '25 09:05 KRASTM

Hello @KRASTM

Thank you and STM team for response. We will apply the above fix and give you feedback.

by-gnome avatar May 23 '25 11:05 by-gnome

Hello @by-gnome,

Any updates, please?

With regards,

KRASTM avatar Aug 08 '25 14:08 KRASTM

Hello @KRASTM

We have reverted our changes to stm32l4xx_hal_sd.c and we cannot reproduce the problem. Therefore we cannot reliably test the fix suggested above. I think we can close this issue. If the problem occurs again, we will test the fix and I will let you know. Thank you.

by-gnome avatar Aug 08 '25 15:08 by-gnome