Skip to main content
PB1
Associate III
May 13, 2024
Solved

STM32F767ZI: Hard fault with FreeRTOS mutexes + DMA I2C

My setting is a Nucleo F767ZI board with a IKS01A2 shield. I created a FreeRTOS project that periodically queries the temperature sensor, calculates an average of temperature data, and prints the temperature on the UART. It has three threads that work as follows:

- The first thread performs a HAL_I2C_Mem_Read_DMA to read temperature from the sensor on the shield, stops on a FreeRTOS event (that is fired by the DMA completion callback), then acquires mutex A, puts the temperature data in a shared circular buffer, releases A, and then sleeps (period: 100 ms).

- The second thread acquires mutex A, calculates the average of the temperatures stored in the shared circular buffer, releases A, then acquires mutex B, puts the average in a shared variable, releases B, and then sleeps (period: 500 ms).

- The third thread acquires mutex B, reads the shared variable with the average temperature, releases B, prints on the UART and then sleeps (period: 1000 ms).

The application fails in few seconds with a hard fault. What I learned from some experiments is that the hard fault does not happen if I disable the DMA I2C read code. When this code is enabled, the only way to avoid the hard fault is disallowing the threads to share the mutexes, e,g, by disabling the second thread.

Am I failing something?

Best,

Pietro

This topic has been closed for replies.
mƎALLEm
mƎALLEmBest answer
ST Technical Moderator
May 14, 2024

Hello @PB1 

Just tested your project (fortunately I have HTS221 sensor in hands :)) and I reproduced the behavior. 

It seems it's a stack size issue of printTask(). I increased it from 128kB to 256kB and the issue disappeared.

To give better visibility on the answered topics, please click "Best answer" on the reply which solved your issue or answered your question.

5 replies

Pavel A.
May 13, 2024

> Am I failing something?

If no one else is working on this code - yes it might be you.

 

Tesla DeLorean
Guru
May 13, 2024

Remember DMA has a scope a lot longer than the functions and code calling it, so don't DMA to auto/local buffers on the stack which may collapse immediately.

On CM7 parts pay attention to cache coherency. And 32-byte cache lines.

On the F767 use DTCM RAM for DMA buffers, it's much less complicated as this memory is not cached, being already 0-wait state and bolted to the wrong side of the core.

Tips, Buy me a coffee, or three.. PayPal Venmo (See Profile) Up vote any posts that you find helpful, it shows what's working..
Pavel A.
May 13, 2024

@Tesla DeLorean But isn't this weird? How the DTCM RAM of 'F7 can be zero wait state if DMA burst can grab it at any moment? Is it a terrible hack?

PB1
PB1Author
Associate III
May 13, 2024

Tried this way:

...
/* USER CODE BEGIN PV */
static uint8_t buf[2] __attribute__((section(".dtcm")));
...
void StartTemperatureTask(void *argument)
{
 ...
 for(;;)
 {
 lastWakeTime += 100;
 osDelayUntil(lastWakeTime);
 hts221_temperature_raw_get_async(&hi2c1, buf);
 ...

but it still generates hard faults.

mƎALLEm
mƎALLEmBest answer
ST Technical Moderator
May 14, 2024

Hello @PB1 

Just tested your project (fortunately I have HTS221 sensor in hands :)) and I reproduced the behavior. 

It seems it's a stack size issue of printTask(). I increased it from 128kB to 256kB and the issue disappeared.

To give better visibility on the answered topics, please click "Best answer" on the reply which solved your issue or answered your question.