3.24. I2C v kódu

machine.I2C zapouzdřuje hardwarový řadič I2C. Vytvořte jej s id sběrnice a volitelnou hodinovou frekvencí:

from machine import I2C

i2c = I2C(2, freq=400_000)

id vybírá, který hardwarový blok I2C se použije; dostupná čísla a piny SDA / SCL, na které se mapují, závisí na desce (viz Desky OpenMV). freq je hodinová rychlost SCL – 100_000 je standardní režim, 400_000 je běžná „rychlá“ rychlost, kterou podporuje většina senzorů.

3.24.1. Skenování sběrnice

scan() projde 7bitový adresní prostor a vrátí seznam každého zařízení, které potvrdilo svou adresu:

>>> i2c.scan()
[0x40, 0x68]

To je první věc, kterou vyzkoušet po zapojení nové sběrnice. Pokud je zařízení na seznamu, zapojení a vytahovací rezistory jsou v pořádku. Pokud je seznam prázdný (nebo kratší, než se očekávalo), podezřívejte vytahovací rezistory, zapojení nebo adresní piny zařízení dříve, než budete podezřívat kód.

3.24.2. Vzor paměťově mapovaného přístupu

Většina I2C senzorů vystavuje svůj stav jako sadu interních registrů: stavové příznaky na jedné adrese, měřené byty na druhé, konfiguraci na třetí. Knihovna má dvě pohodlné metody, které se přímo mapují na vzor „naadresuj zařízení, ukaž na registr, poté čti nebo zapiš data“.

Čtení registru:

addr = 0x68
reg  = 0x3B
data = i2c.readfrom_mem(addr, reg, 6)
# `data` is 6 bytes starting at register 0x3B

Toto jediné volání vydá START, odešle adresu zařízení s bitem zápisu, odešle adresu registru (opakovaný start), znovu odešle adresu s bitem čtení, přečte 6 bytů, poslední odmítne (NACK) a provede STOP. Zařízení vidí standardní sekvenci „čtení z registru“; skript vidí jedno volání v Pythonu.

Zápis do registru:

i2c.writeto_mem(addr, 0x6B, b"\x00")

Tato sekvence je zrcadlovým obrazem téhož: START, adresa + zápis, registr, datový byte, STOP.

U zařízení, jejichž adresa registru je dva byty široká (některé paměti EEPROM a paměti s 16bitovým adresováním), předejte addrsize=16:

data = i2c.readfrom_mem(addr, 0x0100, 32, addrsize=16)

3.24.3. Čtení senzoru

Krátká smyčka, která čte identifikátor WHO_AM_I a osu X akcelerometru na typickém MEMS senzoru:

import time
import struct
from machine import I2C

i2c         = I2C(2, freq=400_000)
ADDR        = 0x68
WHO_AM_I    = 0x75
ACCEL_X_HI  = 0x3B

print("WHO_AM_I:", i2c.readfrom_mem(ADDR, WHO_AM_I, 1)[0])

while True:
    raw = i2c.readfrom_mem(ADDR, ACCEL_X_HI, 2)
    x   = struct.unpack(">h", raw)[0]
    print("accel X:", x)
    time.sleep_ms(100)

readfrom_mem() vrací objekt bytes, takže čtení WHO_AM_I indexuje první (a jediný) byte pomocí [0]. Čtení z akcelerometru jsou dva surové byty, které je třeba sestavit do jedné znaménkové 16bitové hodnoty; formát ">h" modulu struct to provede jako big-endian se znaménkem – pořadí bytů, které používá většina I2C senzorů, opačné než konvence little-endian běžná na UART linkách. struct.unpack() vždy vrací n-tici (jeden prvek na každý znak formátu), takže [0] vytáhne jedinou hodnotu.

3.24.4. Přístup na nižší úrovni

Pro zařízení, která nedodržují vzor mapy registrů, dávají dvě metody na nižší úrovni přímou kontrolu nad fází adresy a směrem dat:

i2c.writeto(addr, b"\x01\x02\x03")    # write 3 bytes to addr
data = i2c.readfrom(addr, 4)          # read 4 bytes from addr

Tyto jsou užitečné pro zařízení s rozhraním proudu příkazů (displeje, některé hodiny reálného času), kde pohodlné pomocné funkce pro mapu registrů zcela nevyhovují.

3.24.5. Bit-banging, když není k dispozici hardwarový blok

machine.SoftI2C poskytuje stejné API na libovolných GPIO pinech a protokol generuje softwarově (bit-banging):

from machine import SoftI2C, Pin

i2c = SoftI2C(scl=Pin("P5"), sda=Pin("P4"), freq=100_000)

Použijte jej, když zařízení potřebuje být na pinech, které nejsou propojeny s hardwarovým blokem I2C, nebo když jsou všechny hardwarové bloky obsazené. Smyčka bit-bangingu je pomalejší než hardwarové I2C a CPU zůstává po celou transakci vytížen, ale API je shodné s I2C, takže stávající kód přejde na nový jen změnou konstruktoru.