CAN-Gateway: Unterschied zwischen den Versionen
(pimp my gate way) |
(++doku) |
||
Zeile 13: | Zeile 13: | ||
}} | }} | ||
Wir haben in ein 19' Rack Gehäuse, das mal aus dem Schrott gezogen wurde, ein CAN-RS232-Gateway eingebaut. Empfangene CAN Pakete werden dabei über RS232 getunnelt, so das eine Software auf einem Client PC diese wieder entkapseln kann. In den Gehäuse gibt es ein Netzteil für die 13V Bus Spannung (Es wurde von 24V umgebaut), und eine Menge Leuchtdioden, um diverse Betriebszustände signalisieren zu können. Außerdem ist eine Hauptplatine vorhanden, auf der ein Atmega8 werkelt. Auf dieser Platine befinden sich auch die Bausteine für den CAN Bus, und ein Max232 für die serielle Seite. Weiterhin gibt es Schieberegister und 16 Treiberstufen für die LEDs im Rest des Rack Gehäuses (Die waren schon so...). | Wir haben in ein 19' Rack Gehäuse, das mal aus dem Schrott gezogen wurde, ein CAN-RS232-Gateway eingebaut. Empfangene CAN Pakete werden dabei über RS232 getunnelt, so das eine Software auf einem Client PC diese wieder entkapseln kann. In den Gehäuse gibt es ein Netzteil für die 13V Bus Spannung (Es wurde von 24V umgebaut), und eine Menge Leuchtdioden, um diverse Betriebszustände signalisieren zu können. Außerdem ist eine Hauptplatine vorhanden, auf der ein Atmega8 werkelt. Auf dieser Platine befinden sich auch die Bausteine für den CAN Bus, und ein Max232 für die serielle Seite. Weiterhin gibt es Schieberegister und 16 Treiberstufen für die LEDs im Rest des Rack Gehäuses (Die waren schon so...). | ||
== Aktuelle Parameter == | |||
* Atmega8 @ 18.432000 MHz | |||
* MCP2515 @ 16.000000 MHz | |||
* 115200 Baud Symbolrate auf der EIA-232 Schnittstelle | |||
* 100 kBit CAN Bus | |||
* 13V Busspannung | |||
* Bus U und I Messung | |||
* /dev/ttyS0 am Server | |||
* Debug LEDs | |||
== RS232-CAN-Gateway Protokoll == | == RS232-CAN-Gateway Protokoll == | ||
Zeile 174: | Zeile 184: | ||
} | } | ||
== | == Energiemessung == | ||
Auf dem CAN-Gateway befindet sich eine Schaltung um die Busspannung und den Strom zu messen. Dazu ist die Spannung über einen Spannungsteiler an einen ADC Pin des ATmega gelegt. Zur Strommessung wird der Spannungsabfall über einen High-Side 0,01 Ohm Shunt-Widerstand mit einem Operationsverstärker differentiell verstärkt und ebenfalls an einen ADC pin des ATmega gelegt. | |||
* | |||
* | === Spannungsmessung === | ||
* | |||
* | Folgende Skizze entspricht der Spannungsmessschaltung: | ||
/ \ Buspower +13V (Ubus) | |||
| | |||
* | --- | ||
| | | |||
| | R1 = 2,7 kOhm | |||
--- | |||
| | |||
|-------------> PC5 [ADC5] +4,81V (Uadc) | |||
| | |||
--- | |||
| | | |||
| | R2 = 1 kOhm | |||
--- | |||
| | |||
| | |||
--- GND | |||
Uadc berechnet sich wie folgt: | |||
R2 | |||
Uadc = ---- * Ubus | |||
R1 | |||
Umgekehrt, um von Uadc auf Ubus zu schließen, bedeutet das also: | |||
Uadc * (R1 + R2) | |||
Ubus = ----------------- | |||
R2 | |||
=== Strommessung === | |||
Folgendes Schaltbild entspricht grob der Strommesschaltung (die echte hat noch fancy Gleichtaktdingsungsstuff, ist aber vernachlässigbar hier): | |||
/ \ Buspower-in +13V (Ubus_in) | |||
| | |||
|---------------- | |||
| | | |||
--- | | |||
| | Rshunt | + Differentialverstärker mit | |||
| | = 0,01 Ohm |---|\ <- 10x Verstärkung (amp = 10) | |||
--- | \ _____ | |||
| | / |--> PC4 [ADC4] (Uadc = Ushunt * 10) | |||
|-------------------|/ | |||
| - | |||
| | |||
| | |||
--> Buspower (Ubus) | |||
Daraus folgt für Uadc: | |||
Uadc = I * Rshunt * 10 | |||
Nach I umgestellt: | |||
Uadc | |||
I = ------------- | |||
amp * Rshunt | |||
[[Kategorie:Automatisierung]] | [[Kategorie:Automatisierung]] | ||
[[Kategorie:Infrastruktur]] | [[Kategorie:Infrastruktur]] |
Version vom 8. November 2011, 00:34 Uhr
Can-Gateway Release status: stable [box doku] | |
---|---|
Description | CAN <-> RS232 Gateway |
Author(s) | Tixiv, Hansinator |
Last Version | 1.1 () |
Platform | AVR (ATMega8) |
License | Source: GPL |
Download | c Code, trac |
Wir haben in ein 19' Rack Gehäuse, das mal aus dem Schrott gezogen wurde, ein CAN-RS232-Gateway eingebaut. Empfangene CAN Pakete werden dabei über RS232 getunnelt, so das eine Software auf einem Client PC diese wieder entkapseln kann. In den Gehäuse gibt es ein Netzteil für die 13V Bus Spannung (Es wurde von 24V umgebaut), und eine Menge Leuchtdioden, um diverse Betriebszustände signalisieren zu können. Außerdem ist eine Hauptplatine vorhanden, auf der ein Atmega8 werkelt. Auf dieser Platine befinden sich auch die Bausteine für den CAN Bus, und ein Max232 für die serielle Seite. Weiterhin gibt es Schieberegister und 16 Treiberstufen für die LEDs im Rest des Rack Gehäuses (Die waren schon so...).
Aktuelle Parameter
- Atmega8 @ 18.432000 MHz
- MCP2515 @ 16.000000 MHz
- 115200 Baud Symbolrate auf der EIA-232 Schnittstelle
- 100 kBit CAN Bus
- 13V Busspannung
- Bus U und I Messung
- /dev/ttyS0 am Server
- Debug LEDs
RS232-CAN-Gateway Protokoll
Das CAN-Gateway verwendet ein einfaches Protokoll, welches Steuerkommandos und CAN-Frames übertragen kann.
RS232-CAN-Gateway Paket | |||
---|---|---|---|
+-------------+-------------+-------------------+----------------+ | uint8_t cmd | uint8_t len | uint8_t[] payload | uint16_t crc16 | +-------------+-------------+-------------------+----------------+ | |||
Feld | Bedeutung | Datentyp | Länge (Bytes) |
cmd | Kommando | unsigned byte | 1 |
len | Payload-Länge | unsigned byte | 1 |
payload | Daten | unsigned byte array | 0-20 |
crc16 | CRC16 Checksumme | unsigned word, MSB first | 2 |
- Maximale Gesamtlänge: 24 Bytes
- Minimale Gesamtlänge: 4 Bytes
Kommunikation (Ablauf)
Zunächst muss zur korrekten Datenübertragung sichergestellt sein, dass Sender und Empfänger synchronisiert sind und sich im selben Zustand befinden. Wenn der Zustand des Empfängers unbekannt ist, muss ein Sender nach dem Einschalten eine Synchronisationssequenz senden. Diese Sequenz besteht aus einer Folge von Nullen die der maximalen Paketlänge entspricht (24 Bytes). Die State-Machine des Empfängers muss garantieren, dass eine Eingabe von 24 Nullbytes in Folge diese in ihren Ausgangszustand versetzt. Die Synchronisation kann auch durchgeführt werden, wenn der Byte-Offset von Sender und Empfänger im laufenden Betrieb nicht mehr synchron ist. Dies tritt z.B. auf, wenn Bytes auf der seriellen Leitung verloren oder Kaputt gehen. Insbesondere eine Fehlinterpretation des Längenbytes macht eine Resynchronisation nötig.
Befinden sich Sender und Empfänger im Ausgangszustand, kann eine Paketübertragung initiiert werden in dem ein Kommandobyte mit einem Wert größer 0 übertragen wird. Die Null ist somit ein reservierter Wert und darf nicht für Kommandos verwendet werden. Das nächste Byte gibt die Länge des Payload an. Ist das Längenbyte 0, wird kein Payload übertragen. Jedes Paket endet mit einer 2-Byte langen CRC16-Checksumme über das gesamte Paket.
Beachte, dass CAN-GW und Host gleichzeitig ein Sender und Empfänger sind. Es existieren also zwei unidirektionale Kommunikationskanäle, die auch unabhängig voneinander (De-)Synchronisiert sein können.
Kommandos
Das Kommando 0x11 kündigt einen CAN-Frame an.
Kommando | Beschreibung | Byte-Wert (hex) | Richtung | Payload |
---|---|---|---|---|
sync | Synchronisationssequenz | 0x00 | beide | - |
setfilter | (nicht implementiert) | 0x10 | GW | - |
packet | Raw CAN-Frame im Payload | 0x11 | beide | CAN-Frame |
setmode | Set CAN Bus Mode (Normal, Debug) (nicht implementiert) |
0x12 | GW | enum { normal, mode_sleep, loopback, listenonly, config } can_mode_t |
error | CAN-GW Errormeldung | 0x13 | Host | - |
notify reset | CAN-GW hat gestartet | 0x14 | Host | (uint8_t) MCUSR & 0xF (reset cause flags) |
ping gateway | CAN-GW Pinganforderung oder Antwort | 0x15 | GW | - |
resync request | Synchronisationssequenz anfordern | 0x16 | beide | - |
version | Firmware Version anfordern oder Antwort | 0x17 | GW | uint8_t major, uint8_t minor |
id string | Firmware ID-String anfordern oder Antwort | 0x18 | GW | reply: nicht null-terminierter string |
packet stats | Packet Counter anfordern oder Antwort | 0x19 | GW | reply: struct { uint32_t rx_count, tx_count, rx_size, tx_size; } |
error stats | MCP2515 Error Counter anfordern oder Antwort | 0x1A | GW | reply: struct { uint8_t rx_errors, tx_errors, error_flags; } |
power draw | Busenergieverbrauchsmessung anfordern oder Antwort | 0x1B | GW | reply: struct { uint16_t v, i, ref, gnd; } |
read ctrl reg | Kontrollegister lesen | 0x1C | GW | reply: uint8_t |
write ctrl reg | Kontrolregister schreiben | 0x1D | GW | uint8_t value; reply: uint8_t new value |
get reset cause | Resetgrund erfragen | 0x1E | GW | (uint8_t) MCUSR & 0xF (reset cause flags) |
Hinweis: Ein Ping darf zwar nur in Richtung Gateway gesendet werden, jedoch muss das Gateway auch mit einem Ping in Richtung Host antworten.
CRC16-Algorithmus
Zur Berechnung der Checksumme wird die CRC16 Routine der AVR-Libc verwendet. Das C-Äquivalent dieser Funktion ist wie folgt:
uint16_t crc16_update(uint16_t crc, uint8_t a) { int i; crc ^= a; for (i = 0; i < 8; ++i) { if (crc & 1) crc = (crc >> 1) ^ 0xA001; else crc = (crc >> 1); } return crc; }
Beispielcode
Folgende C-Struktur beschreibt ein RS232-CAN-Gateway Paket ohne Checksumme.
#define RS232CAN_MAXLENGTH 20 typedef struct { unsigned char cmd; unsigned char len; char data[RS232CAN_MAXLENGTH]; } rs232can_msg;
Folgender C-Code implementiert eine Reentrante Beispiel State-Machine zum Empfang von Paketen für dieses Protokoll:
typedef enum {STATE_START, STATE_LEN, STATE_PAYLOAD, STATE_CRC} canu_rcvstate_t; rs232can_msg canu_rcvpkt; canu_rcvstate_t canu_rcvstate = STATE_START; unsigned char canu_rcvlen = 0; unsigned int crc; //returns Message or 0 if there is no complete message. rs232can_msg * canu_get_nb() { static char *uartpkt_data; unsigned char c; //try to get the next char non-blocking from uart while (uart_getc_nb(&c)) { switch (canu_rcvstate) { case STATE_START: if (c) { canu_rcvstate = STATE_LEN; canu_rcvpkt.cmd = c; } break; case STATE_LEN: canu_rcvlen = (unsigned char)c; if(canu_rcvlen > RS232CAN_MAXLENGTH) { canu_rcvstate = STATE_START; break; } canu_rcvstate = STATE_PAYLOAD; canu_rcvpkt.len = (unsigned char)c; uartpkt_data = &canu_rcvpkt.data[0]; break; case STATE_PAYLOAD: if(canu_rcvlen--) *(uartpkt_data++) = c; else { canu_rcvstate = STATE_CRC; crc = c; } break; case STATE_CRC: canu_rcvstate = STATE_START; crc <<= 8; crc |= c; if(crc == crc16(&canu_rcvpkt.cmd, canu_rcvpkt.len + 2)) return &canu_rcvpkt; break; } } return NULL; }
Energiemessung
Auf dem CAN-Gateway befindet sich eine Schaltung um die Busspannung und den Strom zu messen. Dazu ist die Spannung über einen Spannungsteiler an einen ADC Pin des ATmega gelegt. Zur Strommessung wird der Spannungsabfall über einen High-Side 0,01 Ohm Shunt-Widerstand mit einem Operationsverstärker differentiell verstärkt und ebenfalls an einen ADC pin des ATmega gelegt.
Spannungsmessung
Folgende Skizze entspricht der Spannungsmessschaltung:
/ \ Buspower +13V (Ubus) | --- | | | | R1 = 2,7 kOhm --- | |-------------> PC5 [ADC5] +4,81V (Uadc) | --- | | | | R2 = 1 kOhm --- | | --- GND
Uadc berechnet sich wie folgt:
R2 Uadc = ---- * Ubus R1
Umgekehrt, um von Uadc auf Ubus zu schließen, bedeutet das also:
Uadc * (R1 + R2) Ubus = ----------------- R2
Strommessung
Folgendes Schaltbild entspricht grob der Strommesschaltung (die echte hat noch fancy Gleichtaktdingsungsstuff, ist aber vernachlässigbar hier):
/ \ Buspower-in +13V (Ubus_in) | |---------------- | | --- | | | Rshunt | + Differentialverstärker mit | | = 0,01 Ohm |---|\ <- 10x Verstärkung (amp = 10) --- | \ _____ | | / |--> PC4 [ADC4] (Uadc = Ushunt * 10) |-------------------|/ | - | | --> Buspower (Ubus)
Daraus folgt für Uadc:
Uadc = I * Rshunt * 10
Nach I umgestellt:
Uadc I = ------------- amp * Rshunt