Posts in this series:


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. The OUT registers controls the state of the pin when it is configured for output. One such register is at 0x4100_4490. 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”.