I am writing a machine controller from scratch in order to learn how machine controllers work. The goal is to produce a machine controller similar in capablility as LinuxCNC for mid-range (80-200 MIPS) microcontrollers, because I am not quite satisfied with rigor of Smoothie or Repetier. I have a functional machine controller prototype here, using a non-preemptive RTOS I wrote myself:
I want to migrate to FreeRTOS because it’s preemptive and would eliminate a lot of state machines from my source code. My machine controller generates stepper pulses in software, requiring a tick rate of around 32 KHz. There are four threads that need to run at this rate, one for the interpolators, one for the servos, one for the step pulse generator and one for the stepper chip driver.
The maximum supported tick rate for FreeRTOS looks to be 1 KHz. It would greatly simplify my HAL if I didn’t have run these threads in an interrupt outside of FreeRTOS. What is the best practices sort of way to handle this? Could I use an interrupt to wake the thread (and trigger a context switch)? Thanks!
FreeRTOS doesn’t impose a maximum tick rate, but it is advised not to go
over 1Khz if you are using time slicing, otherwise too much time will be
spent switching between tasks. That advisory really depends on the CPU
you are using and what your application is doing though, so don’t treat
is as any more than a rule of thumb.
Note however that the pdMS_TO_TICKS() macro will not work with a tick
rate over 1KHz as we cannot represent fractions of milliseconds in an
unsigned integer. pdMS_TO_TICKS() is only used for convenience in the
demos though, it is not used in the FreeRTOS kernel itself.
The answer to how to keep interrupts outside of FreeRTOS depends on the
chip you are using. If you are using a Cortex-M3, M4, M4F or M7 then
just keep the priority of the interrupt above
configMAX_SYSCALL_INTERRUPT_PRIORITY - noting that you cannot call any
FreeRTOS API calls from the interrupt’s service routine.
It would greatly simplify my HAL if I didn’t have run these
threads in an interrupt outside of FreeRTOS
I can imagine that the code will look cleaner, simpler, when you use a higher clock-tick rate.
But as you will use a pre-emptive OS, isn’t it possible to have interrupts just wake-up some task? The lightest way of waking up a task is the Task-Notify mechanism. Or you may want to send some messages to a task, using the queue mechanism.
So even if the system clock runs at a 1000 Hz, the actual number of switches per second can be much higher, and the response time will be far shorter that 1 ms.
Hein Tibosch, that’s brilliant- so let me make sure I understand. I can send a message to a task from an interrupt (triggered by a timer), essentially waking it, while keeping the Tick at 1 KHz?
How I do it:
I have a very high interrupt rate from a timer (in fact more than one) doing a lot of things (motor control) and no task has any knowledge of that. Once it is started by a task, it runs completly in “background” only notifying some task if somethin happens or when it ends, these notifications are sent using a queue and wakeup a task that waits for an event that doesn’t happen so often.
In other words: somethings are better done using timers and interrupts without FreeRTOS at all. Those interrupts can have a higher priority so that they go completely undisturbed.
I can send a message to a task from an interrupt (triggered by a timer),
essentially waking it, while keeping the Tick at 1 KHz?
Yes you can. This is sometimes referred to as “deferred interrupt handling”: the ISR code is kept as short as possible. The more lengthy processing is done by a task.
Two things must be remembered:
From an ISR, you can only use API calls that end with ...FromISR()
The interrupt that calls an API may not have a priority higher than configMAX_SYSCALL_INTERRUPT_PRIORITY
( interrupt priorities for ARM processors: the lower the value, the higher the priority, check that out ).
Alain wrote:
some things are better done using timers and interrupts without FreeRTOS at all
I think that Alain refers to Timer-Counters, that are available in every CPU. They can be programmed to issue an interrupt at any speed.
Alain is describing a mix of 1) fast processing is interrupt driven and 2) waking up, notifying tasks.