cancel
Showing results for 
Search instead for 
Did you mean: 

Possible HAL Bug with SDMMC Init clock speeds in HAL_SD_InitCard

Michael_GetElectronic
Associate III

Possible Bug in HAL_SD_InitCard 

Hello wonderful STM community!

I have identified a possible bug in the HAL Layer for the SDMMC peripheral. First time filing a bug report so please let me know if I miss anything import or if I'm completely wrong

System Info

MCU: STM32H5

Firmware Package: STM32Cube FW_H5 V1.5.0

Board: Custom

CubeIDE Version:  1.18.1

Please ask if anything else should be included here! 

Background

For a (u)SD to init it needs the clock speed to be slowed down to 400 kHz or lower, init commands and are then sent before the clock is then taken back up to speed. See this electrical engineering post for a good explanation and further reading.

Symptoms 

uSD does not init correctly and does not return card info 

Cause 

In the file stm32h5xx_hal_sd.c (under HAL Drivers) and the function:

HAL_StatusTypeDef HAL_SD_InitCard(SD_HandleTypeDef *hsd)

There are two relevant lines:

Line 494:

  Init.ClockDiv = sdmmc_clk / (2U * SD_INIT_FREQ);

Line 519:

sdmmc_clk = sdmmc_clk / (2U * Init.ClockDiv);

In Line 494 the division will round down which can result in a clockDiv that will clock the SD slightly above the required 400 kHz. See calculations bellow:

sdmmc_clk = 3000000 (3 MHz)
SD_INIT_FREQ = 400000 (400 kHz)

Init.ClockDiv = 3000000 (3 MHz) / (2U * 400000 (400 kHz));
Init.ClockDiv = 3.75 // This will be rounded down to 3

sdmmc_clk = 3000000/ (2U * 3);
sdmmc_clk = 500000 (500 kHz) // Greater then SD_INIT_FREQ of 400 kHz

// If we use the actual ClockDiv of 3.75:

sdmmc_clk = 3000000/ (2U * 3.75);
sdmmc_clk = 400000 (400 kHz) // Matches SD_INIT_FREQ of 400 kHz

Conditions to Replicate

Set:

 sdmmc_clk % 400000 != 0

Workaround 

Set:

 

 sdmmc_clk % 400000 == 0

 

Proposed Solution 

if (sdmmc_clk % SD_INIT_FREQ != 0)
   Init.ClockDiv = sdmmc_clk / (2U * SD_INIT_FREQ) + 1;
else:
   Init.ClockDiv = sdmmc_clk / (2U * SD_INIT_FREQ)

If the clk can't be divided down to 400 kHz with a clockDiv, divide it down as close as possible then to insure the result frequency will be less then 400 kHz add one to the clockDiv so that the sdmmc is clocked down bellow 400 kHz .

If it can be divided down to exactly 400 kHz (preferred) then do so.  

Footnote

Again, I'm a mere second year computer engineer so I might be completely wrong with the above so please bare with me and provide constructive feedback. 

Cheers,
Michael 

 

1 ACCEPTED SOLUTION

Accepted Solutions
GAA
ST Employee

Hello Michael,

Good catch! Indeed, the initialization card in the previous version cannot proceed with the sequence initialization for frequencies below or equal to 3 MHz. Therefore, we first need to check if the frequency is below SD_INIT_FREQ.

In this condition, the clock divider should be set to 0. Otherwise, it should be calculated as:

Init.ClockDiv = (sdmmc_clk / (2U * SD_INIT_FREQ)) + 1

 

The logic can be expressed as:

 

  if (sdmmc_clk = < SD_INIT_FREQ )
  {
    Init.ClockDiv = 0U;
  }
  else
  {
    Init.ClockDiv = (sdmmc_clk / (2U * SD_INIT_FREQ)) + 1;
  }


Br, 
Ahmed 

View solution in original post

2 REPLIES 2
GAA
ST Employee

Hello Michael,

Good catch! Indeed, the initialization card in the previous version cannot proceed with the sequence initialization for frequencies below or equal to 3 MHz. Therefore, we first need to check if the frequency is below SD_INIT_FREQ.

In this condition, the clock divider should be set to 0. Otherwise, it should be calculated as:

Init.ClockDiv = (sdmmc_clk / (2U * SD_INIT_FREQ)) + 1

 

The logic can be expressed as:

 

  if (sdmmc_clk = < SD_INIT_FREQ )
  {
    Init.ClockDiv = 0U;
  }
  else
  {
    Init.ClockDiv = (sdmmc_clk / (2U * SD_INIT_FREQ)) + 1;
  }


Br, 
Ahmed 

AScha.3
Super User

Hi,

uSD does not init correctly and does not return card info 

yea, this is typical a hardware problem. Not a HAL problem.

The SD-card (every...) can work on this sdmmc interface at 50MHz clock.

And the sdmmc module doing the init for the card, typical at 400kHz itself.

So the (hardware) critical point is: after first communication, the clk speed is switched to full speed,

for the data transfer - This is where the wheat is separated from the chaff.

If the signal has bad CRC at this speed, nothing happens, just error and finish.

+

Just for H563 (i have this) : it worked good with pin setting to medium speed and pullups ON, on all lines;

and at first only use 1bit mode, its more tolerant to reflections etc on the line.

Try...

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