cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H743 SDMMC write problem

Hi,

I have a very strange problem with the STM32H743 SDMMC... I'm using a custom board with a 8GB SDHC Class 10 SD Card. I'm using the CubeMX generated code for SDMMC1, but I checked and it should be the same code as the example project (STM32Cube_FW_H7_V1.7.0\Projects\STM32H743I-EVAL\Applications\FatFs\FatFs_uSD_DMA_Standalone).

Reading and writing with the IDMA works perfectly (once I figured out all the MPU cache challenges).

I'm using a loop to call the FS_FileOperations() function from the example project 100 times. This means, a small .txt file will be written 100 times to the SD card and after each write, the data is read back. Usually this works without an issue, however, I have some SD Cards (they look the same from the outside) that will cause the write operation to get stuck with a massive timeout.

The timeout occurs in this function (sd_diskio_dma.c:(

DRESULT SD_write(BYTE lun, const BYTE *buff, DWORD sector, UINT count)
{
  DRESULT res = RES_ERROR;
  WriteStatus = 0;
  uint32_t timeout;
 /*
  * since the MPU is configured as write-through, see main.c file, there isn't any need
  * to maintain the cache as its content is always coherent with the memory.
  * If needed, check the file "Middlewares/Third_Party/FatFs/src/drivers/sd_diskio_dma_template.c"
  * to see how the cache is maintained during the write operations.
  */
 
  if(BSP_SD_WriteBlocks_DMA(0, (uint32_t*)buff,
                            (uint32_t)(sector),
                            count) == BSP_ERROR_NONE)
  {
    /* Wait that writing process is completed or a timeout occurs */
 
    timeout = HAL_GetTick();
    while((WriteStatus == 0) && ((HAL_GetTick() - timeout) < SD_TIMEOUT))
    {
    }
    /* incase of a timeout return error */
    if (WriteStatus == 0)
    {
      res = RES_ERROR;
    }
    else
    {
      WriteStatus = 0;
      timeout = HAL_GetTick();
 
      while((HAL_GetTick() - timeout) < SD_TIMEOUT)
      {
        if (BSP_SD_GetCardState(0) == SD_TRANSFER_OK)
        {
          res = RES_OK;
          break;
        }
      }
    }
  }
 
  return res;
}

It seems to appear completly random (sometimes it even works all of the 100 times). After the timeout appeared, the SD card no longer accepts read or write data and when trying to reinitialize the SDMMC a RX_OVERRUN occurs. The only way to resolve this, is to completly reset the STM32H7.

Has anyone seen a behavior like this before or can point me in a direction to search for?

I already tried to modify most of the SDMMC parameters, my hardware looks good and for me, the strange thing is that it works perfectly with some SD cards and that this error seems to be completly random.

5 REPLIES 5
TDK
Guru

I've ran into this. The root issue for was the code is unable to keep up with the data coming in. You can slow down the clock or increase optimization. Look at the DMA stream results to verify this is what is happening. The HAL support for SDMMC is not great.

If you feel a post has answered your question, please click "Accept as Solution".

I spent a lot more time on trying to debug this issue... I compared the initialization sequences of multiple SD cards. They are all the same, however I was able to find these differences with the SD card that causes the problems:

There is this function in the HAL code:

HAL_StatusTypeDef HAL_SD_GetCardStatus(SD_HandleTypeDef *hsd, HAL_SD_CardStatusTypeDef *pStatus)

All parameters of the HAL_SD_CardStatusTypeDef are the same exept these two:

EraseSize and ProtectedAreaSize.

EraseSize varies between different cards. I have seen 8, 64 and 512. I don't think there should be an issue with that.

ProtectedAreaSize usually is a large number, but in the case of my bad SD card it is 0. This parameter is called SIZE_OF_PROTECTED_AREA in the SD spefication and from my understanding it should never be 0.

I can't see that the content of the HAL_SD_CardStatusTypeDef is used anywhere else in the HAL code. The bad SD card works perfectly with my Windows PC, so I don't think there is a general issue with this card.

Can anyone explain to me why the STM32H7 might have a problem writing to this card?

EDIT:

Or is there at least a way to safely recover from this state? After the write timeout occured, the only working way I found so far is to completly reset the STM32H7. Reinitializing the SDMMC and even with unplugging and reinserting the SD card will result in an RX_OVERRUN.

Thank you for the quick response. Unfortunatly modifying the code optimization and / or the SDMMC clock speed has no effect on the problem behavior.

I'm using the PLL1Q (200 MHz) as input and the SDMMC clock divider is 0x02 -> 50 MHz clock. Even when chosing a lower SDMMC clock speed, I still have the same behavior. One SD Card works perferctly and the other one randomly gets stuck somewhere in the 100 write cycles.

How can I look at the DMA stream results? I don't have any DMA configuration, because the internal SDMMC DMA (IDMA) is used.

EDIT:

I have the exact same behavior in polling mode, so I guess the DMA is not the problem...

I still have no idea what is causing the issue with some of the SD cards I'm using.

But, at least, I found a workaround to avoid corrupt data or my application to get stuck completly.

The following two lines have to be added to the generated void HAL_SD_MspInit(SD_HandleTypeDef* sdHandle) function:

    __HAL_RCC_SDMMC1_FORCE_RESET();
    __HAL_RCC_SDMMC1_RELEASE_RESET();

The whole function should look like this:

void HAL_SD_MspInit(SD_HandleTypeDef* sdHandle)
{
 
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(sdHandle->Instance==SDMMC1)
  {
  /* USER CODE BEGIN SDMMC1_MspInit 0 */
 
  /* USER CODE END SDMMC1_MspInit 0 */
    /* SDMMC1 clock enable */
    __HAL_RCC_SDMMC1_CLK_ENABLE();
 
    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_GPIOD_CLK_ENABLE();
    /**SDMMC1 GPIO Configuration
    PC8     ------> SDMMC1_D0
    PC9     ------> SDMMC1_D1
    PC10     ------> SDMMC1_D2
    PC11     ------> SDMMC1_D3
    PC12     ------> SDMMC1_CK
    PD2     ------> SDMMC1_CMD
    */
    GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
    GPIO_InitStruct.Pin = GPIO_PIN_12;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
    GPIO_InitStruct.Pin = GPIO_PIN_2;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
 
    // MANUAL CHANGE: this is important for the reset
    __HAL_RCC_SDMMC1_FORCE_RESET();
    __HAL_RCC_SDMMC1_RELEASE_RESET();
 
    /* SDMMC1 interrupt Init */
    HAL_NVIC_SetPriority(SDMMC1_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(SDMMC1_IRQn);
  /* USER CODE BEGIN SDMMC1_MspInit 1 */
 
  /* USER CODE END SDMMC1_MspInit 1 */
  }

I don't know why this is missing in the code generated from CubeMX... It's there in the FatFs_uSD_DMA_Standalone example application.

After adding this, I was able to reset the SDMMC (HAL_SD_DeInit() + BSP_SD_Init()) when the problem occurs during writing to the SD card. However, in this state, the SD card is still stuck and not responding to the initialization sequence. In order get it running, I'm resetting the supply voltage for the SD card before performing the SDMMC reset.

This workaround is not very nice, because it greatly decreases the writing performance for the affected SD cards...

@TDK​ Can you please explain your answer a little bit further? I'm still trying to understand what the problem is...