Embedded
GPIO — General-Purpose I/O
The most basic building block: a pin that firmware can configure as an input or output, and read or drive directly. Everything from bit-banged protocols to chip-select lines for SPI ultimately rests on GPIO.
- What it is
- A pin firmware can configure as input or output and read/drive directly — the lowest-level building block of any digital hardware interface.
- Mental model
- A switch you control from code — push-pull can flip it fully both ways, open-drain can only pull it down and rely on a resistor to pull it back up.
- Key numbers
- A few tens of mA max source/sink current per pin; 3.3 V and 5 V are the common logic levels.
- Reach for it when
- Anything that isn't a dedicated peripheral — LEDs, buttons, chip-select lines, bit-banged protocols.
Pin modes
| Mode | Behavior |
|---|---|
| Input (floating) | High-impedance; reads whatever voltage is externally applied — undefined if nothing drives it. |
| Input, pull-up | Internal resistor weakly pulls the pin high when nothing else drives it. |
| Input, pull-down | Internal resistor weakly pulls the pin low when nothing else drives it. |
| Output, push-pull | Actively drives both high and low — the default for most outputs. |
| Output, open-drain | Can only pull low; needs an external (or internal) pull-up to reach high. Required for shared buses like I2C where multiple devices share a line. |
Why open-drain matters
On a push-pull bus, two devices disagreeing about the line's state fight each other — one drives high, one drives low, and current flows between them (a short). Open-drain avoids this: every device can only pull low or release, so the "loudest" state that wins is always low, and nobody fights over who's allowed to drive high. This is exactly the property I2C depends on for both signaling and simple multi-master arbitration.
Electrical basics worth remembering
- Max source/sink current — a GPIO pin can only supply a few tens of mA; driving an LED directly is fine, driving a motor is not.
- Voltage domains — 3.3 V logic driving a 5 V input is usually fine (check the datasheet's "VIH" threshold); the reverse (5 V driving a 3.3 V-only input) can damage the pin without a level shifter.
- Slew rate / drive strength — many MCUs let you configure how fast a pin switches; faster edges radiate more EMI and can ring on long traces.
Linux userspace: the character-device GPIO API
Modern Linux exposes GPIO to userspace through /dev/gpiochipN
character devices and the libgpiod library (the older
sysfs /sys/class/gpio interface is deprecated). See
Linux → Drivers for the driver-model
context.
# command-line, via libgpiod tools
gpioget gpiochip0 17 # read line 17
gpioset gpiochip0 17=1 # drive line 17 high
Real-world applications
- Status LEDs and buttons — the simplest and most common GPIO use, and usually the first line of code written on new hardware.
- Chip select lines — every device on an SPI bus needs its own GPIO-driven CS pin.
- Bit-banged protocols — when no dedicated peripheral exists, GPIO toggled directly in software can emulate simple protocols (slowly, and with careful timing).
- Interrupt sources — a button press or a sensor's data-ready line wakes the CPU via a GPIO configured for edge-triggered interrupts — see Interrupts.
- Reset and enable lines — power-controlling or resetting a peripheral chip is almost always a plain GPIO output.
A pin left floating (no pull-up/down, nothing driving it) doesn't read as a stable 0 or 1 — it reads noise, and can even oscillate rapidly enough to burn extra power through the input buffer. Always give an unused or momentarily-unconnected input pin a defined pull state.