The ARM Cortex M3 processor implements atomic 32-bit writes, meaning writes of 32-bit values are guaranteed to complete without interruption. This ensures data integrity when writing to memory-mapped peripherals or shared memory locations.
Introduction to Atomicity
Atomicity refers to whether an operation can be interrupted midway through its execution. An atomic operation will either complete fully or not at all – it cannot be left partially finished. This is critical for operations like reading or writing data, where an incomplete write could corrupt the data.
For example, consider writing a 32-bit value to a peripheral register. This may require multiple bus transactions – writing the upper 16 bits, then the lower 16 bits. If the write gets interrupted after the first 16 bits, the register will contain corrupted data. Atomicity prevents this by ensuring the full 32-bit write completes without interruption.
Atomicity in the ARM Cortex M3
The ARM Cortex M3 processor core implements atomicity for 32-bit writes in hardware. This applies to any 32-bit write, including:
- Writing to memory-mapped peripheral registers
- Writing to shared memory locations
- Storing 32-bit values to the stack
The processor ensures these operations complete atomically regardless of interrupts or context switches. For example, a 32-bit write will never be interrupted halfway and resumed later.
Implementation Details
The Cortex M3 achieves atomic 32-bit writes by detecting access sizes and blocking interrupts as needed. If a 32-bit write is detected, interrupts are disabled for the duration of the write. This prevents the write being interrupted partway through.
The processor also contains transaction buffers to queue pending writes. This allows subsequent writes to proceed while an earlier atomic 32-bit write completes. Overall, this hardware implementation provides efficient atomic 32-bit writes without impacting interrupt latency.
Effects on Code
Atomic 32-bit writes happen automatically in hardware, so Cortex M3 code does not have to do anything special to benefit. Any 32-bit store instruction will be atomic, including:
- STR – Store 32-bit register to memory
- PUSH – Store 32-bit register(s) to stack
- STM – Store multiple 32-bit registers to memory
Code does not have to check for atomicity or disable interrupts – the processor takes care of it. This simplifies coding and provides reliable atomic access.
When Atomicity Matters
Atomic 32-bit writes are useful in several cases:
Accessing Memory-Mapped Peripherals
Many peripherals like UARTs and timers use 32-bit registers mapped into the CPU’s memory space. Writing to these registers requires atomic 32-bit accesses to avoid corrupting the peripheral state.
For example, writing a 32-bit timer reload value could require two 16-bit writes. If interrupted in the middle, the timer would be left with an incorrect reload count, causing timing issues. The Cortex M3’s atomic writes prevent this.
Sharing Data Between Tasks
In a RTOS environment, atomicity is very important when sharing data between tasks. If a 32-bit variable is written by one task and read by another, it must be accessed atomically.
The Cortex M3 ensures each 32-bit read or write completes indivisibly. This prevents corrupted data when switching between tasks.
Stack Operations
Pushing/popping 32-bit values to the stack must also be atomic. If interrupted during a multi-word push or pop, the stack pointer could be left in an invalid state leading to hard faults.
The Cortex M3 hardware avoids this by performing all stack operations (push, pop, store, load) as atomic 32-bit accesses, preventing stack corruption.
When Atomicity is Not Needed
While atomic 32-bit accesses are useful in many cases, they are not always needed. Some cases where atomicity is not required:
- Writing to non-shared variables only accessed by one task
- Reading 32-bit values (reads are naturally atomic on Cortex M3)
- 16-bit or 8-bit accesses (performed non-atomically)
- Memory-backed peripheral registers (non-shared so non-atomic access is safe)
In these cases, the overhead of atomic accesses is unnecessary. The Cortex M3 performs these accesses without blocking interrupts, reducing latency.
Disabling Atomicity
In rare cases, atomicity may need to be disabled to reduce interrupt blocking. For example, with very short ISRs where interrupt latency must be minimized.
This can be done globally by clearing the Programmer’s Model > Atomicity Enforcement bit in the Auxiliary Control Register. However, atomicity should only be disabled with great care as it can quickly lead to data corruption issues.
Summary
The Cortex M3 processor implements automatic atomic access for 32-bit data writes, ensuring they complete indivisibly. This prevents data corruption and simplifies software development. Atomicity should be leveraged when accessing shared data structures, peripheral registers, stacks, and other 32-bit values that require an uninterrupted write. For non-shared data, atomicity can be disabled to prioritize low-latency interrupt handling.
Conclusion
Atomic 32-bit writes are a key feature of the Cortex M3 architecture. By understanding how, when, and why to use them, developers can write efficient embedded software that ensures data integrity. Atomic accesses handle the intricacies of shared memory access, simplifying concurrent and RTOS programming.
Overall, the Cortex M3’s atomic write support enables robust and reliable software without imposing overhead during single-threaded or non-shared memory access. This combination of performance, determinism, and reliability makes the Cortex M3 a versatile processor for demanding embedded applications.