Forum: Mikrocontroller und Digitale Elektronik curioses CAN problem (at90can128)


von Daniel (Gast)


Lesenswert?

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..

von Matthias (Gast)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?

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

von Daniel (Gast)


Lesenswert?

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

von Daniel (Gast)


Lesenswert?

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?

von tex (Gast)


Lesenswert?

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.

von Michael S. (schmichael)


Lesenswert?

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.

von Daniel (Gast)


Lesenswert?

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

von Holger (Gast)


Lesenswert?

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

von Christian (Gast)


Lesenswert?

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

von Holger (Gast)


Lesenswert?

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

von Holger (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.