Aus Raspberry Pi Geek 02/2017

Datenaustausch per Funk im SRD-Frequenzband 860 MHz (Seite 2)

Bezüglich des am RasPi einstellbaren Bustakts herrscht in den Foren nicht unbedingt Klarheit. Fest steht jedoch, dass man den Peripheral-Takt im ARM-Core (125 MHz) durch Zweierpotenzen teilen kann. Da das Datenblatt des SX1231 [4] – er ist das Herzstück des RFM69 – einen maximalen SPI-Bus-Takt von 10 MHz vorschreibt, befindet man sich mit 125 MHz / 16 = 8000 kHz auf der sicheren Seite.

Das Funkmodul signalisiert das erfolgreiche Versenden beziehungsweise den korrekten Empfang eines Datagramms per Interrupt-Leitung (DIO0 an GPIO25). Über eine zusätzliche Interrupt-Verbindung (DIO1 an GPIO24) leitet das System im Empfangsbetrieb eine etwaige Zeitüberschreitung weiter. Dazu konfiguriert das Kernel-Modul in der Initialisierungsphase beide GPIOs in Eingangsrichtung und leitet Sie zum Interrupt-Controller des ARM-Cores um.

Entsprechend dem Datenblatt zum SX1231 liegt das Ansprechen der Interrupt-Service-Routinen (ISR) jeweils auf der positiven Flanke der beiden Interrupts an. Um die Reaktionszeit des Kernels nicht zu beeinträchtigen und jeden von der Hardware ausgelösten Interrupt auch tatsächlich zu behandeln, gilt es, die ISRs auf minimale Laufzeit zu trimmen.

SPI-Subsystem

Der Linux-Kernel bietet einen recht komfortablen Funktionsumfang zum Betrieb von Geräten am SPI-Bus an. Durch sogenannte SPI-Messages, die man dem SPI-Subsystem im Kernel als Auftrag übergibt, lässt sich beliebige Hardware am SPI-Bus ansprechen. Solche SPI-Messages weisen den SPI-Hardware-Treiber an, wie genau er mit der Hardware am Bus kommunizieren muss. Sobald es alle in der SPI-Message kodierten Buszugriffe (“SPI-Transfers”) abgearbeitet hat, ruft das SPI-Subsystem das auftraggebende Modul über dessen Callback-Funktion zurück.

Im vorliegenden Fall kann so das RFM69-Kernel-Modul als SPI-Protokoll-Treiber transparent auf die Register (Konfiguration, Steuerung, Status) sowie den Daten-FIFO des RFM69-Funkmoduls zugreifen und damit dessen Funktion steuern [5]. Die entsprechenden Funktionen finden sich im Code des Moduls in den beiden Dateien rfm69gmsk_core.c und rfm69io.c.

Sendebetrieb

Typischerweise befindet sich das RFM69-Funkmodul im Standby-Modus. Mittels entsprechender Registerprogrammierung bereiten Sie es auf den Sendebetrieb vor. Es verbleibt aber solange im Standby, bis das Füllen des FIFOs mit den Sendedaten es in den Sendemodus versetzt. Dann führt der Funkchip die weiteren Arbeitsschritte autonom aus, meldet per Interrupt (DIO0 an GPIO25) das Absetzen des Datagramms und wechselt zurück in den Standby-Modus. Die SPI-Callback-Funktion und die ISR gewährleisten dabei im Wesentlichen die Datenintegrität sowie den korrekten Funktionsablauf ohne Race-Conditions im Kernel.

Doch damit kommen die Unzulänglichkeiten des Linux-Kernels im Echtzeitverhalten zum Tragen: Abhängig vom aktuellen Betriebsmodus schaltet das System im Transceiver verschiedene Interrupt-Quellen auf die DIO-Pins auf – so unter anderem auch beim Einrasten der Phase-Locked-Loop (PLL) auf die Kanalfrequenz am DIO1. Durch die Verzögerung im Bereich von mehreren 100 µs zwischen dem Absetzen einer SPI-Message zum Beschreiben eines Registers und dem tatsächlichen Schreibvorgang gelingt es dem System nicht, schnell und flexibel genug auf alle möglichen Zustandsübergänge im Transceiver zu reagieren.

Den PLL-Lock-Interrupt in einer ISR zu behandeln, obwohl er zur eigentlichen Funktionalität nichts beiträgt, ist also letztlich schlicht der einfacheren Implementierung geschuldet.

Empfangsbetrieb

Der Sendebetrieb erfordert zusätzliche Arbeit. Zuerst programmieren Sie das Funkmodul direkt auf Empfang. Treten in der Folge alle wesentlichen Empfangskriterien auf – Überschreiten der Mindestempfangsleistung (RSSI-Threshold), Detektion der Empfängeradresse (Sync-Word) sowie ein positiver CRC-Check –, teilt die Hardware das dem Kernel-Modul wieder per Interrupt (DIO0 an GPIO25) mit. Die entsprechende ISR liest dann zuerst die empfangenen Daten über eine weitere SPI-Message aus und setzt anschließend in einer Callback-Funktion das Funkmodul in den Standby-Modus zurück.

Außerdem gilt es, im Empfangsbetrieb im Vergleich zum Senden zusätzliche Hürden zu nehmen: Beim Senden hat das Modul den Ablauf komplett unter Kontrolle, beim Empfang von Daten ist dagegen nicht von vornherein klar, wann was geschieht. Sendet zum Beispiel ein anderes Modul ein Datagramm an einen anderen Empfänger auf einem Nachbarkanal, so überschreitet das Signal im lokalen Empfänger mit hoher Wahrscheinlichkeit zumindest die RSSI-Schwelle. Bei guten Übertragungsbedingungen fällt dabei auch der CRC-Check positiv aus, und so lässt sich das ungewollte Datagramm nur an der “fremden” Empfängeradresse erkennen.

An diesem Punkt – irgendwo mittendrin im Empfangsprozess – wartet der Empfänger dann vergeblich auf die aus seiner Sicht einzig akzeptable Adresse. Dieser Zustand lässt sich erst durch eine vorab konfigurierte Zeitüberschreitung erkennen, mittels Timeout-Interrupt (DIO1 an GPIO24) signalisieren und in der zugehörigen ISR durch Abbruch des Empfangs bereinigen.

Das Datagramm

Zur Adressierung verwendet jede Seite eine 4 Byte lange ID, wobei man zwischen Local-ID (LID, die eigene Adresse) und Remote-ID (RID, Adresse der Gegenstelle) unterscheidet.

Auf Hardware-Ebene (“Luftschnittstelle”) beginnt ein Datagramm mit der Präambel, einer Bitfolge aus wechselnden Einsen und Nullen, die dem Empfänger den Beginn einer Übertragung anzeigt. Gleichzeitig dient sie auch dazu, auf die Bitrate zu synchronisieren. Unmittelbar anschließend folgen zunächst die Adresse des Ziels und dann jene des Senders. Erst dann kommen die eigentlichen Nutzdaten, die maximal 60 Byte umfassen dürfen. Den Abschluss bildet ein 2-Byte-CRC, der wie bei den weit verbreiteten Kommunikationsprotokollen X.25 oder HDLC die Integrität der Daten sicherstellt.

Auf Anwendungsebene, also vom Programmiermodell des RFM69 aus betrachtet, gehört aber bereits die Senderadresse zu den Nutzdaten. Das kürzest mögliche Datagramm hat hier also eine Länge von 4 Bytes und enthält nur die RID. Ein solches Datagramm ohne tatsächliche Nutzdaten lässt sich beispielsweise dazu verwenden, den Empfang eines vorangehenden Datagramms zu bestätigen. Das längste Datagramm wiederum besitzt inklusive Adresse eine Größe von 64 Byte. Abbildung 4 veranschaulicht den Datenfluss zwischen der User-Ebene auf Sendeseite über die Ebene des Kernelmoduls bis zum User auf der Empfängerseite.

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDFUmfang: 7 HeftseitenPreis €0,99
(inkl. 19% MwSt.)
RASPBERRY PI GEEK KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Raspberry Pi Geek bei Google Play Readly Logo
Nach oben