Raspberry possiede un bus I2C accessibile all'utente (nota 1). Questa interfaccia permette di collegare numerosi circuiti integrati adatti ad interagire col mondo reale: misurare temperature o tensioni, gestire led, LCD e pulsanti, generare tensioni sono solo alcuni esempi. In questa pagina qualche informazione.
Innanzitutto occorre verificare che il kernel sia configurato per usare l'hardware I2C e che sia presente il software necessario. Se usate una versione di Raspbian decentemente aggiornata i moduli relativi sono già presenti nell'installazione standard, anche se non sono attivi.
La strada più semplice è l'attivazione tramite raspi-config (Advanced Options → I2C)
pi@raspberrypi:~ $ sudo raspi-config
Dopo il riavvio:
pi@raspberrypi:~ $ ls -l /dev/i2c-1
crw-rw---- 1 root i2c 89, 1 Mar 6 13:44 /dev/i2c-1
Serviranno inoltre alcuni pacchetti:
vv@vvrpi ~ $ sudo aptitude install libi2c-dev i2c-tools
Infine, se serve, occorre aggiungere gli utenti che utilizzeranno il bus I2C al gruppo automaticamente creato.
vv@vvrpi ~ $ sudo usermod -a -G i2c vv
Per verificare il funzionamento del bus i2C è necessario collegare almeno un dispositivo slave.
Un primo circuito utilizzato come esempio è quello mostrato nella fotografia di apertura e realizzato interamente su breadboard; è costituito da due dispositivi, tra di loro assolutamente indipendenti e scelti solo perché "erano nel cassetto":
Un secondo circuito usato negli esempi è costituito da RPi demo che, tra gli altri componenti, ospita un LM75A.
Ovviamente è possibile condurre i primi "esperimenti" con qualunque circuito I2C, purché dotato di interfaccia a 3.3 V.
Alcune osservazione comuni:
Ovviamente è possibile scegliere altri indirizzi.
Innanzitutto verifichiamo se i circuiti integrati connessi al bus vengono visti correttamente, attraverso il comando i2cdetect -y 1
L'output fornito dal programma è una tabella simile alla seguente:
0 1 2 3 4 5 6
7 8 9 a b c d e f
00: -- -- -- -- -- --
-- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: 20 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- 4b -- -- --
4f
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
Di seguito alcuni esempi che utilizzano i due comandi i2cget e i2cset, per leggere e scrive nei registri di una periferica.
Il primo esempio utilizza LM77, un sensore di temperatura piuttosto diffuso. Abbiamo già verificato che il suo indirizzo è 0x4B.
Passiamo quindi ad interrogare il dispositivo, leggendo una word dal registro 0x00 dal dispositivo 0x4B sul bus 1 (anche qui si rimanda ai fogli tecnici la spiegazione dettagliata):
vv@vvrpi ~ $ i2cget -y 1 0x4b 0x00 w
0x6001
Qualche dettaglio sul comando, ben sapendo che man i2cget è più esaustivo; come dice il nome, i2cget serve per leggere il contenuto di un registro della periferica. I cinque parametri sono rispettivamente:
La risposta ovviamente deve essere interpretata... Per chi ha fretta, 0x6001 contiene la temperatura in gradi centigradi, in complemento a due (in tutto 9 bit utili più il segno ripetuto 4 volte, con precisione di mezzo grado), seguita da tre bit di stato. Per conoscere la temperatura occorre riordinare i due byte (nell'esempio dobbiamo ottenere 0x0160), togliere i tre bit di destra e dividere per due. Qui sotto un codice esemplificativo (devo dire di non immediata comprensione, Bash non si presta molto a manipolare numeri).
Questo esempio con LM75A è molto simile al precedente: in pratica si tratta solo di interpretare diversamente i due byte ricevuti.
pi@raspberrypi:~ $ i2cget -y 1 0x4f 0x00 w
0x8011
In questo caso 0x11 (17 in decimale) è la parte intera della temperatura e 0x80 è la parte frazionaria, formata dai soli tre bit più significativi (1000 0000 → 0,5 in decimale). A fondo pagina uno script esemplificativo.
Come secondo esempio utilizziamo MCP23017 che mette a disposizione 16 ingressi e uscite digitali.
Per leggere il valore dei bit in ingresso alla porta A occorre effettuare nell'ordine le seguenti tre operazioni (si rimanda al foglio tecnico del MCP23017 per i dettagli):
Di seguito i tre comandi, utilizzando la porta A:
vv@vvrpi ~ $ i2cset -y 1 0x20 0x00 0xFF
vv@vvrpi ~ $ i2cset -y 1 0x20 0x0C 0xFF
vv@vvrpi ~ $ i2cget -y 1 0x20 0x12 b
0x3f
La risposta, tradotta in binario ( 0011 1111 ) indica che i primi due ingressi sono collegati a massa, gli altri 6 sono lasciati non collegati.
Qualche dettaglio su i2cset: come dice il nome, serve per impostare il contenuto di un registro. I cinque parametri (tutti in esadecimale) sono rispettivamente:
Simili sono le operazioni che occorre compiere per scrivere, nel nostro caso accendere i LED. Di seguito si utilizzarà la porta B del MCP23017 per accendere un LED si e l'altro no. Occorre:
vv@vvrpi ~ $ i2cset -y 1 0x20 0x01 0x00
vv@vvrpi ~ $ i2cset -y 1 0x20 0x13 0xAA
Qui sotto, un breve script esemplificativo che accende 8 LED in sequenza (supercar.sh).
La figura seguente mostra lo stato di SDA (in color ocra) e SCL (in rosso) durante la scrittura del byte 0x40 nel registro 0x13 del dispositivo con indirizzo 0x20.
Due osservazioni:
L'immagine seguente mostra, in tempo reale, come il bus evolve durante l'esecuzione del programma "supercar".
Infine un dettaglio del diagramma temporale relativo alla condizione di start e alla trasmissione dei primi due bit: si può osservare come il tempo di salita di entrambi i segnali sia molto più alto rispetto a quello di discesa; inoltre la curva esponenziale è quella tipica della carica di un condensatore attraverso una resistenza. Si tratta di un effetto della resistenza di pull-up del bus I2C, che carica le capacità parassite presente sul bus.
La velocità di clock può essere modificata agendo sui parametri passati al modulo. E' necessario, come root, prima rimuovere il modulo (se già caricato al boot) e poi ricaricarlo con la nuova frequenza. Questa procedura in realtà non è consigliata, in quanto I2C viene usato oggi quasi esclusivamente con clock a 100 KHz.
Per esempio, per aumentare la frequenza a 400 kHz (Fast Speed, secondo lo standard) le operazioni da fare sono le seguenti:
vv@vvrpi ~ $ sudo modprobe -r i2c_bcm2708
vv@vvrpi ~ $ sudo modprobe i2c_bcm2708 baudrate=400000
Ovviamente la modifica è temporanea. Se si vuole renderla permanente è sufficiente agire sul file /etc/modules.
In teoria è possibile impostare anche la cosiddetta Fast Speed Plus (1 MHz) e anche oltre. Purtroppo la scelta operata per le resistenze di pull-up rendono piuttosto difficile salire a questa velocità, a meno di realizzare con molta cura i collegamenti, riducendo al minimo le capacità parassite.
Il grafico seguente è relativo ad un circuito operante ad 1 MHz; pur funzionando correttamente, si vede chiaramente che lavora al limite delle sue possibilità.
Se nel vostro progetto è richiesta una velocità di clock superiore a 100 kHz, probabilmente avete fatto scelte sbagliate in merito alla tipologia del bus, meglio sarebbe stato puntare su altro, come SPI. Tra l'altro lo standard SMBus, molto simile a I2C e per molti versi più "moderno", richiede obbligatoriamente un clock tra 10 e 100 kHz.
Simili esempi sono presenti nelle pagine PIC18 come master I2C e Collegare una periferica I2C al bus USB
Prima di creazione di questa pagina: marzo 2016
Ultima modifica: 30 marzo 2018
Raspberry Pi: note di hardware - Versione 1.31 - Luglio
2019
Copyright 2013-2019, Vincenzo Villa (https://www.vincenzov.net)
Quest'opera è stata rilasciata con licenza Creative Commons | Attribuzione-Condividi allo stesso modo 3.0 Unported.