En référence aux cartes Arduino Uno, Mega2560, Leonardo et autres:
- Comment fonctionne SPI?
- À quelle vitesse est SPI?
- Comment se connecter entre un maître et un esclave?
- Comment faire un esclave SPI?
Remarque: ceci est conçu comme une question de référence.
arduino-uno
arduino-mega
c++
arduino-leonardo
spi
Nick Gammon
la source
la source
Réponses:
Introduction à SPI
L' interface SPI ( Serial Peripheral Interface Bus ) est utilisée pour la communication entre plusieurs périphériques sur de courtes distances et à grande vitesse.
Il existe généralement un seul périphérique "maître" qui initie la communication et fournit l'horloge qui contrôle le débit de transfert de données. Il peut y avoir un ou plusieurs esclaves. Pour plusieurs esclaves, chacun a son propre signal "sélection d'esclave", décrit plus loin.
Signaux SPI
Dans un système SPI complet, vous aurez quatre lignes de signal:
Lorsque plusieurs esclaves sont connectés au signal MISO, ils sont supposés passer à l'état trois fois (conserver une haute impédance) de la ligne MISO jusqu'à ce qu'ils soient sélectionnés par Slave Select. Normalement, Slave Select (SS) devient faible pour l'affirmer. C'est-à-dire qu'il est actif bas. Une fois qu'un esclave particulier est sélectionné, il convient de configurer la ligne MISO en tant que sortie afin de pouvoir envoyer des données au maître.
Cette image montre la manière dont les données sont échangées lorsqu’un octet est envoyé:
Notez que trois signaux sont émis par le maître (MOSI, SCK, SS) et l’un est une entrée (MISO).
Timing
La séquence d'événements est la suivante:
SS
va bas pour l'affirmer et activer l'esclaveSCK
ligne bascule pour indiquer quand les lignes de données doivent être échantillonnéesSCK
( en utilisant la phase d'horloge par défaut)SCK
(en utilisant la phase d'horloge par défaut), en modifiantMISO
/MOSI
si nécessaireSS
passe ensuite à l'état haut pour l'annuler.Notez que:
Les données étant envoyées et reçues sur la même impulsion d'horloge, il n'est pas possible pour l'esclave de répondre immédiatement au maître. Les protocoles SPI attendent généralement du maître qu'il demande des données lors d'une transmission et qu'il reçoive une réponse lors d'une transmission ultérieure.
En utilisant la bibliothèque SPI sur l’Arduino, effectuer un seul transfert ressemble à ceci dans le code:
Exemple de code
Exemple d'envoi uniquement (en ignorant les données entrantes):
Câblage pour SPI de sortie uniquement
Le code ci-dessus (qui envoie uniquement) peut être utilisé pour piloter un registre à décalage série de sortie. Ce ne sont que des périphériques de sortie, nous n'avons donc pas à nous soucier des données entrantes. Dans leur cas, la broche SS pourrait être appelée "broche" ou "verrou".
Le registre à décalage série 74HC595 et diverses bandes de LED en sont quelques exemples. Par exemple, cet écran LED de 64 pixels piloté par une puce MAX7219:
Dans ce cas, vous pouvez voir que le fabricant de la carte a utilisé des noms de signaux légèrement différents:
La plupart des conseils vont suivre un modèle similaire. Parfois, DIN est juste DI (Data In).
Voici un autre exemple, cette fois une carte d'affichage à LED à 7 segments (également basée sur la puce MAX7219):
Ceci utilise exactement les mêmes noms de signaux que l’autre tableau. Dans ces deux cas, vous pouvez voir que la carte n'a besoin que de 5 fils, les trois pour SPI, plus l'alimentation et la terre.
Phase d'horloge et polarité
Vous pouvez échantillonner l'horloge SPI de quatre manières.
Le protocole SPI permet des variations sur la polarité des impulsions d'horloge. CPOL est la polarité de l'horloge et l'ACSP est la phase d'horloge.
Ceux-ci sont illustrés dans ce graphique:
Vous devez vous reporter à la fiche technique de votre appareil pour obtenir la phase et la polarité correctes. Il y aura généralement un diagramme qui montre comment échantillonner l'horloge. Par exemple, à partir de la fiche technique de la puce 74HC595:
Comme vous pouvez le constater, l'horloge est normalement basse (CPOL = 0) et est échantillonnée sur le bord d'attaque (CPHA = 0). Il s'agit donc du mode SPI 0.
Vous pouvez changer la polarité de l'horloge et la phase dans le code comme ceci (choisissez-en un, bien sûr):
Cette méthode est déconseillée depuis les versions 1.6.0 et supérieures de l'IDE Arduino. Pour les versions récentes, vous modifiez le mode d'horloge dans l'
SPI.beginTransaction
appel, comme suit:Commande de données
Le bit par défaut est le plus significatif en premier, mais vous pouvez demander au matériel de traiter le bit le moins significatif en premier, comme ceci:
Encore une fois, ceci est déconseillé dans les versions 1.6.0 et suivantes de l'IDE Arduino. Pour les versions récentes, vous modifiez l'ordre des bits dans l'
SPI.beginTransaction
appel, comme suit:La vitesse
Le paramètre par défaut pour SPI consiste à utiliser la vitesse d'horloge système divisée par quatre, c'est-à-dire une impulsion d'horloge SPI toutes les 250 ns, en supposant une horloge de processeur de 16 MHz. Vous pouvez changer le diviseur d'horloge en utilisant
setClockDivider
comme ceci:Où "diviseur" est l'un des:
Le taux le plus rapide est "diviser par 2" ou une impulsion d'horloge SPI toutes les 125 ns, en supposant une horloge de processeur de 16 MHz. Il faudrait donc 8 * 125 ns ou 1 µs pour transmettre un octet.
Cette méthode est déconseillée depuis les versions 1.6.0 et supérieures de l'IDE Arduino. Pour les versions récentes, vous modifiez la vitesse de transfert dans l'
SPI.beginTransaction
appel, comme suit:Cependant, des tests empiriques montrent qu'il est nécessaire de disposer de deux impulsions d'horloge entre octets, de sorte que la cadence maximale à laquelle les octets peuvent être cadencés est de 1,125 µs chacun (avec un diviseur d'horloge de 2).
Pour résumer, chaque octet peut être envoyé à un débit maximal de un par 1,125 µs (avec une horloge de 16 MHz), ce qui donne un taux de transfert maximal théorique de 1 / 1,125 µs, soit 888 888 octets par seconde (sans le temps système comme le réglage SS sur).
Connexion à Arduino
Arduino Uno
Connexion via les broches numériques 10 à 13:
Connexion via l'en-tête ICSP:
Arduino Atmega2560
Connexion via les broches numériques 50 à 52:
Vous pouvez également utiliser l'en-tête ICSP, similaire à l'Uno ci-dessus.
Arduino Leonardo
Le Leonardo et le Micro n’exposent pas les broches SPI sur les broches numériques, contrairement aux Uno et Mega. Votre seule option est d'utiliser les broches d'en-tête ICSP, comme illustré ci-dessus pour l'Uno.
Plusieurs esclaves
Un maître peut communiquer avec plusieurs esclaves (mais un seul à la fois). Pour ce faire, il affirme SS pour un esclave et le désaffirme pour tous les autres. L'esclave qui a SS affirmé (généralement cela signifie LOW) configure sa broche MISO en tant que sortie afin que l'esclave, et cet esclave seul, puisse répondre au maître. Les autres esclaves ignorent les impulsions d'horloge entrantes si SS n'est pas affirmé. Ainsi, vous avez besoin d’un signal supplémentaire pour chaque esclave, comme ceci:
Dans ce graphique, vous pouvez voir que MISO, MOSI, SCK sont partagés entre les deux esclaves, mais chaque esclave a son propre signal SS (sélection d'esclave).
Protocoles
La spécification SPI ne spécifie pas les protocoles en tant que tels, il appartient donc à chaque paire maître / esclave de s’entendre sur la signification des données. Bien que vous puissiez envoyer et recevoir des octets simultanément, l’octet reçu ne peut pas être une réponse directe à l’octet envoyé (car ils sont assemblés simultanément).
Il serait donc plus logique pour une extrémité d'envoyer une requête (par exemple, 4 pourrait signifier "lister le répertoire du disque"), puis d'effectuer des transferts (éventuellement en envoyant des zéros vers l'extérieur) jusqu'à réception d'une réponse complète. La réponse peut se terminer par un caractère de nouvelle ligne ou 0x00.
Lisez la fiche technique de votre périphérique esclave pour connaître les séquences de protocole attendues.
Comment faire un esclave SPI
L'exemple précédent montre que l'Arduino est le maître, envoyant des données à un périphérique esclave. Cet exemple montre comment l’Arduino peut être un esclave.
Configuration materielle
Connectez deux Arduino Unos ensemble avec les broches suivantes connectées l'une à l'autre:
13 (SCK)
+ 5v (si nécessaire)
Sur l’Arduino Mega, les broches sont 50 (MISO), 51 (MOSI), 52 (SCK) et 53 (SS).
Dans tous les cas, MOSI à une extrémité est connecté à MOSI à l'autre, vous ne les échangez pas (c'est-à-dire que vous n'avez pas MOSI <-> MISO). Le logiciel configure l'une des extrémités de MOSI (extrémité principale) en tant que sortie et l'autre extrémité (extrémité esclave) en tant qu'entrée.
Exemple de maître
Exemple esclave
L'esclave est entièrement guidé par des interruptions, il peut donc faire d'autres choses. Les données SPI entrantes sont collectées dans une mémoire tampon et un indicateur est défini lorsqu'un "octet significatif" (dans ce cas, une nouvelle ligne) arrive. Cela indique à l'esclave de démarrer et de traiter les données.
Exemple de connexion de maître à esclave à l'aide de SPI
Comment obtenir une réponse d'un esclave
Dans la suite du code ci-dessus, qui envoie des données d’un maître SPI à un esclave, l’exemple ci-dessous montre l’envoi de données à un esclave, le fait en faire quelque chose et renvoie une réponse.
Le maître est similaire à l'exemple ci-dessus. Cependant, un point important est la nécessité d'ajouter un léger délai (environ 20 microsecondes). Sinon, l'esclave n'a pas la possibilité de réagir aux données entrantes et de faire quelque chose avec.
L'exemple montre l'envoi d'une "commande". Dans ce cas, "a" (ajouter quelque chose) ou "s" (soustraire quelque chose). Cela montre que l'esclave est en train de faire quelque chose avec les données.
Après avoir activé la sélection par esclave (SS) pour lancer la transaction, le maître envoie la commande, suivie d’un nombre quelconque d’octets, puis déclenche la SS pour mettre fin à la transaction.
Un point très important est que l'esclave ne peut pas répondre à un octet entrant au même moment. La réponse doit être dans l'octet suivant. Cela est dû au fait que les bits envoyés et les bits reçus sont envoyés simultanément. Ainsi, pour ajouter quelque chose à quatre chiffres, nous avons besoin de cinq transferts, comme ceci:
Nous demandons d’abord une action sur le numéro 10. Mais nous n’obtenons pas de réponse avant le prochain transfert (celui sur 17). Toutefois, "a" sera défini sur la réponse à 10. Enfin, nous finirons par envoyer un "factice" numéro 0, afin d'obtenir la réponse pour 42.
Maître (exemple)
Le code de l'esclave fait pratiquement tout dans la routine d'interruption (appelée lorsque les données SPI entrantes arrivent). Il prend l'octet entrant et ajoute ou soustrait selon "l'octet de commande" mémorisé. Notez que la réponse sera "collectée" la prochaine fois dans la boucle. C'est pourquoi le maître doit envoyer un dernier transfert "factice" pour obtenir la réponse finale.
Dans mon exemple, j'utilise la boucle principale pour détecter simplement quand SS monte et efface la commande sauvegardée. De cette façon, lorsque SS est à nouveau bas pour la transaction suivante, le premier octet est considéré comme l'octet de commande.
De manière plus fiable, cela se ferait avec une interruption. En d’autres termes, vous devez connecter physiquement le SS à l’une des entrées d’interruption (par exemple, sur l’Uno), connecter la broche 10 (SS) à la broche 2 (une entrée d’interruption) ou utiliser une interruption de changement de broche sur la broche 10.
Ensuite, l’interruption peut être utilisée pour remarquer que le SS est tiré bas ou haut.
Esclave (exemple)
Exemple de sortie
Sortie de l'analyseur logique
Cela montre le délai entre l'envoi et la réception dans le code ci-dessus:
Nouvelle fonctionnalité dans IDE 1.6.0 et versions ultérieures
La version 1.6.0 de l'EDI a, dans une certaine mesure, modifié le fonctionnement de SPI. Vous devez toujours faire
SPI.begin()
avant d'utiliser SPI. Cela configure le matériel SPI. Cependant maintenant, lorsque vous êtes sur le point de commencer à communiquer avec un esclave , vous aussi faitesSPI.beginTransaction()
pour mettre en place SPI (pour cet esclave) avec le bon:Lorsque vous avez fini de communiquer avec l'esclave, vous appelez
SPI.endTransaction()
. Par exemple:Pourquoi utiliser SPI?
Ceci est une excellente question. Mes réponses sont:
Les deux méthodes ont leur place. I 2 C vous permet de connecter plusieurs périphériques à un seul bus (deux fils, plus la terre). Ce serait donc le choix à privilégier si vous aviez besoin d'interroger un nombre important de périphériques, peut-être assez rarement. Cependant, la vitesse de SPI pourrait être plus pertinente dans les situations où vous devez produire rapidement (par exemple une bande de LED) ou entrer rapidement (par exemple un convertisseur ADC).
Les références
Ma page sur SPI contient également des détails sur SPI bit-banged et sur l'utilisation de l'USART pour obtenir un second SPI matériel sur la puce Atmega328.
Bus d'interface périphérique série - Wikipedia
Pages de référence de la bibliothèque Arduino SPI
Documentation SPI au PJRC
Protocole SPI - Sparkfun
la source
Are you going to cover the weirdness that is the Due's SPI?
- Je ne sais rien du SPI de Due (à part présumer que le protocole global est le même). Vous êtes le bienvenu pour ajouter une réponse couvrant cet aspect.