Switching between different execution contexts is an important concept on Cortex-M processors. When an interrupt occurs, the processor automatically switches from thread mode to handler mode to execute the interrupt service routine (ISR). The ISR needs to run quickly and return control back to the original context. However, there may be cases where the ISR needs to switch context to another thread temporarily before returning to the original thread. This allows higher priority tasks to run during the interrupt.
Execution Contexts
Cortex-M processors have several execution contexts:
- Thread mode – used for regular program execution, has access to full CPU resources
- Handler mode – used for exception handlers like ISRs, has limited access to CPU resources
- Privileged mode – used for privileged system tasks, has full access to CPU resources
By default, the processor starts in thread mode when booting up. It switches to handler mode automatically when an interrupt occurs. The interrupt handler can also trigger a context switch to privileged mode if necessary.
Saving Context State
When switching between contexts, the current context’s state needs to be saved so it can be restored later. This context state includes:
- Register contents
- Stack pointer
- Link register return address
- Processor status flags
The standard way to save the context state is to use the stack. The stack pointer gets pushed onto the stack, then all the general purpose registers, status registers, etc. get pushed. When returning to the original context, the stack gets popped in reverse order.
Most Cortex-M processors have built-in hardware support to automatically save context on interrupts. The CPU stores the context state on the current stack before jumping to the interrupt handler.
Scheduling and Preemption
The ability to suspend execution in one context and resume in another context enables scheduling and preemption capabilities:
- Cooperative scheduling – a task voluntarily gives up control to another waiting task
- Preemptive scheduling – a higher priority task can forcibly interrupt a lower priority task
This is useful for real-time systems where timing deadlines are critical. Interrupt handlers can quickly preempt less urgent tasks when needed.
Context Switching in ISR
Performing a context switch from inside an ISR lets the handler preempt the current thread and run another thread temporarily. Steps:
- ISR prologue runs automatically, saving context state of interrupted thread
- ISR handler checks if higher priority thread is ready to run
- If yes, ISR switches context to higher priority thread:
- Save remaining ISR context state not already saved
- Restore context state of higher priority thread
- Higher priority thread runs until it blocks or finishes
- ISR wraps up execution
- ISR epilogue runs automatically, restoring context state of original interrupted thread
This allows urgent tasks to take precedence over less critical code when an interrupt occurs. The original thread context gets restored as if it were never preempted.
Privileged Context Switch Example
Here is some example code for an ISR handler that performs a context switch to a privileged system task: void SysTick_Handler() { // ISR prologue runs automatically on entry // Check if scheduler says privileged task is due to run if(ready_to_run) { // Manually save remaining ISR context state asm volatile( “mrs r0, psp\n” “stmdb r0!, {r4-r11}\n” ); // Restore privileged task context RestoreContextPrivilegedTask(); // Privileged task runs… // Save privileged task context SaveContextPrivilegedTask(); // Restore remaining ISR context asm volatile( “ldmia r0!, {r4-r11}\n” “msr psp, r0\n” ); } // Finish ISR handler // ISR epilogue runs automatically on exit }
This allows a privileged system task to preempt the ISR, run briefly, then return control to the ISR to finish interrupt handling.
Considerations
Things to keep in mind when context switching within an ISR:
- Context switches add latency and overhead
- Need to check scheduler and ready tasks frequently
- ISR still needs to finish in a timely manner
- Ensure shared resources between contexts are handled properly
- Stack usage can become complex with multiple contexts
So context switching inside ISRs should be done judiciously when absolutely needed by the application.
Benefits
Some benefits of context switching within an ISR:
- Critical tasks get CPU time faster
- More flexibility in preemptive scheduling
- Threads interact seamlessly with ISRs
- Standard context switch methods can be reused
This technique enables real-time performance and robust responsiveness from an overall system perspective.
Conclusion
Context switching inside interrupt handlers allows higher priority threads to run temporarily within an ISR on Cortex-M processors. This provides strong real-time preemptive scheduling capabilities, at the cost of more complex software. Understanding the context state saving, PSP management, and switch methodology is key. Used properly, this technique can enable more responsive real-time embedded systems.