Moin,
ich habe hier ein kleines, selbstgebautes Testboard mit einem
ATMEGA16m1. Ich möchte mit dem vorhandenen CAN-Controller Nachrichten
versenden und auch empfangen. Zum Teil funktioniert das auch schon:
Ich kann Nachrichten in Form von MessageObjects erstellen und versenden.
Die kommen bei meiner Gegenstation auch an (PEAK CAN/USB-Adapter). Der
ATMEGA16m1 empfängt auch Nachrichten meiner Gegenstation und tütet diese
korrekt in die MessageObjects ein. Die Nachrichten kann ich dann auch
aus dem MOb herausholen, allerdings muss ich dazu das RXOK-Bit des
CAN-Controllers anpollen. Das möchte ich nicht machen, ich will den
Controller hiermit nicht blockieren.
Ich habe es bisher jedoch nicht geschafft, beim erfolgreichen Empfang
einer Nachricht einen Interrupt auszulösen. Ich verstehe nicht warum,
denn meiner Meinung nach habe ich alles getan, was dazu notwendig wäre.
Meinem Verständnis nach muss ich die Interrupts in den Registern CANIE2
und CANIE1 für die MOb's aktivieren und zusätzlich noch die
CAN-Interrupts generell aktivieren. Hierzu habe ich im CANGIE das ENIT
und ENRX (für den Empfangsinterrupt) gesetzt.
Es passiert leider absolut gar nichts. Für den Anfang will ich mit dem
Interrupt einfach nur mal einen globalen Boolean toggeln, mit dem ich
dann eine simple LED einschalte. Es tut sich aber nichts. Über Polling
funktioniert das Ganze, daher vermute ich mal, dass ich meinen Interrupt
nicht richtig eingestellt habe (der Polling-Code ist auskommentiert).
Vielleicht hat ja jemand eine gute Idee und kann mir helfen.
Gruß
Nils
Der kleine Nils schrieb:> CANEN2 = 0x00;> CANEN2 = 0x3F; // Alle MObs aktivieren> CANIE1 = 0x3F; // Alle MOb Interrupts aktivieren>> CANGIE = (1<<ENIT) | (1<<ENRX); // Interrupts aktivieren>> CANPAGE = (1<<MOBNB0); // MOb0 auswählen>>> CANGCON = (1<<ENASTB); // CAN-Controller aktivieren> CANSTMOB = 0x00; // Statusregister zurücksetzen> CANCDMOB = (1<<CONMOB1) | (8<<DLC0); // CONMOB1 und DLC0 setzen, rest> auf 0
Das macht so noch wenig Sinn.
Warum werden alle MOBs ohne jede Konfiguration aktiviert?
Vor allem vor der Konfiguration?
"8<<DLC0" funktioniert so auch nicht.
Schau mal hier: Beitrag "CAN beim ATMega16M1 anders als bei 90CANxx?"
Da ist ein funktionierendes Init drin für den Versand einer Botschaft.
Mal eben auf Empfang angepasst:
1
...
2
id = 0x444; // Sende-ID
3
CANPAGE = (0<<4); // select MOB0
4
CANIDT1 = (id >> 3); // Put bits 3-11 of message ID into CANIDT1
5
CANIDT2 = (id << 5); // Put bits 0-2 of message ID into CANIDT2
6
CANIDM1 = 0xff;
7
CANIDM2 = 0xe0;
8
CANIDM4 = (1<<IDEMSK);
9
CANCDMOB = (1<<CONMOB1) | (1<<DLC3); // set to receive, 8-bytes in message
Hallo Rudolph,
vielen Dank für die Antwort.
Rudolph schrieb:> "8<<DLC0" funktioniert so auch nicht.
Da hat sich eine 8 verirrt, das sollte (1 werden. Aber das DLC brauche
ich für's empfangen nicht, daher habe ich es entfernt.
Rudolph schrieb:> Schau mal hier: Beitrag "CAN beim ATMega16M1 anders als bei 90CANxx?">> Da ist ein funktionierendes Init drin für den Versand einer Botschaft.
Ja, das habe ich auch bereits gefunden. Der Versand funktioniert ja auch
tadellos. Auch der Empfang. Aber der Interrupt nicht.
Trotzdem habe ich meinen Code mal abgeändert. Obwohl ich es eigentlich
nicht will eine ID festgelegt - Ich möchte später auf erstmal generell
jede CAN-Nachricht ansprechen. Aber das ist erstmal nebensächlich.
Allerdings leider wie gehabt: Beim Pollen des RXOK klappts, der
Interrupt wird nicht ausgelöst...
Ich habe das mal als Gelegenheit genutzt und Senden implementiert.
Wenn die Botschaft mit der ID 0x333 empfangen wird antwortet der
Controller mit der Botschaft 0x444.
Das filtern macht doch:
CANIDM1 = 0xff;
CANIDM2 = 0xe0;
CANIDM4 = (1<<IDEMSK);
Auf MOB1 alles empfangen müsste so aussehen:
CANPAGE = (1<<4); // select MOB1
CANCDMOB = (1<<CONMOB1); // set to receive
Natürlich davon ausgehend, dass in der Schleife drüber alle Register
genullt wurden. :-)
Das DLC ist fürs Empfangen fester IDs schon interessant, wenn die Größe
nämlich von der eingestellten abweicht, erhält man eine
Data-Length-Code-Warning im CANSTMOB Register.
Ein paar Sachen, die ich an deinem Quellcode nicht verstehe:
Warum wird das MOb1 nicht aktiviert, der Interrupt dafür aber
freigegeben?
Nunja, seisdrum. Ich habe meine Initialisierungsroutine mal angepasst,
so dass die Reihenfolge, in der die Register gesetzt werden deiner
entspricht. Jetzt funktioniert der Interrupt - Vielen Dank schon einmal
an dieser Stelle.
Mir ist noch nicht ganz klar, warum offenbar genau diese Reihenfolge
eingehalten werden muss. Im Datenblatt zum µC habe ich auch nichts dazu
gefunden. Komisch.
Anbei noch mal mein Code für Interessierte
Der kleine Nils schrieb:> Warum wird das MOb1 nicht aktiviert, der Interrupt dafür aber> freigegeben?
Das hatte ich übersehen.
Das funktioniert dennoch weil CANEN1 und CANEN2 garnicht die MOBs
aktivieren, das sind Read-Only Register.
Die beiden Zeilen wirken sich also garnicht aus und können gelöscht
werden.
Irgendwie habe ich das verpeilt als ich um 2006 den Code für den 90CAN
geschrieben habe.
Und da das so funktioniert, war es seitdem eben weitgehend Copy&Paste
für den Teil. :-)
Manmachmal sollte man vielleicht auch funktionierenden Code nochmal mit
einem Blicks ins Datenblatt reviewen. :-)