cancel
Showing results for 
Search instead for 
Did you mean: 

I may have encountered a bug in SDMMC_GetCmdResp1 function.

OPoch
Associate

Hello!

I have a trouble with Timout delay in SDMMC_GetCmdResp1. I invoke HAL_SD_Init from freertos task. Now SD card isn't connected to board. Timout deleay take approximately 30 seconds, but Timout is 5000 ms.

static uint32_t SDMMC_GetCmdResp1(SDMMC_TypeDef *SDMMCx, uint8_t SD_CMD, uint32_t Timeout)
{
  uint32_t response_r1;
  uint32_t sta_reg;
 
  /* 8 is the number of required instructions cycles for the below loop statement.
  The Timeout is expressed in ms */
  register uint32_t count = Timeout * (SystemCoreClock / 8U /1000U);
 
  do
  {
    if (count-- == 0U)
    {
      return SDMMC_ERROR_TIMEOUT;
    }
    sta_reg = SDMMCx->STA;
  }while(((sta_reg & (SDMMC_FLAG_CCRCFAIL | SDMMC_FLAG_CMDREND | SDMMC_FLAG_CTIMEOUT | SDMMC_FLAG_BUSYD0END)) == 0U) ||
         ((sta_reg & SDMMC_FLAG_CMDACT) != 0U ));

My guess is this code doesn't work correctly within FreeRTOS task due to interrupts.

To test this theory I've wrapped code in question with __set_PRIMASK and delay was reduced to 15s (code below)

register uint32_t count = Timeout * (SystemCoreClock / 8U /1000U);
 
  __set_PRIMASK(1); // disable interrupts
  do
  {
    if (count-- == 0U)
    {
      return SDMMC_ERROR_TIMEOUT;
    }
    sta_reg = SDMMCx->STA;
  }while(((sta_reg & (SDMMC_FLAG_CCRCFAIL | SDMMC_FLAG_CMDREND | SDMMC_FLAG_CTIMEOUT | SDMMC_FLAG_BUSYD0END)) == 0U) ||
         ((sta_reg & SDMMC_FLAG_CMDACT) != 0U ));
  __set_PRIMASK(0); // enable interrupts

I decide it using HAL_GetTick().

static uint32_t SDMMC_GetCmdResp1(SDMMC_TypeDef *SDMMCx, uint8_t SD_CMD, uint32_t Timeout)
{
  uint32_t response_r1;
  uint32_t sta_reg;
  uint32_t time;
 
  /* 8 is the number of required instructions cycles for the below loop statement.
  The Timeout is expressed in ms */
  //register uint32_t count = Timeout * (SystemCoreClock / 10U /1000U);
 
  time = HAL_GetTick() + Timeout;
  do
  {
    if (time < HAL_GetTick())
    {
      return SDMMC_ERROR_TIMEOUT;
    }
    sta_reg = SDMMCx->STA;
  }while(((sta_reg & (SDMMC_FLAG_CCRCFAIL | SDMMC_FLAG_CMDREND | SDMMC_FLAG_CTIMEOUT | SDMMC_FLAG_BUSYD0END)) == 0U) ||
         ((sta_reg & SDMMC_FLAG_CMDACT) != 0U ));

Bonus: I have disassembled this code and counted 9 instructions instead of 8 (as written in the comment). below is the image

Disassembler:

0690X00000D9jTIQAZ.png

0 REPLIES 0