Monday, 12 May 2025

Mastering Stack Memory on ARM Cortex-M: Models, Pointers, and Initialization

Stack memory is a region of RAM used for Last-In, First-Out (LIFO) storage of transient data such as function return addresses and local variables. Most CPU architectures, including ARM Cortex-M, provide dedicated PUSH and POP instructions that automatically adjust the stack pointer (SP, register R13) when storing and retrieving data.

Core Uses of Stack Memory

  • Function Calls: The stack holds return addresses and function parameters, enabling nested calls without fixed frame sizes.

  • Local Variables: Space for non-static local variables is allocated on the stack on function entry and reclaimed on exit.

  • Interrupt Contexts: Upon an interrupt or exception, the processor hardware pushes R0–R3, R12, LR, PC, and xPSR onto the stack, preserving thread state and enabling seamless return.

Stack Placement and Memory Layout

RAM in microcontrollers is typically partitioned—via linker scripts—into global data, heap, and stack regions. For example, a 128 KB SRAM might reserve its low addresses for globals, the next block for heap (dynamic allocation), and the high addresses for stack growth. Placing the stack at the top of RAM harnesses the full descending growth model and leaves contiguous space for heap expansion.

Full Descending Stack Model

ARM Cortex-M implements a full descending model: on PUSH, SP is decremented then data stored; on POP, data loaded then SP incremented. SP always points to the most recently pushed item. This model simplifies interrupt entry/exit sequencing and aligns with the ARM Architecture Procedure Call Standard (AAPCS).

Banked Stack Pointers: MSP vs. PSP

Cortex-M cores provide two banked stack pointers:

  • MSP (Main Stack Pointer): Default after reset, used by exception handlers.

  • PSP (Process Stack Pointer): Selectable in thread mode by setting the SPSEL bit in CONTROL
    Switching to PSP lets an RTOS kernel reserve MSP for its own use while giving each task an independent PSP-tracked stack.

Stack Initialization and Overflow Detection

Before main(): The processor fetches the initial SP from the first vector-table entry, setting MSP automatically.
After main(): Applications may reassign SP/PSP to new memory (e.g., external RAM) once initialized.
By monitoring SP against configured limits, software can detect stack overflows, preventing corruption of adjacent memory regions.

Conclusion

Effective stack management in embedded systems hinges on understanding the LIFO storage model, ARM’s full descending operation, and the dual MSP/PSP mechanism. Proper placement—defined by linker scripts—and robust initialization safeguard against overflow and ensure reliable task and interrupt handling in both bare-metal and RTOS environments.

Written By: Musaab Taha


This article was improved with the assistance of AI.

No comments:

Post a Comment