Forum: Mikrocontroller und Digitale Elektronik CAN Bus Byte Order


von Frank (Gast)


Lesenswert?

Hallo zusammen,
falls im falschen Forum gepostet, bitte verschieben.

es geht um eine aus 8 Bytes (Byte 0 bis 7) bestehende CAN Botschaft des 
Datenbereich.
In einer Auswerteinheit muss neben der CAN-ID das Startbit, die Länge 
und die Byte-Order (Intel oder Motorola) engegeben werden.

Es soll nun Byte 2 mit einer Länge von 16 Bit ausgewertet werden, 
demnach belegt die Datenbotschaft zwei Bytes = 16 Bit Länge.

Meiner Meinung nach wäre
- bei Motorola (Big Endian) das Startbit (beginnend mit 0) das Bit Nr. 
16
- bei Intel (little Endian) das Startbit (beginnend mit 0) das Bit Nr. 
23

Liege ich richtig?

lg Frank

von Frank K. (digidax)


Lesenswert?

Ergänzung: die Angabe der Bitnummer, wenn man von 0 bis 63 zählen würde.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Du musst bei der Auswerte-Einheit konfigurieren, wo das Startbit ist? 
Schaue in deren Dokumentation, wie sie diese Angabe interpretiert. 
Wahrscheinlich ist beides mal Bit 0 das Startbit, weil eben die Bits ab 
Position 0 ausgewertet werden, wenn auch in unterschiedlicher 
Reihenfolge.

Aber Achtung, falls du mit Vector DBC-Dateien arbeitest - hier ist das 
Startbit immer die Position des niederwertigsten Bits, und die ist bei 
Big Endian mitten in den Daten, 8 Bits vor Ende... Das ist unüblich und 
verwirrend und selbst der Vector-eigene CANdb++ Editor bekommt das nicht 
richtig hin.

von Peter D. (peda)


Lesenswert?

Wie die Datenbytes zugegriffen werden, steht im Manual des jeweiligen 
CAN-Controllers. Sie sind in der Regel nicht als Word zugreifbar und 
auch nicht bitweise.
Oft ist das Datenregister auch mit Autoincrement zugreifbar, d.h. 
nacheinander werden von der selben Adresse Byte 0..7 gelesen.

von Frank K. (digidax)


Lesenswert?

Über die Interpretation des Startbits schweigt sich die Doku leider aus, 
es kann 0 bis 63 angegeben werden und ja, Du hast den Finger drauf, es 
handelt sich um einen Datensatz aus einer Vector DB, welche mal die 
Bytes von 1 bis 8 und mal von 0 bis 7 benennt. Ähnlich bei den Bits. 
Hier ist eben aufgefallen, dass der gelesene Wert abnormal springt, weil 
es hätte heißen müssen Byte 1 und nicht Byte 2.

Also würde Big Endian (Motorola) dann Byte 0 und 1 wie folgt zählen:
7 6 5 4 3 2 1 0  15 14 13 12 11 10 9 8

dagegen Intel:
0 1 2 3 4 5 6 7  8 9 10 11 12 13 14 15

: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Zeig doch mal einen Ausschnitt aus der Doku, die Konfiguration und einen 
Screenshot aus CANdb++ der fraglichen Signale... Man vertut sich bei 
sowas zu schnell als dass man das vernünftig in Textform wiedergeben 
könnte.

von Frank K. (digidax)


Lesenswert?

Ich durfte leider nur einen Blick in die DB werfen, da die offiziell 
nicht existiert und habe mir die ID, das Byte, die Länge und dass es 
Motorola / Big Endian ist herausgeschrieben, ebenfalls Offset und 
Scalierung zu PHYS Wert.

Im datenstrom selbst ist mir dann aufgefallen, dass Byte 2 den Wert 0x00 
hat und Byte 3 0xF0. Das kann aber nicht sein, denn dieses byte müßte 
auch für diesen Zustand 0x00 sein, also beide Bytes zusammen 0 ergeben. 
Das Byte 1 ist aber 0x00, darum habe ich das Startbit um 8 Stellen 
verringert und siehe da, es geht, die Wert stimmen.

Jetzt hat mich persönlich interessiert, wie ich selbst für einen 
Datenpunkt das Startbit errechnen kann. z.B. folgende CAN Datenbytes mit 
der Konvention das Bits und Bytes von 0 an gezählt werden:

12 34 1F 00 00 34 76 22

Ich weiß, dass die die beiden Bytes 00 00 einen Wert beinhalten, der 16 
Bit belegt, nämlich genau über diese zwei Bytes 3 und 4 geht.

In dem Auswerte Programm gebe ich als Länge 16 Bit ein.
Wenn nun die Byteorder bekannt ist, wie errechne ich dann das Startbit?

: Bearbeitet durch User
von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Frank K. schrieb:
> Wenn nun die Byteorder bekannt ist, wie errechne ich dann das Startbit?

Hängt halt von der Konvention ab... In den meisten Fällen ist das 
Startbit komplett unabhängig von der Byte-Reihenfolge immer das 0. Bit 
welches verarbeitet wird, egal welchen Wert man ihm beimisst. Das wäre 
hier dann immer 24, denn die Bytes 12 34 1F belegen 24 Bits, also ist 
das Bit danach das 24. ... Welches der beiden 0-Bytes jetzt die 
höherwertigen Bits enthält ist dabei unerheblich. Dies ist 
wahrscheinlich bei deinem Gerät das, was du angeben musst.

Nur in den DBC-Dateien ist das so seltsam gemacht: Was dort 
fälschlicherweise "Startbit" genannt wird ist gar nicht das Startbit, 
sondern das niederwertigste Bit, also das Bit welches die 1er enthält. 
Das ist bei Big Endian hier 32, bei Little Endian 24. Das lässt sich so 
umrechnen:

Big Endian:
Niederwertigstes Bit = Startbit + Anzahl Bits - 8

Little Endian
Niederwertigstes Bit = Startbit

Die ganze Logik funktioniert natürlich nur, wenn man von ganzen Bytes 
redet, und das Signal nicht 12 Bits oder so ist.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Beim Auslesen eines CAN-Objekts muß man auch immer die Länge beachten.
Wenn die Länge 3 ist, dann darf man auch nur 3 Bytes auslesen. Liest man 
aber 8 Bytes aus, dann stammen eben die überzähligen 5 Bytes noch von 
einer älteren Nachricht und das ergibt Unsinn.

Was nun die 0..8 Datenbytes im einzelnen bedeuten, legt das 
übergeordnete Protokoll fest und nicht Motorola oder Intel. Da sich 
einfach irgendne Order auszudenken, bis es passen könnte, ist er falsche 
Ansatz. Man muß die Protokollbeschreibung lesen.

von Frank K. (digidax)


Lesenswert?

Ok, danke. Sehr gut erklärt und verstanden.
Dann freu ich mich mal auf das nächste Objekt, was ich vorgesetzt 
bekommen ;-)

lg und schönes WE, Frank

von Rolf M. (rmagnus)


Lesenswert?

Peter D. schrieb:
> Beim Auslesen eines CAN-Objekts muß man auch immer die Länge beachten.
> Wenn die Länge 3 ist, dann darf man auch nur 3 Bytes auslesen. Liest man
> aber 8 Bytes aus, dann stammen eben die überzähligen 5 Bytes noch von
> einer älteren Nachricht und das ergibt Unsinn.
>
> Was nun die 0..8 Datenbytes im einzelnen bedeuten, legt das
> übergeordnete Protokoll fest und nicht Motorola oder Intel.

Du hast noch nicht viel mit Automotive CAN gemacht, oder? Da gibt's für 
den überwiegenden Teil der Botschaften kein übergeordnetes Protokoll, 
sondern eine so genannte Datenbasis. Das ist eine Datei, in der für jede 
Botschaft exakt drin steht, wo welcher Wert steht (und das ist fix - er 
steht immer exakt in dieser Botschaft, exakt an dieser Stelle). Also so 
in der Art: Temperatur ist in Botschaft 0x123 ab Bit-Position 14 und ist 
11 Bits groß. Dazu wird auch eine Byteorder angegeben für Signale, die 
sich über mehr als ein Byte der Botschaft erstrecken. Diese Byteordern 
werden mit "Intel" und "Motorola" bezeichnet. Um also die Temperatur da 
wieder rauszuextrahieren, muss man wissen, welche Bits da nun 
dazugehören, und das hängt auch davon ab, ob Intel- oder 
Motorola-Byteoder.

> Da sich einfach irgendne Order auszudenken, bis es passen könnte, ist er
> falsche Ansatz. Man muß die Protokollbeschreibung lesen.

Das wäre in dem Fall:

Frank K. schrieb:
> Ich durfte leider nur einen Blick in die DB werfen, da die offiziell
> nicht existiert und habe mir die ID, das Byte, die Länge und dass es
> Motorola / Big Endian ist herausgeschrieben, ebenfalls Offset und
> Scalierung zu PHYS Wert.

von Frank K. (digidax)


Lesenswert?

Doch, ich mache sehr viel mit Automtive CAN, sogar mit KBA und ECE 
Zulassung. Ist aber ein anderer Bereich, da es hier nicht um Automative 
geht. CAN Bus ist aber CAN Bus und entsprechend spezifiziert.

Der Fall wurde im ersten Post dargestellt.
Das was Du geschrieben hast ist auch völlig klar.
Das Problem war, dass es nur die Info gab: Botschaft 0x123, DLC 8, Byte 
zwei mit 16 Bit Länge, Motorola.

Was mich beschäftigte: Wie berechnet man das Startbit bei Motorola und 
was wenn es Intel wäre?

Die Antwort hat Niclas G. gegeben:

Big Endian (Motorola)
Niederwertigstes Bit = Startbit + Anzahl Bits - 8

Little Endian (Intel)
Niederwertigstes Bit = Startbit

Was von beiden funktioniert, kann man durch zwei Versuche "probieren".
Hier kam aber erschwerend hinzu, dass die Angabe Byte 2 falsch war, da 
man von Byte 1 bis 8 gezählt hat, demnach war Byte 1 richtig, wenn man 
von 0 bis 7 zählt, was die Auswert Sofware auch macht.

lg Frank

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Frank K. schrieb:
> Doch, ich mache sehr viel mit Automtive CAN,

Meine Aussagen gingen nicht an dich, sondern an Peter.

Frank K. schrieb:
> Das Problem war, dass es nur die Info gab: Botschaft 0x123, DLC 8, Byte
> zwei mit 16 Bit Länge, Motorola.
>
> Was mich beschäftigte: Wie berechnet man das Startbit bei Motorola und
> was wenn es Intel wäre?

Wenn du CANalyzer oder CANoe hast, ist da der CANdb++-Editor dabei. Geht 
angeblich auch mit der Demo-Version. Da kannst du dir ein Signal 
basteln, das diesen Werten entspricht und dir dann die Belegung der 
Bytes ansehen.

von Peter D. (peda)


Lesenswert?

Rolf M. schrieb:
> Du hast noch nicht viel mit Automotive CAN gemacht

Stimmt. Aber warum kann man es nicht eindeutig und klar definieren.
Man kann doch ganz einfach sagen, z.B. Datenbyte 0 ist das LSB und 
Datenbyte 1 das MSB des 16Bit Wertes. Warum muß man alles immer maximal 
umständlich definieren?
Bei Intel und Motorola müßte ich erst nachschlagen, was damit gemeint 
sein könnte. Protokolle sollten immer Architektur unabhängig sein, z.B. 
Network Byte Order.
Wir sind bei unserem CAN-Protokoll dazu übergegangen, alles als String 
zu übertragen. Das macht es maximal einfach zu debuggen und minimal 
mißverständlich.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Peter D. schrieb:
> Rolf M. schrieb:
>> Du hast noch nicht viel mit Automotive CAN gemacht
>
> Stimmt. Aber warum kann man es nicht eindeutig und klar definieren.
> Man kann doch ganz einfach sagen, z.B. Datenbyte 0 ist das LSB und
> Datenbyte 1 das MSB des 16Bit Wertes.

Es kann nicht nur Vielfache von 8 geben. Im Prinzip kann der Wert an 
beliebiger Stelle anfangen und beliebig lang sein.

> Warum muß man alles immer maximal umständlich definieren?

Weil es hier darum geht, dass die Botschaften auch von sehr kleinen µCs 
gelesen werden, und das ggf. in großer Anzahl und Häufigkeit. Man will 
es daher dort möglichst effizient haben und jede Umrechnung einsparen. 
Das mag heute nicht mehr ganz so wichtig sein, aber zu Anfangszeiten des 
CAN musste man sehr sparsam sein.

> Wir sind bei unserem CAN-Protokoll dazu übergegangen, alles als String
> zu übertragen. Das macht es maximal einfach zu debuggen und minimal
> mißverständlich.

Das wäre im Automotive-Bereich viel zu viel Overhead, sowohl im Bezug 
auf die Datenmenge, als auch im Bezug auf den Code zum Auswerten der 
Daten.

von Markus F. (mfro)


Lesenswert?

Peter D. schrieb:
> Bei Intel und Motorola müßte ich erst nachschlagen, was damit gemeint
> sein könnte.

... wer das nachschlagen muß, hat entweder keine Ahnung von 
Computertechnik oder ist beneidenswert jung (und in dem Fall entlastet) 
;)

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Peter D. schrieb:
> Das macht es maximal einfach zu debuggen und minimal
> mißverständlich.

Da mach ich doch mal Eigenwerbung :)
1
#include <cstdint>
2
#include <iostream>
3
#include <uSer.hh>
4
5
struct MyMessage {
6
  USER_STRUCT(MyMessage, uSer::ByteOrder::BE)
7
8
  USER_MEM(std::uint32_t, voltage, uSer::Width<24>)
9
  USER_MEM(std::uint16_t, rpm)
10
  USER_MEM(std::uint16_t, torque)
11
  USER_MEM(std::uint8_t, state)
12
13
  USER_ENUM_MEM(voltage, rpm, torque, state)
14
};
15
16
int main () {
17
  std::uint8_t canMsg [8] { 0x12, 0x34, 0x1F, 0x00, 0x00, 0x34, 0x76, 0x22 };
18
19
  MyMessage msg;
20
  uSer::deserialize (canMsg, msg);
21
  
22
  std::cout << std::hex  << "voltage = 0x" << msg.voltage << "\n"
23
              << "rpm = 0x" << msg.rpm << "\n"
24
              << "torque = 0x" << msg.torque << "\n"
25
              << "state = 0x" << (int) msg.state << "\n";
26
}

Ausgabe:
1
voltage = 0x12341f
2
rpm = 0x0
3
torque = 0x3476
4
state = 0x22

Mit µSer ( https://github.com/Erlkoenig90/uSer ) kann man solche 
CAN-Nachrichten portabel en/de-kodieren; um z.B. zwischen Big Endian und 
Little Endian umzuschalten muss man nur das "BE" durch "LE" tauschen.

Die Definition des structs könnte man sich automatisch aus einer 
DBC-Datei generieren lassen. So ist das leicht anpassbar ohne dass man 
den Code ändern müsste.

von Tim (Gast)


Lesenswert?

Frank K. schrieb:
> Big Endian (Motorola)
> Niederwertigstes Bit = Startbit + Anzahl Bits - 8

Vorsicht, diese Formel stimmt nicht!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.