Kann Raspberry Pi eine 9600-Baud-Serie zuverlässig bumsen und gibt es Beispielcode?


29

Ich frage mich, wie machbar es ist, Bit-Banging zu verwenden, um eine 9600-Baud-Serie über die GPIO-Pins am Raspberry Pi anzusteuern.

Offensichtlich ist Linux keine besonders gute Plattform für das Bitbangen, da es eine große Anzahl von Treibern und anderen Interrupts gibt, die die CPU für längere Zeit (1-10 ms) blockieren können. In letzter Zeit hat sich die Situation jedoch erheblich verbessert, und einige Vorkenntnisse sind nun regelmäßig in Kerneln aktiviert. Ich vermute auch, dass ein in Echtzeit gepatchter Kernel problemlos auf dem Raspberry Pi verwendet werden kann und die angeschlossene Hardware und Treiber sorgfältig ausgewählt werden können.

Mein Standard für Zuverlässigkeit ist, dass es die meiste Zeit innerhalb der normalen 9600-Baud-Serientoleranzen bleiben sollte. Ich bin derzeit nicht sicher, wie viele Fehler in der Praxis tolerierbar sind, aber es gibt Neuübertragungen und Bestätigungen im Protokoll, so dass es zumindest etwas tolerant ist.

Meine Fragen lauten also:

  • Kann Userland Software zuverlässig 9600 Baud Bit-Bang-Geschwindigkeit?
  • Benötigt dies einen in Echtzeit gepatchten Kernel?
  • Mit wie vielen Fehlern muss ich generell rechnen?

Gibt es auch einen Beispielcode, der seriell über GPIO-Bit-Banging arbeitet? Ich weiß von Arduino SoftSerial, aber das war es auch schon.

Nur für den Fall, um die Frage einzuschränken: Dies ist keine standardmäßige serielle Schnittstelle und der UART von Raspberry Pi wird bereits für eine andere serielle Verbindung verwendet. Ich wünsche keine Antworten, die externe Hardware vorschlagen (wie Gertboard oder Arduino), noch Antworten, die von der UART abhängen.


1
+1 Gute Frage. Mich würde auch die Antwort darauf interessieren. Die Frage nach reliabilitykönnte jedoch von den Maßnahmen und Erwartungen abhängen.
Jivings

2
RS-232 benötigt negative Spannungen, aber diese serielle Verbindung verwendet keine RS-232-Spannungen. Ich weiß es nicht, aber ich glaube, dass RPi den Standard-TTL-RS-232-Konverter wie MAX232 oder eines der Dutzenden von Optionen benötigt. Um jedoch klar zu sein, ist dies nicht relevant für meine Frage, ich wollte nur antworten.
Nakedible

4
Es gibt auch einen zweiten UART auf den GPIO-Pins 14 und 15. Es ist jedoch nicht so umfangreich wie das Hauptprogramm
John La Rooy


1
@Nakedible könntest du bitte deine Arbeit teilen? Ich habe ein ähnliches Problem und möchte sehen, wie Sie eine zweite Serie über SPI gemacht haben. danke MSP

Antworten:


15

Ich habe das endlich gelöst, aber auf eine ziemlich unorthodoxe Weise. Ich habe Bit-Banging als zu unzuverlässig aufgegeben und versucht, andere Lösungen zu finden, die es mir ermöglichen, dasselbe zu tun, ohne zusätzliche Hardware hinzuzufügen. Ich habe überlegt, einen Kerneltreiber zu schreiben, der einen Interrupt auf GPIO auslöst und dann den Pin neu als SPI konfiguriert und SPI zum Lesen eines gesamten Datenbytes verwendet - aber dann habe ich eine bessere Idee.

Ich benutze SPI, um die Leitungen mit 20x der Baudrate abzutasten. Ich ignoriere die SCLK- und SS-Pins vollständig, verbinde die RX-Leitung mit MISO und die TX-Leitung mit MOSI. Dies gibt mir einen (1-Bit) Oszilloskop-ähnlichen Einblick in die RX-Leitung und zeigt deutlich, welche Bits in der seriellen Leitung übertragen werden:

00 00 00 00 00 00 
00 00 00 00 01 FF 
FF FF FF FF 00 00 
01 FF FF FF FF FF 
FF FF E0 00 00 00 
00 00 07 FF FF FF 
FF FF 

Daraus ist es eine einfache Sache der Codierung, die richtigen Positionen herauszufinden, von denen die tatsächlichen Datenbits abgetastet werden sollen. Die sendende Seite ist ebenso trivial, ich muss nur jedes Byte in einen langen Strom von Bits konvertieren, wobei das Start- und das Stoppbit enthalten sind.

Dies funktioniert besser als Bit-Banging, da SPI über einen eigenen Takt verfügt, der nicht mit dem Kernel einfriert, und die SPI-Sende- und Empfangsleitungen über ein 16-Byte-FIFO für die Übertragung verfügen, das auch unabhängig von Kernel-Einfrierungen ist. Für 9600 Baud verwende ich einen 250-kHz-SPI-Takt, was bedeutet, dass ich zwischen dem Füllen und Entleeren der FIFOs auch nur eine Millisekunde lang schlafen kann, ohne dass Übertragungsfehler auftreten. Um jedoch auf der sicheren Seite zu sein, benutze ich 300 µs Schlafzeit. Ich habe kurz getestet, wie weit ich dies schieben kann, und mindestens ein 2-MHz-SPI-Takt war noch verwendbar, sodass diese Lösung auch auf höhere Baudraten skaliert.

Der hässliche Teil dieser Lösung ist, dass der Kernel-SPI-Treiber eine solche Übertragung von Streaming-Bits nicht unterstützt. Dies bedeutet, dass ich dies nicht tun kann, indem ich mein eigenes Kernelmodul mit dem Kernel-SPI-Treiber schreibe, und ich kann es auch nicht tun, indem ich /dev/sdidev0.0 aus dem Benutzerland verwende. Auf dem Raspberry Pi können Sie jedoch über mmap (): n / dev / mem direkt auf das SPI und andere Peripheriegeräte zugreifen, wobei die Kernel-Steuerung vollständig umgangen wird. Ich bin nicht sonderlich zufrieden damit, aber es funktioniert einwandfrei und es hat den zusätzlichen Vorteil, dass Segmentierungsfehler im Userland den Kernel nicht zum Absturz bringen können (es sei denn, es kommt versehentlich zu Problemen mit den anderen Peripheriegeräten). Was die CPU-Auslastung anbelangt, scheinen mir 300 µs Ruhezustand ungefähr 7% der CPU-Auslastung konstant zu geben, aber mein Code ist sehr unoptimal. Eine längere Ruhezeit senkt offensichtlich die CPU-Auslastung.

Edit: Ich habe vergessen zu erwähnen, dass ich die nette bcm2835- Bibliothek verwendet habe, um die SPI vom Userland aus zu steuern und sie bei Bedarf zu erweitern.

Zusammenfassend lässt sich sagen, dass ich auf einer seriellen 9600-Baud-Verbindung zuverlässig und vollständig vom Userland aus senden und empfangen kann, indem ich den SPI-Chip direkt über / dev / mem bei 250 kHz auf dem Raspberry Pi verwende.


@ Nakedible - Kannst du etwas näher erläutern oder Links zum mmap () Teil bereitstellen? Ich arbeite an der gleichen Sache.
Jay K

Verwenden Sie die SPI-Hardware auch für die Übertragung?
Cheetah

Ja, das Senden funktioniert auch.
Nakedible

3
Können Sie bitte eine schrittweise Anleitung geben, wie Sie Code senden und empfangen können, und modifizierte Pakete freigeben, wenn Sie etwas verwenden, das Sie selbst gepatcht haben ... TIA!
Valentinstag

10

Es scheint, dass der Raspberry Pi ohne die Echtzeit-Patches (CONFIG_PREEMPT_RT) eine 9600-Baud-Serie nicht zuverlässig basteln kann.

Ich habe einen einfachen Latenz-Tester verwendet, der alle Linux-seitigen Dinge optimal konfiguriert hat (sched_fifo, priority 99, cpu_dma_latench 0us, mlockall). Ich habe versucht, für 100 µsec (ungefähr 9600 Baud) zu schlafen und die Latenzüberschreitung auf einem leisen System für 2 Minuten zu überprüfen. Die Ergebnisse waren:

Min: 12 usek Durchschn .: 24 usek Max: 282 usek

Dies schien das gemeinsame Ergebnis zu sein. Das Maximum variierte bei langsameren Messungen zwischen 100 us und 300 us. Ich habe auch die Verteilung überprüft und es scheint, dass die überwiegende Mehrheit im Bereich von 24 µs liegt. Es gibt nur wenige, die über 50 µs gehen, aber es gibt fast immer einige. Es gibt auch manchmal enorme Latenzen, wie z. B. 4000 µs, aber diese sind selten genug, um zumindest vorerst ignoriert zu werden.

Ich denke, die maximale Latenz sollte unter 50 µs liegen, damit 9600 Baud keine Fehler verursachen. Bei einer Latenz von über 100 µs fehlt beim Senden oder Empfangen ein Bit vollständig.

Dies alles, ohne die GPIO-Pins zu berühren. Da ich selbst mit nur 2 Sekunden keinen sauberen Lauf erzielen konnte, kann ich mit Sicherheit sagen, dass der Raspberry Pi ohne Echtzeit-Patches eine serielle 9600-Baud-Verbindung nicht knacken kann, ohne für längere Zeit Fehler zu generieren.

Ich werde die Echtzeit-Patches später testen, wenn ich die Zeit dazu habe.

(Verwendetes Tool: http://git.kernel.org/?p=linux/kernel/git/clrkwllms/rt-tests.git;a=summary )

Update: Der RPi-Kernel bleibt beim Booten hängen, ohne dass eine SD-Karte erkannt wird, wenn er mit dem Patch-Set CONFIG_PREEMPT_RT kompiliert wurde. Es könnte eine einfache Sache sein, die behoben werden kann, aber da die Unterschiede in der RPi-Quelle chaotisch sind, möchte ich wahrscheinlich warten, bis mehr davon im Hauptkern vorhanden ist.

Das zu testen ist zu schwierig und ich gebe es auf.


0

Du musst nicht bumsen. Sie können im rx gpio einen Benutzer-Land-Interrupt einrichten, um das Fallen des Startbits zu erkennen. Stellen Sie dann einen Zeitinterrupt ein, der in der Mitte der Bits abgetastet werden soll. Ein Kernel-Modul, das das macht, ist machbar.


Aber das ist immer noch ein bisschen hämmernd. In der Tat ist das die Art, wie du normalerweise ein bisschen hämmerst.
Philippos
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.