Hallo, ich sitzte grad seit etlichen Stunden um ein ganz komisches CAN-Problem zu beseitigen. Ich nutze einen Testaufbau mit dem Atmel dvk90can, das einen at90can128 enthält. Mein Can-Netz besteht aus eben diesem Evaluationsboard angeschlossen an einen Fahrzeug-CAN (ja das ist so richtig, gewollt und erlaubt). Mein eigentliches Problem besteht beim Empfangen von Can-Telegrammen. Meine Routinen funktionieren alle hervorragend, bis zu einem bestimmten Zeitpunkt, an dem eine bestimmte Menge an Nachrichten eingegaben ist. In meiner ISR stecke ich die Nachricht in einen FiFo und re-aktiviere anschließend das ensprechende Mob um erneut Daten empfangen zu können. Curioser weise wird nach einer Weile das Mob nicht wieder aktiviert. Das passiert reproduzierbar, aber nach unterschiedlich vielen Nachrichten (meist so nach 1000 bis 100000 Nachrichten). Ich habe 5 Mob mit je einer ID als für den Empfang konfiguriert. (Filter sind jeweils so gesetzt, dass wirklich nur diese 5 Ids empfangen werden) Fällt euch vielleicht was ein, wo ich noch suchen könnte? Der Fakt, das die Kommunikation am Anfang geht, zeigt mit, dass meien Funktionen richtig sind. Im übrigen wird auch parallel noch gesendet, dies wird nie beeinträchtig - der chip stürzt also nicht ab. Was könnte dazu führen, dass das Mob nicht mehr aktiviert wird? vielen dank schonmal..
Mit viel Pech ist das ein Nebeneffekt eines anderen Problems z.B. einem Stack Overflow, der dann irgendeine Variable zerschießt, die in der Funktion zur Reaktivierung des MOBs benutzt wird. Allerdings wird Dir kaum jemand helfen können, ohne den Code vor sich zu haben. Evtl. ist irgendwo auch ein Denkfehler drin. Wir haben hier zwei Baugruppen auf Basis der AVR CAN Controller und die haben noch nie Probleme gemacht. Deshalb glaube ich nicht an einen Hardwarefehler.
Daniel wrote: > Curioser weise wird nach einer Weile das Mob nicht wieder aktiviert. Das > passiert reproduzierbar, aber nach unterschiedlich vielen Nachrichten > (meist so nach 1000 bis 100000 Nachrichten). Das könnte ein Atomic-Problem sein. Du hast den Interrupt und eine Main-Funktion, die beide auf die CAN-Register zugreifen. Dann müssen Read-Modify-Write und 16Bit-Zugriffe atomar gemacht werden. Und auch die Zugriffe auf die FIFO. Ich denke mal, das Enable-Bit ist auch lesbar. Dann lies einfach mal nach dem Setzen zurück, ob es gesetzt ist und wenn nicht, setze es nochmal. Wenn das dann funktioniert, mußt Du ergründen, warum das erste Setzen manchmal nicht geklappt hat. Atomic-Probleme werden oftmals nicht verstanden und werden definitv nicht durch das Betriebssystem abgefangen. In größeren Systemen werden dann festgefressene Tasks durch Timeouts wieder reaktiviert, anstatt die Ursache zu suchen. Peter
hallo, schon mal danke für die tips..doch leider lösen sie das problem noch nicht: ich überprüfe jetzt in der ISR nach dem ich das mob rekonfiguriert habe, ob das Bit wirklich gesetzt ist. Das ist es immer. Trotzdem bricht der Empfang irgendwann ab. Außerdem habe ich die FIFO Funktionen atomar gemacht (also SREG gepuffert, dann cli, dann SREG zurück) Beides brachte es jedoch noch nicht. Auch eine Deaktivierung des ID-Filters brachte keine abhilfe. Ich hatte ein Mob so konfiguriert, dass es alle Nachrichten empfängt. Auch dieses Mob wird nach einiger Zeit mysteriöser Weise "abgeschaltet". Des Weiteren habe ich ein zweites, identisches Board ausprobiert: kein Unterschied. Daher kann ich eigentlich einen Hardwarefehler ausschließen. Außer es ist ein Bug im Chip selbst. Wenn ich, nach dem so ein Mob nicht mehr funktioniert, per Knopfdruck ein weiteres registriere, läuft der Empfang wieder weiter, bis auch dieses irgendwann nicht mehr tut. Selbst wenn ich ganz viele Mobs für den Empfang auf allen Ids konfigurier, kommt der Empfang irgendwann zum erligen. Es dauert halt nur länger (wobei dies länger dauert, als wenn ich die gleiche Anzahl Mobs einzeln "verheize") Mir kam grad der Begriff "zugespamt" in den Sinn... kann es sein, dass da irgendein Stack überläuft oder so?...Wobei der Controller an sich ja normal weiterläuft. Wo könnte ich noch suchen? Was könnte ich noch überprüfen um den Fehler weiter einzugrenzen? Ich hätte auch ein JTAG zur Verfügung. CODE:
1 | //can.c
|
2 | |
3 | ISR( CANIT_vect ){ |
4 | //captures all events, including reception and transmission complete
|
5 | |
6 | //determine what has happened
|
7 | //first step: determine which m0b has caused an interrupt
|
8 | uint8_t mObNumber = 0; |
9 | |
10 | mObNumber = CANHPMOB >>4; |
11 | |
12 | CANPAGE = (mObNumber<<4); //select message object which caused the interrupt |
13 | |
14 | //second step: determine what event has occurred (rx or tx);
|
15 | if(CANSTMOB & (1<<RXOK)){ //reception OK interrupt |
16 | //if there was a message received
|
17 | //clear receive interrupt flag
|
18 | CANSTMOB &= ~(1<<RXOK); |
19 | setLedsToggled(1<<LED7); |
20 | |
21 | MessageObject message; |
22 | uint8_t i; |
23 | |
24 | for(i = 0; i<8; i++){ //get the data |
25 | message.messageData[i] = CANMSG; |
26 | }
|
27 | |
28 | message.messageID = 0; //get the id |
29 | message.messageID |= ((uint16_t) CANIDT1<<8); |
30 | message.messageID |= ((uint32_t) CANIDT2); |
31 | message.messageID >>= 5; |
32 | |
33 | |
34 | //put that message into the buffer; if buffer is full; message will be lost
|
35 | if (putMessageInBuffer(message,&canBufferRec)){ |
36 | setLedsOn(1<<LED6); //geht nie an, es gibt nie einen buffer-overflow |
37 | }
|
38 | |
39 | CANCDMOB = (1<<CONMOB1); //reconfigure mailbox for reception, standard ids |
40 | |
41 | while(!(CANCDMOB & (1<<CONMOB1))){ |
42 | setLedsToggled(LED5); //geht auch nie an, d.h conmob1 wird immer gesetzt |
43 | CANCDMOB = (1<<CONMOB1); |
44 | }
|
45 | |
46 | }
|
47 | else if(CANSTMOB & (1<<TXOK)){ //transmission ok interrupt |
48 | CANSTMOB &= ~(1<<TXOK); //reset flag |
49 | }
|
50 | else{ //something else, most likely an error |
51 | |
52 | }
|
53 | //}
|
54 | }
|
55 | |
56 | CanBuffer canBufferRec = {{}, 0, 0}; |
57 | |
58 | uint8_t putMessageInBuffer(MessageObject mIn, CanBuffer *b) |
59 | {
|
60 | uint8_t sregTemp = SREG; |
61 | cli(); |
62 | |
63 | uint8_t next = ((b->write + 1) & CAN_BUFFER_MASK); |
64 | if (b->read == next){ |
65 | SREG = sregTemp; |
66 | return 1; //buffer is full |
67 | }
|
68 | b->data[b->write] = mIn; |
69 | // *b.data[*b.write & BUFFER_MASK] = byte; // absolutely secure
|
70 | b->write = next; |
71 | |
72 | SREG = sregTemp; |
73 | return 0; |
74 | }
|
75 | uint8_t getMessageFromBuffer(MessageObject *mOut, CanBuffer *b) |
76 | {
|
77 | uint8_t sregTemp = SREG; |
78 | cli(); |
79 | if (b->read == b->write){ |
80 | SREG = sregTemp; |
81 | return 1; //buffer is empty |
82 | }
|
83 | *mOut = b->data[b->read]; |
84 | b->read = (b->read+1) & CAN_BUFFER_MASK; |
85 | SREG = sregTemp; |
86 | return 0; |
87 | }
|
88 | |
89 | uint8_t getAMessage(MessageObject *mOut){ |
90 | uint8_t sregTemp = SREG; |
91 | cli(); |
92 | return getMessageFromBuffer(mOut, &canBufferRec); |
93 | SREG = sregTemp; |
94 | }
|
95 | |
96 | |
97 | //in der can.h
|
98 | typedef struct { |
99 | uint16_t messageID; |
100 | uint8_t messageData[8]; |
101 | //uint8_t extendedId; //0 standardID, 1 extended
|
102 | //for now, always use standard IDs
|
103 | }MessageObject; |
104 | |
105 | typedef struct { |
106 | MessageObject data[CAN_BUFFER_SIZE]; |
107 | uint8_t read; // point to the index with oldest data |
108 | uint8_t write; // points to empty index |
109 | } CanBuffer; |
110 | |
111 | |
112 | //in der Main.c
|
113 | |
114 | int main(void){ |
115 | while(1){ |
116 | |
117 | if(!getAMessage(&m)){ //if there is an new Message available |
118 | |
119 | canData data; |
120 | //data.e = m.messageData;
|
121 | uint8_t i = 0; |
122 | for(i = 0; i<8; i++){ |
123 | data.e[i] = m.messageData[i]; |
124 | }
|
125 | |
126 | //in dem switch wird dann auch noch ein bisschen gerechnet;
|
127 | //die leds flackern eine Weile, bis eben das Mob nicht mehr arbeitet.
|
128 | |
129 | switch (m.messageID) { |
130 | case 0x792:{//ACC_T01 |
131 | setLedsToggled(1<<LED0); |
132 | break;} |
133 | case 0x793:{//ACC_T02 |
134 | setLedsToggled(1<<LED1); |
135 | break;} |
136 | case 0x6B5:{//RADAR_INFO1 |
137 | setLedsToggled(1<<LED2); |
138 | break;} |
139 | case 0x130:{//CLU_1 |
140 | |
141 | setLedsToggled(1<<LED3); |
142 | break;} |
143 | |
144 | case 0x131:{//CLU_2 |
145 | setLedsToggled(1<<LED4); |
146 | break;} |
147 | default:
|
148 | break; |
149 | }
|
150 | }
|
151 | |
152 | }
|
153 | }
|
Falls ihr noch in die Init-Funktion oder Mob-Registrierung gucken wollt, kann ich die natürlich auch noch posten. Ich weiß, dass das ein ziemlich langer Beitrag ist und bedanke mich schonmal fürs lesen. Ich hoffe auch neuen Input, Daniel
also ich hab noch was rausgefunden: wenn ich mir das Can Enable Mob Register (CANEN1/2) anschaue, sehe ich, dass wenn der Empfang zusammenbricht, auch das Mob nicht mehr verwendet wird. Es scheint also darauf hinaus zu laufen, dass ich irgendwo einen Interrupt verpasse, in dem ich das Mob wieder aktiviere müsste. Ist es denn möglich, dass Interrupts auflaufen und nicht abgearbeitet werde? Eigentlich ist es doch so, dass wenn ein Interrupt auftritt, wärend ein anderer gerade verarbeitet wird, wird dieser trotzem im Anschluss auch abgearbeitet. Sollten mehr als einer auftreten, wir nur einer ausgeführt und ich verpasse ein paar Can-Nachrichten (was mir aber egal ist).. Jedenfalls, wenn ich nebenbei nichts mehr sende (normaler Weise sende ich alle 20ms drei Nachriten) scheint es zu keinem Fehler zu kommen (das Ganze lief so, wie es sollte ein paar Minuten lang). Das nützt mir allerdings nichts, da ich die empfangenen Daten ja verarbeiten und wieder raus schicken muss. habt ihr noch ne Idee?
ohne den ganzen Code gelesen zu haben: Du achtest darauf dass die Register für fehlerhafte Sendungen nicht überlaufen? Du achtest darauf, nicht nur die Register neu zu initialisieren, sondern auch die Datenregister auf 0 zu setzen? Der at90Can128 ist mit bis zu 16 Mhz zu takten, wenn ich nicht irre. Reicht die Zeit um Empfang und Sendung abzuarbeiten? Nicht alles, was an Übertragungsraten machbar ist funktioniert dann auch. Die Tatsache dass Du die Interrupts abschaltest heisst nicht, dass nicht synchron Daten ankommen, es heisst nur dass sie keinen Interrupt mehr auslösen. Ankommen und die Box belegen tun sie trotzdem. Die Methode den Interrupt abzuwarten, dann im Reg den letzten Eintrag zu suchen und abzuholen ist bei CAN etwas unpraktisch, weil in der gleichen Zeit neue Nachrichten eingegangen sein können. Besser ist es die alle Nachrichtenregister bei Interrupt auf neue Daten abzufragen.
Hab deinen Code nur kurz überflogen, aber mal so als Fragestellung, was machst du, wenn zwei Message-Objekte gleichzeitig eintreffen? Gibt es für jeden ein RX-Flag? Ich denke fast nicht, kenne allerdings diesen Baustein nicht so. Vielleicht solltest du dir auch überlegen, evtl. auf Polling beim Empfang umzusteigen, wenn dir, wie du oben sagst, es egal ist, wenn du mal eine Nachricht nicht mitbekommst.
ich hab als Work-Around jetzt erstmal die TX-Interrupts abgestellt, die ich eh nur genutz hatte um das tx-ok flag zurück zusetzten, es geht auch ohne; so läuft es vorerst stabil; danke für eure Hilfe
Hallo Daniel, ich habe das gleiche Problem wie du: nach einer gewissen Zeit scheint der CAN-Controller einfach nichts mehr empfangen zu wollen. Ein Ausstellen des TX-Interrupts hat bei mir allerdings auch nicht geholfen. Hast du inzwischen eine Erklärung für das Problem gefunden? Viele Grüße, Holger
Hallo Ich hatte vor einiger Zeit auch ein ähnliches Problem. Der AT90Can hat nach einer gewissen Zeit einfach keine Nachrichten mehr empfangen. Ich hab mir das so erklärt: Die Telegramme werden in der Reihenfolge, in der sie aktiviert werden, den MObs zugeordnet. Dadurch wird auch die Priorität festgelegt, mit der sie abgearbeitet werden. Mobs mit den niedrigsten Nummern haben die höchste Priorität. Wenn ein zu empfangenes Telegramm direkt nach einem aktiviert wird, das zu senden ist, dann gibt es bei dem zu empfangenem Telegramm Probleme. Das Senden ist noch nicht abgeschlossen, wenn der Empfang aktiviert wird. Nach Abschluss des Sendens gibt es ein leeres MOb vor dem empfangenden MOb. Ist ein leeres MOb vor einem Telegramm, das empfangen werden soll, dann wird das Telegramm vom Controller empfangen und quittiert, aber nicht dem richtigem MOb zugeordnet. Somit können die empfangenen Daten nicht ausgewertet werden. Um das Problem zu lösen habe ich alleMObs, in denen Telegramme empfangen werden direkt nach dem Initialisieren des CAN-Controllers aktiviert. Erst danach werden Telegramme versendet. Wenn ein Telegramm empfangen wurde, muss das zugehörige MOb sofort wieder den Empfang aktivieren, bevor ein Telegramm versendet werden kann. Diese Lösung funktionierte dann Fehlerfrei. Danach habe ich das Thema nicht weiter verfolgt. Mfg Christian
Hallo Christian, danke erst einmal für die schnelle Antwort. Ein paar Worte zu meinem CAN-Stack: Ich verwende lediglich 2 MObs: MOb0 dient als Empfänger (der Filter lässt alle Nachrichten durch, die Filterung erfolgt per Software) und MOb1 dient als Sender. Empfangen wird per Interrupt. Beim Senden wird das MOb1 zunächst deaktiviert, dann neu eingerichtet und anschließend wieder aktiviert um zu Senden. Um auf deine Lösung einzugehen: Die Aktivierung des einen Empfangs-MObs erfolgt einmalig zu Beginn. Alle Sendungen werden erst anschließend ausgeführt. Leider habe ich trotzdem das Problem des "sterbenden Empfängers". Grüße, Holger
Hallo zusammen, ich glaube, ich habe eine Lösung gefunden. Im Errata des Datasheets findet sich unter Rev C ein Eintrag, der das Problem zwar nicht 100% trifft, aber dessen Work-around zu funktionieren scheint: Ich habe das MOb 14 als "Dummy-Empfänger" eingestellt. Es lässt also auch alle eigehenden Nachrichten durch. Durch die interne Priorisierung bekommt es nur eine Botschaft, wenn kein anderes Empfangsregsiter momentan bereit ist. In meinem Fall heißt dass: mein einziger Empfänger MOb0 ist momentan nicht bereit. Der Nachteil: ich verliere (zumindest ist der Minimal-Implementierung aus dem Datenblatt) hin und wieder eine Botschaft. Das ist bei meiner speziellen Anwendung allerdings egal! Die neue Konfiguration lief jetzt über nacht (ca. 16 Stunden) problemlos durch. Ich hoffe das hilft dem Einen oder Anderen! Grüße, Holger
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.