Forum: Mikrocontroller und Digitale Elektronik uCCan Interface


von Markus (Gast)


Lesenswert?

Hallo

Ich bin gerade dabei mich in die CAN Schnittstelle einzuarbeiten.
Dazu habe ich beim STM32F0 uC das Manual mehrmals gelesen.
Irgendwie komme ich nicht drauf, wie das Ganze mit den Identifiern und 
den Filtern funktionieren soll.

Angenommen ich habe 2 Geräte, die gewisse Nachrichten erhalten sollen.
Im Manual heisst es ja, dass die Identifier zum einen dazu dienen, die 
Nachricht zu filtern und gleichzeitig aber die Priorität definieren. Je 
niedriger der Wert, desto höher die Prio. Wieso habe ich aber im 
Protokoll ID0-ID10?
Für meine 2 Geräte könnte ich doch nun zB die IDs 1 für Gerät 1 und 0 
für Gerät 2 definieren.

Dazu muss ich mir das CAN receive FIFO mailbox identifier register 
(CAN_RIxR) ansehen.
Klar ist mir, dass ich die Daten direkt aus dem Datenregister 
herauslese. Die DAtenlänge sofern ich die benötige, lese ich aus den DLC 
bits.

Aber wo genau definiere ich nun welche IDs wirklich durch den Filter 
kommen  und im FIFO abgelegt werden sollen.
Mache ich das im FMI[7:0]: Filter match index?
Was ich nicht verstehe auch warum das im Receive Frame steht, das müsste 
doch für die beiden Geräte im Filter fest definiert sein.

Ich bitte um Hilfe, ich sehe den Wald vor lauter Bäume nicht mehr.

von Markus (Gast)


Lesenswert?

Markus schrieb:
> Aber wo genau definiere ich nun welche IDs wirklich durch den Filter
> kommen  und im FIFO abgelegt werden sollen.

Ich meinte natürlich, wo ich die IDs fest definiere, sodass die 
entsprechenden Nachrichten  entsprechend versehenen IDs durch den Filter 
kommen.

von D. Z. (zoundgalaxy)


Lesenswert?

Hey Markus, ich bin auch gerade dabei, mich damit zu beschäftigen, aber 
noch
weit von deinem Stand entfernt. In einem Post, den ich die Tage 
gestartet hatte, wurden mir diese Links gegeben. Vieleicht lösen sie 
dein Problem bzw erklären dein Anliegen.

https://www.electronicshub.org/arduino-mcp2515-can-bus-tutorial/
http://media3.ev-tv.me/CAN%20Due2.2%20User%20Manual.pdf
http://www.grifo.com/PRESS/DOC/Temic/CAN_TUT.PDF

lg

von temp (Gast)


Lesenswert?

hier mal etwas Beispielcode:
1
enum eCanFilterMode
2
{
3
  CF_LISTMODE_FIFO0_STD=0x0,
4
  CF_LISTMODE_FIFO1_STD=0x1,
5
  CF_MASKMODE_FIFO0_STD=0x2,
6
  CF_MASKMODE_FIFO1_STD=0x3,
7
  CF_LISTMODE_FIFO0_EXT=0x4,
8
  CF_LISTMODE_FIFO1_EXT=0x5,
9
  CF_MASKMODE_FIFO0_EXT=0x6,
10
  CF_MASKMODE_FIFO1_EXT=0x7
11
};
12
13
void Can::SetFilter32(int idx, uint32_t id1, uint32_t id2, eCanFilterMode eMode)  
14
{
15
  uint32_t  CAN_msgId1 = 0;
16
  uint32_t  CAN_msgId2 = 0;
17
  
18
  if (idx<0 || idx>13)
19
    return;
20
  
21
  // std or ext message
22
  if ((eMode & 0b100) == 0)  
23
    { // Standard ID
24
    CAN_msgId1  |= (uint32_t)(id1 << 21);
25
    CAN_msgId2  |= (uint32_t)(id2 << 21);
26
    }  
27
  else  
28
    {  // Extended ID
29
    CAN_msgId1  |= (uint32_t)(id1 <<  3) | CAN_TI0R_IDE;
30
    CAN_msgId2  |= (uint32_t)(id2 <<  3) | CAN_TI0R_IDE;
31
    }
32
33
  CAN1->FMR  |=  CAN_FMR_FINIT;                    // set Initialisation mode for filter banks
34
  CAN1->FA1R &=  ~(uint32_t)(1 << idx);            // deactivate filter
35
36
                                                   // initialize filter   
37
  CAN1->FS1R |= (uint32_t)(1 << idx);              // set 32-bit scale configuration
38
  // list or mask Mode ?
39
  if ((eMode & 0b010) == 0)  
40
    CAN1->FM1R |= (uint32_t)(1 << idx);            // set 2 32-bit identifier list mode
41
  else
42
    CAN1->FM1R &= ~((uint32_t)(1 << idx));         // set 2 32-bit identifier mask mode
43
44
  CAN1->sFilterRegister[idx].FR1 = CAN_msgId1;     //  32-bit identifier
45
  CAN1->sFilterRegister[idx].FR2 = CAN_msgId2;     //  32-bit identifier
46
                                 
47
  if ((eMode & 0b001) == 0)  
48
    CAN1->FFA1R &= ~(uint32_t)(1 << idx);  // assign filter to FIFO 0
49
  else
50
    CAN1->FFA1R |= (uint32_t)(1 << idx);   // assign filter to FIFO 1
51
52
  CAN1->FA1R  |=  (uint32_t)(1 << idx);  // activate filter
53
  CAN1->FMR &= ~CAN_FMR_FINIT;           // reset Initialisation mode for filter banks
54
}
55
56
void Can::SetFilter16(int idx, uint32_t id1, uint32_t id2, uint32_t id3, uint32_t id4, eCanFilterMode eMode)  
57
{
58
  uint32_t  CAN_msgId1 = 0;
59
  uint32_t  CAN_msgId2 = 0;
60
  
61
  if (idx<0 || idx>13)
62
    return;
63
                                                  // Setup identifier information
64
  // std or ext message
65
  if ((eMode & 0b100) == 0)  
66
    { // Standard ID
67
    CAN_msgId1=(uint32_t)(id1 << 5) | (id2<<21);
68
    CAN_msgId2=(uint32_t)(id3 << 5) | (id4<<21);
69
    }  
70
  else  
71
    {  // Extended ID
72
    uint32_t r1=(uint32_t)((id1>>13) & 0xffffffe0) | ((id1>>15) & 0x1f) | (1<<3);
73
    uint32_t r2=(uint32_t)((id2>>13) & 0xffffffe0) | ((id2>>15) & 0x1f) | (1<<3);
74
    CAN_msgId1=(r2 & 0xffff)<<16 | (r1 & 0xffff);
75
76
    r1=(uint32_t)((id3>>13) & 0xffffffe0) | ((id3>>15) & 0x1f) | (1<<3);
77
    r2=(uint32_t)((id4>>13) & 0xffffffe0) | ((id4>>15) & 0x1f) | (1<<3);
78
    CAN_msgId2=(r2 & 0xffff)<<16 | (r1 & 0xffff);
79
    }
80
81
  CAN1->FMR  |=  CAN_FMR_FINIT;                    // set Initialisation mode for filter banks
82
  CAN1->FA1R &=  ~(uint32_t)(1 << idx);            // deactivate filter
83
84
                                                   // initialize filter   
85
  CAN1->FS1R &= ~(uint32_t)(1 << idx);             // set 16-bit scale configuration
86
  // list or mask Mode ?
87
  if ((eMode & 0b010) == 0)  
88
    CAN1->FM1R |= (uint32_t)(1 << idx);            
89
  else
90
    CAN1->FM1R &= ~((uint32_t)(1 << idx));         
91
92
  CAN1->sFilterRegister[idx].FR1 = CAN_msgId1;     
93
  CAN1->sFilterRegister[idx].FR2 = CAN_msgId2;     
94
                                 
95
  if ((eMode & 0b001) == 0)  
96
    CAN1->FFA1R &= ~(uint32_t)(1 << idx);  // assign filter to FIFO 0
97
  else
98
    CAN1->FFA1R |= (uint32_t)(1 << idx);   // assign filter to FIFO 1
99
  CAN1->FA1R  |=  (uint32_t)(1 << idx);  // activate filter
100
101
  CAN1->FMR &= ~CAN_FMR_FINIT;                     // reset Initialisation mode for filter banks
102
}

Ich benutze das dann so:
1
  // Filter odometer? and handgas 0x05242500
2
  aCan.SetFilter32(0, 0x05841600, 0x05841600, CF_LISTMODE_FIFO0_EXT);
3
4
  // alle Msg die vom Akku im g2-Protokoll beantwortet werden muessen
5
  aCan.SetFilter32(1, 0x010, 0x051, CF_LISTMODE_FIFO1_STD);
6
  aCan.SetFilter32(2, 0x048, 0x058, CF_LISTMODE_FIFO1_STD);
7
8
  // aus der Antwort 008 00 11 die der Motor der Console sendet brauche ich die RPM für den Idle Timer
9
  aCan.SetFilter32(3, 0x008, 0x008, CF_LISTMODE_FIFO1_STD);
10
    
11
  // Filter for xxx0200? and xxx0300 an Serialnumber
12
  aCan.SetFilter32(4, 0x0300, 0xfeff, CF_MASKMODE_FIFO0_EXT);
13
14
  // change clock from console, toggle light
15
  aCan.SetFilter32(5, 0x05282200, 0x05241800, CF_LISTMODE_FIFO0_EXT);
16
 
17
  // BIB2 idle msg 05640100 0                          
18
  aCan.SetFilter32(6, 0x05640100, 0x05640100, CF_LISTMODE_FIFO0_EXT);
19
20
  // RC3 key press and release msg
21
  aCan.SetFilter32(7, 0x05240000, 0xffff0000, CF_MASKMODE_FIFO0_EXT);

Jedes der Filter kann in unterschiedlichen Modes betrieben werden. 
Entweder 4 einzelene STD-Ids oder jeweils 2 STD-Ids mit Maske.
Oder 2 einzelen EXT-Ids oder eine EXT-Id mit Maske.
Ausserdem gibt es noch die Unterscheidung auf welches der 2 FIFO's das 
Filter angewendet wird.

Der Code ist Teil einer C++ Klasse, sollte aber auch unter reinen C 
funktionieren. Bitte nur als Beispiel ansehen. Da die meisten sicher HAL 
verwenden, erspare ich mir das hier weiter aus zuführen.

von Markus (Gast)


Angehängte Dateien:

Lesenswert?

D. Z. schrieb:
> Hey Markus, ich bin auch gerade dabei, mich damit zu beschäftigen,
> aber
> noch
> weit von deinem Stand entfernt. In einem Post, den ich die Tage
> gestartet hatte, wurden mir diese Links gegeben. Vieleicht lösen sie
> dein Problem bzw erklären dein Anliegen.
>
> https://www.electronicshub.org/arduino-mcp2515-can-bus-tutorial/
> http://media3.ev-tv.me/CAN%20Due2.2%20User%20Manual.pdf
> http://www.grifo.com/PRESS/DOC/Temic/CAN_TUT.PDF
>
> lg

Danke, aber das ist leider auf Arduino bezogen.
Ich habe Verständnisprobleme, wie das nun genau mit den Identifiern  und 
den Daten funktioniert.
Es heisst ja, ich könne mehrere Identifier pro Nachricht vergeben.
Nur weiss ich nicht, wie das gemeint ist.
Ich habe ja eine Datenlänge von 8 Bytes pro Frame.
Damit könnte ich nun eine Temperatur, einen Druck und zB eine 
Geschwindigkeit schicken.
Also zB
rxMeg.Data[0] = Temperatur;
rxMeg.Data[1] = Druck;
rxMeg.Data[2] = Geschwindigkeit;

Jetzt sollte die zu sendende Nachricht mit einem 9 bit Identifier 
versehen werden. Ich verwende den Standard Identifier und nutze den 
DataFrame.
Somit ist das Bit IDE=0 und RTR=0.
Damit ist mein Ich wähle hier ID = 0.
Das entsprechende Register Tx Mailbox fülle ich dann entsprechend dem 
Bild oben aus.

Es gibt sagen wir mal 2 Nodes.
Angenommen CanNode0 findet gerade die Msg mit dem Identifier 0 
interessant, also lässt der Filter die Nachricht mit dem entsprechenden 
Identifier durch und speichert sie im FIFO 0 oder 1, je nach dem welcher 
FIFO gewählt wurde.
Dann könnte ich die Nachricht mit CAN_Receive auslesen und wieder den 
Puffer releasen. So weit so gut.

Was ist aber, wenn nun CanNode1 die Nachricht zwar auch interessant 
findet, aber nur die Temperatur benötigt. CanNode1 müsste demnach aber 
einen anderen Identifier als 0 haben, weil 0 schon vergeben ist, in 
diesem Fall dann eben ID=1, sprich der Registerbereich STID[31:21] 
müsste folgend gesetzt werden -> 000 000 000 01
Dann müsste ich die obige Nachricht mit den 3 Daten aber mit einem 
zusätzlichen Identifier 1 versehen.

Und genau da hört mein Verständnis auf:
1. Wenn ich an beliebige Identifier denke, hätte ich 2^11 Identfizier zu 
vergeben.
2. Wenn ich aber an mehrere Identifier pro Nachricht denke, was ja laut 
wikipedia auch möglich sein sollte, müsste ich aber die Postionen im 
Register 31:21 (Arbitration Field) einzeln ansehen und nicht als eine 
Zahl.

Bei Pkt. 1 kann ich aber keine verschiedenen Identifier vergeben
und bei Pkt. 2 kann ich aber keine beliebige Anzahl an Identifier 
vergeben, sondern maximal 11 gleichzeitig.

Ich wäre euch wirklich sehr dankbar, wenn mir jemand das kurz erklären 
könnte.

von Martin L. (maveric00)


Lesenswert?

Hallo,

ich glaube, Du hast da die Wikipedia etwas falsch verstanden.

Bei CAN hat jede Nachricht einen Identifier und ein Datenfeld. Ein Gerät 
kann verschiedene Nachrichten mit (deswegen) verschiedenen Identifiern 
versenden, Du kannst aber auch in eine Nachricht verschiedene 
Informationen hineinpacken (bis das Datenfeld voll ist).

Das ursprüngliche CAN hatte einen 11 Bit breiten Identifier, es konnten 
also 2048 verschiedene Nachrichten auf einem physikalischen Bus 
versendet werden.

Da das in manchen Netzwerken zu wenig war, wurde der Identifier in einer 
späteren Protokollversion auf alternativ 29 Bit erhöht, wobei aber 
Abwärtskompatibilität gewährleistet wurde, weswegen der Identifier im 
Protokoll in zwei Hälften (11 und 18 Bit) gesendet wird.

In dem Frame werden die (ersten) 11 Bit des Identifiers nun zuerst 
gesendet. Da jeder CAN-Controller während des Sendens auch gleichzeitig 
zurückliest, kann er bei einem 1-Bit erkennen, wenn ein anderer 
Controller gleichzeitig eine 0 sendet (da 0 dominant ist).

Tritt nun eine solche Kollision währen der ersten 12 Bit auf (Identifier 
+ Remote send request), so  hört der Controller, der eine "1" gesendet, 
aber eine "0" empfangen hat auf zu senden, weswegen der Controller mit 
dem "niedrigeren" Identifier gewinnt. Tritt die Kollision später auf, 
hören beide auf zu senden und erzeugen einen Error-Frame (und versuchen 
es später dann noch einmal).

Durch diese Methode wird eine Priorisierung der Nachrichten möglich, 
d.h. Nachrichten mit einem niedrigen Identifier haben Vorrang vor 
Nachrichten mit einem hohen Identifier. Dies führt bei hohen Buslasten 
dazu, dass wichtige Nachrichten (mit niedrigem Identifier) eher 
duchkommen.

Und zu deinen anderen Fragen: In Deinem Fall mit den drei Messwerten 
hast Du zwei Möglichkeiten:

Entweder Du packst Deine drei Messwerte in eine Nachricht mit der ID 0. 
Dann müssen alle Controller, die Interesse an einer der drei Messwerte 
haben die ID 0 empfangen (das Filter entsprechend setzen) und danach 
entscheiden, ob er nur den einen Messwert verwendet (höhere Belastung 
beim Empfänger).

Oder Du sendest die drei Messwerte in drei verschiedenen Nachrichten 
(ID0,ID1,ID2), dann kannst Du auf einen der drei Messwerte filtern (hast 
aber eine höhere Buslast und bei Empfängern die mehr als einen Messwert 
haben möchten mehr Filter belegt).

Daher werden in der Regel Messwerte, die einen logischen Zusammenhang 
haben, in eine Nachricht gepackt, und alle anderen Geräte, die Interesse 
an einem der Messwerte haben, empfangen die ganze Nachricht und werten 
nur die interessanten Datenfelder aus.

Schöne Grüße,
Martin

von Markus (Gast)


Lesenswert?

Martin L. schrieb:
> Hallo,
>
> Schöne Grüße,
> Martin

Hallo Martin

super, vielen Dank für die schöne Erklärung.
Jetzt ist mir dank dir schon Einiges klarer geworden.

Darf ich dich nun auch noch fragen, wie das nun konkret ist mit dem 
identifier register?

Wenn ich den standard identifier benutze und nicht den extended.
Dann ignoriere ich einfach die EXID Bits im register CAN_TIxR.

Aber angenommen ich würde nun doch den extended identifier benutzen.
Weshalb werden dann die LSBs of the extended identifier EXID[17:0] und 
MSBs EXID [28:18] angegeben und nicht gleich die ID, die man möchte.
Ich verstehe gerade nicht, warum LSBs und MSBs, wenn es doch nur einen 
Identifier pro Nachricht gibt und es dadurch nur ein LSB und ein MSB 
gibt, wenn man schon diese Werte angeben muss.

von Thomas F. (igel)


Lesenswert?

Markus schrieb:
> Wenn ich den standard identifier benutze und nicht den extended.
> Dann ignoriere ich einfach die EXID Bits im register CAN_TIxR.

Genau. Dann nutzt du nur die Bits 21 bis 31.

> Aber angenommen ich würde nun doch den extended identifier benutzen.

Dann benutzt du Bit 3 bis 31.

> Weshalb werden dann die LSBs of the extended identifier EXID[17:0] und
> MSBs EXID [28:18] angegeben und nicht gleich die ID, die man möchte.

Vergiss das mit den LSB und MSB. Halte dich einfach an die Bitnummern. 
Umständlich ist nur dass bei 11-Bit ID diese "left-oriented" innerhalb 
der 29 reservierten Bits steht und nicht rechts. So muss man für 11 oder 
29-Bit-ID unterschiedliche Bitschiebereien durchführen.

von Markus (Gast)


Lesenswert?

Thomas F. schrieb:
> Markus schrieb:

> Vergiss das mit den LSB und MSB. Halte dich einfach an die Bitnummern.
> Umständlich ist nur dass bei 11-Bit ID diese "left-oriented" innerhalb
> der 29 reservierten Bits steht und nicht rechts. So muss man für 11 oder
> 29-Bit-ID unterschiedliche Bitschiebereien durchführen.

Alles klar, danke Thomas

von Markus (Gast)


Angehängte Dateien:

Lesenswert?

Guten Morgen zusammen

Ich bin inzwischen bei den Filtern angelangt und habe wieder etwas 
gefunden, was ich auf Anhieb nicht verstehe.

Es gibt 14 Filterbänke jeweils mit 2 32-Bit Registern (CAN_FxR1 und 
CAN_FxR2).
Nun wird auf der Seite 825 vorgeschlagen folgende Konfigurationen 
durchzuführen, wie im bild filterbanks angedeutet.

Ich habe mir nun schon einige Beispiele angesehen mitunter hier:
http://www.diller-technologies.de/stm32_wide.html#can
aber irgendwie fehlt mir das Verständnis, warum und wieso die Bits so 
verschoben werden, wie sie da zu sehen sind (<<3 | 4 etc).

Ich möchte für mich vorerst einmal 2 Beispiele so durchführen, sodass 
ich das Konzept im Bild oben nicht verletze. Damit ist meinem 
Verständnis sicherlich geholfen.

Beispiel 1: Ich möchte nur eine bestimmte Msg mit ID zB 0x0008 filtern
Beispiel 2: Ich möchte Msgs IDs im Bereich von 8-32 nutzen

Jetzt ist die Frage, wie ich da vorzugehen habe.
Wenn es zuerst mein Ziel ist eine bestimmte ID zu filtern (0x0008 Bsp. 
1), dann ergeben sich folgende Überlegungen.
Es gibt 14 Filterbänke, jeweils mit 32-bit Registern.
Da ich ja nur eine 11-bit ID habe reicht bei mir ein 16 bit Filter aus.
Ich möchte auch direkt IDs miteinander vergleichen.
Daher wähle ich den Filter im identifier list mode und setze den Scaler 
auf 16 bit.

Jetzt habe ich aus den 2 32-bit Registern 4 16-bit Filter im Identifier 
list mode gemacht. Ich befinde mich nun im Bild unten in der letzten 
Konfiguration: Four 16-bit Filters - Identifier List

Bin ich soweit richtig?

Jetzt verstehe ich 1. nicht, was die Zahlen in den Klammern sollen, zb
STID[10:3]
Wenn ich nämlich in das Register sehe (Rx_mailbox), gebe ich die STID im 
Register von Bit 21 bis 31 an, EXID von bit 2 bis 20.

2. verstehe ich nicht, ob ich wie ich nun welche Bits zu verschieben 
habe. Aber dazu muss ich erst einmal Pkt. 1 verstehen.

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.