// lesson: funcsel
Routing Pins with FUNCSEL
The SIO can only drive a pin the pin mux actually routes to it. Each of the
RP2040's 30 user GPIOs has a control register in the IO_BANK0 block (base
0x40014000): pin N's GPIO_CTRL register sits at offset N*8 + 4.
Its low five bits โ the FUNCSEL field, bits 4:0 โ pick which peripheral
owns the pin: UART, SPI, PWMโฆ Function 5 is the SIO, i.e. "software
controls this pin". Until you select it, all the GPIO_OUT writing in the
world does nothing visible.
FUNCSEL is where last lesson's warning bites: GPIO_CTRL packs other
fields into the same word (output overrides, interrupt config). Most RP2040
peripherals โ IO_BANK0 included โ actually do get atomic bit manipulation for
free: every register is given a 4KB address slot, and writing to its address
plus 0x1000/0x2000/0x3000 atomically XORs/sets/clears bits with no
read-modify-write at all (datasheet ยง2.1.2). The SIO you just used is the
exception โ it's wired straight to the cores off the normal bus, so it
can't do that trick, which is exactly why it needed its own hand-built
SET/CLR/XOR registers. That alias mechanism is one more address computation
on top of what this lesson is really after, though: the field-update shape
below โ mask, or, store โ which the tests exercise directly on a plain
register variable, and which you need to understand regardless of which
write mechanism eventually lands the bits. So here you'll do it by hand:
uint32_t v = *ctrl;
v &= ~0x1fu; /* clear the FUNCSEL field */
v |= funcsel; /* install the new function */
*ctrl = v;
Mask first, then or โ the classic field update. Getting this wrong by writing the whole word would silently zero every other field in the register.
โบ Select a Pin Function
10 ptsImplement gpio_set_funcsel: update only bits 4:0 of the control register,
preserving all 27 other bits.
Log in to submit a solution and earn points.