Solution for STM32-F7 SDMMC in 4-Bit wide bus mode issue
- December 11, 2023
- 2 replies
- 3812 views
Hey,
I'm working on a project to connect my UHF RFID reader with ProfiNet via the NSHIELD 52-RE extension board. I chose the NUCLEO-F767ZI board for the development because it has an Ethernet interface, which I'm using for the web interface. The content for the web interface is stored on an SD Card connected to the SDMMC1 port of the F7 board. The issue I found is rooted in how the STM32CubeMX generates the code for the project, particularly for the SD card driver. The generated code contains a HAL_SD_Init with an SDMMC_BUS_WIDE_4B setting in the SD_HandleTypeDef.Init structure, which is OK so far. In the next step, the code calls the HAL_SD_ConfigWideBusOperation, which is when the issue appears. The SD_WideBus_Enable routine, which the HAL_SD_ConfigWideBusOperation calls, is reading the SCR register of the SD-Card, and this will fail because the card is initialized in 4-bit bus mode. I have this little workaround, which is somewhat annoying, but it works for now.
this is the original generated code from the STM32CubeMX:
hsd1.Instance = SDMMC1;
hsd1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
hsd1.Init.ClockBypass = SDMMC_CLOCK_BYPASS_DISABLE;
hsd1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
hsd1.Init.BusWide = SDMMC_BUS_WIDE_4B;
hsd1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
hsd1.Init.ClockDiv = 0;
if (HAL_SD_Init(&hsd1) != HAL_OK)
{
Error_Handler();
}
if (HAL_SD_ConfigWideBusOperation(&hsd1, SDMMC_BUS_WIDE_4B) != HAL_OK)
{
Error_Handler();
}
here is my workaround:
hsd1.Instance = SDMMC1;
hsd1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
hsd1.Init.ClockBypass = SDMMC_CLOCK_BYPASS_DISABLE;
hsd1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
hsd1.Init.BusWide = SDMMC_BUS_WIDE_4B;
hsd1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
hsd1.Init.ClockDiv = 0;
if (HAL_SD_Init(&hsd1) != HAL_OK)
{
Error_Handler();
}
// correcting SD-Card clock divider
if (HAL_SD_InitCard_FIX(&hsd1) != HAL_OK)
{
Error_Handler();
}
if (HAL_SD_ConfigWideBusOperation(&hsd1, SDMMC_BUS_WIDE_4B) != HAL_OK)
{
Error_Handler();
}
this function has to be added at the end between USER CODE BEGIN 1 and USER CODE END 1:
/* USER CODE BEGIN 1 */
HAL_StatusTypeDef HAL_SD_InitCard_FIX(SD_HandleTypeDef *hsd)
{
HAL_StatusTypeDef status;
SD_InitTypeDef Init;
/* Default SDMMC peripheral configuration for SD card initialization */
Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
Init.ClockBypass = SDMMC_CLOCK_BYPASS_DISABLE;
Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
Init.BusWide = SDMMC_BUS_WIDE_1B;
Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
Init.ClockDiv = SDMMC_INIT_CLK_DIV;
/* Initialize SDMMC peripheral interface with default configuration */
status = SDMMC_Init(hsd->Instance, Init);
if (status != HAL_OK)
{
return HAL_ERROR;
}
return HAL_OK;
}
/* USER CODE END 1 */
The function declaration is added to the end of the sdmmc.h:
/* USER CODE BEGIN Prototypes */
HAL_StatusTypeDef HAL_SD_InitCard_FIX(SD_HandleTypeDef *hsd);
/* USER CODE END Prototypes */
Since STM32CubeMX will overwrite everything outside of the "USER CODE" definitions, the view lines for the fix have to be copied every time the code is generated by STM32CubeMX. I wish there were a better way to do this, but until the makers of STM32CubeMX decide to change the code regarding this issue, I have to copy the code.
However, I posted this in hope to safe others some time in their projects.
and never forget:
"Always be yourself. Unless you can be a pirate. Then always be a pirate."
