cancel
Showing results for 
Search instead for 
Did you mean: 

Trouble with SDCARD - SDMMC_FLAG_RXOVERR

jagauthier
Associate III

I'm attempting to connect an adafruit SD card reader via SDIO to a Nucleo L476RG.

I'm reading through the source code to do a test of the basic read/write functions.

Initialization and getting card info is successful.

   if (HAL_SD_Init(&hsd1)!=HAL_OK){
	   serprintf("Could not initialize SD card.");
   }
 
   if(HAL_SD_GetCardInfo(&hsd1, &SDCardInfo1) != HAL_OK)
   {
     serprintf("Cardinfo no good.");
     Error_Handler();
   }
      sd_res = HAL_SD_ReadBlocks(&hsd1, Buffer_Block_Rx, WR_ADDR, NUM_BLOCKS, 0xffff);

However, the last call to read blocks fails with SDMMC_FLAG_RXOVERR.

I traced the program through several times and I cannot find the breaking point.

But here's what I have discovered.

HAL_SD_ReadBlocks() calls SDMMC_CmdReadMultiBlock()

SDMMC_CmdReadMultiBlock() calls SDMMC_SendCommand()

Inside SDMMC_SendCommand() something causes the overrun.

But the function is fairly simple:

HAL_StatusTypeDef SDMMC_SendCommand(SDMMC_TypeDef *SDMMCx, SDMMC_CmdInitTypeDef *Command)
{
  uint32_t tmpreg = 0;
 
  /* Check the parameters */
  assert_param(IS_SDMMC_CMD_INDEX(Command->CmdIndex));
  assert_param(IS_SDMMC_RESPONSE(Command->Response));
  assert_param(IS_SDMMC_WAIT(Command->WaitForInterrupt));
  assert_param(IS_SDMMC_CPSM(Command->CPSM));
 
  /* Set the SDMMC Argument value */
  SDMMCx->ARG = Command->Argument;
 
  /* Set SDMMC command parameters */
  tmpreg |= (uint32_t)(Command->CmdIndex         |\
                       Command->Response         |\
                       Command->WaitForInterrupt |\
                       Command->CPSM);
 
  /* Write to SDMMC CMD register */
  MODIFY_REG(SDMMCx->CMD, CMD_CLEAR_MASK, tmpreg);
 
  return HAL_OK;
}

Everything is an assignment.

MODIFY_REG is a macro:

#define MODIFY_REG(REG, CLEARMASK, SETMASK)  WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))

and WRITE_REG is also macro:

#define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK)))

I'm not sure what else to check. Appreciate any help.

6 REPLIES 6
TDK
Guru

The hardware buffer is limited and needs to be read out quick enough that it doesn't overflow, else you get this error (receive buffer overrun).

Solutions:

  • Disable interrupts while calling HAL_SD_ functions.
  • Slow down the SD clock speed.
  • Enable DMA for SD calls.
If you feel a post has answered your question, please click "Accept as Solution".

The data phase of SDMMC have zero tolerance for you to be wandering off task. The FIFO gives some margin, but not much.

ST has done some very inefficient fixes for unaligned memory which can make things worse.

DMA would enforce harder timing on the transfers, and would be immune to interrupts and task switching.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Here's the thing. It never actually reads the buffer.

The block of code is in HAL_SD_ReadBlocks() but is never executed because before this loop SDMMC_FLAG_RXOVERR is already set.

    /* Poll on SDMMC flags */
    dataremaining = config.DataLength;
    while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DATAEND))
    {
      if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXFIFOHF) && (dataremaining > 0U))
      {
        /* Read data from SDMMC Rx FIFO */
        for(count = 0U; count < 8U; count++)
        {
          data = SDMMC_ReadFIFO(hsd->Instance);
          *tempbuff = (uint8_t)(data & 0xFFU);
          tempbuff++;
          dataremaining--;
          *tempbuff = (uint8_t)((data >> 8U) & 0xFFU);
          tempbuff++;
          dataremaining--;
          *tempbuff = (uint8_t)((data >> 16U) & 0xFFU);
          tempbuff++;
          dataremaining--;
          *tempbuff = (uint8_t)((data >> 24U) & 0xFFU);
          tempbuff++;
          dataremaining--;
        }
      }

That said:

I have wrapped the call to HAL_SD_ReadBlocks() like this:

   __disable_irq();
   sd_res = HAL_SD_ReadBlocks(&hsd1, Buffer_Block_Rx, WR_ADDR, NUM_BLOCKS, 0xffff);
   __enable_irq();

I've lowered the clock from 24MHz to 6MHz. Then I replaced HAL_SD_ReadBlocks() with HAL_SD_ReadBlocks_DMA() and I was able to get HAL_OK returned.

I went down this path because I was trying to use FATFS. . Now I need to see if I can make the FATFS code use DMA as well.

Thanks. If you check my comment to @TDK​ I detailed out what I did. And using DMA (at least) returned a non-error.

The buffer doesn't need to be read in order for the buffer to overflow. The buffer is populated by hardware. If the software doesn't start reading it out fast enough, it overflows.

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

Great info. Thanks! Need to troubleshoot the FAT layer now that I know the SD card is working (although I need to test a write)