// lesson: memory-mapped-registers
Memory-Mapped Registers
On a desktop OS, hardware hides behind drivers and system calls. On a microcontroller like the RP2040 (the chip on the Raspberry Pi Pico) the hardware is memory: every peripheral is controlled by registers, and each register is a 32-bit word at a fixed address. Store to the address and the peripheral reacts; load from it and you see the peripheral's state.
The addresses come from the datasheet. For example, the RP2040's SIO
("single-cycle I/O") block โ the fast path the cores use to drive GPIO pins
โ lives at base address 0xd0000000. The register that sets output pins
high, GPIO_OUT_SET, is at offset 0x014, so its full address is
0xd0000014.
In C, "store to an address" is a pointer cast and a write:
#include <stdint.h>
#define SIO_BASE 0xd0000000u
#define GPIO_OUT_SET (SIO_BASE + 0x014u)
*(volatile uint32_t *)GPIO_OUT_SET = 1u << 25; /* LED pin on the Pico */
Two things carry all the weight here:
uintptr_t/ integer-to-pointer casts. A register address arrives as a plain number from the datasheet. Casting it tovolatile uint32_t *tells the compiler "treat this number as the location of a 32-bit word".volatile. It tells the compiler every read and write is observable behavior that must happen exactly as written. Without it, the optimizer may delete "redundant" stores or cache a load in a register โ fatal when the value at that address is changed by hardware, not by your code.
The grader has no Pico attached, so the tests hand your functions the addresses of ordinary variables instead of datasheet constants. The pointer mechanics are identical โ on real hardware the only difference is where the number comes from.
โบ Read and Write a Register
10 ptsImplement mmio_write32 and mmio_read32: given a register's address as a
plain integer, store or load a 32-bit value through it. This pair is the
foundation every later challenge builds on.
Log in to submit a solution and earn points.