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


von Xine L. (xine)


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
1
 
2
interrupt [CAN_IT] void can_isr(void)   // CANIT interrupt vector code
3
{
4
unsigned char save_canpage;
5
save_canpage = CANPAGE;                
6
7
CANPAGE = (1 << MOBNB1);                // Select MOb2.   
8
9
if (CANSTMOB & (1 << RXOK))            
10
        {
11
        can_data = CANMSG;  
12
        lcd_int2bin(can_data);          // Show received data byte
13
        CANSTMOB &= (~(1 << RXOK));  
14
        }       
15
if (CANGSTA & (1 << BOFF))              // Bus off error flag            
16
        {
17
        lcd_putsf("Bus off");
18
        lcd_int2bin(CANREC);            // Show CANTEC register 
19
        CANGSTA &= (~(1 << BOFF));
20
        } 
21
if (CANSTMOB & (1 << DLCW))    // DLC warning flag
22
        {
23
        lcd_putsf("DLCW"); 
24
        CANSTMOB &= (~(1 << DLCW));
25
        delay_ms(200);     
26
        }  
27
if (CANSTMOB & (1 << CERR))    // CRC error flag
28
        {
29
        lcd_putsf("CERR"); 
30
        CANSTMOB &= (~(1 << CERR));
31
        delay_ms(200);     
32
        } 
33
if (CANSTMOB & (1 << SERR))    // Stuff error flag
34
        {
35
        lcd_putsf("SERR"); 
36
        CANSTMOB &= (~(1 << SERR)); 
37
        }
38
if (CANSTMOB & (1 << FERR))    // Form error flag
39
        {
40
        lcd_putsf("FERR"); 
41
        CANSTMOB &= (~(1 << FERR));   
42
        } 
43
if (CANSTMOB & (1 << AERR))
44
        {
45
        lcd_putsf("CAN MOb ACK error"); 
46
        CANSTMOB &= (~(1 << AERR)); 
47
        } 
48
if (CANSTMOB & (1 << AERR))    // MOb ACK error flag
49
        {
50
        lcd_putsf("CAN MOb ACK error"); 
51
        CANSTMOB &= (~(1 << AERR));  
52
        } 
53
if (CANGIT & (0 << AERG))
54
        {
55
        lcd_putsf("CAN general ACK error"); 
56
        CANGIT &= (~(0 << AERG)); 
57
        }
58
if (CANGIT & (1 << CANIT))
59
        {
60
        lcd_putsf("Some interrupt happened");
61
        }
62
CANPAGE = save_canpage; 
63
}          
64
65
66
void can_init(void)     // CAN Controller initialization
67
{
68
int i; 
69
int j;
70
71
#asm("cli")              
72
73
// CAN general initialization: 
74
75
CANTCON = 0x00;         // CAN Timer Clock Period: 0,500 us
76
77
CANBT1 = 0x12;          // CAN baudrate: 100 kbit/s                
78
CANBT2 = 0x0C;
79
CANBT3 = 0x36;                                                          
80
81
CANGIE = (1<<ENRX) | (1<<ENIT) | (1<<ENERR); // Enable interrupt sources 
82
83
CANIE2 = (1 << IEMOB2);                 // MOb2 interrupts.  
84
CANIE1 = 0x00;  
85
86
87
// MOb initialization: Clear all MObs.
88
89
for (i=0; i<15; i++)
90
        {
91
        CANPAGE = (i << 4);             // Select MOb
92
        
93
        CANSTMOB = 0x00;                
94
        CANCDMOB = 0x00;                
95
        
96
        CANIDT4 = 0x00;                 // Delete Id.
97
        CANIDT3 = 0x00;
98
        CANIDT2 = 0x00;
99
        CANIDT1 = 0x00;
100
             
101
        CANIDM4 = 0x00;                 // Delete mask.
102
        CANIDM3 = 0x00;
103
        CANIDM2 = 0x00;
104
        CANIDM1 = 0x00;
105
        
106
        for (j=0; j<8; j++)             // Delete data
107
                {
108
                CANMSG = 0x00;
109
                }
110
        }   
111
          
112
// Enable CAN module: 
113
114
CANGCON = (1 << ENASTB);                // Enable CAN. <=> CANGCON=0x02;      
115
}
116
117
118
119
void can_rx(void)      
120
{
121
CANPAGE = (1 << MOBNB1) | (1 << AINC);     // 2. Select MOb2. 
122
CANCDMOB = (1 << CONMOB1) | (1 << DLC0);   // Enable rx, DLC = 1 (1 byte) 
123
}                   
124
   
125
126
127
void main(void)
128
{
129
130
init();
131
can_init();
132
#asm("sei") 
133
can_rx();  
134
135
while (1)
136
      {
137
      };
138
}

von Xine L. (xine)


Lesenswert?

Hier meine can_tx()-Funktion:
1
 
2
void can_tx(void)
3
{
4
// ++++++++++++++++ Select MOb1 and start tx: +++++++++++++++++++
5
       
6
CANPAGE = (1 << MOBNB1) | (1 << AINC);  // Select MOb2, no auto-increment of index. 
7
8
CANMSG = 0xF0;                          // Put data into mailbox.  
9
10
CANIDT4 = 0x00;                         // Set Id.      
11
CANIDT3 = 0x00;
12
CANIDT2 = 0xA0;
13
CANIDT1 = 0xAA; 
14
          
15
CANCDMOB = (1 << CONMOB0) | (1 << DLC0);        // Enable Tx. Send 1 byte.   
16
}

von Sven (Gast)


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

von Xine L. (xine)


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.

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.