Hard Fault with STM32 and FatFs are an extremely common occurence when you set up a new STM32CubeMX project and forget to set something up properly. Here is a list of what has solved hard faults for me before.
Check the SD/MMC Clock Speed
The clock speed of the SDIO bus matters a lot with SD cards. It is always smart to rule out this issue when developing a fresh application. Especially if you want to ensure compatibility with lower speed grade cards and those low cost dodgy ones. Even though you may not be interested in using a card that costs cents, there is a good chance that someone else will – and your firmware will fail.
ST Micro recommends that you let the SD/MMC peripheral clock sit at 24 MHz (even though you could bypass the peripheral clock divider and do a full 48 MHz).
A 48 MHz clock is only recommended where the PCB design supports it and you are technically bound to use that speed. Typical applications here could be an STM32 video player or recorder.
Note that the SD/MMC peripehral clock supplied in the above case was 24 MHz, which means that all SD cards worked at SDMMC CLK = 12 MHz. Yes, this is too low, but you can live with it if you are using 4-bit SDIO mode. This setting is the most preferable when only using the SD card for low volume and sporadic data transfers.
Link FatFs and SD/MMC Peripheral Correctly
If you set up FatFs from scratch in a new CubeMX project, make sure you remember to select the correct peripheral to link up with FatFs. Forgetting to do this means that your FatFs is using an incorrect peripheral to attempt connection to the SD card!
This can cause hard faults because of unexpected access to a peripheral that has not been set up for FatFs.
You can select the right peripheral for FatFs low level layer in Middleware > FatFs > Advanced Settings.
Make Sure DMA is Enabled and Works
I have noticed that when you enable an SD/MMC peripheral and turn on FatFs, the “Use DMA Template” option is already enabled (with no disable option!). The BSP Code for SD is also force-set to Generic.
This means that the FatFs library is expecting to be able to use the SD/MMC peripheral DMA HAL APIs!
If DMA is not configured properly, you will certainly get a hard fault with STM32 and FatFs library.
Any hard faults that occur from bad DMA settings will most likely be seen in DMA based read functions either in FatFs files or STM32 CubeMX HAL source files. This makes it easy to guess what caused it.
You can access the above settings in System Core > DMA.
I am not sure why this works and am yet to look into the generated code and how it interacts with FatFs. However, after a quick look, it seems like a DMA handle is generated which the FatFs code uses. It could also be that setting up the DMA sets up the DMA and interrupts to a correct initial state. This prevents a run-time hard fault when the system tries to use DMA for data transfer.
For a better idea of how FatFs is configured, look at sd_diskio.c file, where it is easy to see how DMA or non-DMA calls are being made which may cause hard faults.
Check Interrupt Priority if FreeRTOS is Used
Interrupt priorities can be managed in System Core > NVIC. When you enabled DMA interrupts, the priority may get initialized to a default value or 1 or something that does not work with FreeRTOS interrupt management.
Make sure you have the SD/MMC and DMA interrupts enabled – and set to a priority level that FreeRTOS can work with without crashing or getting stuck. I cannot specify a specific number because it could vary with your specific application requirements and FreeRTOS settings.
Call FatFs API with Scheduler Running
If you are attempting to mount an SD card and you get a failure (“NOT READY”) or a hard fault with forced mount via f_mount(), it could meant that the low level hardware was never initialized because code in sd_diskio.c skips initialization attempts if scheduler is not active.
Make sure you call FatFs APIs only from within tasks! Looks like you could change this behavior because this is set by defines within the code, but the default settings cause hardware init to be skipped without a running scheduler.
I hope the above points helped you find a solution! Hard faults with FreeRTOS applications can be very hard to trace because the backtrace does not always lead you back to the exact cause of the problem.
If something else worked for you, help me and others out by leaving a comment below!
Feel free to ask away via the Quick Contact form in the sidebar, or leave a comment below.
- Initial Release: 5 November 2021