nobody wrote on Friday, February 23, 2007:
I’m evaluating FreeRTOS for use in an ARM environment,
it does not seem to be able to support nested IRQs, and does not support
a priority based interrupt service routine. Which, in my definition is
fundamental to a RTOS.
Perhaps I do not see something, could you please point it out?
The problem will not occur unless and until:
(a) you depend on the interrupt controller to prioritize IRQs
(b) and you re-enable IRQs within an IRQ.
here’s the short problem description:
freeRTOS, at startup runs in SVC mode, and switches to SYS mode at the first task.
The ARM - unlike other CPUs does not automatically push anything on the stack.
This is also true of IRQs, ARM instead switches to IRQ mode.
The current CPSR is saved, and the return address+4 is put into the IRQ-R14 (LR)
register. If a second higher priority IRQ occurs, IRQ-R14 is overwritten.
Yes, one could make this work - writing hand crafted IRQ routines in ASM but
it is not possible to _reasonably_ write any IRQs in C using this approach.
Here’s the scenario where I see it failing:
0) Initial state: No irqs pending, in "system mode" tasks running.
1) IRQ occurs.
2) CPU switches to IRQ-MODE,
IRQ-R14 holds return address.
SPSR holds saved PSR value.
3) Code saves some registers, and for example
does "sub lr,lr,#4"
4) – NOTE – Nowhere do I see the code leave
ARM_ISR mode that is the fundamental problem!
5) ISR routines are typically written in C these days.
They often call other C functions in the standard way.
6) Remember: the chip has a priority based IRQ controller.
Assume that a low-priority IRQ has just occured.
And - another HIGH PRIORITY irq is about to occur.
To "nest" interrupts you:
(a) allow the IRQ controller to manage priorities
(b) you then just re-enable IRQs in the CPU early in the IRQ routine.
ie: Often you handle the critical stuff as fast as possible
then re-enable IRQs, and take care of the time consuming
part later, but as part of the same interrupt.
7) During normal function calls the CPU, and the compiler
make use of R14(lr) as the return address.
But remember this question: Which R14 is it? I direct
your attention to the ARM_ARM book 2.3 Registers.
Remember: ‘hidden’ functions also include the
compiler run time “divide” or “mod” routines.
8) In this example - say your C code was dividing
something, and was in the middle of the ‘divide’
helper compiler routine.
Since the CPU is in IRQ mode, R14/LR => IRQ_R14.
[The same can be said about R13/SP]
The contents of the LR register (depending on the
optimization level, type of function, etc) holds
the return address back to your code, or is often
used as an extra temp-register in between calls.
9) The plan here is: "nested interrupts".
The IRQ has not been ACKed in the IRQ controller.
But, the CPU IRQ is re-enabled.
10) The higher priority IRQ occurs.
PROBLEM: remember: The CPU is still in IRQ MODE
R14 holds the ‘return address from divide’
[or something else, R13/SP is a problem also]
11) PROBLEM: the current "r14" - is return address
to your code from "divide_helper"
12) CPU takes the IRQ - and you just lost the
return address from "divide"
Am I missing something?
Or does FreeRTOS - not support any form of interrupt
priority and/or nested interrupts.
What I’m looking for, and cannot seem to find, is the MSR
instruction during any ISR handling that shows the CPU
switching to some other mode of operation.