The more we know the harder it is to defeat us!

Recently I have written a short post about the HAL library created by STM32. The HAL is gaining popularity among hobbyists and is more and more frequently used. However, when you would like to use it for something else than just basic stuff like generating PWM on digital output you have to write it by yourself. Not so long ago I had to use SD card in one of my projects. It turned out that there is no driver for FatFS based on HAL – at least there was not. I decided to write the driver and here you can read about it…

FatFS delivers you with a template which you have to fill up so you can communicate with the SD card. In my case I needed something simple and straightforward. I decided to implement hardware layer for SPI based on HAL. There is no DMA transfer, it is just a simple implementation that works pretty well with not very frequent transfers. It is well-suited for log purposes.

You need to write definition for a few functions:

  • void SELECT(void),
  • void DESELECT(void),
  • void xmit_spi(BYTE Data),
  • BYTE rcvr_spi(void).

Below are definitions of those four functions:

As you can see I am using SPI2 but you can use whatever SPI you want. For details about the HAL functions look up the documentation.

Final remark.

If you do not use chip select pin you can simply pull-down CS input port of SD card and leave SELECT and DESELECT functions empty or create empty macros which would be a bit more efficient.


Below you can find my full implementation of diskio.c based on ChaN original file with some tweaks.



Update 2

I have forgotten to mention that this is non standart implementation in terms of timing. The function disk_timerproc() is required to be called every 10 ms (100 Hz). Since this implementation was using in a project where I was using FreeRTOS with finer grain (0.1 ms) I  had to modify the sdcard_systick_timerproc() function.

If you want it to be standard implementation you have to modify the code above. Simply instead of 100 place 10 and call this function every 1 ms i.e. in SysTick handler. Thanks lauba for pointing this out!

Update 3

Here I present a very simple example how to write data to the SD card:

33 Responses to Using FatFS with HAL

  • lauba says:

    Why do you increment sdcard_timer to 100?
    and where do you call the function sdcard_systick_timerproc? If in systemtick interuppt than is not 10 ms but 100 ms?

  • Yes, you are right. This files are from project where I was using FreeRTOS and I modified the timings. So this is not standard implementation.
    My SystemTick is called every 0.1 ms so the function disk_timerproc() is called every 10 ms as required.

    Thank you for pointing this out! I will add this information to the article.

  • lauba says:

    But what is strange is working also with 100 ms;) and next question do you think about using SD card operations no blocking? for example using DMA for this? because when we want to save a lot of data to SD card than we have to wait when one block will be ready. Next operate with the second again save and wait and in loop the same;)

  • Well, I was using 100 ms because of the original driver, it had 100 ms. Now, I see the newest example of FatFS is calling this every 1 ms. As said before, it can be easily alternated.
    As for the DMA. The example presented here is not very optimal. Each read/write or ioctl is working in a blocking mode. DMA with some FIFO could be used for this. However, for my purposes it is more than enough and for most of other things like data logging it should be also enough as long as you do not write tons of data.

  • shane says:

    Thank you for writing this driver. I have the project compiled but I’m unable to initialize the card. Can you post a small example of initialize, create file, write file, read file?

    • No problem. I will add it to my to do list. However, if you are really concerned about time maybe you should have a look at FatFS website. The Author has published many examples and also some sample code for different platforms.

    • shane says:

      I appreciate your prompt response. I’ve been trying for a few weeks to store time stamps with FatFS + SPI on STM32L4 and I feel like I’m missing something basic to put it all together. Your diskio.c example helps greatly.

      Do I still use the f_*commands* like f_mount and f_open?

    • Yes, you should use the f_*() functions. The driver is driver implementation only — the hardware layer. It is transparent for the user.
      I have also added a very short example how to write some data to a file. I hope it helps.

  • Raahul says:

    Hey, I am trying to interface an SPI-microSD device to an STM32F446RE. I am trying to use the HAL libraries along with FatFS. I am extremely confuse as to how to proceed. Could you please guide me.

    • First you have to decide which SPI are you going to use and you have to configure it accordingly. When you are decided then you have to change the hardware layer of FatFS and you are good to go. By changing the hardware layer you tell FatFS which interface it should use to communicate with the SD card. Those functions were enumerated in my blog post.
      The usage is very simple and straightforward. First you initialize the SPI and you can use the FatFS functions. There is an example in one of the updates to this post.

  • Raahul says:

    Thank you so much for responding. Forgive me, but I am a beginner. Could you tell me exactly what i would have to initialize in the main code, or could you direct me to the blogspot where this has already been explained?

  • Raahul says:

    How do I change this hardware layer of FatFs as well. I am checking CubeMX but I am not able to find anything of that sort.

    • Just to clarify one thing. If you are using my code you should not configure FatFS in CubeMX. The CubeMX version is using SDIO, the hardware layer presented here is using SPI. If that is cleared out then you let’s go to the SPI initialization. You should initialize SPI as Master with FullDuplex, 8 bits, MSB first, low clock polarity and data transfer on rising edge and that’s all. As for the baudrate you can set it for around 10Mbit/s for starters.
      After above is configured then you can adjust the hardware layer for FatFS files with your specific SPI (sd_stm32.c/h files). Finally, you add your logic to the program (FatFS functions).

    • Harryy says:

      Could you tell me what I should exactly do… I skip FatFs configuration in CubeMX, I attached your *.c and *.h file to my software. I add FatFs Library directly from they website but I have lot of problem with compiling of the code. At the end I need mention that I configure SPI interface according your advice. Maybe I don’t catch everything. Thank you in advance for your support.

    • If I find some time I will publish an example. Using FatFS with FreeRTOS is not different than using FatFS without it. Important thing is to prevent interrupts disrupting write on SD card.

    • I have checked them. Also I have received information that there was a problem with the server and maybe it have caused the problem. Please try again, it should work just fine, now.

  • Ehsan says:


    They are working now!

    But another problem: “../Inc/ff.h(96): error: #20: identifier “osSemaphoreId” is undefined”

    Could you please help me?!!

    • From what I can see you are using FatFS from Cube with the CMSIS RTOS also from Cube. Giving one line of code is not enough. It says that a semaphore named osSemaphoreId is undefined. I guess that you are missing headers in ff.h header file.
      The hardware layer I’ve prepared is for SPI and it works with Cube but requires some minor alterations.

    • I do not have an example which only is using SD card. However, in one of the comments I have pointed out how the SPI should be configured. I think this is what you are after, isn’t it. Also I will add this description to the body of the post so it would be easy to find.

  • ali says:

    Why do not work this code sample in stm32f401????
    char buffer[128];
    static FATFS g_sFatFs;
    FRESULT fresult;
    FIL file;
    int len;
    WORD bytes_written;

    //mount SD card
    fresult = f_mount(0, &g_sFatFs);

    //open file on SD card
    fresult = f_open(&file, „file.txt”, FA_OPEN_ALWAYS | FA_WRITE);

    //go to the end of the file
    fresult = f_lseek(&file, file.fsize);

    //generate some string
    len = sprintf( buffer, „Hello World!\r\n”);

    //write data to the file
    fresult = f_write(&file, buffer, n, &bytes_written);

    //close file
    fresult = f_close (&file);

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.