Task switching on Cortex-M microcontrollers can be done using either the Main Stack Pointer (MSP) or Process Stack Pointer (PSP). The MSP is used by default for the main thread of execution, while the PSP is used for context switching to other threads. Switching from using MSP to PSP offers some advantages for multithreaded applications on Cortex-M devices.
Advantages of Using PSP for Task Switching
Here are some of the benefits of switching from MSP to using PSP for task switching on Cortex-M microcontrollers:
- Isolation between threads – Each thread gets its own dedicated stack with PSP, avoiding corruption between threads.
- Simpler context switching – PSP contains only thread specific context during a switch, saving computation.
- Dedicated stack memory – PSP stack space can be allocated separately from main program stack.
- Interrupt handling – Interrupts can still safely use MSP while threads use PSP.
- Reentrancy – Entering same thread through multiple interrupts is easier with PSP separation.
By switching task switching to use the PSP instead of sharing the MSP stack, you can realize these benefits in your multithreaded Cortex-M application.
How PSP Works for Task Switching
The PSP operates by giving each thread its own independent stack space for automatic local variable allocation and context saving during switches. Here is an overview:
- PSP stack space is allocated for each thread you create.
- PSP is initialized to the start of the stack space on thread creation.
- Thread contexts are saved and restored on the individual PSP stacks.
- PSP contains the CPU registers, function call history and local variables for a thread.
- Switching threads simply involves changing the PSP to a new thread’s stack.
This keeps each thread isolated in its own memory space for stack usage. The PSP hardware automatically handles the stack pointer updates during context switches.
Setting Up PSP for Task Switching
To utilize PSP for task switching, you need to configure the Cortex-M accordingly at initialization:
- Enable threading support in the microcontroller by setting CONTROL.FPCA = 0.
- Optionally enable lazy context saving by setting CONTROL.nPRIV = 0.
- Set up PSP stack space for each thread you create.
- Initialize PSP to the starting stack address when creating a thread.
- Use special register access instructions to save and restore PSP context.
- Use PendsV handler or OS scheduler to handle context switching.
This enables PSP functionality and dedicates space for each thread’s stack needs. The system will then handle stack pointer manipulation during each context switch.
Saving and Restoring PSP Context
To perform a context switch the current PSP must first be saved, then the new thread’s PSP can be restored. This is done with special CPU register instructions:
MRS R0, PSP
– Move PSP into R0 register to save current contextSTMDB R0!, {R4-R11}
– Store CPU registers onto current thread’s stackMSR PSP, R0
– Restore R0 back into PSP before next thread startsLDMIA R0!, {R4-R11}
– Load registers for next thread from its saved PSP stack
The PUSH
and POP
instructions can also be used to save context back to the stack pointed to by PSP. This allows full context switch ability utilizing the PSP.
PSP Context Switching Example
Here is an example demonstrating how PSP context switching works with 2 threads:
// Thread 1 context save
MRS R0, PSP // R0 = PSP
STMDB R0!, {R4-R11} // Save regs to stack
// Thread 2 context restore
MSR PSP, R2 // PSP = R2 (Thread 2 stack)
LDMIA R2!, {R4-R11} // Restore Thread 2 registers
This shows the basic PSP manipulation needed to switch between 2 threads using their separate PSP allocated stacks. The MRS
, MSR
, STMDB
and LDMIA
instructions handle the context save and restore.
Using PendSV for PSP Context Switching
The Cortex-M PendSV exception handler can be used along with PSP to implement context switches when an OS scheduler determines a new thread should be executed. This allows low latency context switching:
- Scheduler determines next thread to run and gets its PSP value.
- Current thread’s context is saved back to its stack using PSP.
- Scheduler sets PENDSVSET bit to trigger PendSV interrupt.
- In PendSV handler, PSP is restored from next thread’s saved value.
- Execution returns to next thread when PendSV completes.
This leverages PendSV’s minimal latency interrupt handling to quickly save context and restore the next thread’s PSP for execution. PendSV eliminates the overhead of a full interrupt handler.
Challenges When Switching from MSP to PSP
While using PSP for task switching provides many benefits, there are some challenges to be aware of when changing from an MSP approach:
- PSP increases memory usage since stacks are duplicated per thread.
- Can increase complexity in managing PSP stacks vs single MSP stack.
- Existing code may need significant changes to utilize PSP instead.
- Interrupts should carefully be kept using MSP to avoid conflicts.
- Debugging can be more difficult with separate call stacks per thread.
With proper planning, these challenges can be mitigated. The separation benefits of PSP generally outweigh the costs for most multithreaded applications.
Tips for Switching from MSP to PSP
Here are some tips to help manage the transition from using MSP to PSP for task switching:
- Audit code to find all MSP usage that may need adjustment.
- Allocate PSP stack space at initialization based on thread needs.
- Initialize PSP to stack space start for each new thread.
- Use PUSH/POP carefully to keep symmetric stack usage.
- Create PSP manipulation functions for encapsulation.
- Verify interrupts and handlers continue using MSP.
- Use compiler stack checking tools to help find issues.
Carefully managing the introduction of PSP usage can help make the transition from MSP smooth and avoid subtle stack issues.
Conclusion
Switching Cortex-M task switching from using the Main Stack Pointer to the Process Stack Pointer provides enhanced separation between threads, simplified context switching and dedicated stack space for threads. This comes at the cost of increased memory usage and stack management complexity. With careful planning and testing, most multithreaded applications can benefit from migrating context switching to use the PSP available on Cortex-M microcontrollers.