Gestire i GPIO del Raspberry Pi da riga di comando: Guida a Sysfs
Padroneggia la gestione hardware direttamente da shell
Con questa guida completa vogliamo mostrare come gestire lo switch on/off dei GPIO (General Purpose Input/Output) presenti sulla scheda Raspberry Pi. Questa tecnica, conosciuta come interfaccia sysfs, prevede l’interazione diretta con i pin tramite riga di comando, utilizzando il terminale di Raspberry Pi OS (il sistema un tempo chiamato Raspbian) o di qualsiasi altra distribuzione Linux in uso.
Il grande vantaggio di questo metodo è che non richiede né linguaggi di programmazione né librerie esterne (come RPi.GPIO per Python o WiringPi per C): sfrutta nativamente il file system virtuale del kernel Linux. Per la dimostrazione che segue è stato utilizzato un semplice diodo LED, ma con qualche nozione di elettronica potrete comandare anche carichi a tensione o corrente più elevata, interponendo un transistor, un fotoaccoppiatore o un modulo relè (mai collegare la bobina di un relè direttamente al pin: va comandata tramite un transistor usato come interruttore con un diodo di ricircolo in antiparallelo alla bobina, oppure con un modulo relè che integra già entrambi).
Punto fondamentale di partenza è la directory di sistema /sys/class/gpio/, che contiene le interfacce di controllo dei vari GPIO sotto forma di semplici file di testo.
Nota importante: l’interfaccia sysfs è ufficialmente deprecata nel kernel Linux, anche se è ancora presente su Raspberry Pi OS. Resta ottima per scopi didattici e per piccoli script, ma per i nuovi progetti è consigliabile valutare gli strumenti moderni descritti nel paragrafo finale.
Lo schema elettrico e la numerazione BCM
Nell’esempio seguente utilizzeremo uno schema elettrico minimale, composto da un diodo LED e da una resistenza di limitazione da 150 ohm, collegati al GPIO 15 di un Raspberry Pi (il procedimento vale per tutti i modelli dotati di connettore GPIO, dal Pi 1 al Pi 5).
Attenzione: quando si lavora con sysfs, il numero del GPIO fa sempre riferimento alla numerazione del processore (Broadcom – BCM) e non al numero fisico del pin (BOARD) sul connettore della scheda. Il GPIO 15, ad esempio, corrisponde al pin fisico 10.

Due avvertenze prima di iniziare:
- Offset sui kernel recenti: a partire dal kernel 6.6 (Raspberry Pi OS Bookworm aggiornato) i GPIO in sysfs non sono più numerati da 0, ma partono da una base: ad esempio su Pi 4 e precedenti il GPIO 15 diventa 527 (512 + 15). Per conoscere il numero corretto sul vostro sistema usate
sudo grep GPIO15 /sys/kernel/debug/gpio, che restituisce una riga del tipogpio-527 (GPIO15 ...). Su Raspberry Pi 5 la base è diversa: ricavate il numero sempre con il comando precedente. Su sistemi più datati il numero coincide invece con quello BCM. Negli esempi passo passo che seguono è riportato il numero 15; sui kernel 6.6 e successivi sostituitelo con il numero ricavato (ad esempio 527) anche nel nome della cartella (gpio527invece digpio15). - Permessi: scrivere in
/sys/class/gpio/richiede i privilegi di root oppure l’appartenenza al gruppogpio(l’utente predefinito di Raspberry Pi OS ne fa già parte). Notate chesudo echo 15 > ...non funziona, perché la redirezione viene eseguita dalla shell senza privilegi: usate piuttostoecho 15 | sudo tee /sys/class/gpio/export.
Gestire un GPIO con sysfs passo passo
Per interagire con qualsiasi GPIO e gestirne l’attivazione, dobbiamo seguire questi step fondamentali:
1 – Richiamare il GPIO interessato (Export)
Questo passaggio serve a “prenotare” il pin, comunicando al sistema operativo che intendiamo utilizzarlo dallo spazio utente. Si tratta di scrivere nel file export il numero del GPIO sul quale vogliamo agire. Apriamo quindi il terminale e, volendo lavorare sul GPIO 15, utilizziamo il comando:
echo 15 > /sys/class/gpio/export # kernel datati echo 527 > /sys/class/gpio/export # kernel 6.6+ su Pi 4 e precedenti (512 + 15)
Eseguendo questa istruzione, all’interno della directory /sys/class/gpio/ verrà creata dinamicamente una nuova cartella chiamata gpio15 (oppure gpio527 sui kernel 6.6 e successivi), contenente i file di configurazione per quel pin specifico. Se il pin risulta già esportato, il comando restituirà l’errore Device or resource busy, che in questo caso si può tranquillamente ignorare.
2 – Definire se il nostro GPIO è un Input o un Output (Direction)
Questo passaggio è cruciale: definisce la direzione del segnale, ovvero se il pin deve imporre un livello di tensione (scrivere) oppure rilevare il livello presente su di esso (leggere). Se il nostro obiettivo è pilotare un attuatore (transistor, relè, LED), dovremo impostare il GPIO come output; se invece vogliamo ottenere informazioni da un sensore o leggere la pressione di un pulsante, lo imposteremo come input.
Per farlo, dobbiamo scrivere la parola “in” o “out” all’interno del file direction. Per rendere il nostro GPIO 15 un’uscita, procediamo con:
echo out > /sys/class/gpio/gpio15/direction
3 – Definire lo stato logico del nostro GPIO (Value)
Ora che il pin è configurato come uscita, possiamo fargli emettere un segnale. Abbiamo a disposizione gli stati logici 0 (OFF) e 1 (ON), che corrispondono rispettivamente a 0 V e 3,3 V. (Attenzione a non confondervi con i 5 V presenti su alcuni pin di alimentazione del connettore: i GPIO del Raspberry Pi lavorano rigorosamente a 3,3 V e applicare tensioni superiori può danneggiare irrimediabilmente la scheda. Inoltre ogni pin può erogare solo pochi milliampere: 16 mA è la massima capacità di pilotaggio configurabile, non un valore da sfruttare in modo continuativo; conviene restare sui 2–8 mA per pin e contenere anche la corrente complessiva prelevata da tutti i GPIO, storicamente indicata in circa 50 mA.)
Per accendere il LED collegato al nostro GPIO 15, inviamo il valore 1:
echo 1 > /sys/class/gpio/gpio15/value
Per spegnerlo nuovamente, basterà inviare uno zero:
echo 0 > /sys/class/gpio/gpio15/value
4 – Pulizia delle risorse (Unexport)
Una buona norma di programmazione (spesso trascurata) è quella di rilasciare le risorse del sistema operativo quando abbiamo finito di utilizzarle. Per dire a Linux di rilasciare il GPIO 15 e rimuoverne la cartella, usiamo il comando di unexport:
echo 15 > /sys/class/gpio/unexport
Riassumendo
Per esportare il GPIO 15 come output e impostarlo allo stato logico ON dobbiamo dare i comandi:
echo 15 > /sys/class/gpio/export echo out > /sys/class/gpio/gpio15/direction echo 1 > /sys/class/gpio/gpio15/value
Sui kernel 6.6 e successivi (Pi 4 e precedenti) gli stessi comandi diventano:
echo 527 > /sys/class/gpio/export echo out > /sys/class/gpio/gpio527/direction echo 1 > /sys/class/gpio/gpio527/value
Per esportare un pin diverso, ad esempio il GPIO 14, come output e impostarlo allo stato logico OFF, dobbiamo dare i comandi:
Negli esempi seguenti (GPIO 14 e GPIO 21) vale la stessa regola: sui kernel 6.6 e successivi si somma la base (512 + 14 = 526, 512 + 21 = 533 su Pi 4 e precedenti).
echo 14 > /sys/class/gpio/export echo out > /sys/class/gpio/gpio14/direction echo 0 > /sys/class/gpio/gpio14/value
Nota: i GPIO 14 e 15 sono anche i pin TX e RX della porta seriale (UART). Se la console seriale è attiva (da raspi-config), conviene disabilitarla oppure scegliere altri pin, ad esempio GPIO 17 o 27.
Leggere un input e creare script Bash
Se volessimo leggere lo stato di un pulsante collegato, ad esempio, al GPIO 21, i comandi sarebbero molto simili, ma useremmo in invece di out e il comando cat per visualizzare a schermo il valore (0 oppure 1):
echo 21 > /sys/class/gpio/export echo in > /sys/class/gpio/gpio21/direction cat /sys/class/gpio/gpio21/value
Poiché sysfs non permette di attivare le resistenze di pull-up o pull-down interne, il pulsante va collegato con una resistenza esterna (ad esempio 10 kΩ verso GND o verso 3,3 V): senza di essa l’ingresso resterebbe “flottante” e restituirebbe valori casuali.
Infine, la vera potenza di questo approccio a riga di comando si rivela nella creazione di script automatizzati. Ecco un esempio di un piccolo script Bash che fa lampeggiare il nostro LED per 5 volte di fila, senza dover usare alcun altro linguaggio di programmazione:
#!/bin/bash
# Numero BCM del GPIO
BCM=15
# Sui kernel 6.6 e successivi sysfs numera i GPIO a partire da una base:
# la ricaviamo dal gpiochip del connettore (pinctrl-rp1 su Pi 5,
# pinctrl-bcm2711/bcm2835 sui modelli precedenti). Sui kernel datati vale 0.
BASE=""
for LBL in pinctrl-rp1 pinctrl-bcm; do
for CHIP in /sys/class/gpio/gpiochip*; do
if grep -q "^$LBL" "$CHIP/label" 2>/dev/null; then
BASE=$(cat "$CHIP/base"); break 2
fi
done
done
GPIO=$(( ${BASE:-0} + BCM )) # verificabile con: sudo grep GPIO15 /sys/kernel/debug/gpio
GPIO_PATH=/sys/class/gpio/gpio$GPIO
# Esporta il pin solo se non è già esportato
if [ ! -d "$GPIO_PATH" ]; then
echo $GPIO > /sys/class/gpio/export
sleep 0.1 # attende che il sistema crei i file del pin
fi
# Rilascia il pin anche in caso di interruzione con Ctrl+C
trap 'echo 0 > $GPIO_PATH/value; echo $GPIO > /sys/class/gpio/unexport' EXIT
echo out > $GPIO_PATH/direction
for i in {1..5}
do
echo 1 > $GPIO_PATH/value
sleep 0.5
echo 0 > $GPIO_PATH/value
sleep 0.5
done
echo "Lampeggio completato!"
Salvate lo script, ad esempio come lampeggio.sh, rendetelo eseguibile con chmod +x lampeggio.sh e lanciatelo con sudo ./lampeggio.sh (oppure senza sudo se il vostro utente appartiene al gruppo gpio). Lo script ricava da solo la base dei GPIO, quindi funziona sia sui kernel più datati sia su quelli 6.6 e successivi.
Le alternative moderne: pinctrl e libgpiod
Dato che sysfs è deprecato, sulle versioni recenti di Raspberry Pi OS è disponibile il comando pinctrl, che usa direttamente la numerazione BCM senza alcun offset e funziona su tutti i modelli, Pi 5 compreso:
pinctrl set 15 op dh # GPIO 15 come output, livello alto (ON) pinctrl set 15 op dl # GPIO 15 come output, livello basso (OFF) pinctrl get 15 # mostra lo stato del GPIO 15
In alternativa si possono usare gli strumenti della libreria libgpiod (gpioset, gpioget, gpioinfo), che rappresentano l’interfaccia ufficiale del kernel Linux per la gestione dei GPIO. La sintassi cambia tra la versione 1.x e la 2.x della libreria (la versione installata si controlla con gpioset --version):
# libgpiod 1.x: il comando termina subito dopo aver impostato la linea gpioset gpiochip0 15=1 gpioget gpiochip0 21 # libgpiod 2.x: il chip si indica con -c e gpioset resta in esecuzione, # mantenendo lo stato, finché non si preme Ctrl+C gpioset -c gpiochip0 15=1 gpioget -c gpiochip0 21 # libgpiod 2.x: in alternativa si può usare il nome della linea gpioset GPIO15=1
Sul Raspberry Pi 5 il chip che gestisce il connettore può avere un numero diverso da gpiochip0: verificatelo con gpioinfo oppure usate direttamente il nome della linea.
Preparazione: gruppo gpio e pacchetti
Per usare questi strumenti senza sudo il vostro utente deve appartenere al gruppo gpio. Verificatelo con groups e, se necessario, aggiungetelo (la modifica ha effetto dal login successivo):
groups sudo usermod -aG gpio $USER
Se gli strumenti di libgpiod o per il bus I2C non sono già presenti, si installano con:
sudo apt install gpiod i2c-tools
Ingressi con resistenze di pull-up e pull-down interne
A differenza di sysfs, pinctrl permette di attivare le resistenze interne del pin, evitando la resistenza esterna sul pulsante (per approfondire i concetti di pull-up e pull-down: Arduino: input digitali). Ricordate che sugli ingressi non si devono mai superare i 3,3 V.
pinctrl set 21 ip pu # GPIO 21 come input con pull-up (a riposo legge 1) pinctrl set 21 ip pd # GPIO 21 come input con pull-down (a riposo legge 0) pinctrl set 21 ip pn # GPIO 21 come input senza resistenza interna pinctrl get 21 # legge lo stato del pin (lo/hi) pinctrl get # panoramica di tutti i GPIO
Strumenti utili: pinout e i2cdetect
Il comando pinout (fornito da gpiozero, incluso in Raspberry Pi OS) mostra a video la disposizione del connettore con il nome dei singoli GPIO, mettendo in evidenza le alimentazioni a 3,3 V e 5 V e i pin GND. Ecco l’output su un Raspberry Pi 3 Model B v1.2:
Per risalire all’indirizzo di un dispositivo collegato al bus I2C (che va prima abilitato da raspi-config) si usa i2cdetect del pacchetto i2c-tools. Nell’esempio è collegato un display LCD con indirizzo esadecimale 0x27:
i2cdetect -y 1
Nota su WiringPi (deprecato)
Molte guide usano ancora il comando gpio di WiringPi. Il progetto originale è stato abbandonato nel 2019, il pacchetto non è più nei repository di Raspberry Pi OS e il WiringPi originale non supporta il Raspberry Pi 5; esiste un fork comunitario mantenuto su GitHub, ma per i nuovi progetti è preferibile usare pinctrl o libgpiod. Corrispondenza indicativa dei comandi (GPIO 17 come esempio):
| Operazione | WiringPi (deprecato) | pinctrl |
|---|---|---|
| Uscita a livello alto | gpio -g mode 17 out; gpio -g write 17 1 | pinctrl set 17 op dh |
| Uscita a livello basso | gpio -g write 17 0 | pinctrl set 17 op dl |
| Ingresso con pull-up / pull-down | gpio -g mode 17 up / down | pinctrl set 17 ip pu / pd |
| Lettura stato del pin | gpio -g read 17 | pinctrl get 17 |
| Panoramica di tutti i pin | gpio readall | pinctrl get |
| Scansione bus I2C | gpio i2cdetect | i2cdetect -y 1 |







