Skip to main content
ChrisH
Associate III
July 5, 2017
Question

STM32L4 SDMMC Command Timeout

  • July 5, 2017
  • 5 replies
  • 8983 views
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?

    This topic has been closed for replies.

    5 replies

    ST Technical Moderator
    July 5, 2017
    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

    In order to give better visibility on the answered topics, please click on 'Best answer' on the reply which solved your issue or answered your question. Thanks
    ChrisH
    ChrisHAuthor
    Associate III
    July 5, 2017
    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
    ChrisHAuthor
    Associate III
    July 6, 2017
    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.

    tmtlib
    Associate II
    August 13, 2017
    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);
     }�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

    ChrisH
    ChrisHAuthor
    Associate III
    August 14, 2017
    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.

    Nesrine M_O
    Associate
    October 3, 2017
    Posted on October 03, 2017 at 17:53

    Hi,

    Thanks for highlighting this issue!

    I will check it  with our development team & come back to you ASAP.Sorry for the inconvenience it may bring.

    -Nesrine-

    Peter Olsson
    Associate II
    October 30, 2017
    Posted on October 30, 2017 at 08:28

    Hi Nesrine,

    Any updates on this - will there be a fix when the next versions are released? The initial problem was reported for L4, but it's the same issue of F7.

    Deli Geng
    Visitor II
    November 16, 2017
    Posted on November 16, 2017 at 03:01

    I can also confirm it is the same case with the F4 library, and

    Moshkin.Georgy

    's fix works.

    vladimir boretsky
    Associate
    October 18, 2017
    Posted on October 18, 2017 at 12:26

    Hi friends!

    Do anybody have working project for STM32L476 for READ WRITE files with DMA mode using by FatFs?

    Could you send me this project?

    mailto:boretskyv@gmail.com

    Best regards. 

    JAlth
    Associate
    February 25, 2019

    Dear ST community,

    long story made short:

    the workaround proposed here fixed the problem for me. Thank you!

    Detailed description:

    Am am using the STM32F4. I observed this problem as well, when I started to use FatFS on SDIO SD card with DMA templates (w/o DMA templates, this problem did NOT occur).

    In my situation, the problem was relatively hard to trace - the system resettet randomly from time to time, something between once and up to five times per day. Reason for the reset itself was that the IWDG kicking in.

    And the IWDG kicked in, because the controller got stuck in the function SDMMC_GetCmdResp1 in this loop:

    do
     {
     if (count-- == 0U)
     {
     return SDMMC_ERROR_TIMEOUT;
     }
     
     }while(!__SDIO_GET_FLAG(SDIOx, SDIO_FLAG_CCRCFAIL | SDIO_FLAG_CMDREND | SDIO_FLAG_CTIMEOUT));

    I applied the changes to the function SD_DMAReceiveCplt and modified it to use SDIO, so that my function now looks like this:

    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)SDIO_DCTRL_DMAEN);
     
     /* CHANGED PART START*/
    	/* 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, SDIO_FLAG_CMDREND))
    		{
    			/* Clear only selected flags */
    			__HAL_SD_CLEAR_FLAG(hsd, ((uint32_t)(	SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT |
    																SDIO_FLAG_TXUNDERR | SDIO_FLAG_RXOVERR |
    																SDIO_FLAG_CMDSENT | SDIO_FLAG_DATAEND | SDIO_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);
    	}
     /* CHANGED PART END*/
     
     hsd->State = HAL_SD_STATE_READY;
     
     HAL_SD_RxCpltCallback(hsd);
    }

    From my point of view, ST should seriously investigate this problem.

    Thanks again, @Hockuba.Krzysztof and to all who have been working on this workaround!

    Joachim