www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik CAN-Bus: Tx-Rx-Problem (AT90CAN128)


Autor: Xine L. (xine)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi zusammen,

ich bin so langsam mit meinem Latein am Ende, wobei mein Problem 
folgendes ist:

Ich habe 2 Boards mit je einem AT90CAN128, wovon einer Sender, der 
andere Empfänger ist. Anfangs möchte ich über CAN ein einfaches 
Datenbyte senden, welches empfangen und angezeigt wird. (Später, wenn 
alles funktioniert, schicke ich mehrere Bytes). Das Ganze geschieht bei 
100 kbit/s. Mein benutzter C-Compiler ist CodeVision. Für Sender und 
Empfänger arbeite ich je mit einem Message Object (MOb), und zwar MOb2. 
Die Mask-Register für den Empfänger sind so geschaltet, dass sie alle 
Identifier durchlassen.

Auf der Sendeseite überprüfe ich in 1. Linie, ob das TXOK-flag gesetzt 
wird. Da dies jedoch nicht passiert ist, habe ich auch auf andere Flags 
getestet und sehe nun, dass auf der Sendeseite BERR (bit errors) 
auftreten und letztendlich ein BOFF-flag (bus off) gesetzt wird. 
Letzteres macht ja auch Sinn, da CAN immer wieder erneut versucht zu 
senden, bis der Fehlercounter so hoch ist, dass der Teilnehmer 
abschaltet wird.

Auf beiden Seiten habe ich einen nahezu identischen Code. Natürlich 
überprüfe ich für den Sender das TXOK-flag und für den Empfänger das 
RXOK-flag. Entsprechende Interrupt-enable-Bits habe ich jeweils im 
CANGIE-Register gesetzt.

Das Sendeprogramm geht in die Interrupt-Service-Routine (schließlich 
werden die Flags BERR und BOFF gesetzt). Das Empfangsprogramm erreicht 
seine ISR jedoch nie (was ich komisch finde, denn die Programme sind 
gleich aufgebaut, zumindest müsste irgendein Fehler-Interrupt ausgelöst 
werden meiner Meinung nach...).

Ich habe meinen Empfangscode hier im Anschluss mal gepostet. Der 
Sendecode unterscheidet sich nur durch die darunter gepostete 
can_tx()-Funktion anstelle von can_rx(). (und natürlich durch die 
entsprechenden Registereinstellungen, die nun auf Tx und nicht Rx 
gesetzt sind.)


Sieht von euch jemand einen Bock in meinem Programm oder hat einen Tipp 
für mich? Üebr jede Hilfe bin ich sehr dankbar...

Viele Grüße, Xine
 
interrupt [CAN_IT] void can_isr(void)   // CANIT interrupt vector code
{
unsigned char save_canpage;
save_canpage = CANPAGE;                

CANPAGE = (1 << MOBNB1);                // Select MOb2.   

if (CANSTMOB & (1 << RXOK))            
        {
        can_data = CANMSG;  
        lcd_int2bin(can_data);          // Show received data byte
        CANSTMOB &= (~(1 << RXOK));  
        }       
if (CANGSTA & (1 << BOFF))              // Bus off error flag            
        {
        lcd_putsf("Bus off");
        lcd_int2bin(CANREC);            // Show CANTEC register 
        CANGSTA &= (~(1 << BOFF));
        } 
if (CANSTMOB & (1 << DLCW))    // DLC warning flag
        {
        lcd_putsf("DLCW"); 
        CANSTMOB &= (~(1 << DLCW));
        delay_ms(200);     
        }  
if (CANSTMOB & (1 << CERR))    // CRC error flag
        {
        lcd_putsf("CERR"); 
        CANSTMOB &= (~(1 << CERR));
        delay_ms(200);     
        } 
if (CANSTMOB & (1 << SERR))    // Stuff error flag
        {
        lcd_putsf("SERR"); 
        CANSTMOB &= (~(1 << SERR)); 
        }
if (CANSTMOB & (1 << FERR))    // Form error flag
        {
        lcd_putsf("FERR"); 
        CANSTMOB &= (~(1 << FERR));   
        } 
if (CANSTMOB & (1 << AERR))
        {
        lcd_putsf("CAN MOb ACK error"); 
        CANSTMOB &= (~(1 << AERR)); 
        } 
if (CANSTMOB & (1 << AERR))    // MOb ACK error flag
        {
        lcd_putsf("CAN MOb ACK error"); 
        CANSTMOB &= (~(1 << AERR));  
        } 
if (CANGIT & (0 << AERG))
        {
        lcd_putsf("CAN general ACK error"); 
        CANGIT &= (~(0 << AERG)); 
        }
if (CANGIT & (1 << CANIT))
        {
        lcd_putsf("Some interrupt happened");
        }
CANPAGE = save_canpage; 
}          


void can_init(void)     // CAN Controller initialization
{
int i; 
int j;

#asm("cli")              

// CAN general initialization: 

CANTCON = 0x00;         // CAN Timer Clock Period: 0,500 us

CANBT1 = 0x12;          // CAN baudrate: 100 kbit/s                
CANBT2 = 0x0C;
CANBT3 = 0x36;                                                          

CANGIE = (1<<ENRX) | (1<<ENIT) | (1<<ENERR); // Enable interrupt sources 

CANIE2 = (1 << IEMOB2);                 // MOb2 interrupts.  
CANIE1 = 0x00;  


// MOb initialization: Clear all MObs.

for (i=0; i<15; i++)
        {
        CANPAGE = (i << 4);             // Select MOb
        
        CANSTMOB = 0x00;                
        CANCDMOB = 0x00;                
        
        CANIDT4 = 0x00;                 // Delete Id.
        CANIDT3 = 0x00;
        CANIDT2 = 0x00;
        CANIDT1 = 0x00;
             
        CANIDM4 = 0x00;                 // Delete mask.
        CANIDM3 = 0x00;
        CANIDM2 = 0x00;
        CANIDM1 = 0x00;
        
        for (j=0; j<8; j++)             // Delete data
                {
                CANMSG = 0x00;
                }
        }   
          
// Enable CAN module: 

CANGCON = (1 << ENASTB);                // Enable CAN. <=> CANGCON=0x02;      
}



void can_rx(void)      
{
CANPAGE = (1 << MOBNB1) | (1 << AINC);     // 2. Select MOb2. 
CANCDMOB = (1 << CONMOB1) | (1 << DLC0);   // Enable rx, DLC = 1 (1 byte) 
}                   
   


void main(void)
{

init();
can_init();
#asm("sei") 
can_rx();  

while (1)
      {
      };
}

Autor: Xine L. (xine)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier meine can_tx()-Funktion:
 
void can_tx(void)
{
// ++++++++++++++++ Select MOb1 and start tx: +++++++++++++++++++
       
CANPAGE = (1 << MOBNB1) | (1 << AINC);  // Select MOb2, no auto-increment of index. 

CANMSG = 0xF0;                          // Put data into mailbox.  

CANIDT4 = 0x00;                         // Set Id.      
CANIDT3 = 0x00;
CANIDT2 = 0xA0;
CANIDT1 = 0xAA; 
          
CANCDMOB = (1 << CONMOB0) | (1 << DLC0);        // Enable Tx. Send 1 byte.   
}    

Autor: Sven (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Grundsätzlich macht man normalerweise keine Anzeige auf einem LCD
in der Interupt Routine.
Man merkt sich nur das was man anzeigen will und lässt
das dann die main-funktion tun.

Zum can problem kann ich jetzt nicht so viel sagen, aber
möglicherweise liegt es schon an dem geschwindigkeitsproblem,
welches ich oben beschrieben habe.

Gruß Sven

Autor: Xine L. (xine)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für Deine schnelle Antwort. Jedoch bezweifle ich, dass es an den 
LCD-Ausgabe im Interrupt liegt. Zuvor habe ich Registerinhalte nach der 
Interruptroutine ausgeben lassen, was keinen erkennbaren Unterschied 
machte.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.