Skip to main content

GPIO

GPIO pins are the simplest way for a program to reach the outside world. The name stands for general-purpose input/output: each pin is a wire that your program controls.

PiGPIO 17GNDresistorLEDhighlowwrite(true)write(false)write(true)write(false)

As an output, a pin is a switch your program flips. High connects it to 3.3 volts, and low connects it to ground. That's enough to light an LED or to signal another chip.

As an input, a pin tells your program what voltage it sees, as high or low. That's how a program reads a button, or a sensor that only ever says yes or no.

An input with nothing connected is said to be floating. With no voltage holding it in place, the pin acts like a tiny antenna, picking up stray signals from the wires and electronics around it, so it can read high one moment and low the next.

A pull-up or pull-down gives the pin a resting value. It's a weak connection inside the chip, to 3.3 volts or to ground, that holds the pin at that level while nothing else is driving it. Anything stronger, such as a pressed button, can still pull it the other way.

warning

The Pi's pins work at 3.3 volts, and 5 volts can damage them. They also supply very little power: keep each pin to about 16 milliamps. That lights an LED, but it won't turn a motor, which needs an amplifier circuit or a driver board, such as the LEGO Build HAT.

What uses it​

  • LEDs, on and off
  • Buttons and switches
  • Motion sensors, such as the HC-SR501, which say only "something moved"
  • Reed switches, which close near a magnet
  • Reset lines on other boards: the Build HAT library resets its HAT this way

Finding the pins​

A pin's number and its GPIO number are different

Every pin has two numbers, and they don't match, because they come from different places. The GPIO number comes from the processor, which numbers its own input and output lines. The pin number comes from the Raspberry Pi board: it's where that line ends up on the header, counting from pin 1. Your code uses the GPIO number.

So Pi.digitalOutput(17) means GPIO 17, which is pin 11. Pin 17 is 3.3 V power. Count from pin 1 before you connect anything: a wire on the wrong pin can put 5 volts on a pin that can't take it, and that can destroy the board.

SD card end13.3 V25 V3GPIO 2I²C SDA45 V5GPIO 3I²C SCL6Ground7GPIO 48GPIO 14UART TX9Ground10GPIO 15UART RX11GPIO 1712GPIO 18PWM013GPIO 2714Ground15GPIO 2216GPIO 23173.3 V18GPIO 2419GPIO 10SPI MOSI20Ground21GPIO 9SPI MISO22GPIO 2523GPIO 11SPI SCLK24GPIO 8SPI CE025Ground26GPIO 7SPI CE127GPIO 0HAT ID28GPIO 1HAT ID29GPIO 530Ground31GPIO 632GPIO 12PWM033GPIO 13PWM134Ground35GPIO 19PWM136GPIO 1637GPIO 2638GPIO 2039Ground40GPIO 21
  • Free to use
  • Free until PWM uses it
  • Refused: it belongs to a bus or the board
  • Power
  • Ground

Not every pin is yours to use. digitalOutput and digitalInput refuse the pins that I²C, SPI and UART use, and GPIO 0 and 1, which the board uses to identify a HAT. Thirteen pins are always free: GPIO 4, 5, 6, 16, 17, 20, 21, 22, 23, 24, 25, 26 and 27. GPIO 12, 13, 18 and 19 are free too, until PWM uses them.

Light an LED​

You'll need an LED, a 330 Ω resistor, a breadboard and two jumper wires. The resistor limits the current to about 4 milliamps, which protects both the LED and the pin. An LED only works one way round: its longer leg goes towards the pin.

9111Pin 1 is at the SD card end
  • Pin 9GNDTo the LED's short leg
  • Pin 11GPIO 17To the resistor, then the LED's long leg
Add the Raspberry Pi library first

Pi and its devices come from a library, not from the language, so this code won't build without it. In IntelliJ, choose Tools | Nylon | Add Nylon Library… and pick raspberry-pi. That adds one line to your project's build.markup.code:

(+dependencies : RepositoryDependency coordinate={"com.grandtheorem:raspberry-pi:0.1.0"} /)

Every file starts with its namespace. Pi is the board, and nylon.time gives us sleep.

namespace led

import grandtheorem.rpi.Pi
import namespace nylon.time

Ask the board for GPIO 17 as an output. The number is the GPIO number, not the position on the header.

entrypoint.default main() {
let led = Pi.digitalOutput(17)

write(true) drives the pin high, which lights the LED. Then wait half a second.

for (10 times) {
led.write(true)
sleep(500.milliseconds())

write(false) drives it low, and the LED goes out.

led.write(false)
sleep(500.milliseconds())
}
}

The LED flashes ten times, and the program ends.

Read a button​

Keep the LED where it is, and add a button. Pressing it joins GPIO 4 to ground.

671Pin 1 is at the SD card end
  • Pin 6GNDTo one side of the button
  • Pin 7GPIO 4To the other side of the button

Pull comes from the devices library, which the Raspberry Pi library brings with it.

namespace button

import grandtheorem.rpi.Pi
import grandtheorem.devices.Pull
import namespace nylon.time

Ask for GPIO 4 as an input with its pull-up on, so it reads high until the button pulls it to ground. The LED is an output, as before.

entrypoint.default main() {
let button = Pi.digitalInput(4, Pull.Up)
let led = Pi.digitalOutput(17)

read() answers true for high, so a pressed button reads false. ! flips that into what we mean.

while (true) {
let pressed = !button.read()
led.write(pressed)

Wait a moment before looking again, so the loop isn't flat out.

sleep(10.milliseconds())
}
}

The LED stays lit for as long as you hold the button. This program loops forever, so press Stop in IntelliJ to end it.

Good to know​

Buttons bounce. Metal contacts chatter for a few milliseconds as they close, so one press can look like several. It doesn't matter here, but it will if you count presses.

The board has an LED of its own. Pi.statusLed() gives you a light with no wiring at all, so Pi.statusLed().blink(3) is the smallest program that does something you can see.

note

These programs ran on a Raspberry Pi 3 B+, as this page shows them.