Hard Fault with STM32 and FatFs – SOLVED

DMA Settings for SD/MMC to Prevent Hard Fault

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.

Tested Stable SD/MMC Clock Settings in STM32F7

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.

Advertisement (third-party):

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.

SM/MMC Peripheral Instance Setting in STM32CubeMX

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.

DMA Settings for SD/MMC to Prevent Hard Fault

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.

Advertisement (third-party):

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.

Set up Interrupt Priority for SD/MMC and DMA

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.

FatFs Mount Fails if Scheduler is Stopped
Advertisement (third-party):

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!

Change Log
  • Initial Release: 5 November 2021
References

Related posts

Generating 32-bit STM32 Unique ID

Adding a C callback to ToughGFX Events

STM32 Audio Tutorial (Part 2): Codec I2C Setup