The ARM Cortex-M0 processor implements the PendSV exception handler to allow low priority interrupts to preempt current execution. However, the use of a bootloader can impact how PendSV exceptions are handled. This article provides an in-depth look at PendSV exception handling on the Cortex-M0 and examines how a bootloader can affect it.
Overview of PendSV Exception Handling
The PendSV (pend supervisor call vector) exception has the lowest priority of all exceptions in the Cortex-M0. It is triggered by software to request a context switch to a lower priority thread. This allows low priority interrupts to preempt the currently executing code.
When a PendSV exception is triggered, the processor will finish executing the current instruction, push the context of the current thread to the stack, and vector to the PendSV handler. The PendSV handler will pop the context of the next thread to execute from the stack and return to restore its context. This performs a context switch between the threads.
The PendSV exception is useful for preemptive multitasking and implementing scheduling algorithms. It allows threads of different priorities to be interleaved while sharing the processor.
PendSV Handling Without a Bootloader
In a Cortex-M0 system without a bootloader, PendSV exception handling works as follows:
- The application executes on the main stack.
- A low priority interrupt triggers a PendSV exception request.
- The processor pushes registers to the main stack and vectors to the PendSV handler.
- The PendSV handler switches to the interrupt stack and saves context.
- The handler pops the next thread’s context from the interrupt stack.
- It returns to restore context and resume thread execution.
The key points are:
- The interrupt stack is used for context switching.
- The PendSV handler executes on the interrupt stack.
- The application uses the main stack for regular execution.
This allows low priority interrupts to preempt the application and enable multitasking. The different stacks keep application and interrupt contexts isolated.
PendSV Handling With a Bootloader
A bootloader complicates PendSV handling due to some unique requirements:
- The bootloader runs before the application and cannot rely on application code.
- It must initialize the processor and clocks.
- It loads the application binary from external memory.
To support this, the processor is configured as follows on reset:
- The main stack pointer points to a bootloader stack.
- The interrupt stack pointer points to a small interrupt stack.
- VTOR points to the bootloader vector table.
This allows the bootloader to perform initial setup before the application. However, it creates some challenges for PendSV handling:
- The application expects the main stack, but the bootloader stack is active instead.
- The bootloader stack is too small for application context switches.
- VTOR must be reconfigured to the application vector table.
Therefore, on startup the bootloader must:
- Initialize the processor clocks, peripherals, and interrupt stack.
- Load the application binary into memory.
- Reconfigure VTOR to point to the application vector table.
- Switch from the bootloader stack to the main application stack.
- Jump to the application entry point.
This sequence allows a seamless transition from the bootloader to the application. The application can then use PendSV normally with its expected main stack and vector table.
Bootloader Impact on PendSV Handler
The use of a bootloader thus has a direct impact on the PendSV exception handler:
- It must execute correctly from both the bootloader and application vector tables.
- It needs to detect which stack is active and act accordingly.
- The handler may require different logic before and after switching stacks.
Some key considerations for implementing the PendSV handler with a bootloader:
- Check current stack pointer to see if processing a bootloader or application PendSV.
- Use a separate interrupt stack for both contexts.
- Save minimal context when running from the bootloader stack.
- Reconfigure stack pointer before starting application multitasking.
With these precautions, the PendSV handler can work seamlessly despite starting execution on the bootloader stack before transitioning to the application context.
Example PendSV Handler Implementation
Here is example C code for a PendSV handler that works with a Cortex-M0 bootloader: // PendSV Handler void PendSV_Handler(void) { // Check if currently running on bootloader stack if(CURRENT_SP == BOOTLOADER_STACK) { // Save minimal context to bootloader stack // Exact registers depend on specific bootloader needs // Return to bootloader } else { // Running on main app stack // Save application context // Pop next thread context // Return to new thread } }
The key points are:
- Check current stack pointer to determine context.
- Minimize bootloader context saves.
- Otherwise execute normal thread switch logic.
This allows the PendSV handler to function seamlessly regardless of whether a bootloader or application triggered the exception. The slight increase in complexity enables a robust multitasking system.
Optimizing PendSV Handling
Some optimization techniques can improve PendSV handling with a Cortex-M0 bootloader:
- Process bootloader PendSV exceptions quickly to return to the bootloader fast.
- Save only required registers to the bootloader stack.
- Use compiler optimizations like leaf functions to avoid stack usage.
- Initialize applications stacks and contexts during boot to enable fast switching.
Properly configuring the linker scripts is also important:
- Locate main application stack first in memory for quicker access.
- Place interrupt stack in fast memory if available.
- Preallocate stack areas to enable alignment and prevent fragmentation.
With optimizations like these, the context switch overhead of PendSV handling can be minimized, enabling more responsive and robust multitasking.
Conclusion
In summary, using a bootloader introduces some unique challenges for PendSV exception handling on the Cortex-M0:
- The exception must handle two different stack contexts – the bootloader and application.
- Care must be taken to switch between the bootloader and application stacks.
- The PendSV handler requires slightly more complex logic to support both cases.
However, with proper implementation, the impact on interrupt response and multitasking performance can be minimized. The Cortex-M0 architecture provides flexible mechanisms to handle these dual contexts effectively.
Understanding the impact of a bootloader design is key to creating robust PendSV handling routines. With the guidelines provided, developers can take advantage of preemptive multitasking while still supporting a bootloader for their Cortex-M0 system.