2020-09-23 02:11 PM
Hello,
sometimes the initialization of the SD card fails in function SD_FindSCR.
There seems to be a timing problem between SDMMC_ConfigData and SDMMC_CmdSendSCR because send data starts before SDMMC is ready.
With an additional wait function for status bits it works for me (see code below).
I can't find an exact timing specification between SDMMC process steps (waiting for status bits or time) in hardware documentation (STM32F777).
But it seems that there are some actions required to improve the reliabilty of the SDMMC HAL driver functions in STM32F7xx_HAL_SD.C
static uint32_t SD_FindSCR(SD_HandleTypeDef *hsd, uint32_t *pSCR)
{
SDMMC_DataInitTypeDef config;
uint32_t errorstate;
uint32_t tickstart = HAL_GetTick();
uint32_t index = 0U;
uint32_t tempscr[2U] = {0U, 0U};
uint32_t *scr = pSCR;
/* Set Block Size To 8 Bytes */
errorstate = SDMMC_CmdBlockLength(hsd->Instance, 8U);
if(errorstate != HAL_SD_ERROR_NONE)
{
return errorstate;
}
/* Send CMD55 APP_CMD with argument as card's RCA */
errorstate = SDMMC_CmdAppCommand(hsd->Instance, (uint32_t)((hsd->SdCard.RelCardAdd) << 16U));
if(errorstate != HAL_SD_ERROR_NONE)
{
return errorstate;
}
config.DataTimeOut = SDMMC_DATATIMEOUT;
config.DataLength = 8U;
config.DataBlockSize = SDMMC_DATABLOCK_SIZE_8B;
config.TransferDir = SDMMC_TRANSFER_DIR_TO_SDMMC;
config.TransferMode = SDMMC_TRANSFER_MODE_BLOCK;
config.DPSM = SDMMC_DPSM_ENABLE;
(void)SDMMC_ConfigData(hsd->Instance, &config);
//////////////////////////////////////////////////////////////////////////////
// STA register is 0x00000000 immediately after configuration -> not ready yet
while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXACT))
{
if((HAL_GetTick() - tickstart) >= SDMMC_DATATIMEOUT)
{
return HAL_SD_ERROR_TIMEOUT;
}
}
// STA register is 0x00082000 now -> ready to receive data
// (Bit 13 RXACT: Data receive in progress)
// (Bit 19 RXFIFOE: Receive FIFO empty)
// it takes 32 system clock periods (system clock 216Mhz)
//////////////////////////////////////////////////////////////////////////////
/* Send ACMD51 SD_APP_SEND_SCR with argument as 0 */
errorstate = SDMMC_CmdSendSCR(hsd->Instance);
if(errorstate != HAL_SD_ERROR_NONE)
{
return errorstate;
}
while(!__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT | SDMMC_FLAG_DBCKEND))
{
if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXDAVL))
{
*(tempscr + index) = SDMMC_ReadFIFO(hsd->Instance);
index++;
}
if((HAL_GetTick() - tickstart) >= SDMMC_DATATIMEOUT)
{
return HAL_SD_ERROR_TIMEOUT;
}
}
if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DTIMEOUT))
{
__HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DTIMEOUT);
return HAL_SD_ERROR_DATA_TIMEOUT;
}
else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_DCRCFAIL))
{
__HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DCRCFAIL);
return HAL_SD_ERROR_DATA_CRC_FAIL;
}
else if(__HAL_SD_GET_FLAG(hsd, SDMMC_FLAG_RXOVERR))
{
__HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_RXOVERR);
return HAL_SD_ERROR_RX_OVERRUN;
}
else
{
/* No error flag set */
/* Clear all the static flags */
__HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS);
*scr = (((tempscr[1] & SDMMC_0TO7BITS) << 24) | ((tempscr[1] & SDMMC_8TO15BITS) << 8) |\
((tempscr[1] & SDMMC_16TO23BITS) >> 8) | ((tempscr[1] & SDMMC_24TO31BITS) >> 24));
scr++;
*scr = (((tempscr[0] & SDMMC_0TO7BITS) << 24) | ((tempscr[0] & SDMMC_8TO15BITS) << 8) |\
((tempscr[0] & SDMMC_16TO23BITS) >> 8) | ((tempscr[0] & SDMMC_24TO31BITS) >> 24));
}
return HAL_SD_ERROR_NONE;
}
2020-12-09 07:44 PM
It is ST's Fault. I could say 100% certain of it.
this kind of error %100 cause of : U need a LOW SPEED CLOCK to initialize the SD Card, include its bus-width i.e 4bit or 1bit
ST's bug is , in generated-code it first set the clk speed to high speed (10-25MHz) BEFORE the bus-width change.
but many SD Card Dose NOT support that.
you HAVE TO change the bus-width to 4bit WHILE the clock speed remain in LOW SPEED i.e 400KHz ,but I prefer 100KHz.
so u need to do something
u can set the clock divider in CUBEMX a large Value ,i.e SDMMC.clockDivider=199
than the code generator will let your sdio run in low speed
and AFTER the bus-width change to 4bit operation
U MUST set the
hsd1.Init.ClockDiv = 0;
(void) SDMMC_Init(hsd1.Instance, hsd1.Init);
manual change the clock speed to high speed.
it's a weired bug ST should fix it right now
2022-07-05 07:48 AM
@kgai Thank you very much helped, 2022, the error is still relevant.
2023-09-15 01:01 PM
I have the same problem with STM32F411RE. In the HAL library code SD_FindSCR() function returns scr[1] = 0 and scr[2]=0. I have no problem with 1 bit mode, but when I switch to 4 bit I always get error. I have tried setting the divider to 200, 250, and even 300 with no luck. HAL library outputs error when I set to 4 bit mode. Any suggestions?
2023-10-27 05:59 PM
I'm having the same problem on an STM32F411CEU6. Looking at the SD/MMC protocol, I have a hard time believing 0 is a valid value for the SCR register.
@aserbes, I'm not sure how you got to 300 - 255 is the maximum value for the clock divider.
I used 250, which brought the SD CLK down to 190kHz, but still did not get a value.
2023-10-30 08:02 AM
Was there any solution to the SD_FindSCR() error? I am using a clock divider of 200 in 4bit mode on STM32L496 and the function still never returns a value. All works fine in 1 bit mode.
2023-10-30 09:41 AM
Yes, I found this post very helpful: https://community.st.com/t5/stm32cubemx-mcus/stm32l4-sd-stm32cubemx-v5-0-0-sd-clock-speed-during-call-to/td-p/371550
The problem is that some (many?) SD cards don't like being switched to 4-bit mode while running high speed. I'm using SanDisk, so it's not like this problem is limited to no-name cards either. It appears there's nothing in the SD/MMC spec that says retrieving the SCR register must be done at low-speed (400kHz), so I'm not sure we can expect a solution from ST either.
My workaround, per the post I mentioned, is to drop to 400kHz. HAL will automatically switch back up to high-speed soon thereafter, so only one line of code is needed. BSP_SD_Init() is a weak symbol, so I added the following to a bsp_driver_fixup.c file:
#include "bsp_driver_sd.h"
extern SD_HandleTypeDef hsd;
__weak uint8_t BSP_SD_Init(void)
{
uint8_t sd_state = MSD_OK;
if (BSP_SD_IsDetected() != SD_PRESENT) {
return MSD_ERROR;
}
/* HAL SD initialization */
sd_state = HAL_SD_Init(&hsd);
if (sd_state != MSD_OK)
return sd_state;
/* Drop the clock to low sped when changing CKLCR for 4-bit mode
* See https://community.st.com/t5/stm32cubemx-mcus/stm32l4-sd-stm32cubemx-v5-0-0-sd-clock-speed-during-call-to/td-p/371550
* Calling SDIO_Init(), using the same settings as HAL_SD_InitCard(), will work here as well
*/
MODIFY_REG(hsd.Instance->CLKCR, SDIO_CLKCR_WIDBUS_Msk | 0xFFU, SDIO_BUS_WIDE_1B | SDIO_INIT_CLK_DIV);
/* Enable wide operation */
if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK)
sd_state = MSD_ERROR;
return sd_state;
}
I also had to set an SDIOCLK divide factor to get everything working smoothly (x16 worked for me, STMF411, on a breadboard with 150R series resistors to calm the ringing), but that's a separate issue. It's been working well for me so far.