Beginner's question on tickless operation

Hello,

I have the following problem.

I need to send and receive SPI frames triggered by interrupts or interrupt sequences. By interrupt sequences I mean things like “interrupt A enables interrupt B, and when interrupt B arrives it start an SPI frame”.

The algorithm is quite complicated as the interrupt and SPI-frame sequence flow is dynamically configurable. The actual run-time of the algorithm is quite low as we can use DMA for the SPI, and the decisions themselves (i.e. which interrupts to enable and which data to send) are simple relative to the processor clock speed.

We need to keep jitter to the absolute minimum.

While all this is running, we need communication with the user over a UART, housekeeping, etc.

I was thinking about using FreeRTOS, running the algorithm in a high-priority task, woken up by the interrupts. However, as I understand it, the kernel tick interrupt will still interrupt the high-priority task unpredictably, increasing jitter.

Is it possible to operate FreeRTOS without a tick interrupt? We do not need tasks of the same priority, software timers, or time-outs. As I understand it, that makes the tick count irrelevant (?). Neither Google nor the API give a solution, esp. as the co-routines seem deprecated.

Can I achieve zero jitter added by the RTOS in some other way?

There is a somewhat-related thread at [Why tick is use in RTOS]; all other threads relate to the low-power tick-less mode.

Thanks for any advice.

By default all interrupts including SysTick used by FreeRTOS itself are set to lowest prio.
So they don’t add jitter to the user application when using nested interrupts, which is the default for all MCUs supporting it like Cortex-M3/M4F/7.
Interrupt response might be influenced by FreeRTOS and application code for ISRs using FreeRTOS API due to (very short) critical sections needed by FreeRTOS code but this is usually not a showstopper.
However, if you need very hard real-time behavior you can use ISRs running outside the scope of FreeRTOS (at higher prio) with the appropriate FreeRTOS configuration.
See e.g. this thread and the official docs https://www.freertos.org/RTOS-Cortex-M3-M4.html for the details.

I would do the actual response to the interrupts inside the ISR, as that logic sounds simple. If those routines don’t need to interact with tasks, they can be made very high priority interrupts that even critical sections won’t interfere with.

Hello,

Thanks for the quick responses, but I think I did not communicate my problem clearly enough.

I understand I can run jitter-free interrupts above the tick interrupt priority (also least on platforms supporting BASEPRI).

However, the sequence flow is complicated.

it will be less readable than implementing a single-high priority task with normal, linear code. Just for illustration purposes, take this (abstract) algorithm:

High-priority task:

while (somewhat complex decision criterion) {
if (…)
- Wait for interrupt A
if (…)
- Wait three times for interrupt B
Send SPI data
Wait for DMA-complete interrupt
}

Obviously it is possible to write this as an event-driven program, taking all decisions in the interrupts themselves. However, I tend to think that this would be less readable and more error-prone. So, I would greatly prefer to write it as a task, but then I run into the problem that at every point the tick interrupt can interrupt.

As noted, I am only a beginner at these sort of things. If you can suggest better ways to obtain jitter-free code I would be most grateful.

If the jitter from the tick interrupt is big enough to be a problem, then the best solution is that, at least the part that matters, be done inside the ISR. I suspect that would likely work out as having the kickoff of sending the SPI data be done inside the ISR for B, maybe also the count off of 3 interrupts.

You do put much of the logic done in the task, but the task sets flags for the high priority interrupt, to handle the low-jitter requirements.

Hello Richard,

The problem is the decision in the interrupt handler is configuration-and data-dependent, so it is impossible to offload to a task.

If there is no other solution, I’ll have to work in the interrupts though.

Thanks for your help.

I agree that code in a normal task is less error-prone, and easier to maintain than code that is part of an ISR. You can do so much less in an ISR.

Can you give any numbers? What time precision are you thinking of? And what is the clock-speed of the SPI bus? On what kind of CPU will it run?

I would not worry about the jitter caused by the clock-tick, because as Hartmut and Richard D pointed out, you can use higher priorities.

Have you looked at the FreeRTOS Task Notification functions, like vTaskNotifyGiveFromISR()?

Here is a simple example of an ISR waking up a task:

void tc2_clock_isr( void )
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;

    tc2_clear_flags();
    if( xMyTaskHandle != NULL )
    {
        vTaskNotifyGiveFromISR( xMyTaskHandle, &xHigherPriorityTaskWoken );
        portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
    }
}

void myTask()
{
    for( ;; )
    {
        ulTaskNotifyTake( pdFALSE, ulBlockTime );
    }
}

The above interrupt will do nothing more than clear the timer flags, and notify the high-priority task that will handle the logic.

Of course there is some code to be executed, and time will pass between the hardware event and the activation of the high-priority task. How much time that is mostly depends on the CPU: its clock frequency and its efficiency. But as both your ISR and your task have a high-priority, they won’t be disturbed.
This mechanism has nothing to do with the clock tick.
The macro portYIELD_FROM_ISR() will cause a task switch to myTask, but only if that task has the highest priority.

So yes, I would give it a try with a high-priority task.

His issue seems to be that if the clock tick interrupt occurs roughly coincident with the trigger interrupt, the time processing the tick interrupt creates a ‘jitter’ in his response, that is bigger than he wants. If the time running the tick interrupt itself causes too much jitter, than the only answer is do the work in an ISR (or maybe have no other interrupt, including the tick, in the system). If the jitter caused by critical section is too much, than the ISR needs to be higher in priority then FreeRTOS itself interacts with.

@richard-damon: sorry yes, you’re right. I missed that remark.
Part of the ‘jitter’ can be avoided by starting a critical section immediately after the task is woken up.

But still I am curious: what kind of CPU are you using? At what clock speed?
It sounds like you will create exact delays between actions. How long are such delays and what time precision do expect?

Is it possible to operate FreeRTOS without a tick interrupt?

This sounds a bit like a feature in FreeRTOS called Tickless idle.
@pietro: just to be sure: that is not applicable to your project. Tickless idle is a feature that helps cutting down the power consumption. The CPU will be put in a low-power mode, and the clock-tick will be temporarily suppressed.

Hello Hein,

We did look at the task notifications, but as Richard noted the decision logic can be interrupted by the scheduler.

Thanks for the tickless idle suggestion. We had noted that, but it seems the use cases do not seem to overlap.

We’re currently using a Cortex-M0, but we will almost certainly move to a Cortex-M4, probably at 48 MHz.

The SPI clock speed can be up to 18 MHz, but 4-6 MHz would be more typical. Frames are typically short.

As to the delays… Exact figures are not set in stone, as this is a fairly open-ended and experimental project. We are thinking about delays down to (say) 10 µs, but lower is certainly imaginable. The problem is that we would like these delays configurable. If we stretch that to 100 ms we cannot afford to stay in the original interrupt with a delay loop; housekeeping tasks would starve and fail.

Desired precision is a high as possible without excessive effort. Sorry for the vagueness, we’re still thinking about it.

I readily admit that part of my motivation to ask here is to understand the kernel aspects better. It seems a reasonable use case, and at my level of understanding tick-less operation looks comparatively easy to support in the scheduler.

Yesterday I thought a bit further about it, and I think the most logical experiments are

  1. Measure how long the tick interrupt takes. That would be typical of course, not worst case, but it should give an indication.

  2. See if we can simply disable the tick interrupt after start-up. As long as we don’t rely on kernel timing I think it should not affect the scheduler; for its point of view time will just freeze. The alternative is to feed the scheduler timing information from a hardware timer, but I am not component enough to delve into the FreeRTOS source code and gauge the implications.

Thanks for your hints.

10 us at 48 MHz is 480 machine instructions, which isn’t a lot. That sort of timing would be telling me that it needs to be timed by being in an ISR, an not a task. I might even get tempted to make it an interrupt that isn’t masked by critical sections to be safe, but I suspect you can make that without going that high.

You are also now mentioning a variable delay, but your sample code had no variable delay, just counting off interrupts, unless the three times for interrupt B was your delay.

Some coding techniques come with a cost. Yes, writing the decision tree as a task might be clearer, but gathering the information to a task does cost time, and introduces jitter. Breaking the logic down into simple event driven pieces sometimes helps you define what you need better.

One other point, if the tick timer interrupt is introducing this unacceptable delay, so might ANY interrupt that occurs.If these are the only actions going on, then frankly you don’t need an RTOS, and a standalone program might be cleaner. If you do have other things going on, then fixing the delay from the tick interrupt won’t fix everything. If the issue is that it happens too much, a simple answer is drop the rate of the tick interrupt (if you kept the value from the demos at 1 ms/1000 Hz), I often use 10 ms or 100ms ticks, you could possible go very low if you are thinking you don’t need it at all.

Hello Richard,

Yes, sorry, I should have mentioned that. It is so obvious to me that I even didn’t think about it — one of the interrupt I was talking about was a timer interrupt.

For the other interrupts, we can achieve all housekeeping & communication without interrupts so far.

We will give the implementation with full interrupts a try. Thanks again for all the hints.

You can override the function vPortSetupTimerInterrupt to use a hardware timer: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/master/portable/GCC/ARM_CM4F/port.c#L688

Install xPortSysTickHandler as your timer’s ISR: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/master/portable/GCC/ARM_CM4F/port.c#L494

Thanks.

1 Like

Thanks for the hint @aggarg.