I2C osztály – kétvezetékes soros protokoll

Az I2C egy kétvezetékes protokoll az eszközök közötti kommunikációhoz. Fizikai szinten 2 vezetékből áll: SCL és SDA, azaz az órajel- és az adatvezetékből.

Az I2C objektumok egy adott buszhoz kapcsolódva jönnek létre. Inicializálhatók a létrehozáskor, vagy később is.

Az I2C objektum kiírása a konfigurációjával kapcsolatos információkat ad.

Hardveres és szoftveres I2C megvalósítás egyaránt létezik az I2C és a SoftI2C osztályokon keresztül. A hardveres I2C a rendszer mögöttes hardvertámogatását használja az olvasások/írások végrehajtásához, ami általában hatékony és gyors, de korlátozhatja, hogy mely lábak használhatók. A szoftveres I2C bit-banging technikával valósul meg, bármely lábon használható, de nem olyan hatékony. Ezeknek az osztályoknak ugyanazok a metódusaik érhetők el, és elsősorban a felépítésük módjában különböznek.

Megjegyzés

Az I2C busz a működéséhez felhúzó áramkört igényel mind az SDA, mind az SCL vonalon. Ezek általában 1 - 10 kOhm tartományba eső ellenállások, amelyek az egyes SDA/SCL vonalakat a Vcc-hez kötik. Ezek nélkül a viselkedés nem meghatározott, és a blokkolástól kezdve a váratlan watchdog-újraindításon át egészen az egyszerűen hibás értékekig terjedhet. Gyakran ez a felhúzó áramkör már beépítve megtalálható az MCU-kártyán vagy az érzékelő bővítőkártyáin, de erre nincs szabály. Ezért probléma esetén kérjük, ellenőrizze. Lásd még az Adafruit kiváló tanulási útmutatóját az I2C huzalozásról.

Példa a használatra:

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

Konstruktorok

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

Hozzon létre és adjon vissza egy új I2C objektumot a következő paraméterekkel:

  • Az id egy adott I2C perifériát azonosít. Az engedélyezett értékek az adott porttól/kártyától függenek

  • Az scl egy láb objektum legyen, amely megadja az SCL-hez használandó lábat.

  • Az sda egy láb objektum legyen, amely megadja az SDA-hoz használandó lábat.

  • A freq egy egész szám legyen, amely beállítja az SCL maximális frekvenciáját.

  • A timeout az I2C tranzakciókhoz engedélyezett maximális idő mikroszekundumban. Ez a paraméter egyes portokon nem engedélyezett.

Vegye figyelembe, hogy egyes portoknál/kártyáknál az scl és sda alapértelmezett értékei ebben a konstruktorban módosíthatók. Másoknál az scl és sda rögzített értékűek, amelyek nem módosíthatók.

Általános metódusok

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

Inicializálja az I2C buszt a megadott argumentumokkal:

  • Az scl egy láb objektum az SCL vonalhoz

  • Az sda egy láb objektum az SDA vonalhoz

  • A freq az SCL órajel sebessége

Hardveres I2C esetén a tényleges órajel-frekvencia alacsonyabb lehet a kértnél. Ez a platform hardverétől függ. A tényleges sebesség az I2C objektum kiíratásával állapítható meg.

scan() List[int]

Megvizsgálja az összes I2C címet 0x08 és 0x77 között (beleértve ezeket is), és visszaadja azok listáját, amelyek válaszolnak. Egy eszköz akkor válaszol, ha a címe (beleértve egy írásbitet) a buszra kerül, majd alacsonyra húzza az SDA vonalat.

Elemi I2C műveletek

A következő metódusok az elemi I2C vezérlőbusz-műveleteket valósítják meg, és kombinálhatók bármely I2C tranzakció létrehozásához. Akkor hasznosak, ha nagyobb kontrollra van szükséged a busz felett, egyébként a szabványos metódusok (lásd alább) használhatók.

Ezek a metódusok csak a SoftI2C osztályon érhetők el.

start() None

START feltételt generál a buszon (az SDA alacsonyra vált, miközben az SCL magas).

stop() None

STOP feltételt generál a buszon (az SDA magasra vált, miközben az SCL magas).

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

Bájtokat olvas a buszról, és a buf pufferbe tárolja őket. Az olvasott bájtok száma a buf hossza. Egy ACK kerül a buszra az utolsó kivételével minden bájt fogadása után. Az utolsó bájt fogadása után, ha a nack igaz, akkor NACK kerül kiküldésre, egyébként ACK küldődik (ebben az esetben a periféria azt feltételezi, hogy egy későbbi hívásban további bájtokat fognak olvasni).

write(buf: bytes) int

A buf bájtjait írja a buszra. Minden bájt után ellenőrzi, hogy érkezett-e ACK, és leállítja a fennmaradó bájtok küldését, ha NACK érkezik. A függvény visszaadja a fogadott ACK-k számát.

Szabványos buszműveletek

A következő metódusok a szabványos I2C vezérlő olvasási és írási műveleteket valósítják meg, amelyek egy adott perifériaeszközt céloznak meg.

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

nbytes bájtot olvas az addr által megadott perifériáról. Ha a stop igaz, akkor az átvitel végén STOP feltétel generálódik. Egy bytes objektumot ad vissza az olvasott adattal.

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

Az addr által megadott perifériáról a buf pufferbe olvas. Az olvasott bájtok száma a buf hossza. Ha a stop igaz, akkor az átvitel végén STOP feltétel generálódik.

A metódus a None értéket adja vissza.

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

A buf bájtjait írja az addr által megadott perifériára. Ha egy buf-ból származó bájt írása után NACK érkezik, akkor a fennmaradó bájtok nem kerülnek elküldésre. Ha a stop igaz, akkor az átvitel végén STOP feltétel generálódik, még akkor is, ha NACK érkezik. A függvény visszaadja a fogadott ACK-k számát.

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

A vector-ban található bájtokat írja az addr által megadott perifériára. A vector objektumok puffer protokollt megvalósító elemeinek tuple-je vagy listája legyen. Az addr egyszer kerül elküldésre, majd a vector egyes objektumaiból származó bájtok egymás után íródnak ki. A vector objektumai nulla bájt hosszúak is lehetnek, ebben az esetben nem járulnak hozzá a kimenethez.

Ha a vector egyik objektumából származó bájt írása után NACK érkezik, akkor a fennmaradó bájtok és a fennmaradó objektumok nem kerülnek elküldésre. Ha a stop igaz, akkor az átvitel végén STOP feltétel generálódik, még akkor is, ha NACK érkezik. A függvény visszaadja a fogadott ACK-k számát.

Memóriaműveletek

Egyes I2C eszközök memóriaeszközként (vagy regiszterek halmazaként) viselkednek, amelyekből olvasni és amelyekbe írni lehet. Ebben az esetben két cím tartozik egy I2C tranzakcióhoz: a periféria címe és a memóriacím. A következő metódusok kényelmi függvények az ilyen eszközökkel való kommunikációhoz.

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

nbytes bájtot olvas az addr által megadott perifériáról a memaddr által megadott memóriacímtől kezdve. Az addrsize argumentum a cím méretét adja meg bitekben. Egy bytes objektumot ad vissza az olvasott adattal.

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

Az addr által megadott perifériáról a buf pufferbe olvas a memaddr által megadott memóriacímtől kezdve. Az olvasott bájtok száma a buf hossza. Az addrsize argumentum a cím méretét adja meg bitekben.

A metódus a None értéket adja vissza.

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

A buf-ot írja az addr által megadott perifériára a memaddr által megadott memóriacímtől kezdve. Az addrsize argumentum a cím méretét adja meg bitekben.

A metódus a None értéket adja vissza.

SoftI2C osztály – szoftveresen emulált I2C busz

A SoftI2C osztály az I2C-t tetszőleges GPIO lábak bit-banging technikájával valósítja meg. Ugyanazt a metóduskészletet teszi elérhetővé, mint az I2C, plusz az alacsony szintű elemi buszműveleteket (start(), stop(), readinto(), write()) azon hívók számára, akiknek nem szabványos tranzakciókat kell összeállítaniuk. Akkor használd, ha a szükséges lábak nincsenek hardveres I2C blokkhoz huzalozva, ha több buszra van szükséged, mint amennyit a hardver biztosít, vagy ha olyan eszközökkel akarsz kommunikálni, amelyek szokatlan szekvenciákat igényelnek (extra órajelek, írás utáni ismételt startok stb.).

Konstruktorok

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

Egy scl / sda által vezérelt szoftveres I2C buszt hoz létre.

A freq a cél SCL órajel sebessége Hz-ben (a tényleges sebesség jellemzően alacsonyabb a bit-bang ciklus terhelése miatt).

A timeout az órajel-nyújtás (clock stretching, amikor egy másik eszköz alacsonyan tartja az SCL vonalat a buszon) megvárásának maximális ideje mikroszekundumban; lejártakor egy OSError(ETIMEDOUT) kivétel keletkezik.

Általános metódusok

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

Újrainicializálja a szoftveres I2C buszt a megadott lábakkal és frekvenciával. Egyenértékű egy új SoftI2C létrehozásával ugyanazon az objektumon.

scan() List[int]

Megvizsgálja az összes I2C címet 0x08 és 0x77 között (beleértve ezeket is), és visszaadja azok listáját, amelyek válaszoltak.

Elemi I2C műveletek

A következő metódusok az elemi I2C vezérlőbusz-műveleteket valósítják meg, és kombinálhatók bármely I2C tranzakció létrehozásához. Ezek csak a SoftI2C esetén érhetők el – a hardveres I2C osztály nem teszi elérhetővé őket.

start() None

START feltételt generál a buszon (az SDA alacsonyra vált, miközben az SCL magas).

stop() None

STOP feltételt generál a buszon (az SDA magasra vált, miközben az SCL magas).

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

Bájtokat olvas a buszról a buf pufferbe. len(buf) bájt kerül beolvasásra; minden bájt után ACK küldődik, kivéve az utolsót. Az utolsó bájt után a nack=True (az alapértelmezés) NACK-ot küld az átvitel lezárásához; a nack=False ACK-ot küld, így az eszköz kiválasztva marad egy következő readinto() művelethez.

write(buf: bytes) int

A buf-ot írja a buszra, minden bájt után ellenőrizve az ACK-ot. Az átvitel az első NACK-nál leáll. Visszaadja a fogadott ACK-k számát.

Szabványos buszműveletek

A következő metódusok a szabványos I2C vezérlő olvasási és írási műveleteket valósítják meg, amelyek egy adott perifériaeszközt céloznak meg.

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

nbytes bájtot olvas a 7 bites addr címen lévő eszközről. Ha a stop igaz, az átvitel végén STOP feltétel generálódik.

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

len(buf) bájtot olvas az addr címen lévő eszközről a buf pufferbe. Ha a stop igaz, az átvitel végén STOP feltétel generálódik.

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

A buf-ot írja az addr címen lévő eszközre. Az átvitel az első NACK-nál leáll. Ha a stop igaz, az átvitel végén mindig STOP feltétel generálódik (még korai NACK esetén is). Visszaadja a fogadott ACK-k számát.

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

A vector-ban lévő pufferek összefűzését írja az addr címen lévő eszközre egyetlen tranzakcióként. Az üres pufferek figyelmen kívül maradnak. A stop szemantikája és a visszatérési értéke tekintetében úgy viselkedik, mint a writeto().

Memóriaműveletek

Egyes I2C eszközök memóriaeszközként (vagy regiszterek halmazaként) viselkednek, amelyekből olvasni és amelyekbe írni lehet. Ebben az esetben két cím tartozik egy I2C tranzakcióhoz: a periféria címe és a memóriacím. A következő metódusok kényelmi segédfüggvények az ilyen eszközökkel való kommunikációhoz.

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

nbytes bájtot olvas az addr címen lévő eszközről a memaddr regisztertől kezdve. Az addrsize a regisztercím szélessége bitekben (jellemzően 8 vagy 16).

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

Az addr címen lévő eszközről a buf pufferbe olvas a memaddr regisztertől kezdve.

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

A buf-ot írja az addr címen lévő eszközre a memaddr regisztertől kezdve.