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.