Skip to main content
Graduate
May 13, 2024
Solved

STM32F767ZI: Hard fault with FreeRTOS mutexes + DMA I2C

  • May 13, 2024
  • 4 replies
  • 2025 views

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.
    Best answer by mƎALLEm

    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.

    4 replies

    Super User
    May 13, 2024

    Am I failing something?

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

     

    Graduate II
    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.

    Super User
    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?

    PB1Author
    Graduate
    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ƎALLEmAnswer
    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.