on
2021-09-24
12:17 AM
- edited on
2025-08-21
1:41 AM
by
Laurids_PETERSE
Data logging applications require storing large amounts of data over a period of time. SD cards are a convenient solution for storing data and many STM32 products include the proper hardware interface. Using a standard file system to write data on an SD card ensures that the data is easily accessible on another device or computer. Adding a file system along with an SD card driver is easy to do using the various ST tools available for the STM32 family of microcontrollers.
This article details the process of configuring the SDMMC peripheral for accessing an SD card and configuring the FatFs middleware to create a file system using STM32 and ST toolsets.
Note that this article is also available in video form: STM32 – Creating a file system on an SD card - YouTube
STM32 Discovery kits as well as evaluation boards include an SD card socket. While this example uses the STM32F746G-DISCO board, any other STM32 board with an SD card socket can be used. Ensure appropriate changes are made in the software configuration to accommodate a different target board.
Firstly, we need to create a STM32CubeIDE project where we configure the application to interface with the SD card.
After this is done, the device configuration tool view is open in STM32CubeIDE. From here on, we can configure the MCU to be able to utilize the board's SD card slot.
STM32 MCUs use the SDMMC peripheral to interface to an SD card, we need to configure it before we can write code that uses it. In this article, we also configure DMA access to the SDMMC peripheral to maximize performance.
After adding these requests, the DMA settings panel should look like this:
FatFs is an open-source file system middleware integrated in STM32Cube libraries. It is able to directly utilize the SDMMC peripheral to act as a disk device for the FAT file system. This is also configured through the Device Configuration Tool view.
After the peripheral and middleware configuration is complete, we will also need to modify the clock configuration and certain project settings.
Now that SDMMC and FatFs configuration is complete and the appropriate code is generated, we can start writing user code that accesses the SD card. For the purposes of this article, the code sample below mounts the SD card, create a new FAT file system on it, create a file named "STM32.TXT", and write "STM32 FATFS works great!" to it.
You may copy this snippet into your main.c file - take note of the "/* USER CODE BEGIN x */" markers and place the two sections in the places that these are located in your code.
/* USER CODE BEGIN 1 */
FRESULT res; /* FatFs function common result code */
uint32_t byteswritten, bytesread; /* File write/read counts */
uint8_t wtext[] = "STM32 FATFS works great!"; /* File write buffer */
uint8_t rtext[_MAX_SS];/* File read buffer */
/* USER CODE END 1 */
...
/* USER CODE BEGIN 2 */
if(f_mount(&SDFatFS, (TCHAR const*)SDPath, 0) != FR_OK)
{
Error_Handler();
}
else
{
if(f_mkfs((TCHAR const*)SDPath, FM_ANY, 0, rtext, sizeof(rtext)) != FR_OK)
{
Error_Handler();
}
else
{
//Open file for writing (Create)
if(f_open(&SDFile, "STM32.TXT", FA_CREATE_ALWAYS | FA_WRITE) != FR_OK)
{
Error_Handler();
}
else
{
//Write to the text file
res = f_write(&SDFile, wtext, strlen((char *)wtext), (void *)&byteswritten);
if((byteswritten == 0) || (res != FR_OK))
{
Error_Handler();
}
else
{
f_close(&SDFile);
}
}
}
}
f_mount(&SDFatFS, (TCHAR const*)NULL, 0);
/* USER CODE END 2 */
Finally, you may build the project and run it on the device by starting a debug session.
When the code is executed, the SD card is formatted and the text file is written to it. Inserting the SD card into a host PC, you may read the file, as presented in the screenshot to the right.
Has anyone tried this code on a STM32L471RGT6? It doesn't appear to work and fails at line if(f_mkfs((TCHAR const*)SDPath, FM_ANY, 0, rtext, sizeof(rtext)) != FR_OK
Thanks in advance
I'm using a different board and connector. My connector's detect switch is active high. I had to change this line of code in fatfs_platform.c from "RESET" to "SET".
if(HAL_GPIO_ReadPin(SD_DETECT_GPIO_PORT, SD_DETECT_PIN) != GPIO_PIN_SET)
This has to be changed to set anytime the ioc file is updated.
Also, try setting the SDMMC clock divide factor to something greater than 0. 0x80 for example. ioc configuration, SDMMC1, Parameters tab.
Hi,
I am using the same dev board. Followed all the steps above. My STCubeIDE version is 1.11.2. Program gets stuck at:
if(f_mkfs((TCHAR const*)SDPath, FM_ANY, 0, rtext, sizeof(rtext)) != FR_OK)
{
Error_Handler();
}
with "FR_NOT_READY"
checked and rechecked again, used various SDCards but same.
Any advice is appreciated.
Thanks,
Tim
Made it work with couple of modifications:
1- Moved variables to global
move
"
/* USER CODE BEGIN 1 */
FRESULT res; /* FatFs function common result code */
uint32_t byteswritten, bytesread; /* File write/read counts */
uint8_t wtext[] = "STM32 FATFS works great!"; /* File write buffer */
uint8_t rtext[_MAX_SS];/* File read buffer */
/* USER CODE END 1 */
"
to
"
* USER CODE BEGIN PV */
FRESULT res; /* FatFs function common result code */
uint32_t byteswritten, bytesread; /* File write/read counts */
uint8_t wtext[] = "STM32 FATFS cali666siy great!"; /* File write buffer */
uint8_t rtext[_MAX_SS];/* File read buffer */
/* USER CODE END PV */
"
2- Changed 4B wide operation to 1B operation in "MX_SDMMC1_SD_Init()"
static void MX_SDMMC1_SD_Init(void)
{
/* USER CODE BEGIN SDMMC1_Init 0 */
/* USER CODE END SDMMC1_Init 0 */
/* USER CODE BEGIN SDMMC1_Init 1 */
/* USER CODE END SDMMC1_Init 1 */
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_1B; //Start with 1B instead 4B. Later "SD_Widebus_Enable" command makes it 4B
hsd1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
hsd1.Init.ClockDiv = 0;
/* USER CODE BEGIN SDMMC1_Init 2 */
/* USER CODE END SDMMC1_Init 2 */
}
now it works OK. Tested with 4GB and 16GB FAT32 formatted uSD cards
Tim
Thank's for your advice, now my SD Card program works fine.
My code does not work, I even moved some variables to global, still not working. Please help me out. My hardware PCB uses a 4-bit wide bus, and my SD Card is FAT32 8GB. It only works upto f_mount() which returns FR_OK, but after that, the f_open returns FR_DISK_ERR.
I had the same problem with f_mount(). I use the same solution as described by JBond.1
https://community.st.com/t5/stm32cubemx-mcus/sdcard-does-not-work-with-4bits-wide-bus/td-p/602607
It works fine! You don't need to do the steps described by TKana.1
I use STM32CubeIDE Version: 1.13.2 and STM32CubeF4 Firmware Package V1.27.0 / 11-February-2022
Hello, Can anyone Tell me is it mandatory to Format a new SD Card before writing or Reading data in STM32 MCU. Currently I am facing an issue wherein whenever I try to write data into a new non-formatted SD Card, It gives me an error but whenever I try to write data into a SD card using a card reader, it gets written. Thanks for help in advance.
Hi,
>is it mandatory to Format a new SD Card
NO! You should never format a new sd-card, because they are format to the optimum for that card.
So format -especially as first action on a new system- might with good chance destroy the card or at least make it worse (getting slower) . Especially on new, big (> 32GB) cards in exfat format.
Also dont write - until mount, open directory and reading files working perfect. Then can try write something.
Like others it failed at f_mkfs. I watched the video for this guide...
https://www.youtube.com/watch?v=I9KDN1o6924
...and there is a step missing from this written guide. The missing step, as shown in the video, is to add the DMA Rx and Tx..
Since adding the dma rx/tx and changing the SD mode from 4 bit wide to 1 bit, it now works.
For some reason it does not work in SD mode 4 bit wide
I had the same problems. I couldn't not to get it working in 4bit mode but I got it working in 1 bit mode.
Actually when I tried older version of CubeMX the 4bit mode works. I think there is bug in latest CubeMX.
I got this reply from STM32 tech support
On December 4, 2023 at 2:34 PM
It turned out to be a problem on CubeMX code generation that we cannot configure SDMMC and the FatFS at the same time. This will be fixed in the next release of CubeMX.
I tried new chip and the same problem. I set up 1bit mode in CubeMX, I moved to:
/* USER CODE BEGIN 0 */
FRESULT res; /* FatFs function common result code */
uint32_t byteswritten, bytesread; /* File write/read counts */
uint8_t wtext[] = "new file test"; /* File write buffer */
uint8_t rtext[_MAX_SS];/* File read buffer */
/* USER CODE END 0 */
If you do not have PIN detect for SD card connected change this line change it in fatfs_platform.c
Here is a small update. I tired to setup in SD 4 bits in CubeMX and of course it did not work. New customs another board with STM32H7A3ZIT6. I generated the code anyway and made some custom changes. I initialize it first in 1 bit mode. Then in 4 bit and it worked. DMA setting did not have any influence if it works or nor. My SD card works with speed up to 64 MHz, setup the clock in CubeMX. Also make sure the settings in
static void MX_SDMMC2_SD_Init(void)
{
/* USER CODE BEGIN SDMMC2_Init 0 */
hsd2.Instance = SDMMC2;
hsd2.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
hsd2.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
hsd2.Init.BusWide = SDMMC_BUS_WIDE_1B;
/* USER CODE END SDMMC2_Init 0 */
/* USER CODE BEGIN SDMMC2_Init 1 */
/* USER CODE END SDMMC2_Init 1 */
hsd2.Instance = SDMMC2;
hsd2.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
hsd2.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
hsd2.Init.BusWide = SDMMC_BUS_WIDE_4B;
hsd2.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
hsd2.Init.ClockDiv = 0;
/* USER CODE BEGIN SDMMC2_Init 2 */
/* USER CODE END SDMMC2_Init 2 */
}
here are also fatfs settings which work for me
I have on H743VI SD-card running with no problems (in 4 bit mode, 50MHz clock) :
/* USER CODE END SDMMC1_Init 1 */
hsd1.Instance = SDMMC1;
hsd1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
hsd1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_ENABLE;
hsd1.Init.BusWide = SDMMC_BUS_WIDE_4B;
hsd1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_ENABLE;
hsd1.Init.ClockDiv = 1;
/* USER CODE BEGIN SDMMC1_Init 2 */
if (HAL_SD_Init(&hsd1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE END SDMMC1_Init 2 */
STM32Cube FW_H7 V1.10.0
Had similar issue on STM32F746G-Disco EVB. Changing SDMMC_BUS_WIDE_4B to SDMMC_BUS_WIDE_1B resolved the issue
STM32CubeIDE Version: 1.13.2 Build: 18220_20230914_1601
Same here with STM32F446.
I fixed the SDIO bug by adding the following line:
static void MX_SDIO_SD_Init(void)
{
...
/* USER CODE BEGIN SDIO_Init 2 */
hsd.Init.BusWide = SDIO_BUS_WIDE_1B; //add this line, so that the automatic code generetation with STM32CubeIDE does not override the configuration
/* USER CODE END SDIO_Init 2 */
}
As proposed here SDCARD does not work (FR_NOT_READY) when migrating from FW_F4 V1.27.0 to newer FW_F4 V1.27.1
I am using Nucleo-F446ZE board.
The Platform Settings at FATFS stage, the ioc editor cannot find solutions for Detect_SDIO option.
Can anyone give some advice on how to resolve it?