Das Serial Peripheral Interface (SPI) wurde von Motorola entwickelt, um seine chips zu kommunizieren mit jede andere, ähnlich wie Philips entwickelt den seriellen I2C-bus für die eigene, integrierte schaltungen. Während diese beiden Busse weitgehend die gleiche Arbeit leisten, sind beide fast gleich alltäglich geworden, und viele Peripheriegeräte verwenden entweder das eine oder das andere, um mit einem Host-Mikrocontroller zu kommunizieren. Diese Allgegenwart ist der Grund, warum imps beide unterstützen.

SPI hat einige Vorteile gegenüber I2C, insbesondere Unterstützung für höhere Datenübertragungsrate., SPI verfügt außerdem über eine Duplexfunktion, die es besonders für Anwendungen geeignet macht, die eine gleichzeitige bidirektionale Kommunikation erfordern.

Andererseits benötigt SPI mindestens drei Drähte, die von allen Geräten am Bus gemeinsam genutzt werden, und eine Anzahl von Geräteauswahlleitungen, eine für jedes an das Steuergerät angeschlossene Peripheriegerät. I2C benötigt dagegen nur zwei Drähte; Es verwendet eindeutige Adressen, um alle Geräte auf dem Bus zu identifizieren., Dies macht die Arbeit mit mehreren Geräten einfacher als der adresslose Ansatz von SPI, obwohl einige Entwickler es vorziehen, Hardware zu verwenden, um ein Gerät anstelle von Adressdaten auszuwählen.

Controller und Peripheriegeräte

SPI trennt Geräte in ‚Controller‘ und ‚Peripheriegeräte‘. Nur ein Gerät kann Timing-Impulse senden, um Datenübertragungen zu synchronisieren, und das ist derjenige, der als Controller ausgewählt wurde. Alle anderen, die ihre Timings mit dem Controller synchronisieren, gelten als subsidiäre Peripheriegeräte., Der Controller — der in Ihrem Produkt derzeit sein Imp sein muss-und seine Peripheriegeräte können alle Daten übertragen und empfangen, aber nur der Controller kann das Timing-Muster festlegen, nach dem sie alle arbeiten. Diese Einrichtung eines festen Timing-Schemas macht SPI wie I2C zu einem „synchronen“ Bus.

Der physische Bus

Die SPI-Implementierung des imp hat vier Zeilen:

  • SCLK, das serielle Taktsignal der Steuerung.
  • COPI, kurz für ‚ Controller Out, Peripheral In ‚(manchmal in alten Datenblättern als MOSI bezeichnet).,
  • CIPO, kurz für ‚ Controller In, Peripheral Out ‚(manchmal mit MISO bezeichnet).
  • CS, kurz für ‚Chip Select ‚(manchmal SS, nSS oder SYNC)

COPI und CIPO sind die Datenübertragungsleitungen.

Die imp001 und imp002 bieten keine dedizierten CS-Pins: Stattdessen können Sie einen dieser anderen GPIO-Pins des imp verwenden. Die imp003 und höher bieten dedizierte CS-Pins als Teil ihrer SPI-Busse, die auf der imp Pin mux-Seite markiert sind.

Hinweis Die imp005 bietet eine dedizierte chip wählen pin auf jeder seiner zwei SPI busse. Für spiBCAD ist dies Pin D; für spi0 ist dies Pin CS0., Die imp-API-Methode chipselect () kann verwendet werden, um die Kontrolle über die Assertion und De-Assertion dieser Chip-Select-Pins zu übernehmen (weitere Informationen finden Sie in der Methodendokumentation).


SPI auf dem imp: Bis zu vier Leitungen verbinden sich mit einem einzelnen Peripheriegerät

Dieser Ansatz folgt der Definition von Motorola SPI: dass jede Bustransaktion — im Wesentlichen ein Stapel von Datenbytes — mit einem bestimmten Peripheriegerät verknüpft werden sollte., Texas Instruments hat die SPI-Spezifikation so geändert, dass jedes Byte an ein bestimmtes Peripheriegerät gesendet werden kann, obwohl hierfür eine dedizierte CS-Zeile erforderlich ist. Dieser Modus wird derzeit von keinem imp unterstützt.

Signalisierung

Unter der Annahme, dass ein einzelnes Peripheriegerät an den Controller angeschlossen ist, wird die Kommunikation vom Controller initiiert, der die CS-Leitung niedrig zieht. Der sagt dem Peripheriegerät, sich bereit zu machen, sich zu unterhalten. Jetzt beginnt der Controller mit dem Senden von Taktpulsen entlang der SCLK-Leitung; Typischerweise werden Datenübertragungen an die ansteigende Kante jedes Impulses gesendet, obwohl dies nicht immer der Fall ist.,


Daten ein-und ausschalten: Der imp sendet einen Befehl, das Peripheriegerät gibt Daten zurück

Der Controller überträgt nun Daten auf der COPI-Linie und treibt die Linie aktiv hoch, um eine 1 oder niedrig für eine 0 zu signalisieren. Das Peripheriegerät liest das Signal — was beispielsweise ein Befehl zum Senden eines Sensorlesegeräts sein kann — und gibt diese Informationen in der CIPO-Zeile zurück, wobei die Zeile erneut hoch bleibt, um eine 1 zu signalisieren, oder niedrig, um eine 0 zu übertragen., Diese Anforderung, dass die Leitung aktiv hoch oder niedrig angetrieben wird, anstatt sie sich durch Anschließen eines Widerstands in den einen oder anderen Zustand absetzen zu lassen, ist der Grund, warum SPI höhere Geschwindigkeiten als I2C unterstützen kann. I2C verliert die Übertragungszeit, während sein Pull-up-Widerstand die Leitung auf hoch zurückführt.

Trotzdem ist es eine gute Praxis, auch einen Pull-up auf einer CS-Leitung zu haben, um sicherzustellen, dass er hoch geht, wenn der Imp bootet oder schläft und daher die Leitung nicht manuell hochfahren kann. Wenn Sie die Leitung hoch halten, wird sichergestellt, dass das Peripheriegerät Störungen an den Daten-und Taktleitungen ignoriert.,

Wenn der Controller hat, was er will, fährt er die CS-Leitung noch einmal hoch und das Peripheriegerät kann ruhen.

imp-SPI-Optionen

Jeder imp verfügt über eine Reihe unabhängiger SPI-Busse, auf die als Eigenschaften des Hardwareobjekts des Geräts zugegriffen wird, das beim Start instanziiert wird. Die Pin-Mux-Tabelle jedes imp zeigt, dass es viele Möglichkeiten gibt, je nachdem, welche Art von Imp Sie in Ihrem Produkt verwenden. In diesem Dokument wird davon ausgegangen, dass Sie ein impp verwenden, daher sollten Sie die Pin-Mux-Tabelle konsultieren, wenn Sie mit einem anderen imp arbeiten., Die beiden SPI-Busse des imp001 sind beide dreiadrige Implementierungen des Busses und mit den Pins 1, 8 und 9 bzw. Pins 1 und 5 sind SCLK; 8 und 7 COPI; und 9 und 2 CIPO. Unabhängig davon, welche der beiden Busse Sie verwenden, ist es eine gute Praxis, es am Anfang Alias:

spi1 <- hardware.spi257;spi2 <- hardware.spi189;

Die Konfiguration entweder für den Einsatz ist einfach eine Frage der imp sagen, wie schnell der Bus laufen soll, und eine Reihe von Konstanten zur Verfügung zu stellen, die zusammen bestimmen, wie der Bus funktioniert:

spi1.configure(modeFlags, speed);

Zuerst die Geschwindigkeit., 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 Senden Sie zuerst das höchstwertige Bit (Standard)
LSB_FIRST Senden Sie zuerst das niedrigstwertige Bit
NO_SCLK SCLK pin wird nicht verwendet
USE_CS_L td> Aktivieren sie die verwendung der dedizierten chip wählen pin (imp005 nur)

Diese können kombiniert werden, wenn sie müssen sie zu werden, mit die logische ODER betreiber, |, obwohl einige sind gegenseitig exklusive so sollte nicht kombiniert werden: SIMPLEX_TX und SIMPLEX_RX, für beispiel., Um beispielsweise sowohl CLOCK_IDLE_LOW als auch CLOCK_2ND_EDGE zu verwenden, anstatt eine einzelne Konstante als Parameter in die configure () – Methode einzugeben, würden Sie beide einschließen, getrennt durch das Symbol |:

spi1.configure(SIMPLEX_TX | MSB_FIRST | CLOCK_IDLE_LOW, 400);

Kombinationen können erforderlich sein, wenn sie im Datenblatt des Peripheriegeräts angegeben sind, obwohl dies für den Neuankömmling möglicherweise nicht sofort offensichtlich ist. Datenblätter können über den „SPI-Modus“ eines Geräts oder seine CPOL-Werte (Taktpolarität) und CPHA-Werte (Taktphase) sprechen., CPOL und CPHA bestimmen, welche Kanten des Taktsignals zum Ansteuern und Abtasten von Datensignalen verwendet werden. Jeder dieser beiden Parameter hat zwei mögliche Zustände für insgesamt vier mögliche Kombinationen:


SPI-Modi

SPI-Modi Indizieren Sie diese Kombinationen einfach und nicht die separaten CPOL – und CPHA-Werte. Der Controller und das Peripheriegerät müssen mit den gleichen CPOL-und CPHA-Werten und damit mit demselben Modus kommunizieren., Mehrere Peripheriegeräte können durchaus unterschiedliche Konfigurationen bedeuten, daher muss sich der Controller jedes Mal neu konfigurieren, wenn er mit einem bestimmten Peripheriegerät kommunizieren muss.,die folgende Tabelle:

Lesen und Schreiben von Daten

Nachdem Sie den SPI-Bus konfiguriert haben, senden Sie mit der Methode write() eine Zeichenfolge von Bytes an das Peripheriegerät:

spi1.write("This is an LCD display");

Die Verwendung einer Zeichenfolge ist optional: Sie können auch einen Blob von Rohdatenbytes senden:

local blob = blob(4); // Create a four-byte blob...blob.writen(0xDEADBEEF, 'i'); // ...and write a 32-bit value to itspi1.write(blob);

Ob Sie eine Zeichenfolge oder einen Blob lesen möchten, benötigen Sie eine der beiden SPI-Lesemethoden der imp-API:

local bytes = spi1.readblob(8);local inputString = spi1.readstring(16);

Der als Parameter übergebene ganzzahlige Wert ist jeweils die Anzahl der Bytes, die in das Blob eingelesen werden sollen, und die Anzahl der Zeichen, die in die Zeichenfolge eingefügt werden sollen., Da ein Zeichen ein Byte einnimmt, sind diese beiden Methoden natürlich äquivalent. Letzteres konvertiert Blob einfach in String für Sie.

Aufgrund der „Vollduplex“ – Natur des SPI-Busses treten Schreib-und Lesevorgänge immer gleichzeitig auf. Mit den Lese – und Schreibbefehlen, die wir bisher gesehen haben, werden Daten, die sich in die entgegengesetzte Richtung von demjenigen bewegen, an dem wir interessiert sind, ignoriert oder auf Null gesetzt. Wenn Sie also beispielsweise eine Zeichenfolge schreiben, werden alle Daten ignoriert, die vom Peripheriegerät am imp ankommen., Während einer der beiden Leseoperationen wird eine übereinstimmende Größe von „Dummy“ – Nullbytes in das Peripheriegerät geschrieben: Wenn Sie beispielsweise acht Bytes lesen, werden automatisch acht 0s geschrieben.

Um diese simultane bidirektionale Kommunikation zu verwalten, verfügt die imp-API über eine vierte Methode, die Lese-und Schreibvorgänge kombiniert:

local inputString = spi1.writeread(outputString);

Da der String outputString entlang der COPI-Zeile gesendet wird, wird der Variable inputString durch die auf CIPO kommenden Datenbytes gefüllt. Sie können Zeichenfolgen oder Blobs senden und empfangen, aber sowohl Eingabe als auch Ausgabe müssen vom gleichen Typ sein., Wie groß Ihr Ausgabeblob auch sein mag, Ihr Eingabeblob hat dieselbe Größe. Ebenso haben Eingabe – und Ausgabezeichenfolgen die gleiche Länge.

Full-duplex-Betrieb, kann auch verwendet werden mit Geräte, die tun nicht erwarten zu bedienen, dass Art und Weise — jene, die das Lesen und schreiben von ‚dummy‘ – bytes in einer bestimmten, nicht-null-Wert. Diese Anforderung schließt die Verwendung der regulären Methoden write(), readblob() und readstring() aus, aber writeread() kann an ihrer Stelle verwendet werden, um sicherzustellen, dass die bevorzugten Dummy-Werte des Geräts verwendet werden.,

Beispielcode

Der folgende Code funktioniert mit dem digitalen Beschleunigungsmesser ADXL345 Analog Devices, einem Teil, der SPI zur Kommunikation mit seinem Host-Mikrocontroller verwendet. Es unterstützt auch I2C, und die Pins auf diesem Adafruit Breakout Board, das auf dem Chip basiert, sind entsprechend gekennzeichnet. Das Datenblatt des Chips kann von der Analog Devices-Website heruntergeladen werden.

Wie der Code funktioniert

Wir verwenden den spi257-Bus eines imp001, der am Anfang der Auflistung als spi aliased ist. Wir verwenden auch Pin 8 als CS-Linie. Die Funktion spiWriteReg() zeigt, wie diese verwendet werden., Eine Schreibtransaktion wird durch Umschalten der CS-Zeile low signalisiert. Als nächstes wird die Adresse des Registers, in das wir schreiben möchten, von einer mit Eichhörnchen signierten 32-Bit-Ganzzahl in einen 8-Bit-Wert konvertiert, indem sie in einen Blob geschrieben wird. Dieser Blob wird dann in den SPI-Bus geschrieben. Wir machen dasselbe mit dem Wert, den der ADXL345 in dieses Register aufnehmen soll, und setzen dann die CS-Zeile erneut hoch, um das Ende der Transaktion zu signalisieren.,


Die Adafruit/Analog Devices ADXL345

Die Funktion spiReadReg() funktioniert auf die gleiche Weise, nur diesmal lesen wir nach dem Schreiben der Adresse des Quellregisters Wertdaten aus dem Bus. Der ADXL345 erfordert in diesem Fall einige Anpassungen an der Registeradresse: Bit 7 muss eingestellt werden, um die Transaktion als Lesevorgang zu markieren, und Bit 6 muss eingestellt sein, um dem Chip mitzuteilen, dass wir erwarten, dass mehr als ein einzelnes Byte zurückgesendet wird.,

Wo das richtige Programm startet, konfigurieren wir den SPI-Bus des imp so, dass er den Anforderungen des ADXL345-Chips entspricht. Es verwendet SPI-Modus 3-ie. sowohl CPOL als auch CPHA sollten gesetzt sein-daher verwenden wir den entsprechenden imp-Parameter: CLOCK_IDLE_HIGH | CLOCK_2ND_EDGE im Aufruf configure (). Wir stellen auch die Geschwindigkeit auf 100kHz ein. Als nächstes wird der Pin 8 des imp, der hier als CS-Pin arbeitet, als digitaler Ausgang konfiguriert und hoch eingestellt.


Verdrahtung des ADXL345

Andere Funktionen im Programm initialisieren den ADXL345 selbst und nicht den SPI-Bus., Der ADXL345 wird initialisiert und der Code liest den Wert aus der Registeradresse 0x00 ein, um sicherzustellen, dass das Gerät auf dem Bus vorhanden ist. Der Chip verfügt über einen Selbsttestmodus, der eine Reihe von Kalibrierungsmesswerten ermöglicht; Dies tun wir und speichern die Ergebnisse. Später werden diese Werte in der Funktionsschleife () verwendet, um die endgültigen Messwerte vom Beschleunigungsmesser anzupassen.,

Der ADXL345 speichert seine x -, y-und Z-Achsen-Samples als 16-Bit-Werte, jeweils in zwei 8-Bit-Registern; loop() verwendet die spiReadReg () – Funktion, um die beiden Komponenten jedes Werts zu erfassen und sie dann in einzelne Werte umzuwandeln, indem er das höchstwertige Byte mit 256 multipliziert und dem Ergebnis den Wert des am wenigsten signifikanten Bytes hinzufügt.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.