Hard real time critacal task synchronization

sushant2212 wrote on Friday, September 25, 2015:

Before getting into the problem I would like to give summary of our project:

For our system we’re using a 32bit ARM microcontroller running at clock speed of 48MhZ and need to fetch data through different tasks at different hard real timestamps, like:
T1 to fetch data at 10ms
T2,T3 to fetch data at 30ms
T4,T5,T6 to fetch data at 200ms.

We’ve used round-robin and priority based scheduling for these tasks and the result which we see is not as expected.

If all tasks run at different priority based on frequency at which they need to fetch data , then we’re missing packets for 3-4 timestamps after every 5-7 packets

If all tasks are given same priority e.g tskIDLE_PRIORITY+1, then we do miss packets but also the timestamp is not accurate, like for T1, we sometime get data at 11ms sometime at 9ms.

If we run only one task and get the data then it is always accurate but as we start enabling these tasks one after other then data accuracy is lost. We’re kind of OK if we enable 2 tasks to get data. But if we’ve more than 2 tasks then we’ve never received proper data.

Is there something which we need to take care of for configuring FreeRTOS. Or is there a limitation from FreeRTOS to provide hard real time synchronization for 6 tasks running simulatneously and looking for data at above mentioned frequency?

Thanks in advance,

heinbali01 wrote on Friday, September 25, 2015:

Hi Sushant,

Could you first tell what it means to “fetch data”? Is that a measurement from A/D, an I2C or CAN device? Any other peripheral?
Do you know how long the actual fetching of data lasts, expressed in usec ?


sushant2212 wrote on Friday, September 25, 2015:

Hi Hein,

It is about fetching sensor data.
If seen through FreeRTOS trace I could see that “CPU Usage %” is well under 0.10 % for most of the tasks.

Please let me know if it would be helpful to share statistic report of the trace.


rtel wrote on Friday, September 25, 2015:

But how are you fetching the data? Take collecting data from an ADC every 100ms as an example, one thing you might be doing is configuring a timer to generate an interrupt every 100ms, then startging the ADC conversion from the ISR, then using the ADCs conversion end interrupt to unblock a task - and process the ADC data from within the task - this should be very accurate. Another thing you might be doing is using vTaskDelay() to unblock the task every 100ms, starting the conversion in the task, then polling the ADC registers to see when the conversion ends, after which you process the data in the task - this would not be accurate as it would prevent lower prioirity tasks from running for the entire duration of the ADC conversion.

sushant2212 wrote on Friday, September 25, 2015:

Hi Hein,

4 sensors are fetching data through SPI and 2 sensors fetching data over I2C.
For task synchronization, I’ll explain it below.

There is a timer callback which is registered with timer-frequency of 10ms.
Once this callback is triggered, it does the modulus operation and wakes up different sensor’s task based on their timestamp, e.g
T1 is woken up everytime timer callback is registered,
T2 and T3 we check if (timer-counter % 30 == 0) { Wake-up }
T4,T5,T6 if(timer-counter %200 == 0) {Wake-up}.

NOTE: All these tasks are triggered through queues

These sensors read the data either using SPI or I2C and then post the content buffer (ideally 20 bytes of data) to a transaction manager task to structure it and pass to the output module.

vTaskDelay is not used in any of the tasks and its always triggered through timer callback.


rtel wrote on Friday, September 25, 2015:

…but how is the I2C and SPI comms performed. I2C and SPI are serial
buses, so take time. Are you using interrupts, dma, etc., or just
polling the interfaces from the tasks?

richard_damon wrote on Friday, September 25, 2015:

To expand on Richard’s question, first, you do realize that there will be time slots (every 600 ms) where all 6 tasks need to happen, and that you easily could have I/O time requirements that total up to over a millisecond. (At base speed, I2C transfers 10 bytes per ms, and reading a byte from a sensor can often task 4 bytes of transfer).

Many manufactur provided drivers will be polling based, and thus you won’t get any overlap between I2C and SPI requests.

Another big question is if the driver is reentrent, i.e. able to be called my multiple threads, or do you need to use an external mutex to protect it. Trying to do 2 requests at once via the same interface is likely to cause significant issues.

sushant2212 wrote on Friday, September 25, 2015:


We’re not using any interrupts or dma, just polling interfaces from the task.
Also, we’re not blocking drivers using external mutexes and that makes sense that if we’ve different priority of these tasks then we don’'t see mismatch in timestamp as all tasks would be pooling interfaces with different priority and there won’t be any timeSLICING done by scheduler (if all tasks have same priority).

Still, we would like to know if is there a limitation from FreeRTOS to provide hard real time synchronization for these tasks running simulatneously at different priority and polling interfaces for getting data.


rtel wrote on Friday, September 25, 2015:

Still, we would like to know if is there a limitation from FreeRTOS
to provide hard real time synchronization for these tasks running
simulatneously at different priority and polling interfaces for getting

I’m afraid I don’t understand the question.

If you have a high priority task that is polling an interface (that is,
never entering the Blocked state) while a serial transaction is in
progress (I2C, UART, SPI, etc.) then no lower priority tasks will be
able to run for the entire transaction time. That is not a limitation
of the RTOS, but a design choice on your part.

If you want other tasks to run while the serial transaction is in
progress, and therefore increase the throughput of the entire system as
no CPU cycles will be used up polling for something that has not
happened yet, then it would be better to make your system event driven.

Say you have an SPI transaction that is performed from a high priority
task, and an I2C transaction that is performed from a lower priority
task…then have the high priority task start the SPI transaction then
enter the Blocked state to wait for the transaction to complete
(implying the transaction is performed by interrupts and/or DMA and the
task is unblocked by the interrupt when the transaction is complete).
When the high priority task enters the Blocked state the low priority
task will run and can start its I2C transaction before it too enters the
Blocked state to wait for the transaction to complete. Then you have
both the I2C and SPI running in parallel and the tasks not using any
processing time until either the SPI or the I2C transaction is finished.


richard_damon wrote on Saturday, September 26, 2015:

When using polling interfaces, you totally block lower priority tasks while your task is in the polling loop. This is not condusive to meeting real time requirements. as you lose all the processing time while you are spinning waiting for the I/O to complete. This makes it much harder to meet ‘hard real time’ requirements. The ONLY way to work with real hard time requirements is to analyze your system and design. Draw a time line, mark you 10 ms tick point, draw the tasks taking whatever time it will take to do the I/O (look at what they need to send/receive and the speed of the bus), make an estimate of the processing time to work with the data. Since you are polling, there is ZERO overlap of I/O with processing or I/O with I/O. See if you can meet your timing requirements.

sushant2212 wrote on Tuesday, September 29, 2015:


Thanks for your response, we’d been trying some options to meet timing requirements.
Also, we wanted to know how much CPU time each of these sensor tasks actually take.
We tried FreeRTOS + Trace utility to find out but unfortunately we’re seeing only one instance of any of the tasks created (which basically is the first instance of creating and setting up these sensors), even though we see these tasks running continuously.
We calculate the timestamp at which these tasks actually got CPU slot and communicate to device using SPI/I2C interface, but when we open the trace we don’t see any detail of these tasks at given timestamp.

Could you please help in letting me know if we’re missing out on something to debig these tasks’ execution timestamp using FreeRTOS trace utility.


ammaree wrote on Tuesday, September 29, 2015:

POssibly an easier, lightweight and more accurate mechanism to measure the execution time of a section of code can be done using the FreeRTOS Tick and possibly SysTick mechanisms.

The choice between the mechanisms should be made bnased on the resolution required. I have done some very simple and efficient routines for the CC3200 that handles both uS and mS intervals.

If interested go to https://github.com/ksstech/support_common/blob/master/x_ticktimer.c

sushant2212 wrote on Monday, October 05, 2015:

Hi Andre/Richard,

Thanks for your input.
We’d tried the software to measure the execution time of each task and it worked. We also got FreeRTOS Trace working properly and we could see other important attributes for each of the active tasks.
We have some update on the task synchronization.

Just to over-rule the possibility of blocking SPI interface might be killing time for each tasks, we’ve commented out the communication and having dummy data. We still see that in output file there is loss of data (by observing the sequence number added as an attribute to data packet) .
When we try to retrieve data at a lower frequency and for 3 sensors (e.g 70ms, 170ms,230ms) which are not divisible by any other then we don’t observe any data loss. However if we have similar test done but at higher frequency(20ms, 70ms, 110 ms) then there is frequent packet loss from all sensors.

As we’ve no serial communication in any of the tasks so tasks execution time is minimized.

Could you please suggest some options which we can try to resolve this issue?


richard_damon wrote on Monday, October 05, 2015:

While you say you have execution time minimized, it really sounds like you are running out of CPU cycles at the higher speed. (Note also, even though you have made the periods non-multiples, you still have an occational, every 1540ms, point where all request happen at the same time).

When I run into these sorts of issues, the best solution I have found is to instrument the code to see why I am missing data requests, normally by having each operation log somewhere each time it starts and finishes a data cycle. This could be using the built in Trace facility, or adding your own code to do so. If you can detect that you have hit the data loss case (perhaps by checking how long since you last ran a given task) it is even better.

You need to know time marks when each task starts and finishs its cycle.

When that happens just stop the whole system and look at the results and see WHY you missed your deadline. Plot the task timeline (which task was running at what time) for what has just happened. The proximate cause should be fairly clear, some task didn’t run when it should because some other task was blocking it. Finding the root cause may take a bit longer, but this data should point you to it.

sushant2212 wrote on Monday, October 05, 2015:

Thanks Richard for your input.

I will work on it and keep you posted.