Guidance on Event-Driven Task Synchronization and Data Consistency (STM32F401RE + FreeRTOS)

Hello everyone,

I’m currently developing a machine fault diagnosis system using FreeRTOS on an STM32F401RE board.

The system runs three main tasks as follows:

  1. Sensing Task – Collects 2048 acceleration samples from a USB-based accelerometer.
  2. Model Task – Performs inference using the collected data to determine whether the machine is normal or faulty.
  3. Communication Task – Displays the inference result on an LCD panel.

System Concept

The Sensing Task and Model Task share a global buffer, and The Model Task and Communication Task share another global variable for the model’s output.

Data integrity must be guaranteed:

The model should never read partially updated sensor data, and the communication task should not display outdated results.

Therefore, I want to ensure mutual exclusion and strict task sequencing.

To maintain responsiveness and ensure that results are always up-to-date, I’ve set task priorities as:

Communication Task > Model Task > Sensing Task

Intended Execution Flow

The system follows an event-driven pipeline rather than periodic scheduling:

  1. Sensing Task collects 2048 samples.
  2. Once data collection is complete, it notifies the Model Task.
  3. Model Task performs inference, then notifies the Communication Task.
  4. Communication Task displays the result and finally signals the Sensing Task to start the next cycle.
  5. The cycle repeats indefinitely.

In this architecture, only the Sensing Task remains active most of the time; the Model and Communication tasks stay blocked until they are explicitly triggered by the previous stage.

My Question

I’m trying to design the synchronization and data protection mechanisms properly in FreeRTOS.

Currently, I’m considering two options:

  1. Use binary semaphores for signaling between tasks, so each task wakes up only when its input data is ready.
  2. Use a mutex to protect the shared global buffers from concurrent access (for data consistency).

In other words,

Binary semaphore for task synchronization + Mutex for data consistency

I’d like to confirm if this is considered a good practice or if there’s a more appropriate design pattern in FreeRTOS for this kind of sequential, event-driven system.

Any guidance or feedback would be greatly appreciated.

Thank you in advance for your help!

P.S.

This post was translated from Korean using a generative AI tool.

well, if this is a totally deterministic, sequential control flow, why use seperate tasks in the first place? Couldn’t you use a single task executing

while (1)
{
SampleSensorData();
DetermineDataConsistency();
DisplayResults();
}

You should employ concurrent patterns only where there is concurrency.

1 Like

As RAc says, the way you have described it (Sensing only starts after Communication finishes) has no actual parallelism, so no need to actually have separate tasks.

Assuming you are doing it the way you say for some reason, you can simplify to only having one semaphore for each task, as, for example, After the sensor task finishes, to gives the semaphore for the Model task, and waits for the Semaphore from Communication, which won’t be given until after Model is done with the Sensor buffer.

And if you do want to think about future changes where that might not be true, you don’t really want a mutex, but a pair of semaphores, as some tasks are waiting for the buffer to be free but empty, and others on the same buffer, free but full. The sensor task doesn’t want to be able to take the buffer back after it fills it, but needs to wait for it to be emptied.

IF sensor collection is the slowest part, and you can afford the memory for two sensor buffers, it might make sense to have two buffers and either just copy from collection to processing buffer and immediately signal, or build a protocol to “ping-pong” between the buffers to allow the slow collection to start quickly for more throughput. If you do this, the the “Sensor” task, that should be blocking between points being collected, should probably be the highest priority task, and while it is blocking the Model task can be doing its work.

I would suggest also using a FreeRTOS Event Group rather than a Binary Semaphore so the sensor task can communicate which buffer is ready.