3.22. Le SPI en code

machine.SPI encapsule un contrôleur SPI matériel ; les lignes CS sont de simples sorties Pin gérées par le script. Construisez une instance SPI avec l’identifiant du bus, le débit d’horloge souhaité et (si nécessaire) le mode :

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

L”id sélectionne le bloc SPI matériel à utiliser ; les numéros disponibles et les broches SCK/MOSI/MISO auxquelles ils correspondent dépendent de la carte (voir la Cartes OpenMV). baudrate est la fréquence de SCK en hertz – le débit réellement atteint par le matériel peut être légèrement inférieur en raison de la division d’horloge, ce que la valeur affichée de l’objet SPI indiquera.

La broche CS est construite avec value=1 afin d’être au repos désactivée. Chaque transaction active CS (la met à l’état bas), déplace les octets, puis désactive de nouveau CS (la met à l’état haut).

3.22.1. Lecture, écriture, échange

Trois méthodes couvrent les cas courants :

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() est le chemin rapide en écriture seule ; le contrôleur pousse les octets et ignore ce que le périphérique renvoie sur MISO. read() en est l’image miroir – elle génère N impulsions SCK tout en envoyant un octet factice fixe (0 par défaut) sur MOSI et stocke les octets reçus sur MISO. write_readinto() est la forme full-duplex : elle envoie les octets d’un tampon et stocke les octets MISO simultanés dans un autre. De nombreux périphériques suivent ce schéma – « envoyer un octet de commande, puis lire la réponse dans le transfert suivant » – de sorte que les deux opérations s’intègrent naturellement dans un seul appel à write_readinto.

La plupart des périphériques s’attendent à ce que la ligne CS reste active pendant toute la transaction (des octets de commande jusqu’aux octets de réponse) ; conservez donc l’encadrement cs.value(0) / cs.value(1) autour de la séquence complète, et non autour de chaque appel de méthode.

3.22.2. Une lecture de capteur typique

De nombreux capteurs SPI organisent leur état sous forme d’un ensemble de registres internes et suivent la même forme d’échange : envoyer l’adresse du registre (avec un indicateur lecture/écriture dans le bit de poids fort), puis lire ou écrire les octets du registre. Une lecture du registre 0x0F sur un tel composant :

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]

Le premier octet MISO est inutilisable (le composant recevait encore la commande à ce moment-là) ; le second octet MISO contient le contenu du registre. Le format exact de l’octet de commande – quel bit est l’indicateur lecture/écriture, si l’adresse s’auto-incrémente lors des lectures multi-octets – figure dans la fiche technique du composant.

3.22.3. Bit-banging

L’instance SPI ci-dessus utilise un bloc SPI matériel : un périphérique dédié à l’intérieur du MCU, doté de son propre registre à décalage et de son propre générateur d’horloge, qui produit les signaux SCK / MOSI / MISO directement en silicium. Le logiciel se contente de lui transmettre un octet ; les bits se déplacent sur le fil sans autre intervention du CPU, laissant ce dernier libre d’effectuer d’autres tâches en parallèle.

L’alternative est le bit-banging : le logiciel boucle sur chaque bit et bascule directement les broches GPIO pour produire la même forme d’onde. Aucun périphérique matériel n’est impliqué – le CPU met SCK à l’état bas, positionne MOSI, met SCK à l’état haut, échantillonne MISO, et ainsi de suite pour chaque bit de chaque octet. Cela monopolise le CPU pendant toute la transaction et s’exécute plus lentement que ne le permet le bloc matériel, mais cela fonctionne sur n’importe quelle broche et ne nécessite pas qu’un bloc matériel soit disponible.

machine.SoftSPI est l’implémentation en bit-banging de la même API SPI :

from machine import SoftSPI, Pin

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

Utilisez-la lorsque le composant doit être relié à des broches qui ne sont pas câblées à un bloc SPI matériel, ou lorsque tous les blocs matériels sont déjà utilisés. 500 kHz constitue un plafond confortable sur la plupart des cams ; le CPU reste occupé pendant toute la transaction.