class I2C – un protocollo seriale a due fili¶
I2C è un protocollo a due fili per la comunicazione tra dispositivi. A livello fisico è costituito da 2 fili: SCL e SDA, rispettivamente le linee di clock e dei dati.
Gli oggetti I2C vengono creati collegati a un bus specifico. Possono essere inizializzati al momento della creazione, oppure successivamente.
La stampa dell’oggetto I2C fornisce informazioni sulla sua configurazione.
Esistono implementazioni I2C sia hardware che software, tramite le classi I2C e SoftI2C. L’I2C hardware utilizza il supporto hardware sottostante del sistema per eseguire le letture/scritture ed è solitamente efficiente e veloce, ma può avere restrizioni su quali pin possono essere utilizzati. L’I2C software è implementato tramite bit-banging e può essere utilizzato su qualsiasi pin, ma non è altrettanto efficiente. Queste classi mettono a disposizione gli stessi metodi e differiscono principalmente per il modo in cui vengono costruite.
Nota
Il bus I2C richiede una circuiteria di pull-up sia su SDA che su SCL per il suo funzionamento. Di solito si tratta di resistori nell’intervallo di 1 - 10 kOhm, collegati da ciascuna linea SDA/SCL a Vcc. Senza di essi, il comportamento è indefinito e può variare dal blocco, a un reset inatteso del watchdog, fino a valori semplicemente errati. Spesso questa circuiteria di pull-up è già integrata nella scheda MCU o nelle schede breakout dei sensori, ma non è una regola assoluta. Quindi controlla in caso di problemi. Vedi anche questa eccellente guida di apprendimento di Adafruit sul cablaggio I2C.
Esempio di utilizzo:
from machine import I2C
i2c = I2C(freq=400000) # create I2C peripheral at frequency of 400kHz
# depending on the port, extra parameters may be required
# to select the peripheral and/or pins to use
i2c.scan() # scan for peripherals, returning a list of 7-bit addresses
i2c.writeto(42, b'123') # write 3 bytes to peripheral with 7-bit address 42
i2c.readfrom(42, 4) # read 4 bytes from peripheral with 7-bit address 42
i2c.readfrom_mem(42, 8, 3) # read 3 bytes from memory of peripheral 42,
# starting at memory-address 8 in the peripheral
i2c.writeto_mem(42, 2, b'\x10') # write 1 byte to memory of peripheral 42
# starting at address 2 in the peripheral
Costruttori¶
- class machine.I2C(id: int, *, scl: Pin | None = None, sda: Pin | None = None, freq: int = 400000, timeout: int = 50000)¶
Costruisce e restituisce un nuovo oggetto I2C utilizzando i seguenti parametri:
id identifica una particolare periferica I2C. I valori consentiti dipendono dalla particolare porta/scheda
scl deve essere un oggetto pin che specifica il pin da utilizzare per SCL.
sda deve essere un oggetto pin che specifica il pin da utilizzare per SDA.
freq deve essere un intero che imposta la frequenza massima per SCL.
timeout è il tempo massimo in microsecondi consentito per le transazioni I2C. Questo parametro non è ammesso su alcune porte.
Nota che alcune porte/schede avranno valori predefiniti di scl e sda che possono essere modificati in questo costruttore. Altre avranno valori fissi di scl e sda che non possono essere modificati.
Metodi generali¶
- init(scl: Pin, sda: Pin, *, freq: int = 400000) None¶
Inizializza il bus I2C con gli argomenti specificati:
scl è un oggetto pin per la linea SCL
sda è un oggetto pin per la linea SDA
freq è la frequenza di clock di SCL
Nel caso dell’I2C hardware, la frequenza di clock effettiva può essere inferiore a quella richiesta. Ciò dipende dall’hardware della piattaforma. La frequenza effettiva può essere determinata stampando l’oggetto I2C.
Operazioni I2C primitive¶
I seguenti metodi implementano le operazioni primitive del bus controller I2C e possono essere combinati per realizzare qualsiasi transazione I2C. Sono forniti nel caso in cui sia necessario un maggior controllo sul bus, altrimenti possono essere usati i metodi standard (vedi sotto).
Questi metodi sono disponibili solo nella classe
SoftI2C.- readinto(buf: bytearray, nack: bool = True, /) None¶
Legge byte dal bus e li memorizza in buf. Il numero di byte letti è la lunghezza di buf. Dopo aver ricevuto tutti i byte tranne l’ultimo verrà inviato un ACK sul bus. Dopo che l’ultimo byte è stato ricevuto, se nack è true verrà inviato un NACK, altrimenti verrà inviato un ACK (e in questo caso la periferica presuppone che altri byte verranno letti in una chiamata successiva).
Operazioni standard del bus¶
I seguenti metodi implementano le operazioni standard di lettura e scrittura del controller I2C che si rivolgono a un determinato dispositivo periferico.
- readfrom(addr: int, nbytes: int, stop: bool = True, /) bytes¶
Legge nbytes dalla periferica specificata da addr. Se stop è true viene generata una condizione di STOP al termine del trasferimento. Restituisce un oggetto
bytescon i dati letti.
- readfrom_into(addr: int, buf: bytearray, stop: bool = True, /) None¶
Legge in buf dalla periferica specificata da addr. Il numero di byte letti sarà la lunghezza di buf. Se stop è true viene generata una condizione di STOP al termine del trasferimento.
Il metodo restituisce
None.
- writeto(addr: int, buf: bytes, stop: bool = True, /) int¶
Scrive i byte da buf sulla periferica specificata da addr. Se viene ricevuto un NACK dopo la scrittura di un byte da buf, i byte rimanenti non vengono inviati. Se stop è true viene generata una condizione di STOP al termine del trasferimento, anche se viene ricevuto un NACK. La funzione restituisce il numero di ACK ricevuti.
- writevto(addr: int, vector: tuple | list, stop: bool = True, /) int¶
Scrive i byte contenuti in vector sulla periferica specificata da addr. vector deve essere una tupla o una lista di oggetti che supportano il buffer protocol. L”addr viene inviato una sola volta e poi i byte di ciascun oggetto in vector vengono scritti in sequenza. Gli oggetti in vector possono avere lunghezza zero byte, nel qual caso non contribuiscono all’output.
Se viene ricevuto un NACK dopo la scrittura di un byte di uno degli oggetti in vector, i byte rimanenti, e qualsiasi oggetto rimanente, non vengono inviati. Se stop è true viene generata una condizione di STOP al termine del trasferimento, anche se viene ricevuto un NACK. La funzione restituisce il numero di ACK ricevuti.
Operazioni di memoria¶
Alcuni dispositivi I2C si comportano come un dispositivo di memoria (o un insieme di registri) da cui è possibile leggere e su cui è possibile scrivere. In questo caso ci sono due indirizzi associati a una transazione I2C: l’indirizzo della periferica e l’indirizzo di memoria. I seguenti metodi sono funzioni di comodità per comunicare con tali dispositivi.
- readfrom_mem(addr: int, memaddr: int, nbytes: int, *, addrsize: int = 8) bytes¶
Legge nbytes dalla periferica specificata da addr a partire dall’indirizzo di memoria specificato da memaddr. L’argomento addrsize specifica la dimensione dell’indirizzo in bit. Restituisce un oggetto
bytescon i dati letti.
- readfrom_mem_into(addr: int, memaddr: int, buf: bytearray, *, addrsize: int = 8) None¶
Legge in buf dalla periferica specificata da addr a partire dall’indirizzo di memoria specificato da memaddr. Il numero di byte letti è la lunghezza di buf. L’argomento addrsize specifica la dimensione dell’indirizzo in bit.
Il metodo restituisce
None.
class SoftI2C – bus I2C emulato via software¶
La classe SoftI2C implementa l’I2C tramite bit-banging di pin GPIO arbitrari. Espone la stessa interfaccia di metodi di I2C più le operazioni primitive di basso livello del bus (start(), stop(), readinto(), write()) per i chiamanti che devono assemblare transazioni non standard. Usala quando i pin di cui hai bisogno non sono collegati a un blocco I2C hardware, quando hai bisogno di più bus di quelli forniti dall’hardware, oppure per dialogare con dispositivi che richiedono sequenze insolite (clock aggiuntivi, start ripetuti dopo le scritture, ecc.).
Costruttori¶
- class machine.SoftI2C(scl: Pin, sda: Pin, *, freq: int = 400000, timeout: int = 50000)¶
Costruisce un bus I2C software pilotato da
scl/sda.freqè la frequenza di clock SCL desiderata in Hz (la frequenza effettiva è tipicamente inferiore a causa dell’overhead del ciclo di bit-bang).timeoutè il tempo massimo in microsecondi di attesa per il clock stretching (SCL tenuto basso da un altro dispositivo sul bus); alla scadenza viene sollevato unOSError(ETIMEDOUT).Metodi generali¶
Operazioni I2C primitive¶
I seguenti metodi implementano le operazioni primitive del bus controller I2C e possono essere combinati per realizzare qualsiasi transazione I2C. Sono esclusivi di SoftI2C – la classe hardware
I2Cnon li espone.- readinto(buf: bytearray, nack: bool = True, /) None¶
Legge byte dal bus in
buf. Vengono lettilen(buf)byte; dopo ogni byte tranne l’ultimo viene inviato un ACK. Dopo l’ultimo byte,nack=True(il valore predefinito) invia un NACK per terminare il trasferimento;nack=Falseinvia un ACK in modo che il dispositivo resti selezionato per una successivareadinto().
Operazioni standard del bus¶
I seguenti metodi implementano le operazioni standard di lettura e scrittura del controller I2C che si rivolgono a un determinato dispositivo periferico.
- readfrom(addr: int, nbytes: int, stop: bool = True, /) bytes¶
Legge
nbytesdal dispositivo all’indirizzo a 7 bitaddr. Sestopè true viene generata una condizione di STOP al termine del trasferimento.
- readfrom_into(addr: int, buf: bytearray, stop: bool = True, /) None¶
Legge
len(buf)byte dal dispositivo all’indirizzoaddrinbuf. Sestopè true viene generata una condizione di STOP al termine del trasferimento.
- writeto(addr: int, buf: bytes, stop: bool = True, /) int¶
Scrive
bufsul dispositivo all’indirizzoaddr. La trasmissione si interrompe al primo NACK. Sestopè true viene sempre generata una condizione di STOP al termine del trasferimento (anche in caso di NACK anticipato). Restituisce il numero di ACK ricevuti.
- writevto(addr: int, vector: tuple | list, stop: bool = True, /) int¶
Scrive la concatenazione dei buffer in
vectorsul dispositivo all’indirizzoaddrcome una singola transazione. I buffer vuoti vengono ignorati. Si comporta comewriteto()per quanto riguarda la semantica distope il valore di ritorno.
Operazioni di memoria¶
Alcuni dispositivi I2C si comportano come un dispositivo di memoria (o un insieme di registri) da cui è possibile leggere e su cui è possibile scrivere. In questo caso ci sono due indirizzi associati a una transazione I2C: l’indirizzo della periferica e l’indirizzo di memoria. I seguenti metodi sono ausili di comodità per dialogare con tali dispositivi.
- readfrom_mem(addr: int, memaddr: int, nbytes: int, *, addrsize: int = 8) bytes¶
Legge
nbytesdal dispositivo all’indirizzoaddra partire dal registromemaddr.addrsizeè la larghezza dell’indirizzo del registro in bit (tipicamente8o16).