RFM12 Protokoll Stack

Aus der Mikrocontroller.net Artikelsammlung, mit Beiträgen verschiedener Autoren (siehe Versionsgeschichte)
Wechseln zu: Navigation, Suche


A
V
R
Application
Mgmt      µIP ... Serial
RFM12_LLC
RFM12_MAC
RFM12_PHY
GPIO SPI UART


Dieser Artikel beschreibt einen ISO/OSI Protokoll Stack für den RFM12 Funkchip.
Einige Hardwarebeispiele finden sich in AVR RFM12.
Fehler und Anregungen können gerne auf der Diskussionsseite besprochen werden.

Eine Referenz-Implementierung für den AVR wird in folgendem SVN-Repository bereitgestellt:

svn://mikrocontroller.net/rfm12/trunk/RFM12_Stack
Implementierungskriterien
  • Wo möglich werden Callback-Funktionen anstatt FIFOs verwendet um RAM zu sparen.
  • Interruptgesteuerter Ablauf des Stacks
  • Funktionen sollten nicht blockieren

Layer 1: Physical

Layer1 State Diagram

Der Physical-Layer kümmert sich um die direkte Ansteuerung des RFM12. Alle Funktionen des Chips werden als Software-API bereitgestellt.

Folgende Eigenschaften sind bereits vom RFM12 vorgegeben:

Definiert werden muss jedoch noch:

  • Baudrate (Vorschlag: feste Kanal-Baudraten-Zuordnung)
  • Zuordnung von Frequenzen zu Kanälen
  • Bandbreite der Kanäle
  • Management der Sendeleistung/Empfangsempfindlichkeit

API

void RFM12_PHY_modeTX(void);

void RFM12_PHY_modeRX(void);

bool RFM12_PHY_busy(void);

void RFM12_setBaudrate(uint32_t baud);

void RFM12_setCenterFrequency(uint16_t freq);

void RFM12_setDataFilter(bool autoLock, bool fastMode, bool analog, uint8_t dqdThres);

void RFM12_setReceiverBandwidth(RFM12_VDI_t vdi, RFM12_RxBW_t bandwidth, RFM12_GAIN_t gain, RFM12_RSSI_t drssi);

void RFM12_setPowerManagement(bool enRX, bool enBB, bool startTX, bool enSynth, bool enOSC, bool enBat, bool enWkT, bool clkOff);

void RFM12_setTransmitPower(RFM12_Power_t power, RFM12_TxDev_t deviation);

Layer 2: Data Link

Media Access Control (MAC)

Hier noch ein paar Anregungen zur Verbesserung des MAC: [1]

Der MAC-Layer ist sehr einfach gehalten und regelt den Zugriff auf das Medium. Hier soll ein CSMA/CA Verfahren eingesetzt werden.

  1. Im Grundzustand befindet sich der RFM12 im Empfangsmodus und wartet auf eine SYNC-Sequenz.
  2. Kommt eine Sendeanforderung, wird so lange gewartet bis das Medium frei ist, dann darf nach Ablauf einer (pseudo) zufälligen Zeitspanne gesendet werden.
  3. Wurde gerade ein Paket empfangen, darf sofort ein ACK gesendet werden.
  4. Die maximale Paketlänge beträgt 50ms. Die maximale Anzahl Bytes hängt daher von der Baudrate ab.

Der Frameaufbau ist teilweise vom RFM12 vorgegeben (SYNC-Erkennung). Der Start-Of-Frame (SOF) dient der Synchronisation. Als End-Of-Frame (EOF) wird ebenfalls die Sequenz 0xAA verwendet. Diese darf im Datenteil nicht vorkommen!

MAC Frameaufbau
SOF Sync n Byte Daten EOF
Bits 16 16 0 - 8*n 8
Wert 0xAA 0xAA 0x2D 0xD4 Daten 0xAA

API

void RFM12_MAC_setChannel(uint8_t channel);

bool RFM12_MAC_isReceiving(void);

bool RFM12_MAC_mediaBusy(void);

void RFM12_MAC_startCtrlTransmission(void);

void RFM12_MAC_endCtrlTransmission(void);

Logical Link Control (LLC)

Der LLC-Layer kümmert sich um die Sicherung der zu übertragenden Daten. Außerdem können Geräte direkt mit ihrer Adresse (7-Bit) angesprochen werden.

FEC
Alle Bytes werden auf eine 16-Bit Hamming-Sequenz erweitert, wodurch die Datenrate halbiert wird.
Dies erlaubt es einzelne Bitfehler zu korrigieren.
Bei zu vielen Fehlern können diese jedoch nicht erkannt werden.
Im Hamming-Code kommt die Sequenz 0xAA nicht vor (siehe MAC-Layer).
Die FEC sorgt außerdem dafür, dass genügend 0-1 Übergänge vorkommen. So kann der Empfänger den Takt auch bei langen Paketen besser halten.
CRC
Der gesamte Frame wird nochmals durch eine Checksumme gesichert. (CRC-8: x8 + x5 + x4 + 1)
Version
Das Versionsfeld gibt die verwendete Version an (aktuell ist Version 1 = 0b00).
Wenn die Version nicht unterstützt ist, wird der Empfang abgebrochen.
Adressierung
Broadcast (0xff) an alle Geräte (immer ohne ACK)
127 Multicast-Gruppen (0x80 - 0xfe)
128 Geräteadressen (0x00 - 0x7f) (mit oder ohne ACK)
LLC Frameaufbau (Version 1)
Version need ACK is ACK TypeID Empfänger Sender 0-m Byte Daten CRC-8
Bits (vor FEC) 2 1 1 4 8 8 0 - 8*m 8
Bits (nach FEC) 4 2 2 8 16 16 0 - 16*m 16

API

void RFM12_LLC_registerType(RFM12_ProtocolID_t typeID, RFM12_L3_Protocol_t proto);

uint8_t RFM12_LLC_sendFrame(RFM12_ProtocolID_t proto, uint8_t receiver, bool requireACK);

Layer 3: Network

Für den Network-Layer werden nur einige Beispiele angeführt. Ab hier können beliebige eigene Protokolle eingesetzt werden. Das verwendete Protokoll wird durch die TypeID im LLC-Layer angegeben. Die Layer-3-Protokolle sollten nach Möglichkeit nur über die LLC-API mit dem Rest des Stacks kommunizieren.

Die TypeIDs sind wie folgt definiert:

Typ 0: Management

Management Protokoll:

  • Muss immer implementiert sein
  • Sollte ähnliche Funktionen bieten wie das Service Discovery Protocol (SDP) bei Bluetooth
  • Unterscheidung Request / Response
Nachrichten
ID Request Response
0x00 Device Discovery Device Information
0x01 Available Layer 3 Protos Protocol Information


Typ 1: Bytestream

Die Einteilung in Pakete wird aufgehoben. Daten kommen 1:1 in der Reihenfolge an, wie sie gesendet wurden.

API

void RFM12_Serial_setPeer(uint8_t peer);

bool RFM12_Serial_txAvailable(void);

void RFM12_Serial_txData(uint8_t data);

bool RFM12_Serial_rxAvailable(void);

uint8_t RFM12_Serial_rxData(void);

Typ 3: IPv4

z. B. uIP TCP/IP Stack von Adam Dunkels <adam@dunkels.com>


Anhänge

Sequenzdiagramme

Empfang:

RX Sequenz

Senden:

TX Sequenz

Frames

Beachte: Durch die Hamming-Codierung sind alle Bytes innerhalb des MAC-Layer doppelt so lang wie angegeben!

MAC LLC L3
Frameaufbau
SOF Sync Empfänger Sender need ACK | is ACK | | | TypeID 0-28 Byte Daten CRC-8 EOF
Bits 16 16 8 8       1     |      1      |1|1|    4    0-224 8 8
Wert 0xAA 0xAA 0x2D 0xD4 0xAA

Kanalzuordnung

433MHz Band
Kanal 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Mittenfrequenz 431.0 431.5 432.0 432.5 433.0 433.5 434.0 434.5 435.0 435.5 436.0 436.5 437.0 437.5 438.0 438.5
Baudrate 9.6k 19.2k 115.2k 9.6k 19.2k 115.2k 9.6k 19.2k 115.2k 9.6k 19.2k 115.2k 9.6k 19.2k 115.2k 9.6k


In der EU sind nur die Kanäle 5-7 möglich. Alle anderen Frequenzen stören andere Funkdienste und können zu nicht unerheblichen Bußgeldern und Kosten für Messeinsätze führen. Achtung: die Module dürfen auf den anderen Kanälen nur von Personen mit Amateurfunkgenehmigung betrieben werden!

Die o.g. Tabelle verwendet anscheinend gerundete Werte. Für die (je nach Baudrate und Frequenzhub) drei freien Kanäle ergeben sich folgende Eigenschaften:

Kanal Mittenfrequenz Bandbreite untere Kanalgrenze obere Kanalgrenze
5 433,34 MHz ± 290 kHz 433,05 MHz 433,63 MHz
6 433,92 MHz ± 290 kHz 433,63 MHz 434,21 MHz
6 breit 433,92 MHz ± 870 kHz 433,05 MHz 434,79 MHz
7 434,50 MHz ± 290 kHz 434,21 MHz 434,79 MHz

Wie man hierbei sieht, fallen die Kanalgrenzen genau auf den zugelassenen freien Bereich von 433,05 MHz bis 434,79 MHz. Mit weniger Bandbreite lassen sich auch mehr Kanäle unterbringen.

Hamming-Tabelle

Encodieren

Algorithmus Beispiel
1: 8-Bit Wert 10010110
2: 4-7 0-3 1001 0110
3: HammingE[(4-7)] HammingE[(0-3)] 0xC7 0x38
4: high low 11000111 00111000
5: 16-Bit Codewort 11000111 00111000


HammingE
0 1 2 3 4 5 6 7 8 9 A B C D E F
0x15 0x02 0x49 0x5E 0x64 0x73 0x38 0x2F 0xD0 0xC7 0x8C 0x9B 0xA1 0xB6 0xFD 0xEA

Die Einträge in der Tabelle sind so gewählt, dass der Code den maximalen Hamming-Abstand von 4 Bit hat.

Dekodieren

In der Tabelle HammingD stehen nur 4-Bit breite Werte. Um einen 8-Bit Wert zu erhalten müssen also 2 Einträge aus der Tabelle ausgewählt werden.

Wird nun ein 16-Bit Wert empfangen, bestimmt das High-Byte den ersten Eintrag, das Low-Byte den zweiten.

Es können bis zu zwei gekippte Bits im High- und im Low-Byte korrigiert werden.

Update: Dies stimmt so leider nicht, da der Code 2 Bit Fehler nur erkennen, aber nicht eindeutig reparieren kann. Beispiel: 0x29=0b00101001 kann durch zwei Bitfehler sowohl vom Code 0x2f=0b001011111 (codewort für 7) als auch vom Code 0x38=0b00111001 (codewort für 6) oder von Code 0x49=0b01001001 (Codewort für 2) entstanden sein. Eine eindeutige Rekonstruktion ist für zwei Bitfehler also nicht möglich. Für einen solchen Code wäre ein Hammingabstand von 5 erforderlich (lt. Wikipedia). Leider gibt es keinen (8,4,5) Code (8 Symbolbits, davon 4 Datenbits, alle Symbole haben Hammingabstand von 5).

(TODO die Tabelle überarbeiten und die nichteindeutigen Symbole markieren...)

Algorithmus Beispiel (mit Bitfehlern)
1: 16-Bit Codewort 11010111 00101001
2: high low 11010111 00101001
3: HammingD[high] HammingD[low] 0x09 0x06 (oder 0x07 oder 0x02...)
4: 4-7 0-3 1001 0110
5: 8-Bit Wert 10010110


HammingD
0 1 2 3 4 5 6 7 8 9 A B C D E F
0 0x01 0x00 0x01 0x01 0x00 0x00 0x01 0x01 0x02 0x02 0x01 0x03 0x0A 0x02 0x03 0x07
1 0x00 0x00 0x01 0x01 0x00 0x00 0x01 0x00 0x06 0x02 0x03 0x0B 0x02 0x00 0x03 0x03
2 0x04 0x0C 0x01 0x05 0x04 0x04 0x05 0x07 0x06 0x06 0x07 0x07 0x06 0x07 0x07 0x07
3 0x06 0x04 0x05 0x05 0x04 0x00 0x0D 0x05 0x06 0x06 0x06 0x07 0x06 0x06 0x07 0x07
4 0x00 0x02 0x01 0x01 0x04 0x00 0x01 0x09 0x02 0x02 0x03 0x02 0x02 0x02 0x03 0x03
5 0x08 0x00 0x01 0x05 0x00 0x00 0x03 0x01 0x02 0x02 0x03 0x03 0x03 0x02 0x03 0x03
6 0x04 0x04 0x05 0x05 0x04 0x04 0x04 0x05 0x06 0x02 0x0F 0x07 0x04 0x06 0x07 0x07
7 0x04 0x05 0x05 0x05 0x04 0x04 0x05 0x05 0x06 0x06 0x07 0x05 0x06 0x0E 0x03 0x07
8 0x08 0x0C 0x01 0x09 0x0A 0x08 0x09 0x09 0x0A 0x0A 0x0B 0x0B 0x0A 0x0A 0x0A 0x0B
9 0x08 0x08 0x09 0x0B 0x08 0x00 0x0D 0x09 0x0A 0x0B 0x0B 0x0B 0x0A 0x0A 0x0B 0x0B
A 0x0C 0x0C 0x0D 0x0C 0x0C 0x0C 0x0D 0x0D 0x0E 0x0C 0x0F 0x0F 0x0A 0x0E 0x0F 0x07
B 0x0C 0x0C 0x0D 0x0D 0x0D 0x0C 0x0D 0x0D 0x06 0x0E 0x0F 0x0B 0x0E 0x0E 0x0D 0x0F
C 0x08 0x08 0x09 0x09 0x08 0x09 0x09 0x09 0x0A 0x02 0x0F 0x0B 0x0A 0x0A 0x0B 0x09
D 0x08 0x08 0x08 0x09 0x08 0x08 0x09 0x09 0x08 0x0A 0x0B 0x0B 0x0A 0x0E 0x03 0x0B
E 0x0C 0x0C 0x0F 0x0D 0x04 0x0C 0x0D 0x09 0x0F 0x0E 0x0F 0x0F 0x0E 0x0E 0x0F 0x0F
F 0x08 0x0C 0x0D 0x05 0x0C 0x0E 0x0D 0x0D 0x0E 0x0E 0x0F 0x0F 0x0E 0x0E 0x0F 0x0E