HomeAbout UsContact Us

Cortex-M FPU Context Switching: Lazy Stacking vs Eager State Save

By Jithin Tom
Published in Embedded Concepts
August 10, 2026
3 min read
Cortex-M FPU Context Switching: Lazy Stacking vs Eager State Save

Table Of Contents

01
Lazy Stacking Mechanism
02
The Deferred Stacking Trap
03
Eager State Preservation
04
Per-Task Configuration in an RTOS
05
Quantitative Comparison
06
Practical Recommendations
07
Summary
08
Related Reading
09
References
10
Frequently Asked Questions

FPU context switching on Cortex-M is a subtle but critical design decision that directly impacts worst-case interrupt latency and real-time determinism. The ARMv7-M and ARMv8-M architectures provide two mechanisms: lazy stacking (default) and eager state preservation. Choosing between them — or configuring them per-task — requires understanding the exact hardware behavior and your application’s FPU usage profile.

Lazy Stacking Mechanism

On exception entry, the Cortex-M processor hardware automatically stacks the general-purpose registers (R0-R3, R12, LR, PC, xPSR) onto the current stack. For the FPU registers (S0-S31, FPSCR), the behavior is controlled by FPCCR.LSPEN (Lazy State Preservation Enable, bit 30):

  • LSPEN = 1 (default): The processor marks the FPU state as “dirty” in the CONTROL register (FPCA bit) but does not push S0-S31/FPSCR. The first FPU instruction executed after return triggers a deferred stacking exception, where the processor saves the full FPU state before executing the instruction.
  • LSPEN = 0: The processor unconditionally pushes all 33 FPU registers on every exception entry (eager save).

The lazy path saves cycles when the interrupted code never touches FPU — common in interrupt handlers that only manipulate integer state.

+--------------------------------------------------------------+
| EXCEPTION ENTRY SEQUENCE |
+--------------------------------------------------------------+
| |
| Hardware auto-saves: R0-R3, R12, LR, PC, xPSR |
| (8 registers, ~12 cycles) |
| |
| If LSPEN=1 (lazy): |
| - Sets CONTROL.FPCA = 1 (FPU context active) |
| - No FPU registers stacked |
| - Cost: ~2 cycles |
| |
| If LSPEN=0 (eager): |
| - Pushes S0-S31, FPSCR (33 registers) |
| - Cost: ~34-50 cycles |
| |
+--------------------------------------------------------------+

The Deferred Stacking Trap

When the task resumes and executes its first FPU instruction (e.g., VADD.F32 S0, S1, S2), the processor detects CONTROL.FPCA=1 and takes a deferred stacking exception (a special exception type, not a standard interrupt). This exception:

  1. Pushes S0-S31 and FPSCR onto the stack
  2. Clears CONTROL.FPCA
  3. Returns to the FPU instruction, which now executes normally

The latency of this deferred stacking is non-deterministic from the application’s perspective — it depends on when the first FPU instruction occurs. In a hard real-time system, this spike can cause deadline misses if it happens inside a high-priority control loop.

+--------------------------------------------------------------+
| DEFERRED STACKING EXCEPTION FLOW |
+--------------------------------------------------------------+
| |
| Task Context Kernel/ISR Task Resumes |
| +------------+ +------------+ +------------+ |
| | ... | | Exception | | VADD.F32 | |
| | VADD.F32 | --> | Entry | --> | (traps) | |
| | ... | | (lazy) | | Deferred | |
| +------------+ +------------+ | Stacking | |
| | Exception | |
| | Push S0-31 | |
| | Clear FPCA | |
| | Retry VADD | |
| +------------+ |
| |
| Latency spike: 34-50 cycles on Cortex-M4/M7 |
| Unpredictable: depends on when first FPU insn executes |
| |
+--------------------------------------------------------------+

Eager State Preservation

Setting FPCCR.LSPEN = 0 forces the processor to push all 33 FPU registers on every exception entry, regardless of whether the interrupted code uses FPU. The cost is paid upfront and deterministically:

  • Exception entry: +34-50 cycles (vs ~2 for lazy)
  • Exception return: +34-50 cycles for FPU register restore
  • No deferred stacking exception — FPU instructions execute immediately on resume

Eager preservation makes sense when:

  1. Most tasks use FPU heavily (DSP, motor control, sensor fusion) — the lazy trap fires on nearly every context switch anyway
  2. Deterministic latency is required — safety-critical systems where WCET analysis must account for worst-case stacking
  3. Interrupt frequency is high — the overhead of repeated deferred stacking traps exceeds the one-time eager cost

Per-Task Configuration in an RTOS

A well-designed RTOS exposes FPU policy per-task. The typical implementation:

// Task creation with FPU policy
typedef enum {
FPU_POLICY_LAZY = 0, // Default: LSPEN=1
FPU_POLICY_EAGER = 1, // Force eager: LSPEN=0
FPU_POLICY_NONE = 2 // Task never uses FPU (compiler flag)
} fpu_policy_e;
BaseType_t xTaskCreateWithFPU(TaskFunction_t pxTaskCode,
const char *pcName,
configSTACK_DEPTH_TYPE usStackDepth,
void *pvParameters,
UBaseType_t uxPriority,
TaskHandle_t *pxCreatedTask,
fpu_policy_e fpuPolicy);
// During task context switch (simplified)
void vTaskSwitchContext(void) {
// Save outgoing task's FPU state if FPU was active
if (pxCurrentTCB->fpuPolicy == FPU_POLICY_EAGER) {
vFPU_SaveState(pxCurrentTCB->fpuContext);
} else if (pxCurrentTCB->fpuPolicy == FPU_POLICY_LAZY) {
// Lazy: FPCCR.LSPEN=1, hardware handles on first FPU use
FPCCR |= (1 << 30); // LSPEN = 1
}
// Configure incoming task
if (pxNextTCB->fpuPolicy == FPU_POLICY_EAGER) {
FPCCR &= ~(1 << 30); // LSPEN = 0 (eager)
vFPU_RestoreState(pxNextTCB->fpuContext);
} else {
FPCCR |= (1 << 30); // LSPEN = 1 (lazy)
}
}

The RTOS must also manage FPCCR.ASPEN (Automatic State Preservation Enable, bit 31) which controls whether the processor automatically preserves FPU state on nested exceptions. For most RTOS ports, ASPEN=1 is correct.

Quantitative Comparison

ScenarioLazy StackingEager Save
Task never uses FPU+2 cycles (FPCA set)+34-50 cycles wasted
Task uses FPU once per switch+34-50 cycles (deferred)+34-50 cycles (upfront)
Task uses FPU heavily+34-50 cycles per switch+34-50 cycles per switch
WCET determinismNon-deterministic spikeFixed, known cost
Nested interrupt latencyVariable (depends on FPCA)Predictable

Rule of thumb: If >80% of context switches involve FPU usage, eager save wins. If FPU usage is rare or sporadic, lazy stacking saves significant cycles.

Practical Recommendations

  1. Default to lazy stacking for general-purpose tasks — it costs nearly nothing when FPU is unused.
  2. Enable eager save for tasks running control loops, DSP filters, or sensor fusion where FPU is used on every iteration.
  3. Disable FPU entirely (FPU_POLICY_NONE) for tasks that provably never use floating-point — the compiler won’t emit FPU instructions, and the kernel skips all FPU context logic.
  4. Measure, don’t guess — instrument your RTOS port to count lazy vs eager context switches and deferred stacking exceptions in your actual workload.

Summary

Cortex-M FPU context switching is not a one-size-fits-all setting. Lazy stacking is the safe default for mixed workloads, but eager preservation eliminates non-deterministic latency spikes for FPU-intensive real-time tasks. A capable RTOS should expose this as a per-task policy, allowing the firmware engineer to match the hardware behavior to the task’s computational profile. The key insight: the deferred stacking exception is a hardware-managed trap with variable timing — if your deadline analysis cannot tolerate that variance, force eager save.

References

  1. ARM, Cortex-M4 Devices Generic User Guide, Section 4.6 “Floating-Point Context Control Register (FPCCR)”, Document ARM DUI 0553A
  2. ARM, ARMv7-M Architecture Reference Manual, Section B1.5.13 “Floating-point context control”, ARM DDI 0403E
  3. FreeRTOS, Running FreeRTOS on ARM Cortex-M3/M4, https://freertos.org/Documentation/02-Kernel/03-Supported-devices/04-Demos/ARM-Cortex/RTOS-Cortex-M3-M4
  4. Joseph Yiu, The Definitive Guide to ARM Cortex-M3 and Cortex-M4 Processors, 3rd Edition, Chapter 14 “Floating-Point Unit”
  5. STMicroelectronics, STM32F4 Series Reference Manual (RM0090), Section 4.3.3 “FPU context switching”, https://www.st.com/content/ccc/resource/technical/document/reference_manual/3d/6d/5a/66/b4/99/40/d4/DM00031020.pdf/files/DM00031020.pdf/jcr:content/translations/en.DM00031020.pdf

Frequently Asked Questions

What is lazy FPU stacking on Cortex-M?

Lazy stacking defers saving FPU registers (S0-S31, FPSCR) until the interrupted task actually uses floating-point instructions. The processor sets a flag in CONTROL register and only stacks the FPU state on first FPU access after context switch.

When does eager state save outperform lazy stacking?

Eager saving wins when context switches are frequent and most tasks use FPU — the unconditional save/restore cost is lower than repeated lazy-stacking traps. It also eliminates non-deterministic latency spikes from deferred stacking.

How does the FPCCR register control FPU context switching behavior?

FPCCR (Floating-Point Context Control Register) bits ASPEN (automatic state preservation enable) and LSPEN (lazy state preservation enable) control the behavior. LSPEN=1 enables lazy stacking (default); clearing it forces eager save on every exception entry.

What is the typical latency penalty of lazy stacking on first FPU use?

The first FPU instruction after context switch triggers a deferred stacking exception, adding 34-50 cycles (Cortex-M4/M7) for the full 32-register push. This non-deterministic spike can violate hard real-time deadlines in safety-critical loops.

Can lazy stacking be disabled per-task in an RTOS?

Yes. An RTOS can clear FPCCR.LSPEN during task creation for FPU-intensive tasks, forcing eager save. The RTOS must also manage FPCCR.THREAD (thread mode FPU access) and ensure FPCCR.USER (user mode FPU access) aligns with privilege level.

Tags

cortex-mfpucontext-switchinglazy-stackingrtosarm

Share


Previous Article
SPI Slave DMA Implementation on STM32 for High-Throughput Data Acquisition
Jithin Tom

Jithin Tom

A Closer Look at C/C++, RTOS, and Embedded Systems

Related Posts

Cortex-M SysTick Timer Configuration and Usage
Cortex-M SysTick Timer Configuration and Usage
July 27, 2026
3 min
© 2026, All Rights Reserved.
Powered By Netlyft

Quick Links

Advertise with usAbout UsContact Us

Social Media