SoC
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
  • Arm Cortex M3
  • Contact
Reading: Manually Stacking Registers for Cortex-M Context Switching
SUBSCRIBE
SoCSoC
Font ResizerAa
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
Search
  • Home
  • Arm
  • Arm Cortex M0/M0+
  • Arm Cortex M4
Have an existing account? Sign In
Follow US
  • Looking for Something?
  • Privacy Policy
  • About Us
  • Sitemap
  • Contact Us
© S-O-C.ORG, All Rights Reserved.
Arm

Manually Stacking Registers for Cortex-M Context Switching

Holly Lindsey
Last updated: September 22, 2023 11:59 am
Holly Lindsey 7 Min Read
Share
SHARE

Context switching on Cortex-M microcontrollers requires manually saving and restoring register contents when switching between tasks. This involves stacking key registers onto the process stack during a context switch so their values can be preserved for the next time the task executes. Care must be taken to save all necessary registers in the correct order. This article provides a step-by-step guide on how to properly stack registers manually in Cortex-M devices for context switching.

Contents
Overview of Context SwitchingProcess for Stacking RegistersStack Frame FormatSaving Special RegistersCaveats and ConsiderationsTypical Context Switching WorkflowContext Switching ExampleTools for Debugging Stacked RegistersConclusion

Overview of Context Switching

Context switching allows multiple tasks to share a single Cortex-M processor. A context switch suspends execution of one task and starts running another. In doing so, the processor state for the original task must be saved so it can be restored later when that task resumes. The processor state includes register contents like the program counter, stack pointer, and general purpose registers.

Cortex-M devices have banked register sets which help with context switching. For example, the xPSR, PC, LR, and SP registers are banked for each exception/privilege level. This allows each task to use its own unique SP value without conflicting. However, the general purpose R0-R12 registers are shared and must be manually saved/restored during a context switch.

Process for Stacking Registers

When a context switch occurs, follow these steps to save register state:

  1. Get stack pointer for outgoing task from its PSP register
  2. Push remaining general purpose registers R4-R11 onto stack
  3. Push LR (EXC_RETURN) onto stack
  4. Push execution context ID value onto stack
  5. Get stack pointer for incoming task from its PSP register
  6. Pop execution context ID off incoming task’s stack
  7. Pop return address off stack into LR
  8. Pop general purpose registers R4-R11 off stack

This process manually stacks the necessary registers R4-R12, LR, and an execution context ID onto the outgoing task’s stack. The registers are stacked in a certain order to allow for easy popping off the incoming task’s stack. The context ID identifies what task the stacked registers belong to.

Stack Frame Format

The stack frame created by the register stacking follows this format: /* Stack grows down */ SP-> +0 R4 +4 R5 +8 R6 +12 R7 +16 R8 +20 R9 +24 R10 +28 R11 +32 LR +36 Context ID

This shows the order each register is stacked downwards from the stack pointer. When popping the stack for the incoming task, the registers can be restored by reading up the stack.

Saving Special Registers

Beyond R4-R12 and LR, several special registers may also need to be manually stacked, depending on your context switching needs:

  • PSR – Program status register flags like interrupts enabled could be stacked
  • PRIMASK – Priority mask register for interrupts
  • FAULTMASK – Fault exception masking
  • BASEPRI – Base priority masking level
  • CONTROL – Special CPU control registers

Whether you need to stack these depends on if your tasks require their values preserved. Stacking PSR is common to save interrupt enabled/disabled state.

Caveats and Considerations

Here are some important caveats when manually stacking registers:

  • Ensure stack pointers use 8 byte alignment for Cortex-M devices
  • Double check you restore registers for incoming task properly
  • Beware stack overflows and underflows
  • Stack can be corrupted if interrupts occur during switch
  • Switch code must be in Privileged Thread mode
  • Stacked data could be corrupted if tasks use same stack

Improper stacking or alignment during a context switch can lead to hard faults or stack corruption errors. The switch code itself must also be immune to interrupts which could corrupt the stack frame being created.

Typical Context Switching Workflow

A typical workflow for Cortex-M context switching looks like:

  1. Save context of outgoing task
  2. Update OS task control data structures
  3. Restore context of incoming task
  4. Incoming task resumes execution

The critical parts are the calls to save and restore the register contexts. This is where the manual stacking of registers occurs according to the procedure described earlier.

Context Switching Example

Here is an example code snippet that performs a context switch between two tasks using manual register stacking: // curr_task points to OS task control block of current running task // next_task points to OS task control block for new task to switch to void ContextSwitch(struct OSTask *curr_task, struct OSTask *next_task) { // Get stack pointer to use uint32_t curr_sp = curr_task->sp; uint32_t next_sp = next_task->sp; // Push registers R4-R11 to save context __asm volatile( “PUSH {R4-R11} \n\t” “PUSH {LR} \n\t” // EXC_RETURN saved here “PUSH {R0} \n\t” // Task ID ); // Update OS control data structures SelectNextTask(next_task); // Pop registers R4-R11 to restore new context __asm volatile( “POP {R0} \n\t” // Task ID “POP {LR} \n\t” “POP {R4-R11} \n\t” ); // Load stack pointer for next task __set_PSP(next_sp); }

This shows the inline ARM assembly used to actually stack the registers during the switch. The OS kernel handles the rest like selecting the new task and updating scheduling algorithms.

Tools for Debugging Stacked Registers

Debugging manually stacked registers during context switching can be tricky. Here are some tools that can help:

  • JTAG debugger single stepping and register views
  • Overflow stack canaries to detect corruption
  • ARM Keil / GDB debugger stack unwinding
  • Debug printf() statements in switch code
  • Checksum or hash stack data to check integrity

JTAG debugging provides the lowest level visibility into stacked register contents. Stack canaries are values placed in memory to detect overflow corruption. Debug messages can log info at key points during the switch. And checksums can validate the stack data hasn’t been corrupted during saving/restoring.

Conclusion

Manually stacking registers is a key part of enabling preemptive context switching on Cortex-M devices. The steps outlined here guide you through the process of properly ordering which registers to push and pop during a switch. Following these techniques allows multiple tasks to share the Cortex-M processor efficiently and effectively.

Newsletter Form (#3)

More ARM insights right in your inbox

 


Share This Article
Facebook Twitter Email Copy Link Print
Previous Article Loading the EXC_RETURN Value for Cortex-M Context Switching
Next Article Switching from MSP to PSP for Cortex-M Task Switching
Leave a comment Leave a comment

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

2k Followers Like
3k Followers Follow
10.1k Followers Pin
- Sponsored-
Ad image

You Might Also Like

Using ST-Link debugger with Cortex-M1 FPGA design

The ST-Link debugger is an extremely useful tool for debugging…

6 Min Read

ARM Cortex-M compiler differences (Keil, IAR, Linaro, Yagarto and GNU Tools for ARM Embedded Processors)

When developing for ARM Cortex-M microcontrollers, the choice of compiler…

4 Min Read

What is Controller Area Network (CAN) Bus?

The Controller Area Network (CAN) bus is a robust vehicle…

14 Min Read

What is ARMv8-M in Arm Cortex-M series?

ARMv8-M refers to the latest architecture version of the Cortex-M…

6 Min Read
SoCSoC
  • Looking for Something?
  • Privacy Policy
  • About Us
  • Sitemap
  • Contact Us
Welcome Back!

Sign in to your account