Module 10 · Labs 6–8
I/O
With the system understood from the boot ROM up, you wire real parts to the 40-pin header and talk to them from Linux: first the electrical limits of a pin and what it can drive, then GPIO, then the buses, reading each part's datasheet and checking every transaction on a logic analyser.
The interfaces
| Interface | What it is | From Linux | Lab part |
|---|---|---|---|
| GPIO | A pin driven high or low, or read; 3.3 V logic, small currents, pull-ups and edges | The GPIO character device through libgpiod | LEDs and buttons (Lab 6) |
| I2C | Two shared wires, addressed devices, open-drain signalling | i2c-tools, the i2c-dev interface, or a kernel driver | DS3231 clock, SSD1306 display (Lab 7) |
| SPI | Clock, two data lines and a chip select; four modes; full duplex | spidev, or a kernel driver | MCP3008 ADC (Labs 7–8) |
| UART | Asynchronous serial: framing, baud rate, flow control | /dev/tty* | A link to a PC at two baud rates (Lab 8) |
| PWM | A square wave whose duty cycle sets brightness, speed or position | The PWM class in /sys | Final projects |
A pin's electrical limits
The system-on-chip's datasheet gives the exact figures for its pads; these are the rules that follow from them.
| Limit | What it means | What to do |
|---|---|---|
| 3.3 V logic | High is about 3.3 V and low about 0 V. The inputs are not 5 V tolerant. | Never connect a 5 V signal to a pin; put a level shifter between a 5 V part's output and the pin. |
| A few milliamps per pin | Past that, the pin's voltage sags, the pad heats and it can be damaged. | Drive an LED through a resistor sized for a few milliamps; switch anything larger with a MOSFET. |
| A shared I/O supply | Every pin draws from the chip's 3.3 V I/O rail. | Do not light a row of LEDs straight from pins at full current; use a driver chip or MOSFETs. |
| A floating input | An input with nothing driving it reads at random. | Give it a pull-up or pull-down, in the circuit or the pad's own. |
| The 3.3 V and 5 V header pins | Supply pins from the board's regulators, not GPIO; what they give comes out of the board's own power budget (module 2). | Power sensors and modules from a 3.3 V pin. The 5 V pin powers only a load switched through a MOSFET that draws under about 200 mA, such as lab 6's motor or a relay coil; anything larger gets its own supply, sharing only ground with the board. A servo runs from its own 5 V supply, sharing only ground with the board; only its control signal comes from a pin. Sensors stay on 3.3 V so their signals do too. |
| Motors, relays, solenoids | Coils draw large currents, more when they start, and make a voltage spike when they are switched off. | Switch them with a logic-level MOSFET and put a flyback diode across the coil. |
What a pin can drive
| Load | Typical current | How to drive it |
|---|---|---|
| LED | Rated 2 to 10 mA | Straight from the pin, through a series resistor sized for about 2 mA: R = (3.3 V − the LED's voltage) ÷ the current |
| Piezo buzzer | A few mA | Straight from the pin; a PWM pin plays a tone |
| Relay coil | Tens of mA | Through a MOSFET with a flyback diode across the coil, from the 5 V pin |
| Very small DC motor, like lab 6's | Under about 200 mA | Through a logic-level MOSFET with a flyback diode, from the 5 V pin; switching the gate on and off quickly sets its speed |
| Larger DC motor | Hundreds of mA and up, more when it starts or stalls | Its own supply, switched by a MOSFET with a flyback diode, sharing only ground with the board |
| Hobby servo | Hundreds of mA | Its own 5 V supply, sharing only ground with the board; only the control signal comes from a pin |
| LED strip, high-power LED | Up to amps | Its own supply, switched by a MOSFET or driven by a driver chip |
An LED, and a motor
GPIO from Linux
libgpiod's command-line tools are installed with the course tools in lab 1; each one's --help shows the options of the installed version.
| Tool | What it does |
|---|---|
gpiodetect | Lists the GPIO chips |
gpioinfo | Lists every line of a chip, with its name, direction and who is using it |
gpioset | Drives a line high or low |
gpioget | Reads a line |
gpiomon | Waits for and prints edges on a line |
The GPIO pinout gives each header pin's chip and line. A line already claimed by a bus or a driver cannot be used as a GPIO: gpioinfo names its user.
Key ideas
- Before a header pin is a GPIO or a bus signal, its pad has to be multiplexed to that function (module 9).
lgpio pinmux 7J1 <pin>lists the functions a pin's pad can carry;gpioinfoshows whether a bus, a driver or a program holds it now. - A pin is a 3.3 V logic signal that can supply only a few milliamps. It can light an LED through a resistor; anything that needs more current is switched by a MOSFET: a very small motor or a relay coil, under about 200 mA, from the 5 V pin, and anything larger, such as a bigger motor or an LED strip, from its own supply with grounds joined. A servo is different: it runs from its own 5 V supply and takes only its control signal from a pin.
- Linux is not a hard real-time system: the same GPIO toggle takes a different time under load. Lab 6 measures this as a histogram.
- A datasheet's register map is the contract: Lab 7 reads the clock's time registers by hand before using any library.
- A logic analyser shows what actually happened on the wires, which is often not what the code meant.
Resources
| Resource | Use in this module |
|---|---|
| GPIO pinout: Das Frite · Solitude | Which pins carry each bus; select a bus in the legend to relabel the header |
| How to enable UART A and 921600 baud on S805X boards | A second UART on the header (Das Frite's chip family) |
| How to enable and control PWMs on Solitude | PWM from Linux |
| libgpiod | The GPIO library the labs use |