Search topics...
Interrupts & PrioritiesShared Data Protectionfoundational

What is a critical section and how do you implement one on Cortex-M?

0 upvotes
Practice with AISoon
Study the fundamentals first — Interrupts & Priorities topic page

A critical section is a region of code that must execute atomically with respect to interrupts — no ISR can fire during the critical section, ensuring that shared data is read or modified without interference. On Cortex-M, the simplest implementation is to disable all interrupts at the start and re-enable them at the end using the CMSIS intrinsics __disable_irq() and __enable_irq(). These map directly to the CPSID I and CPSIE I instructions, which clear and set the PRIMASK register's I-bit. When PRIMASK is set, all interrupts with configurable priority are masked — only NMI and HardFault can still fire.

c
__disable_irq();
// Read or modify shared data — no ISR can fire here
shared_timestamp = local_timestamp;
shared_value = local_value;
__enable_irq();

The critical caveat with this simple approach is that it unconditionally enables interrupts at the end, even if interrupts were already disabled before the critical section (e.g., if this code is called from another critical section or from an ISR). The correct pattern saves and restores the previous interrupt state:

c
uint32_t primask = __get_PRIMASK();
__disable_irq();
// Critical region
__set_PRIMASK(primask); // Restore previous state

This is nestable — if interrupts were already disabled, they stay disabled after the restore. Every production-quality RTOS provides macros for this (taskENTER_CRITICAL() / taskEXIT_CRITICAL() in FreeRTOS), and bare-metal projects should adopt the same pattern. The most important rule: keep critical sections as short as possible. Every microsecond spent with interrupts disabled is a microsecond of added worst-case latency for every interrupt in the system. Copy data into local variables inside the critical section, then process it outside. A candidate who describes using __disable_irq() / __enable_irq() without mentioning the save/restore pattern or the latency impact is missing production-level understanding.

Source: Interrupts & Priorities Q&A