3.22. SPI v kódu

machine.SPI obaluje hardwarový řadič SPI; linky CS jsou běžné výstupy Pin spravované skriptem. Vytvořte instanci SPI s id sběrnice, požadovanou rychlostí hodin a (pokud je potřeba) režimem:

from machine import SPI, Pin

spi = SPI(0, baudrate=1_000_000, polarity=0, phase=0)
cs = Pin("P3", Pin.OUT, value=1)         # CS idle high

Parametr id vybírá, který hardwarový blok SPI se má použít; dostupná čísla a piny SCK/MOSI/MISO, na které se mapují, závisí na desce (viz Desky OpenMV). baudrate je frekvence SCK v hertzích – skutečná rychlost, kterou hardware dosáhne, může být kvůli dělení hodin mírně nižší, což ukáže vypsaná hodnota objektu SPI.

Pin CS je vytvořen s value=1, takže je v klidu deaktivován. Každá transakce aktivuje CS (stáhne ho na nízkou úroveň), přesune bajty a CS znovu deaktivuje (stáhne ho na vysokou úroveň).

3.22.1. Čtení, zápis, výměna

Tři metody pokrývají běžné případy:

cs.value(0)
spi.write(b"\x10\x20\x30")              # send 3 bytes, ignore what comes back
cs.value(1)

cs.value(0)
data = spi.read(4)                      # read 4 bytes; sends 0x00 while reading
cs.value(1)

rx = bytearray(2)
cs.value(0)
spi.write_readinto(b"\x9F\x00", rx)     # send 0x9F, 0x00; receive 2 bytes
cs.value(1)

write() je rychlá cesta pouze pro zápis; řadič odešle bajty a zahodí cokoli, co periferie poslala zpět na MISO. read() je zrcadlovým obrazem – vyšle N impulzů SCK, přičemž na MOSI posílá pevný výplňový bajt (ve výchozím stavu 0) a ukládá bajty z MISO. write_readinto() je plně duplexní forma: odešle bajty z jednoho bufferu a současně ukládá bajty z MISO do druhého. Mnoho periferií používá tento vzor – „odešli příkazový bajt, pak v dalším přenosu přečti odpověď“ – takže obě operace přirozeně zapadají do jediného volání write_readinto.

Většina periferií očekává, že linka CS zůstane aktivní po celou transakci (od příkazových bajtů až po bajty odpovědi), takže ponechte závorky cs.value(0) / cs.value(1) kolem celé sekvence, nikoli kolem každého volání metody.

3.22.2. Typické čtení ze senzoru

Mnoho SPI senzorů organizuje svůj stav jako sadu interních registrů a řídí se stejným tvarem výměny: odeslat adresu registru (s příznakem čtení/zápisu v nejvyšším bitu), poté přečíst nebo zapsat bajty registru. Čtení registru 0x0F na takovém zařízení:

rx = bytearray(2)
cs.value(0)
spi.write_readinto(b"\x8F\x00", rx)     # 0x80 = "read" flag, then reg 0x0F
cs.value(1)
register_value = rx[1]

První bajt z MISO je nepoužitelný (zařízení v té chvíli ještě přijímalo příkaz); druhý bajt z MISO obsahuje obsah registru. Přesný formát příkazového bajtu – který bit je příznakem čtení/zápisu, zda se adresa při vícebajtovém čtení automaticky inkrementuje – najdete v datasheetu zařízení.

3.22.3. Bit-banging

Výše uvedená instance SPI používá hardwarový blok SPI: vyhrazenou periferii uvnitř MCU s vlastním posuvným registrem a generátorem hodin, která produkuje průběhy SCK / MOSI / MISO přímo v křemíku. Software jí jen předá bajt; bity se pohybují po vodiči bez další pomoci CPU, čímž ponechává CPU volné pro paralelní práci na něčem jiném.

Alternativou je bit-banging: software prochází ve smyčce každý bit a přímo přepíná piny GPIO, aby vytvořil stejný průběh. Není zapojena žádná hardwarová periferie – CPU stáhne SCK na nízkou úroveň, nastaví MOSI, stáhne SCK na vysokou úroveň, vzorkuje MISO a tak dále pro každý bit každého bajtu. To vytíží CPU po celou transakci a běží pomaleji, než dokáže hardwarový blok, ale funguje to na jakémkoli pinu a nepotřebuje volný hardwarový blok.

machine.SoftSPI je bit-bang implementace stejného SPI API:

from machine import SoftSPI, Pin

spi = SoftSPI(baudrate=500_000, polarity=0, phase=0,
              sck=Pin("P2"), mosi=Pin("P0"), miso=Pin("P1"))

Použijte ji, když zařízení potřebuje být na pinech, které nejsou zapojeny k hardwarovému bloku SPI, nebo když jsou všechny hardwarové bloky obsazeny. 500 kHz je pohodlný strop na většině kamer; CPU zůstává vytížené po celou transakci.