cancel
Showing results for 
Search instead for 
Did you mean: 

SDIO interface not working in 4Bits with STM32F4 Firmware Package

ANauz.1
Senior

Hello,

Working on an STM32F412 µC, with the last F4 firmware package ans last MX

When configuring to use SDIO with 1Bit interface, everything works fine. But when configuring to use a 4bits interface, there is an error 

In BSP_SD_Init(); there is an error when calling HAL_SD_ConfigWideBusOperation()

I have tried to make it work with FreeRTOS and FreeRTOS-Plus-FAT and... it work.

As I do not always want to have project with FreeRTOS, would it be possible to ST to integrate working SD initialisation in 4 bit mode.

Reading the following:

https://community.st.com/t5/stm32-mcus-products/sdio-4-bit-mode-with-stm32cubemx/td-p/406139

https://stackoverflow.com/questions/72984923/stm32f746-sd-card-crc-failing-in-4-bit-mode-but-working-fine-in-1-bit-mode

It seems that the problem is known for a long time, with no solution provided by ST. ST should at least integrate the evolution provide by FreeRTOS to make STM32 firmware package at least work in every mode possible!

It seems unbelievable to me that STM32 FW package do not integrate corrections of problems that are knows for years

Thank you

Regards

 

 

 

 

1 ACCEPTED SOLUTION

Accepted Solutions
FBL
ST Employee

Hello @ANauz.1 ,

Thank you for your feedback. The issue is tracked since a while (155983) I will keep you updated once the fix is published. For now,  in case we choose SDIO Mode option "SD 4 bits Wide bus" from Cubemx "Pinout & Configuration" interface :

  1. Step 1 - hsd.Init.BusWide set to SDIO_BUS_WIDE_1B just for initialization.
  2. Step 2 - Call HAL_SD_Init(&hsd)
  3. Step 3 - Call HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B)
static void MX_SDIO_SD_Init(void)
{

  /* USER CODE BEGIN SDIO_Init 0 */

  /* USER CODE END SDIO_Init 0 */

  /* USER CODE BEGIN SDIO_Init 1 */

  /* USER CODE END SDIO_Init 1 */
  hsd.Instance = SDIO;
  hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
  hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;
  hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
  hsd.Init.BusWide = SDIO_BUS_WIDE_1B;
  hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
  hsd.Init.ClockDiv = 0;
  if (HAL_SD_Init(&hsd) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SDIO_Init 2 */

  /* USER CODE END SDIO_Init 2 */

}

 I hope this helps!

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

View solution in original post

9 REPLIES 9
FBL
ST Employee

Hello @ANauz.1 ,

Thank you for your feedback. The issue is tracked since a while (155983) I will keep you updated once the fix is published. For now,  in case we choose SDIO Mode option "SD 4 bits Wide bus" from Cubemx "Pinout & Configuration" interface :

  1. Step 1 - hsd.Init.BusWide set to SDIO_BUS_WIDE_1B just for initialization.
  2. Step 2 - Call HAL_SD_Init(&hsd)
  3. Step 3 - Call HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B)
static void MX_SDIO_SD_Init(void)
{

  /* USER CODE BEGIN SDIO_Init 0 */

  /* USER CODE END SDIO_Init 0 */

  /* USER CODE BEGIN SDIO_Init 1 */

  /* USER CODE END SDIO_Init 1 */
  hsd.Instance = SDIO;
  hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
  hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;
  hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
  hsd.Init.BusWide = SDIO_BUS_WIDE_1B;
  hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
  hsd.Init.ClockDiv = 0;
  if (HAL_SD_Init(&hsd) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SDIO_Init 2 */

  /* USER CODE END SDIO_Init 2 */

}

 I hope this helps!

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

It has been reported at least in January 2015:

https://community.st.com/t5/stm32-mcus-products/sdio-4bit-mode-fatfs-and-stm32cubemx-on-stm32f401-discovery/m-p/442538/highlight/true#M139949

A quote from the next post of that ST employee in that topic is just hilarious:

"STM32CubeMX team are aware of this limitation. Just keep an eye out for the next updates!"

Yeah, just keep an eye out... for 9+ years!

hello @Piranha  ,

i tried using sdio ...many times, now on H563-nucleo board. not working, with setting from Cube.

no surprise for you, i suppose.  9 y are a long time in computer business, new young people now working on this.

so they make things "better", restricting, what silly user can choose : on H563, sdio setting force (no choice) to high speed and no-pull setting of port pins, what is just wrong. I tried, setting to pullup and medium speed -> works.

setting from STM / Cube not working.

AScha3_0-1697056612321.png

and the Azure/rtos + Filex (no more Fatfs to choose ! ) NOT working at all.

I killed Filex, copied (new) Fatfs by Mr. Chang in. this works. with pullup on + medium speed, not with STM settings.

So now i more and more understand, your statements about mental constitution of the programmers involved.

 

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

I also cannot understand how it is possible that the issue is around since 2015 and you still didn't manage to solve it.

The workaroud seems to work, but actually the code you add should go into 

/* USER CODE BEGIN SDIO_Init 2 */
-> Code Here
/* USER CODE END SDIO_Init_2 */

 And look as follows

static void MX_SDIO_SD_Init(void)
{

  /* USER CODE BEGIN SDIO_Init 0 */

  /* USER CODE END SDIO_Init 0 */

  /* USER CODE BEGIN SDIO_Init 1 */

  /* USER CODE END SDIO_Init 1 */
  hsd.Instance = SDIO;
  hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
  hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;
  hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
  hsd.Init.BusWide = SDIO_BUS_WIDE_1B;
  hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
  hsd.Init.ClockDiv = 0;
  
  /* USER CODE BEGIN SDIO_Init 2 */
if (HAL_SD_Init(&hsd) != HAL_OK) 
{
Error_Handler();
}
if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK)
{
Error_Handler();
} /* USER CODE END SDIO_Init 2 */ }

I configured the .ioc file to have the SDIO in 1bit mode. 

Make sure that the additional pins required for 4bit mode, namely uSD_D1, uSD_D2, uSD_D3 have a label and are corretly initialized (they should appear in GPIO -> Single Mapped Signals), although they appear in yellow in the pinout in CubeMX (since they are not linked to the SDIO peripheral in the .ioc) - See picture (for STM32F469I-DISCO)

Capture.PNG

 

 

tizdipietro
Associate III

I spent many hours fixing this issue, you can find a working solution, SDIO 4bit mode with DMA at 12Mhz with detailed instructions on how to set up everything here GitHub Repo

I suggest you carefully read the readme in the repo, everything is explained there.

just what you should add: GPIO settings !

set all pins : pullup on;

and speed : medium or high (depends on chip, to high speed makes reflections/ringing; so lowest possible speed setting is best.)

and clock: (i always use) 100MHz , div 1 ; (gives 50M , typical for standard sd-cards)

and fatfs setting : ( i use) long filenames enable; exfat enable ; ( most new >16GB cards are exfat formatted 🙂 )

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

@FBL 

I am also facing the same problem, and I have not received any specific answers for it yet. However, my system is working fine with 1-bit SDIO. I am using the Discovery board of STM32F407VGT6 (DMSTF4BB - link). Additionally, I have noticed one more thing: even when using a 1-bit SDIO configuration, we still need to connect all four data buses (D0, D1, D2, D3) along with SDIO_cmd and SDIO_CK. Also, include the SDIO detect (GPIO input) on PB15 in my case.

Embedded_Engineer_0-1701077523049.jpeg

 

apart from this I am also facing issue as " 

I am currently working on a project that involves integrating USB functionality for data transfer and data logging on an STM32F407VG micro-controller. Specifically, I want to log data files on an SD card and enable the user to download these logged files from the SD card via USB. Additionally, I'd like to allow users to copy files from their PC to the SD card via USB, all through the STM32F407VG using the SDIO communication protocol.

I'm facing a challenge in making the USB_OTG_FS (On-The-Go Full Speed USB) and the SD card (using FatFS) work together seamlessly. I would greatly appreciate your guidance and any insights you might have on how to achieve this integration.
"

 

 

 

 

Here is my sample code:

#include "usbd_storage_if.h"

extern SD_HandleTypeDef hsd;

#define STORAGE_LUN_NBR 1
#define STORAGE_BLK_NBR 0x10000
#define STORAGE_BLK_SIZ 0x200

const int8_t STORAGE_Inquirydata_FS[] = {

0x00,
0x80,
0x02,
0x02,
(STANDARD_INQUIRY_DATA_LEN - 5),
0x00,
0x00,
0x00,
'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ', /* Manufacturer : 8 bytes */
'P', 'r', 'o', 'd', 'u', 'c', 't', ' ', /* Product : 16 Bytes */
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
'0', '.', '0' ,'1' /* Version : 4 Bytes */
};


static int8_t STORAGE_Init_FS(uint8_t lun);
static int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size);
static int8_t STORAGE_IsReady_FS(uint8_t lun);
static int8_t STORAGE_IsWriteProtected_FS(uint8_t lun);
static int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);
static int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);
static int8_t STORAGE_GetMaxLun_FS(void);

 

USBD_StorageTypeDef USBD_Storage_Interface_fops_FS =
{
STORAGE_Init_FS,
STORAGE_GetCapacity_FS,
STORAGE_IsReady_FS,
STORAGE_IsWriteProtected_FS,
STORAGE_Read_FS,
STORAGE_Write_FS,
STORAGE_GetMaxLun_FS,
(int8_t *)STORAGE_Inquirydata_FS
};

int8_t STORAGE_Init_FS(uint8_t lun)
{

return (USBD_OK);

}


int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size)
{

HAL_SD_CardInfoTypeDef info;
int8_t ret = -1;

HAL_SD_GetCardInfo(&hsd, &info);

*block_num = info.LogBlockNbr - 1;
*block_size = info.LogBlockSize;
ret = 0;
return ret;


}


int8_t STORAGE_IsReady_FS(uint8_t lun)
{

return (USBD_OK);

}

int8_t STORAGE_IsWriteProtected_FS(uint8_t lun)
{

return (USBD_OK);

}


int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{

int8_t ret = -1;

HAL_SD_ReadBlocks(&hsd, buf, blk_addr, blk_len, HAL_MAX_DELAY);

/* Wait until SD card is ready to use for new operation */
while (HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER){}
ret = 0;
return ret;

}

int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{

int8_t ret = -1;

HAL_SD_WriteBlocks(&hsd, buf, blk_addr, blk_len, HAL_MAX_DELAY);

while (HAL_SD_GetCardState(&hsd) != HAL_SD_CARD_TRANSFER){}
ret = 0;
return ret;

}

int8_t STORAGE_GetMaxLun_FS(void)
{

return (STORAGE_LUN_NBR - 1);

}

please go through my code (atteched below) and let me know what to do? and how to integrate USB and SD card simultaneously?


my observation: I took two STM32F407VGT6 microcontrollers and connect them the to same SDIO
source it(setup) is not working when both boards are powered on but when USB and FATFS works fine seperatly the problem is in two pins (PC10 and PC11) D2 & D3 please give me solution for the following:

  1. How do I configure USB_OTG_FS as a USB Device in STM32CubeMX or other development tools?
  2. What are the essential initialization and setup steps for using the USB_OTG_FS as a USB Device alongside the FatFS library for SD card communication?
  3. Are there any sample code snippets or project examples that demonstrate this integration?
  4. What should I be mindful of when managing the data transfer between the USB and SD card to avoid conflicts or data corruption?
Andrew Androsow
Associate II

Hello! I had the similar problem. My app (there is not any  FreeRTOS ) works well in 1-bit mode, but in -bit mode not working at all (to be honest - sometimes with very old 1Gb SD card). The wires from SD card to STM32 have  length roughly 50 millimeters. I tried a chunk of  old interface cable from old HDD, but I have not success. Finally I got several simple wires and connect 50Ohm resistors next to the SDIO Card slot in series with each wire (exclude Vss and GND). The interface started works well in 4-bi mode.

MLiak.1
Associate II

Hello!

1. uSD cards ALWAYS initialize with 1-bit wide bus. Even if card will work in 4-bit wide bus mode.

2.This initialization error (hsd.Init.BusWide = SDIO_BUS_WIDE_4B) has been around from year to year (for more than 4 years!), at least in the F4xx series.

So...

I manually edited this wrong line in the initialization code for a very long time, and in the end I found a fairly elegant solution.

The generated file "sdio.c" has two sections for user code:

 

/* USER CODE BEGIN SDIO_Init 1 */ ... /* USER CODE END SDIO_Init 1 */

 

and

 

/* USER CODE BEGIN SDIO_Init 2 */ ... /* USER CODE END SDIO_Init 2 */

 

After the initialization code has been generated, copy the code to the section

/* USER CODE BEGIN SDIO_Init 1 */, specify the correct bus width for initialization (hsd.Init.BusWide = SDIO_BUS_WIDE_1B;), and add conditional compilation directives.

Result, for example:

 

 

   /* USER CODE BEGIN SDIO_Init 1 */

   hsd.Instance = SDIO;
   hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
   hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;
   hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
   // Corrected bus wide for initialization
   hsd.Init.BusWide = SDIO_BUS_WIDE_1B;
   hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
   hsd.Init.ClockDiv = 0;
#define ONLY_USER_INIT // Tired of editing the code every time you change, the line "hsd.Init.BusWide = SDIO_BUS_WIDE_4B;"
#ifndef ONLY_USER_INIT

   /* USER CODE END SDIO_Init 1 */

   // Originally generated code
   hsd.Instance = SDIO;
   hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
   hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;
   hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
   hsd.Init.BusWide = SDIO_BUS_WIDE_4B;
   hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
   hsd.Init.ClockDiv = 0;

   /* USER CODE BEGIN SDIO_Init 2 */

#endif //ifndef ONLY_USER_INIT

   /* USER CODE END SDIO_Init 2 */

 

 

In the future, when you change anything in the configurator, only the code between the lines

/* USER CODE END SDIO_Init 1 */ and /* USER CODE BEGIN SDIO_Init 2 */ will be changed, and this section of code is excluded from compilation.