Moin
ich habe vor an einen CAN-Bus mehrere AT90CAN128 zu hängen. Als CAN
Software benutze ich den aktuellen Treiber von Atmel. Empfangen werden
die Daten über eine SIG_CAN Interruptroutine.
CAN 1: sendet 100 CAN Nachrichten
CAN 2: empfängt und gibt die Bytes über den UART aus
CAN 3: empfängt maskiert (wertet also keine Nachricht aus)
So, jetzt das Problem:
Wenn CAN 1 100 Nachrichten schnell hintereinander sendet (CMD_TX_DATA)
empfängt CAN 2 (CMD_RX) nur jede 12. Nachricht.
Kann ich irgendein Bit setzen oder irgendein Nachrichtentyp verwenden,
damit der Sender mitbekommt, dass die Daten von CAN 2 nicht richtig
empfangen wurden. Und er die Daten nochmal sendet.
Hier nachmal die wichtigsten Passagen vom Code. Der Rest ist der
Standard von Atmel.
unsigned char can_get_MOB_int(void)
{
unsigned char i;
for(i=0;i < 8; i++) // MOB 0 - 7 durchsuchen
{
if(!CHECKBIT(CANEN2,i)) return (i); // Falls Daten enthalten sind, die
Nummer zurück geben
}
for(i=8;i < 15; i++) // MOB 8 - 9 durchsuchen
{
if(!CHECKBIT(CANEN1,(i-8))) return (i); // Falls Daten enthalten sind,
die Nummer zurück geben
}
return (0xFF); // 0xFF zurückgeben, wenn nichts gefunden wurde
}
SIGNAL (SIG_CAN_INTERRUPT1)
{
unsigned char temp;
unsigned char buffer[8];
unsigned long int u32_temp;
st_cmd_t msg; // Strukur für die CAN Message
msg.pt_data = &buffer[0];
msg.handle=can_get_MOB_int();//MOB finden
can_get_status(&msg); //Daten werden ausgelesen
Can_get_ext_id(u32_temp)
printf("%u %i=> %i,%i,%i,%i,%i,%i,%i,%u\n",(unsigned int)
u32_temp,msg.handle,buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],bu
ffer[5],buffer[6],buffer[7]);
SETBIT(CANCDMOB,7); //MOB wieder für den empfang freigeben
temp=CANSTMOB; //im CAN Status Register den Receive Interrupt
löschen
CLEARBIT(temp,RXOK);
CANSTMOB=temp;
}
Danke im Voraus
Tobi
Hallo Tobi
der Grund dafür, dass Du nur jede 12.te Nachricht empfängst, dürfte der
Aufruf von printf im CAN Interrupt sein, welche den Interrupt ziemlich
lange blockiert.
Gruss
Philipp
printf("%u %i=> %i,%i,%i,%i,%i,%i,%i,%u\n",(unsigned int)
u32_temp,msg.handle,buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],bu
ffer[5],buffer[6],buffer[7]);
So ein printf-Monster im Interrupt - das ist wirklich mutig.
1. Im CAN-IR die Daten in ein Fifo schreiben
2. in main das Fifo leeren und auf den UART ausgeben
3. Das Fifo gross genug machen
4. die msg-Daten in main in einen String wandeln
5. den String per IR ausgeben
6. währenddessen einen 2.String von main vorbereiten lassen
bdw.:
wie schnell ist Dein CAN?
wie schnell ist Dein UART?
wie schnell ist Dein ATmega?
Gruß, Stefan
Danke für die schnellen Antworten
Mein CAN läuft mit 100kHz
UART 9600
AT90CAN128 16MHz
Ich weiß, dass die printf Ausgabe den ganzen Controller ausbremst. Es
soll auch in erster Linie zur Kontrolle sein und später auch
rausfliegen. Aber trotzdem kann es sein, dass der Controller in
irgendeiner Form beschäftigt ist und er Nachrichten vom CAN nicht
mitbekommt.
Ich dachte, dass der CAN-Bus das vielleicht alles selber regeln kann.
Also, wenn irgendeine Nachricht nicht "richtig" empfangen wurde er diese
einfach nochmal schickt.
Ich habe jetzt den CAN-Controller nach der ISR disabled, die Daten
ausgewertet und dann wieder enabled. Das funktioniert auch alles
wunderbar, wenn es nur einen Sender und einen Empfänger gibt. Der Sender
schickt die Nachrichten, bis diese empfangen werden. Es kommen also alle
Daten an.
Wenn jetzt der 2. Empfänger dran ist, empfängt er hat eben die Daten
solange der 1. Empfänger die Daten auswertet. Und so bekommt der 1.
Empfänger auch nicht alle Nachrichten mit.
Tobi
>Mein CAN läuft mit 100kHz>UART 9600
wie soll das gehen?
Dein String ist ca. 45 Byte = 450 Bit lang. Braucht bei 9600Baud ca.
50ms. In der Zeit kann der CAN 39 komplette msgs verschicken!
>Also, wenn irgendeine Nachricht nicht "richtig" empfangen wurde er diese>einfach nochmal schickt.
Den CAN schert es nicht, ob ein anderer Busteilnehmer mit de empfangenen
Datenmengen Probleme hat (das ist auch ganz gut so, sonst könnte ein
lahmer Busteilnehmer den kompletten Bus lahmlegen).
Ausnahme:
Wenn es nur einen empfangenden Busteilnehmer gibt und dieser sendet kein
ACK auf die msg, dann wiederholt der Sender die msg ständig.
Das ist der Grund, warum Dir keine Daten verlorengehen, wenn nur 1 Tln
am Bus hängt und dessen CAN disabled wird - der Sender wiederholt die
Daten solange, bis der Empfänger wieder enabled wird. Dies ist aber ein
Sonderfall am Bus, auf den Du nicht bauen kannst.
1. Warum 100khz?
Lass den CAN nur so schnell laufen, wie Dein Programm auch arbeiten
kann.
2. Warum nur 9600 Baud?
115kbaud sind eigendlich kein Problem. Aber beachte: auch das wird
Dir
einen kontinuierlichen Datenempfang nicht sicherstellen, weil aus
128 Bit auf dem CAN ca. 450 Bit auf der RS232 werden, weil Du die
Binärdaten vom AVR in ASCII-Daten umwandelst.
3. printf aus der IR raus und ein Fifo einbauen!
Gruß, Stefan
Danke
dass der UART rausfliegt ist keine Frage.
Und wenn ich das richtig verstanden habe, muss ich ich selber dafür
sorgen, dass der CAN-Bus immer empfangstbereit ist. Werde jetzt mal ein
FIFO programmieren.
Gruß
Tobi
Du mußt mehrere MOBs zu einem Puffer zusammenfügen, damit Du einen
auswerten kannst, während der andere schon reinkommt.
Aber Achtung, dabei kann sich die Paketreihenfolge vertauschen !
Meistens wird aber ein ganz einfaches Protokoll verwendet:
Von jedem Pakettyp (Identifier) wird nur ein Paket gesendet und dann auf
eine Antwort (Bestätigung) gewartet, ehe das nächste gesendet wird
(Ping-Pong-Prinzip).
Peter
Das alles habe ich bisher mit einem aktiven MOB getestet, wenn ich mehr
MOBs aktiviere erhalte ich natürlich mehr Nachrichten. Das ist klar. Ich
wollte jetzt erstmal prinzipell das geklärt haben.
Dieses Pin-Pong-Prinzip habe ich mir auch schon überlegt, ist aber
natürlich mit mehr Software verbunden.
Kann das vielleicht der CAN-Bus übernehmen?
Auf Seite 243/244 steht etwas von Automatic Reply. Aber wenn ich das
richtig verstehe antwortet ein Teilnehmer mit einem Daten-Frame auf ein
Remote-Frame.
Was ich suche ist eine automatische Bestätigung auf ein Daten-Frame.
Gruß
Tobi