3.22. SPI a kódban

A machine.SPI egy hardveres SPI vezérlőt csomagol be; a CS vonalak közönséges Pin kimenetek, amelyeket a szkript kezel. Hozz létre egy SPI példányt a busz azonosítójával, a kívánt órajel-sebességgel és (ha szükséges) a móddal:

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

Az id választja ki, hogy melyik hardveres SPI blokkot használja; az elérhető számok és az SCK/MOSI/MISO lábak, amelyekhez hozzá vannak rendelve, a paneltől függenek (lásd a OpenMV kártyák oldalt). A baudrate az SCK frekvenciája hertzben – a hardver által ténylegesen elért sebesség az órajel-osztás miatt kissé alacsonyabb lehet, amit az SPI objektum kinyomtatott értéke megmutat.

A CS láb value=1 értékkel jön létre, így deaktivált állapotban vár. Minden tranzakció aktiválja a CS-t (alacsonyra hajtja), átmozgatja a bájtokat, majd ismét deaktiválja a CS-t (magasra hajtja).

3.22.1. Olvasás, írás, csere

Három metódus fedi le a gyakori eseteket:

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)

A write() a csak írásra szolgáló gyors út; a vezérlő kitolja a bájtokat, és eldobja azt, amit a periféria a MISO-n visszaküldött. A read() ennek a tükörképe – N darab SCK impulzust léptet ki, miközben egy rögzített üres bájtot (alapértelmezetten 0) küld a MOSI-n, és eltárolja a MISO bájtokat. A write_readinto() a teljes duplexű forma: elküldi a bájtokat az egyik pufferből, és a vele egyidejű MISO bájtokat egy másikba tárolja. Sok periféria ezt a mintát használja – „küldj egy parancsbájtot, majd olvasd be a választ a következő átvitelben” – így a két művelet természetesen illeszkedik egyetlen write_readinto hívásba.

A legtöbb periféria elvárja, hogy a CS vonal a teljes tranzakció alatt aktiválva maradjon (a parancsbájtoktól a válaszbájtokig), ezért tartsd a cs.value(0) / cs.value(1) zárójeleket az egész szekvencia köré, ne pedig az egyes metódushívások köré.

3.22.2. Egy tipikus érzékelő-olvasás

Sok SPI érzékelő belső regiszterek halmazaként szervezi az állapotát, és ugyanazt a csere-alakzatot követi: küldd el a regisztercímet (a felső bitben egy olvasási/írási jelzővel), majd olvasd vagy írd a regiszter bájtjait. A 0x0F regiszter olvasása egy ilyen eszközön:

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]

Az első MISO bájt értéktelen (az eszköz ekkor még a parancsot fogadta); a második MISO bájt tartalmazza a regiszter tartalmát. A pontos parancsbájt-formátum – hogy melyik bit az olvasási/írási jelző, és hogy a cím automatikusan növekszik-e többbájtos olvasásnál – az eszköz adatlapjában található.

3.22.3. Bit-banging

A fenti SPI példány egy hardveres SPI blokkot használ: egy dedikált perifériát az MCU-n belül, saját léptetőregiszterrel és órajel-generátorral, amely az SCK / MOSI / MISO jelalakokat szilíciumban állítja elő. A szoftver csak átad neki egy bájtot; a bitek további CPU-segítség nélkül mozognak a vezetéken, így a CPU szabadon végezhet más munkát párhuzamosan.

Az alternatíva a bit-banging: a szoftver minden biten végigiterál, és közvetlenül a GPIO lábakat kapcsolgatja ugyanazon jelalak előállításához. Nincs hardveres periféria a folyamatban – a CPU alacsonyra hajtja az SCK-t, beállítja a MOSI-t, magasra hajtja az SCK-t, mintavételezi a MISO-t, és így tovább minden bájt minden bitjére. Ez lefoglalja a CPU-t a teljes tranzakció idejére, és lassabban fut, mint amit a hardveres blokk képes, de bármely lábon működik, és nincs szükség hozzá szabad hardveres blokkra.

A machine.SoftSPI ugyanazon SPI API bit-bang megvalósítása:

from machine import SoftSPI, Pin

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

Akkor használd, ha az eszköznek olyan lábakon kell lennie, amelyek nincsenek hardveres SPI blokkhoz bekötve, vagy ha a hardveres blokkok mind használatban vannak. Az 500 kHz kényelmes felső határ a legtöbb kamerán; a CPU a teljes tranzakció idejére elfoglalt marad.