Stack Memory

MSP vs PSP stacks, operation.

Mohith N
Updated: 19 March 2026
8 min read

The stack is a last-in first-out memory structure used to store local variables, function return addresses, and processor context during exceptions. On ARM Cortex-M, the stack is a central architectural element, and understanding the difference between the MSP (Main Stack Pointer) and PSP (Process Stack Pointer) is essential for writing RTOS-based embedded systems and debugging hard faults.

ARM Cortex-M Stack ArchitectureMain Stack (MSP)Used by exceptions and privileged threadHigher Address (Stack Base)xPSR saved by HWPC (return address)LR (EXC_RETURN)R12, R3, R2, R1, R0MSP points here (Top)SPStack grows downwardFull Descending modelProcess Stack (PSP)Used by RTOS tasks in Thread modeTask Stack BaseTask local variablesSaved R4-R11 (SW saved)HW saved R0-R3,R12,LR,PC,xPSRPSP points here (Top)PSPEach RTOS task has own PSPKernel uses MSP exclusively
Figure 1: ARM Cortex-M dual stack architecture showing MSP for exceptions and PSP for RTOS tasks

Core Concept Explanation

ARM Cortex-M implements the Full Descending (FD) stack model. This means the stack pointer starts at a high memory address and decrements before writing each new value. A PUSH instruction first decrements SP by 4 bytes (for a 32-bit register) and then writes the register value to the new SP address. A POP instruction reads from the current SP address and then increments SP by 4 bytes.

The two stack pointers, MSP and PSP, are implemented as two separate physical registers inside the processor. The CONTROL register bit 1 (SPSEL) determines which SP is active in Thread mode. When SPSEL = 0, Thread mode uses MSP. When SPSEL = 1, Thread mode uses PSP. Handler mode (exception execution) always uses MSP regardless of SPSEL. This separation is fundamental to RTOS design because it prevents a buggy application task from corrupting the kernel or exception handler stack.

On every exception entry, the processor performs automatic state saving (stacking) by pushing eight registers: xPSR, PC, LR, R12, R3, R2, R1, and R0 onto the currently active stack (MSP or PSP depending on which was active in Thread mode). This saves 32 bytes of stack space per exception entry and happens entirely in hardware with no software intervention needed.

MSP vs PSP Comparison

The MSP is initialized from the first 4 bytes of the vector table at address 0x00000000 during reset. This is how the processor knows where to start the main stack before any software runs. The PSP must be explicitly initialized by software before an RTOS task is launched. The RTOS kernel sets up each task's initial stack frame with a crafted initial PC, LR, and register values so that when the task is first scheduled, it appears to return from a non-existent exception and begins execution correctly.

Stack overflow is a critical concern. The Cortex-M has no hardware stack overflow detection in M3 (Cortex-M33 and newer provide Stack Limit Registers). In Cortex-M3/M4, the MPU is configured to place a no-access region at the bottom of each task stack. Any access beyond the stack limit triggers a MemManage fault, allowing the RTOS to detect the overflow and take corrective action rather than silently corrupting adjacent memory.

Mathematical Expression

Stack memory consumption for a task can be estimated before deployment. For a task with maximum call depth D, each level of function call pushes a stack frame. The minimum frame size is 8 registers (32 bytes) for the hardware-saved context, plus the callee-saved registers R4-R11 (32 bytes), plus any local variables on the stack. Total minimum stack requirement is estimated as: Stack = (D x (frame size)) + ISR stack overhead + safety margin.

Practical Understanding

FreeRTOS on Cortex-M configures each task to use PSP. When the SysTick exception fires, the processor automatically pushes the 8-register hardware frame onto PSP, then switches to Handler mode (using MSP). The FreeRTOS PendSV handler saves R4-R11 onto PSP, saves the current PSP value into the TCB (Task Control Block), loads the next task's saved PSP from its TCB, restores R4-R11 from the new PSP, and then performs a BX LR with EXC_RETURN value 0xFFFFFFFD to return to Thread mode using PSP. The processor then automatically unstacks the eight registers from the new task's PSP and resumes execution at the saved PC.

Example
Given:
A FreeRTOS task with call depth D = 4 function levels
Each level uses hardware frame + callee-saved: 8 + 8 = 16 registers = 64 bytes
Local variables per level: average 32 bytes
ISR overhead (nested, max 1 level): 64 bytes
Safety margin: 128 bytes

Why this formula applies:
Total stack must hold all call frames plus exception entry frame.

Formula:
Stack = (D x (HW_frame + callee_frame + locals)) + ISR_overhead + margin

Substitution:
Stack = (4 x (32 + 32 + 32)) + 64 + 128

Calculation:
Stack = (4 x 96) + 192
Stack = 384 + 192
Stack = 576 bytes

Final Answer:
Minimum task stack size = 576 bytes. Rounded up to next power-of-2 for alignment: 1024 bytes (1 KB) is a safe allocation.
Exam Tip: GATE and university questions frequently ask which registers are hardware-saved on Cortex-M exception entry. The answer is exactly 8: xPSR, PC, LR, R12, R3, R2, R1, R0. R4-R11 are NOT hardware-saved and must be saved manually by the ISR or RTOS context switch code.

Mechanism: Stack Operation During Exception

Cortex-M Exception Entry Stack OperationBefore ExceptionTask local dataTask local dataPSP (active task)ExceptiontriggersAfter StackingTask local dataTask local dataxPSR (HW saved)PC (return addr)LR (EXC_RETURN)R12R3, R2, R1, R0New PSP topISR (MSP)ISR executes hereUses MSPindependentlyMSP areaSwitch toMSP+Handler32 bytes = 8 registers auto-saved on PSP. ISR runs from MSP.
Figure 2: Cortex-M exception entry showing automatic 8-register stacking on PSP before ISR executes using MSP
  • On exception entry, the processor reads the active SP (MSP or PSP depending on Thread mode configuration) and pushes R0-R3, R12, LR, PC, xPSR in that order, decrementing SP by 32 bytes.
  • After stacking, Handler mode begins using MSP. LR is loaded with an EXC_RETURN value encoding whether to return to Thread or Handler mode and which SP to use on return.
  • On exception return (BX LR with EXC_RETURN value), the processor unstacks the 8 saved registers from the saved SP, restoring the interrupted context.
  • Tail-chaining allows the processor to chain from one ISR to the next pending IRQ without unstacking and restacking, saving 12 cycles per chained exception.
  • Late arrival allows a higher-priority IRQ that arrives after exception entry has begun to preempt, replacing the in-progress vector fetch without re-stacking since registers were already saved.

Quick Revision

  • Cortex-M uses Full Descending stack: SP decrements before write (PUSH), increments after read (POP).
  • MSP: used by Handler mode always, and by Thread mode when CONTROL.SPSEL = 0. Initialized from vector table address 0x00000000.
  • PSP: used by Thread mode when CONTROL.SPSEL = 1. Each RTOS task gets its own PSP value stored in its TCB.
  • Hardware saves exactly 8 registers on exception: xPSR, PC, LR, R12, R3, R2, R1, R0 (32 bytes). R4-R11 require manual saving.
  • Stack size formula: Stack = (call depth x frame size) + ISR overhead + safety margin.
  • Exam trap: Handler mode ALWAYS uses MSP. Only Thread mode can switch to PSP. Writing CONTROL.SPSEL in Handler mode has no effect.
  • EXC_RETURN value in LR determines return behavior: 0xFFFFFFF9 = Handler/MSP, 0xFFFFFFFD = Thread/PSP, 0xFFFFFFF1 = Handler/MSP (nested).

ARM Stack Memory

Test your knowledge on this topic!

Question 1 of 3

Q1.In which operational mode does the Cortex-M processor mandate the use of the Main Stack Pointer (MSP)?