Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Manufacturing Technology >> Herstellungsprozess

XMOS startKIT:Aufbau eines XMOS- und Raspberry Pi-Roboters XMP-1

Einführung

Das XMOS startKIT von Farnell (oder Newark) ist eine sehr kostengünstige (12 £ inkl. MwSt.) Prozessorplattform, die gut mit dem Raspberry Pi funktioniert. Zusammen ist es möglich, Roboteranwendungen zu konstruieren, bei denen fast kein Löten erforderlich ist.

Das XMOS startKIT ist ein Board fast in Kreditkartengröße mit einem XMOS-Chip darauf mit mehreren „XMOS-Kernen“, die in C programmiert werden können. Die XMOS-Technologie ermöglicht einen parallelen Betrieb mit hoher Geschwindigkeit und geringem Jitter. Dies sind genau die Eigenschaften, die für Robotikanwendungen ideal sein könnten.

Zusammen mit etwas Code, der auf dem XMOS startKIT-Board und auf dem Raspberry Pi (RPI) ausgeführt werden soll, werden die Boards verwendet, um eine einfache kompakte mobile Plattform zu konstruieren (ich nenne es jetzt XMP, XMOS Mobile Platform anstelle eines Roboters) on im XMOS-Geist, alles mit 'X' voranzustellen).

Obwohl der XMP-1 kein großer Roboter ist, bis er einige Sensoren und mehr Programmierung hat, könnte er in Zukunft für Robotik-Experimente erweitert werden. Der XMP-1 verwendet kostengünstige Standardhardware und keine exotischen Werkzeuge außer Schraubendreher, Drahtschneider und Zangen.

Dieser Beitrag behandelt die Kommunikation zwischen dem RPI- und XMOS-Board unter Verwendung einer seriellen Peripherieschnittstelle (SPI) und wie man den XMP-1 aufbaut und über einen Webbrowser steuert.

Das Video hier zeigt, wie XMP-1 eine Route beigebracht wird; der erste versuch es zu benutzen! Es würde von einer besseren Benutzeroberfläche profitieren. XMP-1 kann sich ziemlich schnell bewegen, aber ich habe es hier mit niedriger Geschwindigkeit gemütlich gemacht. Auf der rechten Seite befindet sich die Browsersteuerung und unten ist die Konsolenausgabe, die nur einige Keep-Alive- und Statusmeldungen generiert, um zu sehen, was passiert.

Dieses nächste Video unten zeigt den XMP-1, der versucht, die Route abzuspielen und dabei Leiden und Schmerzen verursacht. Meine kostengünstigen Servos mit kontinuierlicher Rotation (die zum Antrieb der Räder verwendet werden) waren nicht sehr gut und XMP-1 hat noch keine Sensoren.

Ein bisschen mehr Details

Dieser Beitrag ist eigentlich Teil 2 einiger XMOS startKIT-Experimente. Teil 1 enthält die XMOS-Einführung, Terminologie, Architektur und eine Kurzanleitung mit Beispielprogrammen. Wenn Sie sich für die Technik interessieren, kann es hilfreich sein, zuerst Teil 1 zu verfolgen, damit dieser Teil 2 mehr Sinn macht. Dieser Teil 2 soll ein einfaches Framework für die Hochgeschwindigkeitskommunikation zwischen dem Raspberry Pi und dem XMOS startKIT-Board aufbauen. Das Framework sollte universell genug sein, um es für viele Projekte verwenden zu können (Robotik war nicht meine Absicht). Der XMP-1 ist wirklich nur ein Nebenprodukt, um die Kommunikation zwischen Raspberry Pi und XMOS-Board zu testen. Es wird hier aufgezeichnet, falls es nützlich ist. (Beachten Sie, es gibt auch einen Teil 3 mit dem Titel XMOS startKIT:XMOS and Raspberry Pi Oszilloscope XAE 1000, der die in diesem Beitrag besprochene SPI-Fähigkeit wiederverwendet und die Verwendung des im XMOS-Chip vorhandenen Analog-Digital-Wandlers (ADC) vorstellt , und wie man Echtzeitgrafiken in einem Webbrowser ausführt).

Wenn Sie nur daran interessiert sind, XMP-1 zu erstellen und zu verwenden, können Sie einfach den Code am Ende des Beitrags nehmen, kompilieren und in Flash (wie in Teil 1 beschrieben) auf dem XMOS startKIT-Board und dem Raspberry Pi speichern und Folgen Sie einfach den Abschnitten, die die XMP-1-Hardware-Montage beschreiben, und überspringen Sie alle anderen Inhalte hier. Wenn Sie daran interessiert sind, Hardware mit dem Raspberry Pi und einem Webbrowser zu steuern, kann ein Teil des Codes hier wiederverwendet werden. Um jedoch das Beste aus der Kombination von Raspberry Pi und XMOS startKIT herauszuholen, können die restlichen Informationen hier nützlich sein, wenn Sie das startKIT noch nicht kennen.

Lösungsübersicht – Hardware und Software

Hier ist ein Foto des fertigen XMP-1, der aufgeladen wird. Für den Außeneinsatz habe ich ein 802.11-Hotspot-Gerät (MiFi) verwendet, auf dem der Browser auf einem Mobiltelefon ausgeführt wurde.

Das Diagramm unten zeigt die ungefähre Anordnung der Bits und Teile von der Rückseite des XMP-1 aus gesehen. Sie können sehen, dass es ziemlich einfach ist – XMP-1 war nur ein schnelles Experiment.

Der Raspberry Pi (RPI) wird verwendet, um alle Netzwerkaktivitäten abzuwickeln. Es betreibt einen kleinen Webserver und der größte Teil des Codes ist in JavaScript auf einer Node.js-Plattform geschrieben. Das RPI kommuniziert die Motorsteuergeschwindigkeiten (eigentlich wurden für XMP-1 Servos mit kontinuierlicher Rotation verwendet) über eine serielle Schnittstelle (SPI) an die XMOS startKIT-Platine. Das XMOS startKIT ist für die Einspeisung von Pulsweitenmodulationssignalen (PWM) an die Motoren verantwortlich.

Der RPI wird über einen 802.11-WLAN-USB-Adapter mit dem Netzwerk verbunden.

Der vollständige Schaltplan ist hier gezeigt. Die Hardware und der Aufbau werden später beschrieben.

Das folgende Diagramm zeigt die Software, die auf dem RPI und auf dem startKIT implementiert wird. Es sieht viel aus, ist es aber nicht und kann in kleine Teile zerlegt werden, die weiter unten beschrieben werden. Wie bereits erwähnt, befindet sich der gesamte Quellcode am Ende dieses Beitrags, sodass er bei Bedarf ohne Änderungen verwendet werden kann.

Kurz gesagt, der grüne Block übernimmt die Webinteraktion und bestimmt die Geschwindigkeit und Richtung der Motoren basierend auf den Benutzereingaben. Der grüne Block stellt dem Benutzer eine Webseite (index.html) zur Verfügung, die die Benutzeroberfläche enthält. Das Programm xmos_servo ist eine kleine in C geschriebene Software, die die gewünschte Geschwindigkeit/Richtung in Datenbytes der seriellen Peripherieschnittstelle übersetzt, die an das startKIT gesendet werden. Die startKIT-Software gliedert sich in drei Teile, die gleichzeitig auf separaten XMOS-Kernen laufen. Der spi_process wandelt die SPI-Signale in Daten um, die in einem Array gespeichert werden. Der data_handler-Code untersucht das Array, um zu entscheiden, was zu tun ist (die einzige Schlussfolgerung, die er heute macht, ist die Manipulation der Servos). Der servo_handler-Prozess gibt einen Impulsstrom an die Servos aus, damit sie sich mit der gewünschten Geschwindigkeit drehen können. All diese Blöcke werden weiter unten genauer erklärt.

Serielle Peripherieschnittstelle (SPI)

SPI basiert auf vier Adern, die als SS, SCLK, MISO und MOSI bekannt sind, und einer Zuordnung von Master und Slave für die beiden an der Kommunikation beteiligten Geräte. Beim RPI- und XMOS-Board ist das RPI das Master-Gerät und für die Erzeugung des Taktsignals verantwortlich. Der RPI überträgt Daten auf dem MOSI-Draht und empfängt Daten auf dem MISO-Draht. Das bedeutet, dass die SPI-Schnittstelle gleichzeitig bidirektional Daten übertragen kann. In der Praxis können, wenn Einwegdaten erforderlich sind, entweder das MOSI- oder das MISO-Signal in Abhängigkeit von der interessierenden Richtung ignoriert werden.

Der Screenshot des Oszilloskops hier (Einzelsignale und die automatisierte SPI-Decodierung von einem Tektronix MSO2024B-Oszilloskop) zeigt ein Beispiel für die SPI-Kommunikation mit dem Raspberry Pi. SPI kann auf verschiedene Weise konfiguriert werden; Sie können in diesem Beispiel sehen, dass drei Bytes Daten vom Master (RPI) zum Slave (XMOS-Board) übertragen wurden und dass es 0x02, 0x00 und 0x10 waren und entweder keine Daten oder 0x00, 0x00, 0x00 von der übertragen wurden Slave zum Master gleichzeitig.

Der SS-Draht ist ein Chip-Select-Signal (aktiv niedrig). Der RPI hat zwei Pins an seinem 26-poligen Anschluss, die für SS verwendet werden könnten; sie sind im Diagramm unten blau eingekreist und mit CE0 und CE1 gekennzeichnet. Dies bedeutet, dass der RPI auf Wunsch mit zwei SPI-Slave-Geräten kommunizieren kann. In diesem Fall wurde nur einer der CE-Pins verwendet – ich habe CE1 gewählt.

Steuerung von Hobby-Servomotoren

Hobby-Servomotoren erzeugen eine Bewegung basierend auf einem Eingangssignal. Sie drehen normalerweise weniger als eine volle Umdrehung. Normalerweise dreht sich ein Hobby-Servo in einem Bereich von etwa 180 Grad. Die Abtriebswelle kann mit (beispielsweise) Gestängen verbunden werden, damit sich die Räder basierend auf dem Eingangssignal ganz nach links oder ganz rechts (oder irgendetwas dazwischen) drehen.

Das Diagramm unten zeigt die Einbauten eines typischen Hobby-Servos (von dieser Seite übernommen). Links (in Blau) befindet sich ein konventioneller Gleichstrommotor. Es ist stark untersetzt und rechts ist die letzte Welle zu sehen, die mit einem blauen Arm verbunden ist, der beispielsweise mit einer Radlenkung verbunden werden könnte. Unter der Endwelle befindet sich ein Potentiometer, das Rückmeldung über die genaue Position der Endwelle gibt. Ein Hobbyservo ist daher ein geschlossenes Regelkreissystem und kann sich selbst korrigieren, wenn der Arm versehentlich aus der gewünschten Position gestoßen wird.

Hobby-Servos haben normalerweise drei Anschlüsse; 0V, 5V und Signal. Die Signalleitung ist ein digitaler Eingang zum Servo und erfordert ein PWM-Signal. Die Größe der Impulsbreite bestimmt den Winkel, in den sich die Welle bewegt. Das PWM-Signal muss sich alle 20 ms wiederholen, und eine Impulsbreite von 1,5 ms führt dazu, dass sich die Welle in eine zentrierte Position bewegt. Eine Breite von 1 ms bewegt das Servo vollständig in eine Richtung und eine Breite von 2 ms bewegt das Servo vollständig in die andere Richtung (weiter unten werden einige Oszilloskopspuren der Servosteuerung angezeigt).

Es gibt eine Art von modifiziertem Servo, das als "kontinuierliche Rotation" bekannt ist. Es handelt sich um ein modifiziertes Servo, bei dem das Potentiometer zusammen mit allen Endanschlägen entfernt wird und die Schaltung davon überzeugt wird, dass sich das Servo noch in der zentrierten Position befindet. Das Senden von PWM mit einer anderen Impulsbreite als 1,5 ms bewirkt, dass sich der Mechanismus mit einer von der Impulsbreite abhängigen Geschwindigkeit im oder gegen den Uhrzeigersinn dreht. Der XMP-1 verwendet zwei Hobby-Servos mit kontinuierlicher Rotation, einen für jedes Rad. Sie sind kein optimaler Weg, um eine kontrollierte Bewegung zu erzielen (XMP-2 verwendet DC-Bürstenmotoren), da sie für einen anderen Zweck als die ursprüngliche Absicht für Hobby-Servos verwendet werden, aber sie haben den Vorteil, dass sie von einem digitalen gesteuert werden können Logiksignal und benötigen keine externe H-Brückenschaltung.

Hobby-Servokabel können je nach Hersteller unterschiedlich farblich gekennzeichnet sein. Normalerweise ist der Mitteldraht rot und geht auf +5V. Das schwarze oder braune Kabel ist 0V. Das weiße oder gelbe Kabel ist der PWM-Signaleingang.

Entwicklung starten – Boards anschließen

Für die Entwicklung der Software wurden RPI und startKIT über ein Flachbandkabel und eine IDC-Steckverbinder-Konfektionierung verbunden – diese können mit einem Schraubstock konfektioniert oder fertig gekauft werden. Für eine selbstkonfektionierte Version lohnt es sich, einen zusätzlichen IDC-Anschluss zu kaufen, der als Debug-Anschluss in der Mitte des Kabels verwendet wird, um das Sondieren von Signalen mit einem Multimeter oder Oszilloskop zu erleichtern.

Implementieren von SPI (spi_process) auf dem XMOS startKIT

Die Verwendung der XMOS-Entwicklungsumgebung (xTIMEcomposer) wurde in Teil 1 behandelt. Die folgenden Screenshots zeigen die Windows-Version von xTIMEcomposer, aber die Linux-Version sieht identisch aus (und möglicherweise sieht die Mac-Version auch ähnlich aus).

An dieser Stelle können Sie im xSOFTip-Labor mit der rechten Maustaste auf die SPI-Slave-Funktionsbibliothek klicken und die Bibliothek in den Arbeitsbereich importieren. Ich bin kein Experte für xTIMEcomposer, daher verwende ich es hier wahrscheinlich falsch, aber der Quellcode und die Header-Datei für die Bibliothek wurden in einem separaten Ordner im Projekt-Explorer angezeigt (unten blau eingekreist):

Die Dateien mussten sich im Ordner spi-test befinden (so dass sie wie oben grün eingekreist erscheinen), damit ich die Dateien spi_slave.h und spi_slave.xc manuell aus dem Ordner module_spi_slave/src in den spi-test kopiert habe /src-Ordner mit Windows Explorer.

Die Software verwendet das Konzept von Ports, um die Ausgabe zu steuern oder die Eingabe zu lesen. Es gibt eine Zuordnung zwischen diesen logischen Ports und der physischen Zuordnung zum Pin auf dem Chip. Die Zuordnungen können in bestimmten Kombinationen geändert werden (Siehe Abbildung 3 im PDF-Dokument Einführung in die XS1-Ports).

Eingangs-/Ausgangsports auf XMOS-Geräten können 1, 4, 8, 16 oder 32 Bit breit sein. Wenn Sie mit dem Teil entwerfen, möchten Sie möglicherweise bestimmte Funktionen 1-Bit-Ports oder andere Funktionen Multi-Bit-Ports zuweisen. Daher ist Abbildung 3 sehr nützlich, um zu bestimmen, welche Ports und Pins zu verwenden sind.

Da sich der SPI-Slave-Code jetzt im spi-test/src-Ordner befindet, wurde dieser Code leicht modifiziert. Der Bibliothekscode geht davon aus, dass die Ports, die für die SPI-Schnittstelle verwendet werden, alle 1-Bit-Ports sind, während der Raspberry Pi SPI SS-Pin (CE1) mit einem 32-Bit-Port auf der XMOS-Platine verbunden ist. Abbildung 8 aus dem PDF-Dokument startKIT Hardware Manual ist unten dargestellt. In der Mitte in Grün sehen Sie den 2×13-Wege-Header, der die Verbindung zwischen dem XMOS-Board und dem Raspberry Pi herstellt. Links und rechts in Blau sind die physischen Pin-Namen auf dem Chip (X0D0, X0D11 usw.) Die hervorgehobenen Pinwerte sind die logischen Portnummern. P1A, P1D usw. sind Single-Bit-Ports. P32A1 ist die erste Binärziffer eines 32-Bit-Ports

An der SPI-Bibliothek wurden einige Änderungen vorgenommen und der gesamte Code ist an den Beitrag angehängt, daher werden hier nur einige Codeschnipsel beschrieben, kein Kopieren/Einfügen erforderlich, der vollständige Code ist am Ende dieses Beitrags angehängt kann verwendet werden.

Die SPI-Schnittstelle auf dem XMOS-Gerät wird wie hier gezeigt initialisiert. Es wird weiter unten erklärt.

+ Quellansichtsebene erweitern
  1. void spi_slave_init(spi_slave_interface &spi_if)
  2. {
  3.     int clk_start;
  4.     set_clock_on(spi_if.blk);
  5.     configure_clock_src(spi_if.blk, spi_if.sclk);
  6.     configure_in_port(spi_if.mosi, spi_if.blk);
  7.     configure_out_port(spi_if.miso, spi_if.blk, 0);
  8.     start_clock(spi_if.blk);
  9.     zurück;
  10. }

Wie im Beitrag zu Teil 1 erwähnt, können I/O zu genauen Zeiten in das XMOS-Gerät ein- und ausgetaktet werden. Im obigen Code wird die Funktion set_clock_on (definiert in der XMOS-Headerdatei xs1.h) verwendet, um einen der integrierten Taktmechanismen im XMOS-Chip einzuschalten. Das Diagramm unten (aus dem Dokument Einführung in XS1-Ports) zeigt diesen Mechanismus in Gelb. Die Funktion configure_clock_src dient zur Auswahl einer externen Uhr (im Diagramm blau dargestellt). Es wird mit dem SCLK-Pin des Raspberry Pi verbunden. Die Funktionen configure_in_port und configure_out_port werden verwendet, um Ports an den Taktmechanismus zu binden. Sowohl das MOSI- als auch das MISO-Signal (unten grün dargestellt) sind so konfiguriert, dass sie an den Taktmechanismus gebunden sind.

Die Art und Weise, wie serielle Daten auf XMOS-Geräten gehandhabt werden, ist wirklich ordentlich. Der Code hier wird weiter unten erklärt. Zuerst wird eine Struktur verwendet, die Details zu den Ports enthält, die als SPI-Schnittstelle verwendet werden sollen.

+ Quellansichtsebene erweitern
  1. typedef struct spi_slave_interface
  2. {
  3.     Uhr blk;
  4.     im Port ss;
  5.     im gepufferten Port:8 mosi;
  6.     out-gepufferter Port:8 miso;
  7.     in port sclk;
  8. } spi_slave_interface;

Die interessanten Zeilen oben beziehen sich auf die Portvariablen mosi und miso. Sie wurden als Typ port:8 deklariert. Wenn den Variablen 1-Bit-Portadressen zugewiesen werden, deserialisiert das XMOS-Gerät automatisch den 1-Draht-Bitstrom in 8-Bit-Werte.

Es macht den Rest des SPI-Codes wirklich einfach. Hier ist der Code, der die SPI-Dateneingabe vom Raspberry Pi verwaltet:

+ Quellansichtsebene erweitern
  1. void spi_slave_in_buffer(spi_slave_interface &spi_if, unsigned char buffer[], int num_bytes)
  2. {
  3.     unsignierte int Daten;
  4.     unsigned int vlen=0;
  5.     clearbuf(spi_if.miso);
  6.     clearbuf(spi_if.mosi);
  7.     for (int i = 0; i < num_bytes; i++)
  8.     {
  9.         spi_if.mosi :> Daten;
  10.         data=data<<24;
  11.         buffer[i]=bitrev(data);
  12.         if (i==2)
  13.         {
  14.             vlen=(((unsigned int)buffer[1])<<8) | (unsigned int)buffer[2];
  15.             if (vlen==0)
  16.                 Pause;
  17.         }
  18.         if (i >= vlen+2)
  19.         {
  20.             Pause;
  21.         }
  22.     }
  23. }

Im obigen Code sehen Sie, dass es eine for-Schleife gibt und innerhalb der Schleife die Zeile spi_if.mosi :> data; wird verwendet, um 8 Informationsbits auf der MOSI-Leitung in die Variable namens data einzulesen.

Die nächsten beiden Zeilen werden verwendet, um die Bits innerhalb des Bytes umzudrehen und dann werden die Daten in einem Puffer-Array gespeichert.

Die nächsten Zeilen bedürfen einer Erläuterung; sie beziehen sich auf das gewünschte Protokoll. Es war beabsichtigt, einen universellen Code zu erstellen, der für viele Dinge verwendet werden kann, nicht nur für XMP-1. Wenn der Raspberry Pi Daten an das XMOS startKIT-Board sendet, muss das XMOS-Board wissen, wie viele Bytes an Daten zu erwarten sind. Dies könnte hart codiert sein, aber es wäre unflexibel.

Es wurde beschlossen, ein sehr einfaches Protokoll „Tag (oder Typ), Länge, Wert“ (TLV) zu verwenden. Das erste Byte, das der Raspberry Pi übertragen muss, ist ein Tag oder Identifier im Bereich 0-255 (also ein Byte). Es liegt am Benutzer zu entscheiden, was die Werte darstellen. Beispielsweise könnte ein Wert von 1 „Motordrehzahl einstellen“ bedeuten und ein Wert von 2 „Scheinwerferhelligkeitsintensität einstellen“. Die zweiten beiden Bytes sind ein 16-Bit-Wert, der angibt, wie viele Wert- (d. h. Daten-)Bytes folgen sollen. Ich habe mich entschieden, dies auf 4 kByte (4096 Byte) zu beschränken, was viele Anwendungsfälle erfüllen sollte, aber der tatsächliche Wert kann durch Anpassen einer BUFLEN-Definition im Code geändert werden.

Daher beträgt die minimale Anzahl von Bytes, die über die SPI-Schnittstelle gesendet werden, drei (Tag und eine Länge von 0x0000) und die maximale Anzahl von 4099, was ein Tag und eine Länge von 0x1000 ist (dies ist 4096 in hexadezimaler Form) und 4096 Datenbytes.

Das Protokoll wurde etwas verfeinert, so dass eine ungerade Tag-Nummer bedeutet, dass der Raspberry Pi eine Antwort zurück erwartet in der folgenden SPI-Kommunikation, die er nach Abschluss des aktuellen TLV-Streams initiiert, und eine gerade Tag-Nummer bedeutet, dass der Raspberry Pi keine Antwort erwartet zurück.

Dies ist ein sehr einfaches Protokoll, das jedoch viele übliche Anforderungen erfüllen sollte. Es wird auch in der folgenden Tabelle erklärt, wobei die blaue Zahl der SPI-Byte-Index im empfangenden 4099-Byte-Puffer ist.

Zurück zum vorherigen Code-Schnipsel ist zu sehen, dass die nächsten paar Zeilen den Inhalt von Puffer[1] und Puffer[2] im laufenden Betrieb überprüfen, während die SPI-Daten empfangen werden. Es wird erwartet, dass der Inhalt die Länge hat, die im obigen Diagramm zu sehen ist (siehe blauer Pufferindex). Sobald der Code die Restlänge bestimmt hat, akzeptiert er genau diese Anzahl von Datenbytes und dann wird die Routine beendet.

Das deckt den SPI-Eingang zum XMOS-Board auf der MOSI-Leitung ab. Die SPI-Ausgabe des XMOS-Bausteins auf der MISO-Leitung funktioniert auf ähnliche Weise, wobei die Länge gleichzeitig auf der MOSI-Leitung im laufenden Betrieb erneut überprüft wird, damit die Funktion beendet werden kann, sobald die angeforderte Anzahl von Bytes übertragen wurde.

Prozessübergreifende Kommunikation

Nachdem nun SPI herausgefunden und ein Protokoll implementiert war, um Daten variabler Länge in beide Richtungen bis zu einer Länge von 4096 Bytes auszutauschen, wurden einige Überlegungen zum Hauptteil des Programms angestellt. Es war klar, dass ein XMOS-Kern für die Verarbeitung der SPI-Aufgabe bestimmt sein würde, aber der Rest des Codes muss sich möglicherweise in einem oder mehreren zusätzlichen XMO-Scores befinden.

In Teil 1 wurde beschrieben, wie Tasks auf verschiedenen XMOS-Kernen parallel laufen und wie die Tasks miteinander kommunizieren können, indem sie Werte in Kanäle schieben. Es gibt eine andere Art der Kommunikation zwischen den Kernen und verwendet das Konzept der „Transaktionen über Schnittstellen“ anstelle von Kanälen. Es ist flexibler, da Sie mehrere Variablen unterschiedlichen Typs von einem XMOS-Kern an einen anderen senden können. Die Transaktionstypen werden ähnlich wie bei einem C-Funktionsprototyp definiert. Dies alles wird viel klarer, wenn man sich ein Beispiel ansieht.

Wenn eine Anwendung beispielsweise eine Aufgabe hat, die eine Anzeige steuert, möchte eine sendende Aufgabe möglicherweise die Anzeige ein- oder ausschalten oder ein Pixel plotten. Die Schnittstellendefinition für die Kommunikation zwischen den beiden XMOS-Kernen könnte etwa so aussehen:

+ Quellansichtsebene erweitern
  1. Schnittstelle program_display
  2. {
  3.     void backlight(int state, int color) ; // Transaktionstyp 1
  4.     void plot(int x, int y, int color); // Transaktionstyp 2
  5. };

Die Schnittstellenkommunikation ist unidirektional. Wenn das Display also Informationen wie (beispielsweise) den Touchscreen-Status senden möchte, müsste eine andere Schnittstelle in die andere Richtung verwendet werden. Daraus wird deutlich, dass Schnittstellen eine Client- und eine Serverseite haben. Das Diagramm hier zeigt zwei XMOS-Kerne (in Lila), zwei Schnittstellen (in Grau) und die erste Schnittstelle (genannt program_display) ermöglicht zwei verschiedene Arten von Transaktionen (in blau) über die program_display-Schnittstelle.

Das Tolle an der Verwendung von Schnittstellen und Transaktionstypen ist, dass Sie ähnlich wie bei C-Funktionsprototypen Rückgabewerte haben und Referenzen auf Variablen übergeben können, sodass, obwohl die Kommunikation immer von der Clientseite der Schnittstelle initiiert wird, die Datenübertragung kann in beide Richtungen auftreten. Ein weiteres sehr interessantes Feature, das im Diagramm nicht gezeigt wird, ist die Möglichkeit für das Server-Ende, eine „Benachrichtigung“ an das Client-Ende zu senden. Dies kann ein Signal an den Client sein, auf die übliche Weise eine Transaktion durchzuführen, um vielleicht einige Daten abzurufen. Diese Funktion wird im XMP-1-Code verwendet. Weitere Informationen zur genauen Codierung der Schnittstellen und zum Senden von Daten und Benachrichtigungen werden daher weiter unten erläutert.

Entwurf der IPC-Architektur zur Verarbeitung von SPI-Inhalten

Die Handhabung der SPI-Schnittstelle wurde bereits beschrieben. Nun muss der Inhalt der SPI-Nachrichten einer Task in sinnvoller Weise zur weiteren Verarbeitung präsentiert werden. Ausgestattet mit dem Wissen über Schnittstellen und Transaktionen war es möglich, damit zu beginnen, Funktionen auf separate XMOS-Kerne zu verteilen und die Kommunikation zwischen den Prozessen zu entwerfen, um zu einem universellen Framework zu gelangen, das es ermöglicht, nützliche Nachrichteninhalte vom RPI an das XMOS zu senden Board und umgekehrt, und verarbeitet werden.

Das Diagramm hier zeigt, was entwickelt wurde (ein ähnliches Diagramm wie zuvor, nur dass es jetzt eine zeitliche Abfolge von oben nach unten gibt).

Wenn der Raspberry Pi eine Nachricht an das XMOS-Board senden möchte, erstellt der RPI die Nachricht im zuvor beschriebenen TLV-Format. Die Informationen werden dann auf dem MOSI-Signalkabel ausgetaktet (in der oberen Abbildung oben grün dargestellt). Gleichzeitig muss das XMOS-Gerät etwas zurücksenden, aber da es noch keine Informationen zum Zurücksenden gibt, kann die MISO-Zeile Müll oder alle Nullwerte enthalten, wie in Rosa dargestellt. Die Funktion spi_process sammelt die Nachricht in einem Puffer (ein Array von unsignierten Zeichen) und initiiert dann eine Transaktion zu einem separaten data_handler XMOS-Kern. Der data_handler ist dafür verantwortlich, den Inhalt der Nachricht zu verarbeiten und optional Informationen an den spi_process XMOS-Kern zurückzusenden, sodass jeder nachfolgende SPI-Austausch nützliche Daten anstelle von Müllwerten an den Raspberry Pi zurücksenden kann.

Die Daten könnten zwischen spi_process und data_handler gesendet werden, indem eine Kopie des Puffers erstellt wird. Stattdessen ist es jedoch möglich, einfach einen Zeiger an den Pufferspeicher zu übergeben. Eine Möglichkeit, dies zu tun, besteht darin, die Kontrolle der Zeiger- und Pufferspeicherorte von spi_process zu data_handler zu „verlagern“. Sobald data_handler mit der Nachrichtenüberprüfung fertig ist, kann er die Kontrolle wieder an spi_process zurückgeben, indem er die Rückgabevariable verwendet, die in Transaktionen verwendet werden kann. Aus diesem Grund enthält das obige Diagramm eine Transaktion namens array_data mit einem Parameter, der als beweglicher Zeiger definiert ist, und einem Rückgabewert, der ebenfalls als beweglicher Zeiger definiert ist. Auf diese Weise hat immer nur ein XMOS-Kern Zugriff auf den Pufferspeicher.

Dies sind die verwendeten Schnittstellen:

+ Quellansichtsebene erweitern
  1. Schnittstelle zu_rpi
  2. {
  3.     void code(unsigned char c);
  4. };
  5. Schnittstelle from_rpi
  6. {
  7.     unsigned char* movable array_data(unsigned char* movable bufp);
  8. };

Der spi_handler-Code weist Platz für einen Puffer zu und übergibt dann die Kontrolle über den Puffer an den data_handler-Code, indem die Zeile buf=c.array_data(move(buf)) verwendet wird, die im Code hier gezeigt wird:

+ Quellansichtsebene erweitern
  1. ungültig
  2. spi_process(Schnittstelle zu_rpi Server s, Schnittstelle von_rpi Client c)
  3. {
  4.   nicht signierter Zeichenspeicher[4099];
  5.   unsigned char* movable buf=storage;
  6.   …
  7.   buf=c.array_data(move(buf));
  8.   …
  9.   auswählen
  10.   {
  11.     case s.code(unsigned char c):
  12.       if (c==SEND)
  13.       {
  14.         spi_slave_out_buffer(spi_sif, buf, 4099);
  15.       }
  16.       Pause;
  17.   }
  18. }

Der data_handler-Code erhält die Kontrolle über den Puffer, und wenn gewünscht wird, dass eine Antwort an das RPI bei einer nachfolgenden SPI-Transaktion gesendet wird, wird der Puffer mit einer Antwort gefüllt. Schließlich wird die Kontrolle über den Puffer an den spi_handler-Prozess zurückgegeben.

+ Quellansichtsebene erweitern
  1. ungültig
  2. data_handler(Schnittstelle zu_rpi Client c, Schnittstelle von_rpi Server s)
  3. {
  4.   auswählen
  5.   {
  6.       case s.array_data(unsigned char* movable vp) -> unsigned char* movable vq:
  7.          // vq enthält die Daten von SPI. Wir können damit und
  8.          // Jede Antwort wird auch hier aufgebaut:
  9.          vq[0]=0x22; // Tag
  10.          vq[1]=0x00; // Länge
  11.          vq[2]=0x00; // Länge
  12.          vq=move(vp); // übergeben die Zeigersteuerung zurück an spi_process
  13.          tosend=1;
  14.          Pause;
  15.      }
  16.   if (zum Senden)
  17.   {
  18.     c.code(SEND); // send a code to spi_process so that it is aware there is data to send to RPI
  19.   }
  20. }

Earlier it was mentioned that if an odd tag value was sent by the RPI then this would be an indication that the RPI expected a response message from the XMOS startKIT board on the subsequent SPI exchange. This is implemented by both the spi_process and data_handler making a note that a return message is expected if the first byte received is an odd value. Once data_handler has finished constructing the return message in the buffer memory it moves the buffer pointer back to the spi_process XMOS core and also sends a code transaction which could contain a message such as “ready to send”. The spi_process XMOS core is now ready for any subsequent SPI exchange. If the data_process doesn’t want to send any message back to the Raspberry Pi (for example if the tag was even valued) then the code transaction is not sent (or a different code could be sent such as “not ready to send”).

In the graphic diagram earlier you can see that the subsequent SPI exchange did transmit data back to the Raspberry Pi on the MISO wire.

To summarize, the spi_process and data_process present a fairly general-purpose capability to exchange data bidirectionally between the RPI and XMOS board.

Implementing PWM (servo_handler) on the startKIT

To test out the general purpose architecture, it was decided to use it to control many devices. The devices ended up being hobby servos because they require very little electrical interfacing effort – no H-bridge or transistor driver is needed – and the servo input wire can be directly connected to an XMOS output pin. I didn’t have many servos, so although the code implements 8 servo control, only two were used for XMP-1.

The code could be modified to provide DC motor control too (with a suitable external H-bridge circuit).

It was decided to use a single XMOS core to handle the eight servos. The diagram below shows the total of three XMOS processes used in the solution. The new addition is the servo_handler task which is shown on the right. This task has an array that stores the current servo values. As soon as the task starts up, the values are initialized to a centered value (or standstill for a continuous rotation servo) and then every microsecond the task wakes up to check if the servo PWM signal needs adjustment.  If it does then the servo port output is toggled. After 20msec the process repeats.

For more detail:XMOS startKIT Building an XMOS and Raspberry Pi Robot XMP-1


Herstellungsprozess

  1. MQTT-Kommunikation zwischen NodeMCU und Raspberry Pi 3 B+
  2. Python- und Raspberry Pi-Temperatursensor
  3. Einfache Temperatur und Luftfeuchtigkeit auf Raspberry Pi
  4. Raspberry Pi Temperatur- und Lichtsensor
  5. Raspberry Pi Sensor- und Aktuatorsteuerung
  6. Aeroponik mit Raspberry Pi und Feuchtigkeitssensor
  7. NEUES HIMBEE PI 3 MODELL B + FUNKTIONEN UND KAUF
  8. Roboter mit Raspberry Pi und Bridge Shield
  9. BeagleBone und Raspberry Pi erhalten FPGA-Add-ons
  10. Bau des MonkMakes Raspberry Pi Robot Kit