cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L4 SDMMC Command Timeout

ChrisH
Associate III
Posted on July 05, 2017 at 10:53

While using SDMMC with FatFS to interface with SDCards occasionally I get Command Timeout when issuing:

SDMMC_CmdReadSingleBlock

This is when using new 1.7.0 drivers. Did anyone experience similar issue?

29 REPLIES 29
Imen.D
ST Employee
Posted on July 05, 2017 at 17:47

Hi

Hockuba.Krzyszto.002

,

I recommend you to use the latest STM32CubeL4 v1.8.1 and have a look into

FatFs_uSD

example for your board, this will help you to develop your application:

STM32Cube_FW_L4_V1.8.1\Projects\STM32L496G-Discovery\Applications\FatFs\FatFs_uSD

With Regards

Imen

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen
Posted on July 05, 2017 at 20:05

Hi

‌ I'm indeed using latest 1.8.1 and had a look at examples. This doesn't really help and microcontroller still ends up occasionallyin Command Timeout. Only using taskENTER_CRITICAL(); as well as taskEXIT_CRITICAL(); 'solves' the problem the Read Single Block command becomes:

uint32_t SDMMC_CmdReadSingleBlock(SDMMC_TypeDef *SDMMCx, uint32_t ReadAdd){ SDMMC_CmdInitTypeDef sdmmc_cmdinit; uint32_t errorstate = SDMMC_ERROR_NONE; /* Set Block Size for Card */ sdmmc_cmdinit.Argument = (uint32_t)ReadAdd; sdmmc_cmdinit.CmdIndex = SDMMC_CMD_READ_SINGLE_BLOCK; sdmmc_cmdinit.Response = SDMMC_RESPONSE_SHORT; sdmmc_cmdinit.WaitForInterrupt = SDMMC_WAIT_NO; sdmmc_cmdinit.CPSM = SDMMC_CPSM_ENABLE; taskENTER_CRITICAL(); SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit); /* Check for error conditions */ errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_READ_SINGLE_BLOCK, SDMMC_CMDTIMEOUT); taskEXIT_CRITICAL(); return errorstate;}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

This bug can be reproduced by placing interrupt at command which is on line 13 above on unmodified code and going step by step into next function. SDMMC_GetCmdResp1 will timeout every time in my case, when in runtime application timeouts only occasionally,I can't really say when exactly and what is happening in between. But clearly looks like peripheral is missing the response from SD Card.

ChrisH
Associate III
Posted on July 06, 2017 at 02:05

Ok after some time I found a bug. I'm running FreeRTOS with a couple of tasks so overall we have a pretty complex system. Becuase DMA transfer is very quick and happens independently to the system, DMA interrupt can occur before the command can read a response. 

SD_DMAReceiveCplt callback clears out all static flags which result in CMDREND flag being cleared before SDMMC_GetCmdResp1 can read it. Not sure how ST sees it but in my humble opinion this is a bug. This doesn't concern DMA Write because the command is issued before the transfer starts. This bug was actually introduced after SD drivers rewrite.

Posted on July 12, 2017 at 16:01

DAHMEN.IMEN

‌ I would like for someone from ST to comment on my observations as It seems that read operation while using DMA is non-atomic and can run into timeout while in fact, it was successful.

Posted on July 26, 2017 at 12:13

Hi Imen,

I have reproduced the same issue.

SDMMC_CmdReadSingleBlock() and SDMMC_CmdSendStatus() functions often end with timeout on our complex system with FreeRTOS, multiple interrupts and DMA channels used.

It did not happen in previous versions of HAL library. I have tested it on the same hardware, so no hardware issue here.

I request, that ST investigates this issue.

Regards,

Tomasz
Posted on August 13, 2017 at 22:20

I am using HAL library (no FreeRTOS or any other OS). Following code stuck in

SDMMC_GetCmdResp1 function if HAL_Delay(1) is commented. Although I am not sure about that. But when i disabled SDIO global interrupt, then problem did not occured.It seems that HAL_SD_IRQHandler somehow interacts with DMA operation. I do not use any interrupts/callbacks for SDIO.

With

SDIO global interrupt disabled i have an another problem, now for write operation: after calling HAL_SD_WriteBlocks_DMA function HAL_SD_GetCardState never returns HAL_SD_CARD_TRANSFER value and stuck with endlessly returningHAL_SD_CARD_RECEIVING.

Any Ideas?

ch=HAL_SD_ReadBlocks_DMA(&hsd, (uint8_t*)&tmpBuffer, sdaddr, 32);
 comSend((uint8_t *)&ch,1);
 while (1)
 {
 ch=HAL_SD_GetCardState(&hsd);
 if (ch==HAL_SD_CARD_TRANSFER) break;
 // HAL_Delay(1);
 }�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

Posted on August 14, 2017 at 16:46

This is irrelevant to the topi but I will answer it, obviously when using DMA use interrupts with SDIO interrupt having higher priority than DMA interrupt for SDIO peripheral. Before each transfer you need to configure DMA accordingly (transfer direction - memory to periph or periph to men). Lastly don’t use pooling to check if transfer finished use callbacks and then execute function getcardstate. Read manual for SDIO you will understand why you need to do all above.

Posted on August 29, 2017 at 12:41

I've seen the exact same issue. It seems ST needs to fix this in STM32CubeMX. RIght now I've commented out the following line in SD_DMAReceiveCplt():

__HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);

I'm sure this is not the perfect solution, but it works for now

Posted on August 29, 2017 at 15:11

I'm happy you are optimistic but it has been almost 2 months now and still, no one replied fromST Engineers to comment on this issue. I modified ReciveCplt in this way so it leaves flags that CMD Resp checks and clears rest of them.

/**
 * @brief DMA SD receive process complete callback 
 * @param hdma: DMA handle
 * @retval None
 */
static void SD_DMAReceiveCplt(DMA_HandleTypeDef *hdma) 
{
 SD_HandleTypeDef* hsd = (SD_HandleTypeDef* )(hdma->Parent);
 uint32_t errorstate = HAL_SD_ERROR_NONE;
 
 /* Send stop command in multiblock write */
 if(hsd->Context == (SD_CONTEXT_READ_MULTIPLE_BLOCK | SD_CONTEXT_DMA))
 {
 errorstate = SDMMC_CmdStopTransfer(hsd->Instance);
 if(errorstate != HAL_SD_ERROR_NONE)
 {
 hsd->ErrorCode |= errorstate;
 HAL_SD_ErrorCallback(hsd);
 }
 }
 
 /* Disable the DMA transfer for transmit request by setting the DMAEN bit
 in the SD DCTRL register */
 hsd->Instance->DCTRL &= (uint32_t)~((uint32_t)SDMMC_DCTRL_DMAEN);
 
 /* Check current state of Command Register and don't clear those flags */
 if (hsd->Context == (SD_CONTEXT_READ_SINGLE_BLOCK | SD_CONTEXT_DMA))
 {
 if (__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_CMDREND)) {
 /* Clear only selected flags */
 __HAL_SD_CLEAR_FLAG(hsd, ((uint32_t)(SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT |
 SDMMC_FLAG_TXUNDERR | SDMMC_FLAG_RXOVERR |
 SDMMC_FLAG_CMDSENT | SDMMC_FLAG_DATAEND | SDMMC_FLAG_DBCKEND)));
 } else {
 /* Clear all the static flags */
 __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
 }
 }
 else
 {
 /* Clear all the static flags */
 __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
 }
 
 hsd->State = HAL_SD_STATE_READY;
 HAL_SD_RxCpltCallback(hsd);
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?