Forum: Mikrocontroller und Digitale Elektronik CAN im AVR32 (Konfiguration der Register)


von Felix D. (skyfox) Benutzerseite


Lesenswert?

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

: Bearbeitet durch User
von Felix D. (skyfox) Benutzerseite


Lesenswert?

Hallo noch Mal.

Ich glaube, ich habe mittlerweile eine Lösung für mein Problem. 
Vielleicht hilft es nur, bis ich mit dem CAN tatsächlich unter Last 
arbeiten will, aber für meinen Test reicht es.

Ein Delay in der receive() Methode von 10ms hat geholfen. (Bei weiteren 
Problemen erde ich erst Mal daran schrauben.)
1
    ...
2
    while(!(&mChannelAddr->MOBSR+(RX_MOB*OFFSET))->rxok) {};
3
    delay_us(10000)
4
    ...
5
     }

Bei 16 MHz habe ich delay_us() mit dem COUNT Register (COUNT/16) in us 
implementiert.

Vielleicht hilft's ja jemandem weiter.

Schönan Gruß

Skyfox

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.