Library 21- Read SD card with FatFs on STM32F4
Finally I got it working properly. Reading SDcard was very awesome for me for first time, so I decided to make a library for STM32F4xx devices and post it to my website. It’s basically just communication interface between STM32F4 and FatFS library by Chan. It supports SPI or SDIO communication. Library also supports USB communication, but for that purpose you need USB stack too. USB is available here.
Below I’m showing how to setup everything with STM32F4 to get SD card working with SPI or SDIO communication.
FATFS library can be used everywhere, but really, everywhere, not just SDCARD or USB flash drive. I’ve made an update to use source for FATFS SDRAM on STM32F429-Discovery or STM32F4x9-EVAL boards. Click here for more info.
Future updates will include also SPI FLASH (prototoype functions are added to FATFS library but not implemented yet) and option for user to add custom functions for FATFS low level.
FatFS Library
If you are interested for FATFS using HAL drivers, check here.
Features
- Fatfs by Chan supported, version R0.11
- Support for SDIO or SPI interface
- SDIO works with 1- or 4-bit mode
- Support for Card detect pin
- Can be disabled
- Support for Write protect pin
- Can be disabled
- Custom fat time
- Enables you to implement your own time using RTC
- Updates
- Version 1.2 – August 29, 2014
- Version 1.3 – December 06, 2014
- FatFs version R0.10C now implemented
- Version 1.4 – December 29, 2014
- Added support for truncate file from beginning
- Version 1.5 – February 17, 2015
- FatFs version R0.11 now implemented
- Fixed problem which appers sometime using SDIO
Dependencies
- CMSIS
- STM32F4xx
- STM32F4xx RCC
- STM32F4xx GPIO
- STM32F4xx SPI (only when SPI)
- STM32F4xx DMA (only when SDIO)
- STM32F4xx SDIO (only when SDIO)
- MISC (only when SDIO)
- TM
- TM SPI (only when SPI)
- TM DELAY (only when SPI)
- TM GPIO
- defines.h
- attributes.h
- TM SPI (only when SPI)
- FatFs by Chan (included in library)
Pinout
Because different connections are possible, you have different pinouts. They are in table below:
NR | SDIO Interface | SPI Interface | |||||
---|---|---|---|---|---|---|---|
Name | STM32F4xx | Description | Name | STM32F4xx | Description | ||
4-bit | 1-bit | ||||||
1 | CD/DAT3 | PC11 | Connector data line 3 | CS | PB5 | Chip select for SPI | |
2 | CMD | PD2 | PD2 | Command/Response line | MOSI | PA7 | Data input for SPI |
3 | VSS1 | GND | GND | GND | VSS1 | GND | GND |
4 | VDD | 3.3V | 3.3V | 3.3V Power supply | VDD | 3.3V | 3.3V Power supply |
5 | CLK | PC12 | PC12 | Clock | SCK | PA5 | Clock for SPI |
6 | VSS2 | GND | GND | GND | VSS2 | GND | GND |
7 | DAT0 | PC8 | PC8 | Connector data line 0 | MISO | PA6 | Data output for SPI |
8 | DAT1 | PC9 | Connector data line 1 | ||||
9 | DAT2 | PC10 | Connector data line 2 |
Card detect and write protect pins are not part of SD card, but part of SDcard connector. They are listed below, and are same for both communications:
Name | STM32F4xx | Description |
---|---|---|
WP | PB7 | Write protect pin. Pin low when write is enabled |
CD | PB6 | Card detect pin. Pin low when card detected |
By default, both pins are disabled in library. If you want to use them, you have to enable them in defines.h file
1 2 3 4 5 6 7 8 9 10 11 12 |
/* Use detect pin */ #define FATFS_USE_DETECT_PIN 1 /* Use writeprotect pin */ #define FATFS_USE_WRITEPROTECT_PIN 1 /* If you want to overwrite default CD pin, then change this settings */ #define FATFS_USE_DETECT_PIN_PORT GPIOB #define FATFS_USE_DETECT_PIN_PIN GPIO_PIN_6 /* If you want to overwrite default WP pin, then change this settings */ #define FATFS_USE_WRITEPROTECT_PIN_PORT GPIOB #define FATFS_USE_WRITEPROTECT_PIN_PIN GPIO_PIN_7 |
SDIO Communication
STM32F4xx has internal SDIO peripheral to work with SD cards. Also, SDIO communication is faster than SPI, but if you don’t need speed in your project, you can use SPI aswell. With default settings, SDIO 4-bit mode communication is used. It means, that you need all four data lines. SDIO also supports 1-bit mode, where you need only Data0, CMD and CLK pins. To activate 1-bit mode, add this to your defines.h file:
1 2 3 4 5 |
/* Activate SDIO 1-bit mode */ #define FATFS_SDIO_4BIT 0 /* Activate SDIO 4-bit mode */ #define FATFS_SDIO_4BIT 1 |
To be able to get SDIO to work, you have to include these files:
- tm_stm32f4_fatfs.h
- tm_stm32f4_fatfs.c
- fatfs/diskio.h
- fatfs/diskio.c
- fatfs/ff.h
- fatfs/ff.c
- fatfs/ffconf.h
- fatfs/integer.h
- fatfs/option/syscall.c
- fatfs/option/unicode.c
- fatfs/drivers/fatfs_sd_sdio.h
- fatfs/drivers/fatfs_sd_sdio.c
And also make sure, that you include all STM32F4xx peripherals to work with. What it needs is described under “Dependencies” section.
SPI Communication
If you want to use SPI communication instead of SDIO on STM32F4xx for any reason, you can do that. To enable SPI communication, open your defines.h file and set constant
1 2 |
/* Use SPI communication with SDCard */ #define FATFS_USE_SDIO 0 |
Now, SPI is activated. Make sure, that you include dependencies libraries, described in “Dependencies” section. By default SPI1 is used with Pinspack 1, but you can set it to your own SPI (in defines.h file) with
1 2 3 |
/* Select your SPI settings */ #define FATFS_SPI SPI1 #define FATFS_SPI_PINSPACK TM_SPI_PinsPack_1 |
Look here to see, which pins are associated with each SPI. For SPI is also used CS (Chip select) pin. You can leave it’s settings as it is, or change it to what you want. You can do this with (in defines.h)
1 2 3 |
/* Custom CS pin for SPI communication */ #define FATFS_CS_PORT GPIOB #define FATFS_CS_PIN GPIO_Pin_5 |
To properly work with SPI communication, you need files below:
- tm_stm32f4_fatfs.h
- tm_stm32f4_fatfs.c
- fatfs/diskio.h
- fatfs/diskio.c
- fatfs/ff.h
- fatfs/ff.c
- fatfs/ffconf.h
- fatfs/integer.h
- fatfs/option/syscall.c
- fatfs/option/unicode.c
- fatfs/drivers/fatfs_sd.h
- fatfs/drivers/fatfs_sd.c
Fatfs
To work with files, you have to use fatfs library. In order to get it work properly, you should check it’s manual here. My library is used only for “behind the scenes” settings, to get communication with SD card properly.
Custom get_fattime() function
Fatfs supports get_fattime() function, which returns time in integer format. By default get_fattime() returns time 0. That means 1.1.1980 00:00:00 time. If you have any RTC library or you want to set your own time, then you should set define in defines.h file:
1 2 |
//Use custom get_fattime() function #define FATFS_CUSTOM_FATTIME 1 |
After you set this, you have to create your project function:
1 2 3 4 5 6 7 8 9 10 |
//Use custom get_fattime function //Implement RTC get time here if you need it DWORD get_fattime (void) { return ((DWORD)(2014 - 1980) << 25) // Year 2014 | ((DWORD)7 << 21) // Month 7 | ((DWORD)10 << 16) // Mday 10 | ((DWORD)16 << 11) // Hour 16 | ((DWORD)0 << 5) // Min 0 | ((DWORD)0 >> 1); // Sec 0 } |
My libraries for RTC
Changelogs
- Fixed error for SPI communication
1.\FATFS\diskio.c(211): error: #167: argument of type "void *" is incompatible with parameter of type "BYTE" .
My functions
I have also made some additional functions:
- TM_FATFS_DriveSize
- Get full drive size and free space on your disk
- TM_FATFS_TruncateBeginning
- Truncate file from beginning
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
/** * Get SD card drive size * * Parameters: * - uint32_t* total: * Pointer to variable to store total size of card * - uint32_t* free: * Pointer to variable to store free space on card * * Returns FRESULT struct members. If data are valid, FR_OK is returned. */ FRESULT TM_FATFS_DriveSize(uint32_t* total, uint32_t* free); /** * Get SD card drive size * * Parameters: * - uint32_t* total: * Pointer to variable to store total size of card * - uint32_t* free: * Pointer to variable to store free space on card * * Returns FRESULT struct members. If data are valid, FR_OK is returned. */ FRESULT TM_FATFS_USBDriveSize(uint32_t* total, uint32_t* free); /** * Truncate beginning of file * * Parameters: * - FIL* fil: * Pointer to already opened file * - uint32_t index: * Number of characters that will be truncated from beginning. * If index is more than file size, everything will be truncated, but file will not be deleted * * Example * - You have a file, it's content is: "abcdefghijklmnoprstuvwxyz", * - You want to truncate first 5 bytes, * - Call TM_FATFS_TruncateBeginning(&opened_file, 5); * - You will get new file data: "fghijklmnoprstuvwxyz" * * Returns FRESULT struct members. If everything ok, FR_OK is returned. */ FRESULT TM_FATFS_TruncateBeginning(FIL* fil, uint32_t index); |
What could possibly go wrong?
You know, Murphy’s law 🙂 In this section I will add possible problems and (I hope) how to get it fixed.
- Card not recognized by Fatfs
- Is your card formatted in FAT16 or FAT32 format?
Example
I have test this example with SPI and SDIO interface. In both cases I got the same result. I used 2 and 8GB cards in FAT16 format. In example below, default settings are in use, so:
- SDIO interface
- Card detect OFF
- Write protect OFF
- Led status
- No leds on: It has not been mounted ok
- Check if pinout is correct, also make sure FAT16 is selected
- Only GREEN led on: mounted ok and opened ok, but data could not be written
- Only RED led on: mounted OK, but could not open file
- Maybe you have enabled Write protect pin. Disable it for this example
- Both ON: everything OK
- No leds on: It has not been mounted ok
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
/** * Keil project example for FATFS * * @author Tilen Majerle * @email tilen@majerle.eu * @website http://stm32f4-discovery.net * @ide Keil uVision 5 */ #include "defines.h" #include "stm32f4xx.h" #include "tm_stm32f4_delay.h" #include "tm_stm32f4_disco.h" #include "tm_stm32f4_fatfs.h" #include <stdio.h> #include <string.h> int main(void) { //Fatfs object FATFS FatFs; //File object FIL fil; //Free and total space uint32_t total, free; //Initialize system SystemInit(); //Initialize delays TM_DELAY_Init(); //Initialize LEDs TM_DISCO_LedInit(); //Mount drive if (f_mount(&FatFs, "", 1) == FR_OK) { //Mounted OK, turn on RED LED TM_DISCO_LedOn(LED_RED); //Try to open file if (f_open(&fil, "1stfile.txt", FA_OPEN_ALWAYS | FA_READ | FA_WRITE) == FR_OK) { //File opened, turn off RED and turn on GREEN led TM_DISCO_LedOn(LED_GREEN); TM_DISCO_LedOff(LED_RED); //If we put more than 0 characters (everything OK) if (f_puts("First string in my file\n", &fil) > 0) { if (TM_FATFS_DriveSize(&total, &free) == FR_OK) { //Data for drive size are valid } //Turn on both leds TM_DISCO_LedOn(LED_GREEN | LED_RED); } //Close file, don't forget this! f_close(&fil); } //Unmount drive, don't forget this! f_mount(0, "", 1); } while (1) { } } |
View project on Github, download library below.
Read SD card with SDIO or SPI on STM32F4xx using FatFS by Chan
Recent comments