cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 SDIO conflict with debuger opperations

Julien Bouille
Associate III

Hi everybody,

i m facing issues interfacing High Speed SD memory cards.

With low speed type SD card everything look to work well. But when i use fast cards, i got error reads.

The thing is that only appen if the debug is running. Without the debuger attached to my board no problemes appen when using High speed sd cards.

Any one understand what could make the debugger interfer with the application ? Is there somekind of blocking events or interrupt or clock instability because of it that could make the sd card crash ?

tanks.

23 REPLIES 23
Julien Bouille
Associate III

STM32F446RE on discovery board.

Even with lower clock rates the SDHC card refuse to work properly. Still no issues with the lowCost/lowSpeed one.

It is the function f_read that come back with a "Low level IO error" ...

After some debuging i ve discover a variable associate in timeout control that was set to zero in a unexpect way as it was set to some value in the beginin of the function and then was not writed anymore in it. So i m wondering if something is not overflowing on it. But why i should do it with some cards and not others ???

Julien Bouille
Associate III
/**
  * @brief  Reads block(s) from a specified address in a card. The Data transfer 
  *         is managed by polling mode.
  * @note   This API should be followed by a check on the card state through
  *         HAL_SD_GetCardState().
  * @param  hsd Pointer to SD handle
  * @param  pData pointer to the buffer that will contain the received data
  * @param  BlockAdd Block Address from where data is to be read 
  * @param  NumberOfBlocks Number of SD blocks to read
  * @param  Timeout Specify timeout value
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks, uint32_t Timeout)
{
  SDIO_DataInitTypeDef config;
  uint32_t errorstate = HAL_SD_ERROR_NONE;
  uint32_t tickstart = HAL_GetTick();
  uint32_t count = 0U, *tempbuff = (uint32_t *)pData;
  
  if(NULL == pData)
  {
    hsd->ErrorCode |= HAL_SD_ERROR_PARAM;
    return HAL_ERROR;
  }
 
  if(hsd->State == HAL_SD_STATE_READY)
  {
    hsd->ErrorCode = HAL_DMA_ERROR_NONE;
    
    if((BlockAdd + NumberOfBlocks) > (hsd->SdCard.LogBlockNbr))
    {
      hsd->ErrorCode |= HAL_SD_ERROR_ADDR_OUT_OF_RANGE;
      return HAL_ERROR;
    }
    
    hsd->State = HAL_SD_STATE_BUSY;
    
    /* Initialize data control register */
    hsd->Instance->DCTRL = 0U;
    
    if(hsd->SdCard.CardType != CARD_SDHC_SDXC)
    {
      BlockAdd *= 512U;
    }
      
    /* Set Block Size for Card */
    errorstate = SDMMC_CmdBlockLength(hsd->Instance, BLOCKSIZE);
    if(errorstate != HAL_SD_ERROR_NONE)
    {
      /* Clear all the static flags */
      __HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);      
      hsd->ErrorCode |= errorstate;
      hsd->State = HAL_SD_STATE_READY;
      return HAL_ERROR;
    }
    
    /* Configure the SD DPSM (Data Path State Machine) */
    config.DataTimeOut   = SDMMC_DATATIMEOUT;
    config.DataLength    = NumberOfBlocks * BLOCKSIZE;
    config.DataBlockSize = SDIO_DATABLOCK_SIZE_512B;
    config.TransferDir   = SDIO_TRANSFER_DIR_TO_SDIO;
    config.TransferMode  = SDIO_TRANSFER_MODE_BLOCK;
    config.DPSM          = SDIO_DPSM_ENABLE;
    SDIO_ConfigData(hsd->Instance, &config);
    
    /* Read block(s) in polling mode */
    if(NumberOfBlocks > 1U)
    {
      hsd->Context = SD_CONTEXT_READ_MULTIPLE_BLOCK;
      
      /* Read Multi Block command */ 
      errorstate = SDMMC_CmdReadMultiBlock(hsd->Instance, BlockAdd);
    }
    else
    {
      hsd->Context = SD_CONTEXT_READ_SINGLE_BLOCK;
      
      /* Read Single Block command */
      errorstate = SDMMC_CmdReadSingleBlock(hsd->Instance, BlockAdd);
    }
    if(errorstate != HAL_SD_ERROR_NONE)
    {
      /* Clear all the static flags */
      __HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
      hsd->ErrorCode |= errorstate;
      hsd->State = HAL_SD_STATE_READY;
      return HAL_ERROR;
    }
      
    /* Poll on SDIO flags */
#ifdef SDIO_STA_STBITERR
    while(!__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DATAEND | SDIO_STA_STBITERR))
#else /* SDIO_STA_STBITERR not defined */
    while(!__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DATAEND))
#endif /* SDIO_STA_STBITERR */
    {
      if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_RXFIFOHF))
      {
        /* Read data from SDIO Rx FIFO */
        for(count = 0U; count < 8U; count++)
        {
          *(tempbuff + count) = SDIO_ReadFIFO(hsd->Instance);
        }
        tempbuff += 8U;
      }
      
      if((Timeout == 0U)||((HAL_GetTick()-tickstart) >=  Timeout))
      {
        /* Clear all the static flags */
        __HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
        hsd->ErrorCode |= HAL_SD_ERROR_TIMEOUT;
        hsd->State= HAL_SD_STATE_READY;
        return HAL_TIMEOUT;
      }
    }
    
    /* Send stop transmission command in case of multiblock read */
    if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_DATAEND) && (NumberOfBlocks > 1U))
    {    
      if(hsd->SdCard.CardType != CARD_SECURED)
      {
        /* Send stop transmission command */
        errorstate = SDMMC_CmdStopTransfer(hsd->Instance);
        if(errorstate != HAL_SD_ERROR_NONE)
        {
          /* Clear all the static flags */
          __HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
          hsd->ErrorCode |= errorstate;
          hsd->State = HAL_SD_STATE_READY;
          return HAL_ERROR;
        }
      }
    }
    
    /* Get error state */
    if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_DTIMEOUT))
    {
      /* Clear all the static flags */
      __HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
      hsd->ErrorCode |= HAL_SD_ERROR_DATA_TIMEOUT;
      hsd->State = HAL_SD_STATE_READY;
      return HAL_ERROR;
    }
    else if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_DCRCFAIL))
    {
      /* Clear all the static flags */
      __HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
      hsd->ErrorCode |= HAL_SD_ERROR_DATA_CRC_FAIL;
      hsd->State = HAL_SD_STATE_READY;
      return HAL_ERROR;
    }
    else if(__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_RXOVERR))
    {
      /* Clear all the static flags */
      __HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
      hsd->ErrorCode |= HAL_SD_ERROR_RX_OVERRUN;
      hsd->State = HAL_SD_STATE_READY;
      return HAL_ERROR;
    }
    
    volatile static uint32_t time;
 
    /* Empty FIFO if there is still any data */
    while ((__HAL_SD_GET_FLAG(hsd, SDIO_FLAG_RXDAVL)))
    {
      *tempbuff = SDIO_ReadFIFO(hsd->Instance);
      tempbuff++;
      
      time = HAL_GetTick();
 
      if((Timeout == 0U)) //||((time-tickstart) >=  Timeout))
      {
        // Clear all the static flags
        __HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);        
        hsd->ErrorCode |= HAL_SD_ERROR_TIMEOUT;
        hsd->State= HAL_SD_STATE_READY;
        return HAL_ERROR;
      }
    }
    
    /* Clear all the static flags */
    __HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_FLAGS);
    
    hsd->State = HAL_SD_STATE_READY;
    
    return HAL_OK;
  }
  else
  {
    hsd->ErrorCode |= HAL_SD_ERROR_BUSY;
    return HAL_ERROR;
  }
}

Line 171... the timeout is set to 0x7fffffff so it should never append , but it do !

After debuging is saw that the timeout variable was set to zero INSIDE the function in a unexpected way.

.... :frog_face:

Ok, EVAL, DISCOVERY and NUCLEO are different classes of boards.

Is this the board you are using?

https://www.st.com/en/evaluation-tools/nucleo-f446re.html

In order to debug SDIO interaction you need to do it at the low level interfaces, not the top level application. I would recommend looking at the ErrorCode values in the SDIO structure in the read/write routines in the DISKIO layer, and perhaps instrumenting those routines to output a message if the read/write fails. Failure is often cascading, there may have been a failure prior to the one that ultimately gets propagated to f_read()

Whose debugger/toolchain are you using?

Assume the use of standard SDIO pins PC[8..12] and PD2, do you have GPIO for a card detect?

I would expect the EVAL board code to be a workable starting point for a port to the NUCLEO board

STM32Cube_FW_F4_V1.21.0\Drivers\BSP\STM32446E_EVAL\stm32446e_eval_sd.c

STM32Cube_FW_F4_V1.21.0\Projects\STM32446E_EVAL\Applications\FatFs\FatFs_uSD

SDHC and SDXC cards have different expectations and commands, depending on the driver code more aggressive clocking may be selected. They should be capable of 50 MHz operation, but ST frequently clocks at around 24 MHz, but this depends on the SDCLK and PLL settings.

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

I use Atollic sutdio with their free compiler.

The clock is running at 24MHz yes.

The function in his deepest level crash where i said in the code i post up

Julien Bouille
Associate III

The code is based on the demo code and work... but not with the SDHC

Julien Bouille
Associate III

i will tchek sdio errors codes..

Sorry, didn't see the code post. Still this looks like POLLED code.

Not sure if flow-control works on the F446, was definitely a problem on F429, would recommend disabling. See BSP_SD_Init() or HAL_SD_Init()

Seen other reports of the timeout code being broken, and this code potentially exceeding buffer bounds. Also complaints about GCC and the polling loop.

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

I got a error with the CRC... so i guess it mean a hardware probleme...

https://community.st.com/s/question/0D50X00009XkW7XSAV/fmount-fails-using-stm32l4-w-sdmmc

In disk_write() add instrumentation to exit path

 

 if (res != RES_OK)

   printf("W %5d %2d (%08X)\n", sector, count, uSdHandle.ErrorCode);

Could do similar things on disk_read too.

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

The strange think is that even if lower clock speed the same error still occure