GPIO: Driving LEDs & Reading Buttons

Enable the port clock, set pin modes, write outputs atomically and read inputs — then debounce a real-world button.

General-purpose I/O is the first peripheral everyone programs. On an STM32F4 it takes three steps: switch on the port's clock, configure each pin's mode, then read IDR or write BSRR/ODR.

A complete bare-metal GPIO program

RCC_AHB1ENR enables the clocks for ports A and C; a peripheral without a clock ignores every write.

MODER has two bits per pin; 01 makes PA5 an output, 00 makes PC13 an input.

BSRR's low 16 bits set pins and its high 16 bits reset them, each in one atomic write.

IDR holds the current input levels; the Nucleo button pulls PC13 low when pressed.

Debouncing a mechanical button

GPIOA->MODER |= (1UL << 10); // before enabling the clock Enable RCC_AHB1ENR's GPIOA bit first

With the port clock off, writes to its registers are ignored — the classic 'my LED never turns on' bug.

if (button_pressed()) count++; // polled every loop Debounce and act on the transition (released → pressed)

Contact bounce and the loop speed turn one press into dozens of counts.

Why read back RCC_AHB1ENR after enabling a clock?

On some STM32 parts a peripheral needs a couple of cycles after its clock is enabled; the read-back forces the write to complete before the next access.

How many bits per pin does STM32 MODER use, and what do they mean?

Two: 00 input, 01 general-purpose output, 10 alternate function, 11 analog.