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
SPSELbit 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