class I2C – een tweedraads serieel protocol

I2C is een tweedraads protocol voor communicatie tussen apparaten. Op fysiek niveau bestaat het uit 2 draden: SCL en SDA, respectievelijk de klok- en datalijn.

I2C-objecten worden gemaakt en gekoppeld aan een specifieke bus. Ze kunnen tijdens het maken worden geïnitialiseerd, of pas later.

Door het I2C-object af te drukken krijgt u informatie over de configuratie ervan.

Er bestaan zowel hardware- als software-implementaties van I2C via de klassen I2C en SoftI2C. Hardware-I2C maakt gebruik van de onderliggende hardwareondersteuning van het systeem om de leesacties/schrijfacties uit te voeren en is meestal efficiënt en snel, maar kan beperkingen hebben op welke pinnen kunnen worden gebruikt. Software-I2C wordt geïmplementeerd met bit-banging en kan op elke pin worden gebruikt, maar is niet zo efficiënt. Deze klassen hebben dezelfde methoden beschikbaar en verschillen voornamelijk in de manier waarop ze worden geconstrueerd.

Notitie

De I2C-bus vereist pull-upcircuits op zowel SDA als SCL voor de werking ervan. Meestal zijn dit weerstanden in het bereik van 1 - 10 kOhm, aangesloten van elke SDA/SCL naar Vcc. Zonder deze is het gedrag ongedefinieerd en kan variëren van blokkeren, onverwachte watchdog-reset tot gewoon verkeerde waarden. Vaak is dit pull-upcircuit al ingebouwd in het MCU-bord of de sensor-breakoutborden, maar daar bestaat geen regel voor. Controleer dit dus bij problemen. Zie ook deze uitstekende leidraad van Adafruit over I2C-bedrading.

Voorbeeldgebruik:

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

Constructors

class machine.I2C(id: int, *, scl: Pin | None = None, sda: Pin | None = None, freq: int = 400000, timeout: int = 50000)

Construeer en retourneer een nieuw I2C-object met de volgende parameters:

  • id identificeert een bepaald I2C-randapparaat. Toegestane waarden hangen af van de specifieke port/board

  • scl moet een pin-object zijn dat de te gebruiken pin voor SCL aangeeft.

  • sda moet een pin-object zijn dat de te gebruiken pin voor SDA aangeeft.

  • freq moet een geheel getal zijn dat de maximale frequentie voor SCL instelt.

  • timeout is de maximale tijd in microseconden die voor I2C-transacties is toegestaan. Deze parameter is op sommige ports niet toegestaan.

Merk op dat sommige ports/boards standaardwaarden voor scl en sda hebben die in deze constructor kunnen worden gewijzigd. Andere hebben vaste waarden voor scl en sda die niet kunnen worden gewijzigd.

Algemene methoden

init(scl: Pin, sda: Pin, *, freq: int = 400000) None

Initialiseer de I2C-bus met de gegeven argumenten:

  • scl is een pin-object voor de SCL-lijn

  • sda is een pin-object voor de SDA-lijn

  • freq is de SCL-kloksnelheid

In het geval van hardware-I2C kan de werkelijke klokfrequentie lager zijn dan de gevraagde frequentie. Dit is afhankelijk van de platformhardware. De werkelijke snelheid kan worden bepaald door het I2C-object af te drukken.

scan() List[int]

Scan alle I2C-adressen tussen 0x08 en 0x77 inclusief en retourneer een lijst van de adressen die reageren. Een apparaat reageert als het de SDA-lijn laag trekt nadat zijn adres (inclusief een schrijfbit) op de bus is verzonden.

Primitieve I2C-bewerkingen

De volgende methoden implementeren de primitieve I2C-controllerbusbewerkingen en kunnen worden gecombineerd om elke gewenste I2C-transactie samen te stellen. Ze worden geleverd als u meer controle over de bus nodig hebt, anders kunnen de standaardmethoden (zie hieronder) worden gebruikt.

Deze methoden zijn alleen beschikbaar op de SoftI2C-klasse.

start() None

Genereer een START-conditie op de bus (SDA gaat naar laag terwijl SCL hoog is).

stop() None

Genereer een STOP-conditie op de bus (SDA gaat naar hoog terwijl SCL hoog is).

readinto(buf: bytearray, nack: bool = True, /) None

Leest bytes van de bus en slaat ze op in buf. Het aantal gelezen bytes is de lengte van buf. Na ontvangst van alle bytes behalve de laatste wordt een ACK op de bus verzonden. Nadat de laatste byte is ontvangen, wordt een NACK verzonden als nack waar is, anders wordt een ACK verzonden (en in dit geval gaat het randapparaat ervan uit dat er in een latere aanroep meer bytes worden gelezen).

write(buf: bytes) int

Schrijf de bytes uit buf naar de bus. Controleert dat na elke byte een ACK wordt ontvangen en stopt met het verzenden van de resterende bytes als een NACK wordt ontvangen. De functie retourneert het aantal ontvangen ACK’s.

Standaard busbewerkingen

De volgende methoden implementeren de standaard lees- en schrijfbewerkingen van de I2C-controller die zijn gericht op een bepaald randapparaat.

readfrom(addr: int, nbytes: int, stop: bool = True, /) bytes

Lees nbytes van het randapparaat dat is opgegeven door addr. Als stop waar is, wordt aan het einde van de overdracht een STOP-conditie gegenereerd. Retourneert een bytes-object met de gelezen data.

readfrom_into(addr: int, buf: bytearray, stop: bool = True, /) None

Lees in buf van het randapparaat dat is opgegeven door addr. Het aantal gelezen bytes is gelijk aan de lengte van buf. Als stop waar is, wordt aan het einde van de overdracht een STOP-conditie gegenereerd.

De methode retourneert None.

writeto(addr: int, buf: bytes, stop: bool = True, /) int

Schrijf de bytes uit buf naar het randapparaat dat is opgegeven door addr. Als na het schrijven van een byte uit buf een NACK wordt ontvangen, worden de resterende bytes niet verzonden. Als stop waar is, wordt aan het einde van de overdracht een STOP-conditie gegenereerd, zelfs als een NACK wordt ontvangen. De functie retourneert het aantal ontvangen ACK’s.

writevto(addr: int, vector: tuple | list, stop: bool = True, /) int

Schrijf de bytes uit vector naar het randapparaat dat is opgegeven door addr. vector moet een tuple of lijst zijn van objecten met het bufferprotocol. Het addr wordt eenmaal verzonden en vervolgens worden de bytes van elk object in vector opeenvolgend uitgeschreven. De objecten in vector mogen een lengte van nul bytes hebben, in welk geval ze niet bijdragen aan de uitvoer.

Als na het schrijven van een byte uit een van de objecten in vector een NACK wordt ontvangen, worden de resterende bytes en eventuele resterende objecten niet verzonden. Als stop waar is, wordt aan het einde van de overdracht een STOP-conditie gegenereerd, zelfs als een NACK wordt ontvangen. De functie retourneert het aantal ontvangen ACK’s.

Geheugenbewerkingen

Sommige I2C-apparaten fungeren als een geheugenapparaat (of set registers) waarvan kan worden gelezen en waarnaar kan worden geschreven. In dit geval zijn er twee adressen verbonden aan een I2C-transactie: het randapparaatadres en het geheugenadres. De volgende methoden zijn gemaksfuncties om met dergelijke apparaten te communiceren.

readfrom_mem(addr: int, memaddr: int, nbytes: int, *, addrsize: int = 8) bytes

Lees nbytes van het randapparaat dat is opgegeven door addr, beginnend bij het geheugenadres dat is opgegeven door memaddr. Het argument addrsize geeft de adresgrootte in bits aan. Retourneert een bytes-object met de gelezen data.

readfrom_mem_into(addr: int, memaddr: int, buf: bytearray, *, addrsize: int = 8) None

Lees in buf van het randapparaat dat is opgegeven door addr, beginnend bij het geheugenadres dat is opgegeven door memaddr. Het aantal gelezen bytes is gelijk aan de lengte van buf. Het argument addrsize geeft de adresgrootte in bits aan.

De methode retourneert None.

writeto_mem(addr: int, memaddr: int, buf: bytes, *, addrsize: int = 8) None

Schrijf buf naar het randapparaat dat is opgegeven door addr, beginnend bij het geheugenadres dat is opgegeven door memaddr. Het argument addrsize geeft de adresgrootte in bits aan.

De methode retourneert None.

class SoftI2C – software-geëmuleerde I2C-bus

De SoftI2C-klasse implementeert I2C door willekeurige GPIO-pinnen te bit-bangen. Het biedt hetzelfde methodenoppervlak als I2C plus de primitieve laagniveaubusbewerkingen (start(), stop(), readinto(), write()) voor aanroepers die niet-standaard transacties moeten samenstellen. Gebruik het wanneer de pinnen die u nodig hebt niet zijn aangesloten op een hardware-I2C-blok, wanneer u meer bussen nodig hebt dan de hardware biedt, of om te communiceren met apparaten die ongebruikelijke sequenties vereisen (extra klokken, herhaalde starts na schrijfacties, enz.).

Constructors

class machine.SoftI2C(scl: Pin, sda: Pin, *, freq: int = 400000, timeout: int = 50000)

Construeer een software-I2C-bus aangedreven door scl / sda.

freq is de doel-SCL-kloksnelheid in Hz (de werkelijke snelheid is meestal lager vanwege de overhead van de bit-bang-lus).

timeout is de maximale tijd in microseconden om te wachten op clock stretching (SCL laag gehouden door een ander apparaat op de bus); bij het verstrijken wordt een OSError(ETIMEDOUT) opgeworpen.

Algemene methoden

init(scl: Pin, sda: Pin, *, freq: int = 400000) None

Herinitialiseer de software-I2C-bus met de gegeven pinnen en frequentie. Gelijkwaardig aan het construeren van een nieuwe SoftI2C op hetzelfde object.

scan() List[int]

Scan alle I2C-adressen tussen 0x08 en 0x77 inclusief en retourneer een lijst van de adressen die reageerden.

Primitieve I2C-bewerkingen

De volgende methoden implementeren de primitieve I2C-controllerbusbewerkingen en kunnen worden gecombineerd om elke gewenste I2C-transactie samen te stellen. Ze zijn alleen voor SoftI2C – de hardware-klasse I2C biedt ze niet.

start() None

Genereer een START-conditie op de bus (SDA gaat naar laag terwijl SCL hoog is).

stop() None

Genereer een STOP-conditie op de bus (SDA gaat naar hoog terwijl SCL hoog is).

readinto(buf: bytearray, nack: bool = True, /) None

Lees bytes van de bus in buf. Er worden len(buf) bytes gelezen; na elke byte behalve de laatste wordt een ACK verzonden. Na de laatste byte verzendt nack=True (de standaardwaarde) een NACK om de overdracht te beëindigen; nack=False verzendt een ACK zodat het apparaat geselecteerd blijft voor een volgende readinto().

write(buf: bytes) int

Schrijf buf naar de bus, waarbij na elke byte op een ACK wordt gecontroleerd. De overdracht stopt bij de eerste NACK. Retourneert het aantal ontvangen ACK’s.

Standaard busbewerkingen

De volgende methoden implementeren de standaard lees- en schrijfbewerkingen van de I2C-controller die zijn gericht op een bepaald randapparaat.

readfrom(addr: int, nbytes: int, stop: bool = True, /) bytes

Lees nbytes van het apparaat op het 7-bits adres addr. Als stop waar is, wordt aan het einde van de overdracht een STOP-conditie gegenereerd.

readfrom_into(addr: int, buf: bytearray, stop: bool = True, /) None

Lees len(buf) bytes van het apparaat op addr in buf. Als stop waar is, wordt aan het einde van de overdracht een STOP-conditie gegenereerd.

writeto(addr: int, buf: bytes, stop: bool = True, /) int

Schrijf buf naar het apparaat op addr. De overdracht stopt bij de eerste NACK. Als stop waar is, wordt aan het einde van de overdracht altijd een STOP-conditie gegenereerd (zelfs bij een vroege NACK). Retourneert het aantal ontvangen ACK’s.

writevto(addr: int, vector: tuple | list, stop: bool = True, /) int

Schrijf de aaneenschakeling van de buffers in vector naar het apparaat op addr als een enkele transactie. Lege buffers worden genegeerd. Gedraagt zich als writeto() wat betreft de stop-semantiek en retourwaarde.

Geheugenbewerkingen

Sommige I2C-apparaten fungeren als een geheugenapparaat (of set registers) waarvan kan worden gelezen en waarnaar kan worden geschreven. In dit geval zijn er twee adressen verbonden aan een I2C-transactie: het randapparaatadres en het geheugenadres. De volgende methoden zijn gemakshulpmiddelen om met dergelijke apparaten te communiceren.

readfrom_mem(addr: int, memaddr: int, nbytes: int, *, addrsize: int = 8) bytes

Lees nbytes van het apparaat op addr beginnend bij register memaddr. addrsize is de registeradresbreedte in bits (meestal 8 of 16).

readfrom_mem_into(addr: int, memaddr: int, buf: bytearray, *, addrsize: int = 8) None

Lees in buf van het apparaat op addr beginnend bij register memaddr.

writeto_mem(addr: int, memaddr: int, buf: bytes, *, addrsize: int = 8) None

Schrijf buf naar het apparaat op addr beginnend bij register memaddr.