L’Interface périphérique série (SPI) a été développée par Motorola pour permettre à ses puces de communiquer entre elles, tout comme Philips a conçu le bus série I2C pour ses propres circuits intégrés. Alors que ces deux bus font en grande partie le même travail, les deux sont devenus presque aussi monnaie courante, et de nombreux périphériques utilisent l’un ou l’autre pour communiquer avec un microcontrôleur hôte. Cette ubiquité est pourquoi imp soutien les deux.
SPI présente certains avantages par rapport à I2C, en particulier la prise en charge d’un taux de transfert de données plus élevé., SPI a également une capacité duplex qui le rend particulièrement approprié aux applications qui exigent la communication bidirectionnelle simultanée.
D’autre part, SPI nécessite au moins trois fils, partagés par tous les périphériques du bus, et un certain nombre de lignes de sélection de périphériques, une pour chaque périphérique connecté au périphérique contrôleur. I2C, en revanche, ne nécessite que deux fils; il utilise des adresses uniques pour identifier tous les périphériques du bus., Cela rend le travail avec plusieurs périphériques plus simple que L’approche sans adresse de SPI, bien que certains développeurs préfèrent utiliser du matériel pour sélectionner un périphérique plutôt que des données d’adresse.
les Contrôleurs Et Périphériques
SPI sépare de dispositifs dans « contrôleurs » et » périphériques’. Un seul appareil peut envoyer des impulsions de synchronisation pour synchroniser les transferts de données, et c’est celui choisi pour être le contrôleur. Tous les autres, qui synchronisent leurs timings avec le contrôleur, sont considérés comme des périphériques subsidiaires., Le contrôleur-qui dans votre produit doit actuellement être son imp-et ses périphériques peuvent tous transmettre et recevoir des données, mais seul le contrôleur peut établir le modèle de synchronisation selon lequel ils fonctionnent tous. Cette mise en place d’un schéma de synchronisation fixe est ce qui fait de SPI, comme I2C, un bus « synchrone ».
le Bus physique
l’implémentation SPI de l’imp a quatre lignes:
- SCLK, le signal d’horloge série du contrôleur.
- COPI, abréviation de ‘Controller Out, Peripheral In’ (parfois étiqueté MOSI dans les anciennes fiches techniques).,
- OPIC, abréviation de « Controller In, Peripheral Out » (parfois appelé MISO).
- CS, abréviation de « Chip Select » (parfois étiqueté SS, nSS ou SYNC)
COPI et OPIC sont les lignes de transfert de données.
Les imp001 et imp002 ne fournissent pas de broches CS dédiées: vous pouvez utiliser n’importe laquelle des autres broches GPIO de ces imp. Les imp003 et up fournissent des broches CS dédiées dans le cadre de leurs bus SPI, marquées sur la page imp pin MUX.
Remarque l’imp005 fournit une broche de sélection de puce dédiée sur chacun de ses deux bus SPI. Pour spiBCAD, il s’agit de La Broche D; pour spi0, il s’agit de la broche CS0., La méthode API IMP chipselect () peut être utilisée pour prendre le contrôle de l’assertion et de la désassertion de ces broches chip select (veuillez consulter la documentation de la méthode pour plus d’informations).
SPI sur l’imp: jusqu’à quatre lignes se connectent à un seul périphérique
Cette approche suit la définition de Motorola de SPI: chaque transaction de bus — essentiellement un lot d’octets de données — doit être liée à un périphérique spécifique., Texas Instruments a modifié la spécification SPI pour permettre à chaque octet d’être envoyé à un périphérique spécifique, bien que cela nécessite une ligne CS dédiée. Ce mode n’est actuellement pris en charge par aucun imp.
signalisation
En supposant que nous ayons un seul périphérique connecté au contrôleur, les communications sont initiées par le contrôleur tirant la ligne CS bas. Le indique au périphérique de se préparer à converser. Maintenant, le contrôleur commence à envoyer des impulsions d’horloge le long de la ligne SCLK; généralement, les transmissions de données sont verrouillées sur le bord montant de chaque impulsion, bien que ce ne soit pas toujours le cas.,
synchronisation des données: l’imp envoie une commande, le périphérique renvoie des données
Le contrôleur transmettra maintenant des données sur la ligne COPI, conduisant activement la ligne haute pour signaler un 1 ou faible pour un 0. Le périphérique Lira le signal — qui pourrait être une commande pour qu’une lecture de capteur soit envoyée, par exemple — et il retournera cette information sur la ligne de L’OPIC, encore une fois conduisant la ligne à rester haute pour signaler un 1 ou la conduisant bas pour transmettre un 0., Cette exigence selon laquelle la ligne doit être entraînée activement haut ou bas, plutôt que de la laisser s’installer dans un État ou dans l’autre en connectant une résistance, est la raison pour laquelle SPI peut supporter des vitesses plus élevées que I2C. I2C perd le temps de transmission tandis que sa résistance pull-up renvoie la ligne à haute.
cela dit, il est néanmoins bon d’avoir également un pull-up sur une ligne CS pour s’assurer qu’il va haut lorsque le lutin démarre ou dort et ne peut donc pas conduire la ligne haut manuellement. Garder la ligne haute garantit que le périphérique ignorera tous les problèmes sur les lignes de données et d’horloge.,
lorsque le contrôleur a ce qu’il veut, il conduit la ligne CS haute une fois de plus, et le périphérique peut se reposer.
imp SPI Options
chaque imp a un certain nombre de bus SPI indépendants, accessibles en tant que propriétés de l’objet matériel du périphérique, qui est instancié au démarrage. Le tableau pin MUX de chaque imp montre qu’il existe de nombreux choix, en fonction du type de imp que vous utilisez dans votre produit. Ce document suppose que vous utilisez un imp001, vous devriez donc consulter la table pin mux si vous travaillez avec un imp différent., Les deux bus SPI de l’imp001 sont tous deux des implémentations à trois fils du bus, et connectés aux broches 1, 8 et 9, et 2, 5 et 7, respectivement. Les épingles 1 et 5 sont SCLK; 8 et 7 COPI; et 9 et 2 OPIC. Quel que soit l’un des deux bus que vous utilisez, il est recommandé de l’alias au début:
spi1 <- hardware.spi257;spi2 <- hardware.spi189;
configurer l’un ou l’autre pour l’utiliser consiste simplement à dire à l’imp à quelle vitesse vous voulez que le bus fonctionne, et à fournir un ensemble de constantes qui déterminent ensemble le fonctionnement du bus:
spi1.configure(modeFlags, speed);
tout d’abord, la vitesse., This is simply an integer value giving the throughput in kiloHertz (kHz):
The specific SPI data rates available (in kHz) are as follows:
imp001, imp002 | imp003 | imp004m | imp005 | imp006 | |
spi189 | spi257 | spiEBCA spiLGDK |
spiAHSR spiGJKL |
spiBCAD spi0 |
spiXTUVW |
15,000 | 30,000 | 18,000 | 24,000 | The SPI data rates available range from 5KHz to 22.,8MHz The SPI is clocked by dividing 160MHz by any integer from 7 to 32,000 inclusive |
Min. 187KHz, max. 750KHz |
7500 | 15,000 | 9000 | 12,000 | ||
3750 | 7500 | 4500 | 6000 | ||
1875 | 3750 | 2250 | 3000 | All others | |
937.50 | 1875 | 1125 | 1500 | Min. 187KHz, theoretical max. 24MHz |
|
468.75 | 937.50 | 562.50 | 750 | ||
234.,375 | 468.75 | 281.25 | 375 | ||
117.1875 | 234.375 | 140.,g) edge | |||
msb_first | envoyer le bit le plus significatif en premier (par défaut) | ||||
Lsb_first | envoyer le bit le moins significatif en premier | ||||
no_sclk | la broche SCLK n’est pas utilisée | ||||
USE_CS_L | activer l’utilisation de la broche de sélection de puce dédiée (imp005 uniquement) |
ceux-ci peuvent être combinés, si vous en avez besoin, en utilisant l’opérateur logique or, |
, bien que certains soient mutuellement exclusifs, être combiné: simplex_tx et simplex_rx, par exemple., Pour utiliser CLOCK_IDLE_LOW et CLOCK_2ND_EDGE, par exemple, au lieu d’entrer une seule constante comme paramètre dans la méthode configure (), vous devez inclure les deux, séparés par le symbole |
:
spi1.configure(SIMPLEX_TX | MSB_FIRST | CLOCK_IDLE_LOW, 400);
des combinaisons peuvent être nécessaires si elles sont spécifiées par la fiche technique du périphérique, bien que cela ne soit pas immédiatement évident pour le nouveau venu. Les fiches techniques peuvent parler du « mode SPI » d’un périphérique, ou de ses valeurs CPOL (polarité D’Horloge) et CPHA (Phase D’horloge)., CPOL et CPHA déterminent quels bords du signal d’horloge sont utilisés pour piloter et échantillonner les signaux de données. Chacun de ces deux paramètres a deux états possibles, pour quatre combinaisons possibles en tout:
Modes SPI
Les Modes SPI indexent simplement ces combinaisons plutôt que les valeurs CPOL et CPHA distinctes. Le contrôleur et le périphérique doivent communiquer en utilisant les mêmes valeurs CPOL et CPHA, et donc le même Mode., Plusieurs périphériques peuvent signifier différentes configurations, de sorte que le contrôleur devra se reconfigurer chaque fois qu’il doit communiquer avec un périphérique spécifique.,le tableau suivant:
lecture et écriture de données
Après avoir configuré le bus SPI, utilisez la méthode write() pour envoyer une chaîne d’octets au périphérique:
spi1.write("This is an LCD display");
l’utilisation D’une chaîne est facultative: vous pouvez également envoyer un blob d’octets de données brutes:
local blob = blob(4); // Create a four-byte blob...blob.writen(0xDEADBEEF, 'i'); // ...and write a 32-bit value to itspi1.write(blob);
lire une chaîne ou un blob, vous avez besoin de l’une des deux méthodes de lecture SPI de L’API IMP:
local bytes = spi1.readblob(8);local inputString = spi1.readstring(16);
la valeur entière passée en paramètre est, respectivement, le nombre d’octets à lire dans le blob et le nombre de caractères à mettre dans la chaîne., Bien sûr, puisqu’un caractère prend un octet, ces deux méthodes sont équivalentes. Ce dernier convertit simplement blob en chaîne pour vous.
en raison de la nature « full duplex » du bus SPI, les Écritures et les lectures se produisent toujours simultanément. Avec les commandes de lecture et d’écriture que nous avons vues jusqu’à présent, les données se déplaçant dans la direction opposée à celle qui nous intéresse sont ignorées ou mises à zéro. Ainsi, lorsque vous écrivez une chaîne, par exemple, toutes les données arrivant à l’imp du périphérique sont ignorées., Lors de l’une ou l’autre des deux opérations de lecture, une taille correspondante de zéro octet « factice » est écrite sur le périphérique: si vous lisez huit octets, disons, huit 0 sont écrits automatiquement.
pour gérer cette communication bidirectionnelle simultanée, l’API imp dispose d’une quatrième méthode qui combine les lectures et les Écritures:
local inputString = spi1.writeread(outputString);
ainsi, lorsque la chaîne outputString est envoyée le long de la ligne COPI, la variable inputString est remplie par les octets de données arrivant sur CIPO. Vous pouvez envoyer et recevoir des chaînes ou des blobs, mais l’entrée et la sortie doivent être du même type., Quelle que soit la taille de votre blob de sortie, votre blob d’entrée sera de la même taille. De même, les chaînes d’entrée et de sortie seront de même longueur.
le fonctionnement en duplex intégral peut également être utilisé avec des périphériques qui ne s’attendent pas à fonctionner de cette façon — ceux qui nécessitent que les octets « factices » en lecture et en écriture soient une valeur spécifique non nulle. Cette exigence exclut l’utilisation des méthodes régulières write(), readblob() et readstring (), mais writeread() peut être utilisé à leur place pour s’assurer que les valeurs factices préférées du périphérique sont utilisées.,
exemple de Code
le code suivant fonctionne avec L’accéléromètre numérique Analog Devices ADXL345, une pièce qui utilise SPI pour communiquer avec son microcontrôleur hôte. Il prend également en charge I2C, et les broches de cette carte Adafruit breakout, qui est basée sur la puce, sont étiquetées en conséquence. La fiche technique de la puce peut être téléchargée à partir du site Web D’Analog Devices.
Comment fonctionne le Code
Nous utilisons le bus spi257 d’un imp001, alias SPI près du début de la liste. Nous avons également alias pin 8 comme la ligne CS. La fonction spiWriteReg () montre comment ceux-ci sont utilisés., Une transaction d’écriture est signalée en commutant la ligne CS bas. Ensuite, l’adresse du Registre dans lequel nous voulons écrire est convertie d’un entier signé Écureuil 32 bits en une valeur de 8 bits en l’écrivant dans un blob. Ce blob est ensuite écrit sur le bus SPI. Nous faisons la même chose avec la valeur que nous voulons que L’ADXL345 mette dans ce registre, puis nous définissons à nouveau la ligne CS haute pour signaler la fin de la transaction.,
Le Adafruit/Analog Devices ADXL345
la fonction spiReadReg() fonctionne de la même manière, mais cette fois, nous lisons les données de valeur du bus après avoir écrit l’adresse du registre source. L’ADXL345 nécessite des ajustements à l’adresse du Registre dans ce cas: le bit 7 doit être défini pour marquer la transaction comme une opération de lecture, et le bit 6 doit être défini pour indiquer à la puce que nous nous attendons à ce que plus d’un seul octet soit renvoyé.,
lorsque le programme démarre correctement, nous configurons le bus SPI de l’imp pour qu’il corresponde aux exigences de la puce ADXL345. Il utilise le mode SPI 3-ie. CPOL et CPHA doivent tous deux être définis — nous utilisons donc le paramètre imp équivalent: CLOCK_IDLE_HIGH | CLOCK_2ND_EDGE dans l’appel configure (). Nous avons également réglé la vitesse à 100 kHz. Ensuite, la broche 8 de l’imp, qui fonctionne ici en tant que broche CS, est configurée en tant que sortie numérique et réglée haute.
câblage de L’ADXL345
D’autres fonctions du programme initialisent L’ADXL345 lui-même plutôt que le bus SPI., L’ADXL345 est initialisé, et le code lit dans la valeur de l’adresse de registre 0x00
pour s’assurer que le périphérique est présent sur le bus. La puce a un mode d’auto-test qui permet de prendre une série de lectures d’étalonnage; ce que nous faisons et stockons les résultats. Plus tard, dans la fonction loop (), ces valeurs sont utilisées pour ajuster les lectures finales de l’accéléromètre.,
L’ADXL345 enregistre ses échantillons des axes x, y et z sous forme de valeurs de 16 bits, chacune dans deux registres de 8 bits; loop() utilise la fonction spiReadReg() pour acquérir les deux composants de chaque valeur, puis les convertit en valeurs uniques en multipliant l’octet le plus significatif par 256 et en ajoutant au résultat la valeur