How ARM Cortex-M Accesses Peripherals: Explained Simply
ARM Cortex-M microcontrollers access peripherals through
memory-mapped registers, where each peripheral is assigned a specific address range in the system memory. The CPU reads from or writes to these addresses using standard load/store instructions, allowing direct control of hardware devices.Syntax
ARM Cortex-M accesses peripherals by reading or writing to specific memory addresses mapped to peripheral registers. The syntax involves using pointers to these addresses in C or assembly code.
For example, to access a peripheral register:
volatile uint32_t *PERIPHERAL_REG = (volatile uint32_t *)0x40000000;— pointer to peripheral register address*PERIPHERAL_REG = value;— write value to peripheralvalue = *PERIPHERAL_REG;— read value from peripheral
c
volatile uint32_t *PERIPHERAL_REG = (volatile uint32_t *)0x40000000; *PERIPHERAL_REG = 0x01; // Write to peripheral register uint32_t value = *PERIPHERAL_REG; // Read from peripheral register
Example
This example shows how to turn on an LED connected to a GPIO peripheral by writing to its data register. The GPIO base address and register offset are used to form the register address.
c
#include <stdint.h> #define GPIO_BASE 0x40020000 #define GPIO_ODR_OFFSET 0x14 int main() { volatile uint32_t *GPIO_ODR = (volatile uint32_t *)(GPIO_BASE + GPIO_ODR_OFFSET); *GPIO_ODR |= (1 << 5); // Set bit 5 to turn on LED while(1) {} return 0; }
Output
The LED connected to GPIO pin 5 turns ON.
Common Pitfalls
Common mistakes when accessing peripherals include:
- Not using
volatilekeyword, causing the compiler to optimize away necessary reads/writes. - Using incorrect peripheral base addresses or offsets.
- Not enabling the peripheral clock before access.
- Ignoring peripheral register bit fields and writing incorrect values.
Always check the microcontroller's reference manual for correct addresses and initialization steps.
c
/* Wrong: Missing volatile, may optimize out access */ uint32_t *GPIO_ODR = (uint32_t *)(0x40020014); *GPIO_ODR = 0x20; // May not actually write /* Correct: Use volatile to prevent optimization */ volatile uint32_t *GPIO_ODR = (volatile uint32_t *)(0x40020014); *GPIO_ODR = 0x20; // Guaranteed write
Quick Reference
Key points to remember when accessing peripherals on ARM Cortex-M:
- Peripherals are accessed via memory-mapped registers at fixed addresses.
- Use
volatilepointers to prevent compiler optimizations. - Always consult the device datasheet for correct base addresses and register offsets.
- Enable peripheral clocks before accessing registers.
- Use bitwise operations to set or clear specific bits safely.
Key Takeaways
ARM Cortex-M accesses peripherals using memory-mapped registers with fixed addresses.
Use volatile pointers in code to ensure proper peripheral register access.
Always enable peripheral clocks before reading or writing registers.
Refer to the microcontroller's manual for correct addresses and register details.
Use bitwise operations to modify peripheral register bits safely.