Hallo zusammen.
Ich habe ein kleines Problem mit dem CAN-Interface des AT32CU3C1512.
Erst einmal gehe ich davon aus, dass ich dieses Problem bin und nicht
der AVR :-)
Kurz zur Hardware IST-Situation:
Es handelt sich um eine selbst entwickelte Platine mit AVR32
(AT32UC3C1512) die auch die CAN-Schnittstellen des Prozessors nach außen
führt.
Ich setze einen USB-CAN Adpter von PEAK ein und kommuniziere, unter
Linux Ubuntu 14.04, mit dem canplayer (can-utils) mit dem Prozessor.
Rudimentär funktioniert das auch, allerdings "verschluckt" der AVR
Nachrichten.
Meine Testapplikation auf dem AVR soll folgendes tun:
Eine empfangene Nachricht in ein Senderegister kopieren und dann zurück
senden.
Mit dem canplayer schicke ich zwei Nachrichten im Abstand von einer
Sekunde und diese kommen auch wieder zurück. Schicke ich das ganze noch
Mal, kommt die Nachricht, die davor gesendet wurde, zurück. Die zweite
Nachricht kommt dann original zurück. Um das zu beobachten hänge ich mit
wireshark auf der CAN Schnittstelle. Zusätzlich habe ich einen
Logic-Analyzer mit CAN-Interpreter an CAN-TX/RX welcher mir die Ausgaben
des wireshark bestätigt.
hier noch ein paar Auszüge aus dem Quelltext. Das Ganze ist auch
Bestandteil einer eigenen Framework Entwicklung, weswegen der Code hier
etwas anders aussieht als üblich. Wenn noch jemand weitere Informationen
oder Auszüge benötigt, bitte einfach melden.
Das CANIF des Controllers wird folgendermaßen initialisiert:
1 | #define TX_MOB 0
|
2 | #define RX_MOB 1
|
3 | #define OFFSET 0x3
|
Hier verwende ich die ersten beiden Nachrichten. Der Offset springt um
3*32 bit in den MOBCTRLn Registern. (Im Datenblatt sind es 12*8 bit
(0xC))
Hier die initialisierung der Register.
1 | bool CanTransceiverAvr32::open(unsigned long baudRate) {
|
2 | GpioEnableModulePin(mRxPin,mRxFunc);
|
3 | GpioEnableModulePin(mTxPin,mTxFunc);
|
4 |
|
5 | mChannelAddr->CANCTRL.init = 1; //Initialization of the CAN channels
|
6 | while(mChannelAddr->CANSR.ces == 1) {} ; //wait for disabling the channel
|
7 | mChannelAddr->CANCTRL.init = 0;
|
8 |
|
9 | //Configuration for 16MHz
|
10 | switch(baudRate) {
|
11 | case 125000:
|
12 | mChannelAddr->CANCFG.pres = 7;
|
13 | mChannelAddr->CANCFG.prs = 5;
|
14 | mChannelAddr->CANCFG.phs1 = 5;
|
15 | mChannelAddr->CANCFG.phs2 = 2;
|
16 | break;
|
17 |
|
18 | //Transmit
|
19 | (&mChannelAddr->MOBCTRL+(TX_MOB*OFFSET))->am = 1; //Automatic mode
|
20 | (&mChannelAddr->MOBCTRL+(TX_MOB*OFFSET))->dir = 1; //Transmission
|
21 | (&mChannelAddr->MOBCTRL+(TX_MOB*OFFSET))->dlc = 8; //Data length code
|
22 | mCanMessage[TX_MOB].msg.rtr = 0; // remote transmission request
|
23 |
|
24 |
|
25 | //Receive
|
26 | (&mChannelAddr->MOBCTRL+(RX_MOB*OFFSET))->am = 0; //Automatic mode 0
|
27 | (&mChannelAddr->MOBCTRL+(RX_MOB*OFFSET))->dir = 0; //Reception
|
28 | (&mChannelAddr->MOBCTRL+(RX_MOB*OFFSET))->dlc = 8; //Data length code
|
29 | mCanMessage[RX_MOB].msg.rtr = 0; // remote transmission request
|
30 |
|
31 | mChannelAddr->CANCFG.ovrm = 1; //Overrun mode disabled
|
32 | mChannelAddr->CANCFG.cmode = 0; //Operating mode = Normal mode
|
33 | mChannelAddr->CANCFG.sm = 1; //Sampling method
|
34 | mChannelAddr->CANCFG.sjw = 1; //Synchronization Jump Width
|
35 | mChannelAddr->CANCTRL.ovrq = 1; //Overload frame to provide extra delay between two messages
|
36 |
|
37 | mChannelAddr->canramb = (long unsigned int)mCanMessage;
|
38 | mChannelAddr->CANCTRL.cen = 1; //Channel enable
|
39 | // CANSR.ces bit is set after 11 consecutive recessive bits (BUS-idle) are detected on Bus.
|
40 | while(!mChannelAddr->CANSR.ces){}; //wait for channel enable status
|
41 | // Initialization done.
|
42 | mChannelAddr->CANISCR.lsmob = 0b111111;
|
43 | mChannelAddr->mober = 1<<RX_MOB; //Enable MOb1
|
44 | return true;
|
45 | }
|
Hier die receive()-Methode
1 | unsigned short CanTransceiverAvr32::receive(int *mode, uint32_t *id, uint8_t *canData,int *length) {
|
2 |
|
3 | mChannelAddr->mober = 1<<RX_MOB; //Enable MOb1
|
4 | if(mChannelAddr->CANSR.rs){
|
5 | while(!(&mChannelAddr->MOBSR+(RX_MOB*OFFSET))->rxok) {};
|
6 | *mode = mCanMessage[RX_MOB].msg.ide;
|
7 | *id = mCanMessage[RX_MOB].msg.id;
|
8 | *length = (&mChannelAddr->MOBCTRL+(RX_MOB*OFFSET))->dlc;
|
9 | canData[0] = mCanMessage[RX_MOB].msg.db0;
|
10 | canData[1] = mCanMessage[RX_MOB].msg.db1;
|
11 | canData[2] = mCanMessage[RX_MOB].msg.db2;
|
12 | canData[3] = mCanMessage[RX_MOB].msg.db3;
|
13 | canData[4] = mCanMessage[RX_MOB].msg.db4;
|
14 | canData[5] = mCanMessage[RX_MOB].msg.db5;
|
15 | canData[6] = mCanMessage[RX_MOB].msg.db6;
|
16 | canData[7] = mCanMessage[RX_MOB].msg.db7;
|
17 | *length = (&mChannelAddr->MOBCTRL+(RX_MOB*OFFSET))->dlc;
|
18 |
|
19 | (&mChannelAddr->MOBSCR+(RX_MOB*OFFSET))->rxok = 1;
|
20 | mCanMessage[RX_MOB].msg.rtr = 0;
|
21 | mChannelAddr->mober = 1<<RX_MOB; //enable MOb1
|
22 | return 1;
|
23 | }
|
24 | }
|
25 | return 0;
|
26 | }
|
Und hier die transmit()-Methode:
1 | bool CanTransceiverAvr32::transmit(int mode, uint32_t id, uint8_t *canData,int length) {
|
2 | mCanMessage[TX_MOB].raw.data0 = 0; //delete old data
|
3 | mCanMessage[TX_MOB].raw.data1 = 0;
|
4 | mCanMessage[TX_MOB].raw.idRaw = 0;
|
5 | (&mChannelAddr->MOBSCR+(TX_MOB*OFFSET))->txok = 1; // Reset TX_OK
|
6 | mChannelAddr->mober = 0<<TX_MOB; //disable MOb0
|
7 | (&mChannelAddr->MOBCTRL+(TX_MOB*OFFSET))->am = 0; // No automatic transmit
|
8 | (&mChannelAddr->MOBCTRL+(TX_MOB*OFFSET))->dir = 0; // No transmit
|
9 | mCanMessage[TX_MOB].msg.id = id;
|
10 | mCanMessage[TX_MOB].msg.ide = mode;
|
11 | mCanMessage[TX_MOB].msg.rtr = 1;
|
12 | mCanMessage[TX_MOB].msg.undef1 = 0;
|
13 | mCanMessage[TX_MOB].msg.db0 = canData[0];
|
14 | mCanMessage[TX_MOB].msg.db1 = canData[1];
|
15 | mCanMessage[TX_MOB].msg.db2 = canData[2];
|
16 | mCanMessage[TX_MOB].msg.db3 = canData[3];
|
17 | mCanMessage[TX_MOB].msg.db4 = canData[4];
|
18 | mCanMessage[TX_MOB].msg.db5 = canData[5];
|
19 | mCanMessage[TX_MOB].msg.db6 = canData[6];
|
20 | mCanMessage[TX_MOB].msg.db7 = canData[7];
|
21 |
|
22 | // Once data is written in MOb-Area use MOBCTRL to take control of message
|
23 | (&mChannelAddr->MOBCTRL+(TX_MOB*OFFSET))->dlc = length;
|
24 | (&mChannelAddr->MOBCTRL+(TX_MOB*OFFSET))->dir = 1; // Transmit
|
25 | mChannelAddr->mober = 1<<TX_MOB; //enable MOb0
|
26 | // MOb will be send if idle state is detected
|
27 | // (11 consecutive recessive bits)
|
28 | while(!mChannelAddr->CANSR.ts){}; //Transmission status
|
29 | if(!(&mChannelAddr->MOBSR+(TX_MOB*OFFSET))->txok) {
|
30 | return false;
|
31 | }
|
32 | else {
|
33 | (&mChannelAddr->MOBSCR+(TX_MOB*OFFSET))->txok = 1;
|
34 | } return true;
|
35 | }
|
Zum Schluß noch ein Auszug aus der main()
1 | void main() {
|
2 | ...
|
3 | // canTr is a pointer to a CAN-Transceiver from the framwork.
|
4 | CanTransceiver *canTr=can->GetTransceiver(0);
|
5 | canTr->open(125000);
|
6 | while(true){
|
7 | if(canTr->receive(&mode,&id,canData,&length)>0){
|
8 | canTr->transmit(mode,id+1,canData,length);
|
9 | }
|
10 | }
|
Interrupt getrieben ist das Ganze nicht! Da es sich um eine
Testapplikation handelt polle ich den Nachrichtenempfang.
Ich empfange eine Nachricht in dem ich das RS-Register (reception state)
abfrage. Ist es gesetzt polle ich auf RXOK (Es sind kein Flags im
MASK-Register gesetzt), dann hole ich mir die Daten aus dem RAM,
schreibe sie in das TX-MOb mit einer um eins erhöhten ID um die
Nachrichten unterscheiden zu können und setze den entsprechenden
TX-ENABLE zu senden. Wie gesagt, das Ganze funktioniert das erste Mal,
wenn ich den canplayer erneut dieselben Daten senden lasse geht die
erste Nachricht korrekt über den Bus, aber die letzte vom ersten
Durchlauf kommt wieder zurück.
Ich hoffe es ist klar geworden, was für ein Problem ich habe. Ich
versuche in den nächsten Tagen noch einen Screenshot vom wireshark an zu
hängen.
Okay, ich habe gerade festgestellt, dass in diesem Beitrag noch nicht
ein einziges Fragezeichen steht :-)
Hat jemand von Euch vielleicht eine Idee was ich bei der Initialisierung
vergessen habe oder was am Konzept des Nachrichtenempfangs falsch ist?
Evtl. irgendwas zu schnell? Delays sind nicht drin.
Danke im Vorraus
Skyfox