Each real time task has its own stack memory area so the context can be saved by simply pushing processor registers onto the
Saving the AVR context is one place where assembly code is unavoidable.
portSAVE_CONTEXT() is implemented as a macro, the source code for which is given below:
asm volatile (
"push r0 nt" (1)
"in r0, __SREG__ nt" (2)
"cli nt" (3)
"push r0 nt" (4)
"push r1 nt" (5)
"clr r1 nt" (6)
"push r2 nt" (7)
"push r3 nt"
"push r4 nt"
"push r5 nt"
"push r30 nt"
"push r31 nt"
"lds r26, pxCurrentTCB nt" (8)
"lds r27, pxCurrentTCB + 1 nt" (9)
"in r0, __SP_L__ nt" (10)
"st x+, r0 nt" (11)
"in r0, __SP_H__ nt" (12)
"st x+, r0 nt" (13)
Referring to the source code above:
- Processor register R0 is saved first as it is used when the status register is saved, and must be saved with its
- The status register is moved into R0 (2) so it can be saved onto the stack (4).
- Processor interrupts are disabled (3). If portSAVE_CONTEXT() was only called from within an ISR there would be no
need to explicitly disable interrupts as the AVR will have already done so. As the portSAVE_CONTEXT() macro is also
used outside of interrupt service routines (when a task suspends itself) interrupts must be explicitly cleared as early as
- The code generated by the compiler from the ISR C source code assumes R1 is set to zero. The original value of R1 is
saved (5) before R1 is cleared (6).
- Between (7) and (8) all remaining processor registers are saved in numerical order.
- The stack of the task being suspended now contains a copy of the tasks execution context. The kernel stores
the tasks stack pointer so the context can be retrieved and restored when the task is resumed. The X processor register is
loaded with the address to which the stack pointer is to be saved (8 and 9).
- The stack pointer is saved, first the low byte (10 and 11), then the high nibble (12 and 13).
Next: RTOS Implementation – Restoring The Context
Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.