clasa I2C – un protocol serial cu două fire¶
I2C este un protocol cu două fire pentru comunicarea între dispozitive. La nivel fizic constă din 2 fire: SCL și SDA, respectiv liniile de ceas și de date.
Obiectele I2C sunt create atașate la o magistrală specifică. Ele pot fi inițializate la creare sau inițializate mai târziu.
Afișarea obiectului I2C vă oferă informații despre configurația acestuia.
Există atât implementări hardware, cât și software ale I2C, prin clasele I2C și SoftI2C. I2C hardware folosește suportul hardware subiacent al sistemului pentru a efectua citirile/scrierile și este de obicei eficient și rapid, dar poate avea restricții privind pinii care pot fi utilizați. I2C software este implementat prin bit-banging și poate fi folosit pe orice pin, dar nu este la fel de eficient. Aceste clase au aceleași metode disponibile și diferă în principal prin modul în care sunt construite.
Notă
Magistrala I2C necesită un circuit de pull-up atât pe SDA, cât și pe SCL pentru funcționarea sa. De obicei, acestea sunt rezistoare în intervalul 1 - 10 kOhm, conectate de la fiecare SDA/SCL la Vcc. Fără acestea, comportamentul este nedefinit și poate varia de la blocare, resetare neașteptată a watchdog-ului, până la pur și simplu valori greșite. Adesea, acest circuit de pull-up este deja integrat în placa MCU sau în plăcile breakout pentru senzori, dar nu există o regulă în acest sens. Așadar, verificați în caz de probleme. Consultați și acest excelent ghid de învățare de la Adafruit despre cablarea I2C.
Exemplu de utilizare:
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
Constructori¶
- class machine.I2C(id: int, *, scl: Pin | None = None, sda: Pin | None = None, freq: int = 400000, timeout: int = 50000)¶
Construiește și returnează un nou obiect I2C folosind următorii parametri:
id identifică un anumit periferic I2C. Valorile permise depind de portul/placa anume
scl trebuie să fie un obiect pin care specifică pinul de utilizat pentru SCL.
sda trebuie să fie un obiect pin care specifică pinul de utilizat pentru SDA.
freq trebuie să fie un întreg care setează frecvența maximă pentru SCL.
timeout este timpul maxim în microsecunde permis pentru tranzacțiile I2C. Acest parametru nu este permis pe unele porturi.
Rețineți că unele porturi/plăci vor avea valori implicite pentru scl și sda care pot fi modificate în acest constructor. Altele vor avea valori fixe pentru scl și sda care nu pot fi modificate.
Metode generale¶
- init(scl: Pin, sda: Pin, *, freq: int = 400000) None¶
Inițializează magistrala I2C cu argumentele date:
scl este un obiect pin pentru linia SCL
sda este un obiect pin pentru linia SDA
freq este rata de ceas SCL
În cazul I2C hardware, frecvența reală a ceasului poate fi mai mică decât frecvența solicitată. Aceasta depinde de hardware-ul platformei. Rata reală poate fi determinată prin afișarea obiectului I2C.
Operații I2C primitive¶
Următoarele metode implementează operațiile primitive de magistrală ale controllerului I2C și pot fi combinate pentru a realiza orice tranzacție I2C. Ele sunt furnizate dacă aveți nevoie de mai mult control asupra magistralei, altfel pot fi folosite metodele standard (vezi mai jos).
Aceste metode sunt disponibile doar pe clasa
SoftI2C.- start() None¶
Generează o condiție START pe magistrală (SDA trece la nivel jos în timp ce SCL este la nivel înalt).
- stop() None¶
Generează o condiție STOP pe magistrală (SDA trece la nivel înalt în timp ce SCL este la nivel înalt).
- readinto(buf: bytearray, nack: bool = True, /) None¶
Citește octeți de pe magistrală și îi stochează în buf. Numărul de octeți citiți este lungimea lui buf. Un ACK va fi trimis pe magistrală după primirea tuturor octeților, cu excepția ultimului. După primirea ultimului octet, dacă nack este adevărat atunci va fi trimis un NACK, altfel va fi trimis un ACK (și în acest caz perifericul presupune că vor fi citiți mai mulți octeți într-un apel ulterior).
Operații standard de magistrală¶
Următoarele metode implementează operațiile standard de citire și scriere ale controllerului I2C care vizează un anumit dispozitiv periferic.
- readfrom(addr: int, nbytes: int, stop: bool = True, /) bytes¶
Citește nbytes de la perifericul specificat de addr. Dacă stop este adevărat, atunci se generează o condiție STOP la sfârșitul transferului. Returnează un obiect
bytescu datele citite.
- readfrom_into(addr: int, buf: bytearray, stop: bool = True, /) None¶
Citește în buf de la perifericul specificat de addr. Numărul de octeți citiți va fi lungimea lui buf. Dacă stop este adevărat, atunci se generează o condiție STOP la sfârșitul transferului.
Metoda returnează
None.
- writeto(addr: int, buf: bytes, stop: bool = True, /) int¶
Scrie octeții din buf către perifericul specificat de addr. Dacă se primește un NACK după scrierea unui octet din buf, atunci octeții rămași nu sunt trimiși. Dacă stop este adevărat, atunci se generează o condiție STOP la sfârșitul transferului, chiar dacă se primește un NACK. Funcția returnează numărul de ACK-uri primite.
- writevto(addr: int, vector: tuple | list, stop: bool = True, /) int¶
Scrie octeții conținuți în vector către perifericul specificat de addr. vector trebuie să fie un tuplu sau o listă de obiecte cu protocolul buffer. addr este trimis o singură dată, apoi octeții din fiecare obiect din vector sunt scriși secvențial. Obiectele din vector pot avea lungime zero octeți, caz în care nu contribuie la ieșire.
Dacă se primește un NACK după scrierea unui octet din unul dintre obiectele din vector, atunci octeții rămași și orice obiecte rămase nu sunt trimiși. Dacă stop este adevărat, atunci se generează o condiție STOP la sfârșitul transferului, chiar dacă se primește un NACK. Funcția returnează numărul de ACK-uri primite.
Operații de memorie¶
Unele dispozitive I2C acționează ca un dispozitiv de memorie (sau un set de registre) din care se poate citi și în care se poate scrie. În acest caz există două adrese asociate unei tranzacții I2C: adresa perifericului și adresa de memorie. Următoarele metode sunt funcții de conveniență pentru a comunica cu astfel de dispozitive.
- readfrom_mem(addr: int, memaddr: int, nbytes: int, *, addrsize: int = 8) bytes¶
Citește nbytes de la perifericul specificat de addr începând de la adresa de memorie specificată de memaddr. Argumentul addrsize specifică dimensiunea adresei în biți. Returnează un obiect
bytescu datele citite.
- readfrom_mem_into(addr: int, memaddr: int, buf: bytearray, *, addrsize: int = 8) None¶
Citește în buf de la perifericul specificat de addr începând de la adresa de memorie specificată de memaddr. Numărul de octeți citiți este lungimea lui buf. Argumentul addrsize specifică dimensiunea adresei în biți.
Metoda returnează
None.
clasa SoftI2C – magistrală I2C emulată software¶
Clasa SoftI2C implementează I2C prin bit-banging pe pini GPIO arbitrari. Ea expune aceeași suprafață de metode ca I2C plus operațiile primitive de magistrală de nivel scăzut (start(), stop(), readinto(), write()) pentru apelanții care au nevoie să asambleze tranzacții non-standard. Folosiți-o atunci când pinii de care aveți nevoie nu sunt conectați la un bloc I2C hardware, când aveți nevoie de mai multe magistrale decât oferă hardware-ul sau pentru a comunica cu dispozitive care necesită secvențe neobișnuite (ceasuri suplimentare, START-uri repetate după scrieri etc.).
Constructori¶
- class machine.SoftI2C(scl: Pin, sda: Pin, *, freq: int = 400000, timeout: int = 50000)¶
Construiește o magistrală I2C software acționată de
scl/sda.freqeste rata țintă de ceas SCL în Hz (rata reală este de obicei mai mică din cauza supraîncărcării buclei de bit-bang).timeouteste timpul maxim în microsecunde de așteptare pentru întinderea ceasului (SCL menținut la nivel jos de un alt dispozitiv de pe magistrală); la expirare se ridică o eroareOSError(ETIMEDOUT).Metode generale¶
Operații I2C primitive¶
Următoarele metode implementează operațiile primitive de magistrală ale controllerului I2C și pot fi combinate pentru a realiza orice tranzacție I2C. Ele sunt disponibile doar pe SoftI2C – clasa hardware
I2Cnu le expune.- start() None¶
Generează o condiție START pe magistrală (SDA trece la nivel jos în timp ce SCL este la nivel înalt).
- stop() None¶
Generează o condiție STOP pe magistrală (SDA trece la nivel înalt în timp ce SCL este la nivel înalt).
- readinto(buf: bytearray, nack: bool = True, /) None¶
Citește octeți de pe magistrală în
buf. Se citesclen(buf)octeți; un ACK este trimis după fiecare octet, cu excepția ultimului. După ultimul octet,nack=True(valoarea implicită) trimite un NACK pentru a încheia transferul;nack=Falsetrimite un ACK astfel încât dispozitivul să rămână selectat pentru unreadinto()ulterior.
Operații standard de magistrală¶
Următoarele metode implementează operațiile standard de citire și scriere ale controllerului I2C care vizează un anumit dispozitiv periferic.
- readfrom(addr: int, nbytes: int, stop: bool = True, /) bytes¶
Citește
nbytesde la dispozitivul de la adresa pe 7 bițiaddr. Dacăstopeste adevărat, se generează o condiție STOP la sfârșitul transferului.
- readfrom_into(addr: int, buf: bytearray, stop: bool = True, /) None¶
Citește
len(buf)octeți de la dispozitivul de laaddrînbuf. Dacăstopeste adevărat, se generează o condiție STOP la sfârșitul transferului.
Operații de memorie¶
Unele dispozitive I2C acționează ca un dispozitiv de memorie (sau un set de registre) din care se poate citi și în care se poate scrie. În acest caz există două adrese asociate unei tranzacții I2C: adresa perifericului și adresa de memorie. Următoarele metode sunt funcții auxiliare de conveniență pentru comunicarea cu astfel de dispozitive.
- readfrom_mem(addr: int, memaddr: int, nbytes: int, *, addrsize: int = 8) bytes¶
Citește
nbytesde la dispozitivul de laaddrîncepând de la registrulmemaddr.addrsizeeste lățimea adresei de registru în biți (de obicei8sau16).