Memory Mapped I/O on Microcontrollers
Posts in this series:
- Memory Mapped I/O Adventure
- Memory Mapped I/O on Microcontrollers
- Memory Mapped I/O and PCIe
- Userspace Memory Mapped I/O
If you’ve worked with microcontrollers, you might already be familiar with MMIO - it’s the typical way the micro’s peripherals are configured. Let’s use the ATSAMD21 from Atmel as an example. Grab the datasheet from here. The first thing we want to look at is the system or physical memory map. This is found in section 9.2 and shows how memory locations map to different targets.
RAM starts at
0x2000_0000 and extends to
0x2000_8000 (on the largest parts).
Any memory location in that range will be routed to RAM.
Here’s an example of code that reads/writes RAM:
uint8_t *ptr = (uint8_t*)0x20001234; *ptr = 42; printf("ptr = %hhu\n", *ptr);
The IO pins are controlled by the PORT module, described in section 22.
OUT registers controls the state of the pin when it is configured for output.
One such register is at
Here’s an example of code that sets a GPIO output pin state:
uint8_t *ptr = (uint8_t*)0x41004490; uint8_t val = *ptr; val |= (1 << 4); *ptr = val;
The part that is interesting here is that the OUT register is accessed exactly the same way as RAM: that’s the “Memory Mapped” part of “Memory Mapped I/O”.