Hallo Leute, ich arbeite jetzt schon ein paar tage an der Realisierung eines CAN Moduls mit dem dsPIC33EV32GM102 als Controller und einem MCP2551 als CAN Transceiver. Als zweiten Knoten auf dem Bus benutze ich ein MCP2515 Demo Board von Microchip. Nun zu meinem Problem. Leider funktioniert die CAN Kommunikation weder aus- noch eingehend. Ich habe viele der verfügbaren Beispielcodes implementiert, leider ohne Erfolg. Ich habe auch noch nicht ganz verstanden wie die Datenübertragung per DMA und das ECAN Peripherie-Modul sich gegenseitig triggern. So weit ich es verstanden habe, setzte ich das Bit für einen Message Transmit Request. Dieser löst einen Interrupt aus (der nicht aktiviert sein darf, so dass er vom DMA Controller abgearbeitet wird). Der DMA Controller beginnt dann die Daten aus dem RAM in den Transmit Buffer des CAN Moduls zu kopieren und löst nach Beenden des Vorgangs den DMA Interrupt aus. So weit ich verstehe mü+sste das CAN Modul dann automatisch die Daten an den Transceiver weiterreichen. Mein CAN Bus ist für 125kbits/s konfiguriert und mein Controller läuft auf 35MHz. Sowohl Standard Messages, als auch Extended Messages werden unterstützt. Empfangen werden sollen diverse verschiedene Adressen, deshalb sind so viele Filter konfiguriert. Ich bin für jede Hilfe sehr dankbar! Wünsche ein schönes Wochenende! Robin Hier mal noch der relevante Code: Oscillator Konfiguration:
1 | |
2 | CLKDIVbits.PLLPRE = 0b0000; //Quartz oscillator frequency is divided by 2 |
3 | PLLFBDbits.PLLDIV = 0b000100001; //PLL feedback divides F_PLL by 35 |
4 | CLKDIVbits.PLLPOST = 0b01; //Further divides by 4 -> F_osc = 35MHz |
5 | |
6 | //built in unlock sequence for OSCCON high byte
|
7 | __builtin_write_OSCCONH(0x03); //New clock source is 0b011 (Primary Oscillator with PLL) |
8 | |
9 | //iniiate clock switching
|
10 | __builtin_write_OSCCONL(OSCCON | 0x01); |
11 | |
12 | // Wait for Clock switch to occur
|
13 | while (OSCCONbits.COSC!= 0b011); |
14 | |
15 | // Wait for PLL to lock
|
16 | while (OSCCONbits.LOCK!= 1); |
Anlegen der Buffer:
1 | #define NUM_OF_ECAN_BUFFERS 16
|
2 | |
3 | |
4 | __eds__ unsigned int canbuf[NUM_OF_ECAN_BUFFERS][8] |
5 | __attribute__((eds,aligned(NUM_OF_ECAN_BUFFERS * 16))); //16 buffers with 8 words each (256 byte) |
Relevanter Ausschnitt aus der Initialisierung:
1 | //CAN
|
2 | C1CTRL1bits.REQOP = 0b100; //Switch to configuration mode |
3 | while(C1CTRL1bits.OPMODE != 0b100); //Wait for operation mode to change |
4 | |
5 | C1CTRL1bits.WIN = 1; //filter window |
6 | C1CTRL1bits.CSIDL = 0; //CAN module continues operation in device IDLE |
7 | C1CTRL1bits.CANCKS = 0; //F_CAN is equal to F_P=17,5MHz |
8 | C1CFG1bits.BRP = 0b000111; //T_Q is 2x7x1/F_CAN= 800ns |
9 | C1CFG1bits.SJW = 0b00; //SJW is 1T_Q |
10 | C1CFG2bits.PRSEG = 0b100; //Prop segment is 3T_Q |
11 | C1CFG2bits.SEG1PH = 0b100; //Segment 1 is 3T_Q |
12 | C1CFG2bits.SEG2PH = 0b100; //Segment 2 is 3T_Q |
13 | C1CFG2bits.SEG2PHTS = 0; |
14 | C1CFG2bits.SAM = 1; //Bus line is sampled three times per sample point |
15 | C1CFG2bits.WAKFIL = 0; //CAN bus line filter is used for wake up |
16 | C1FEN1 = 0x3FFF; //Enable Filter 0:13 |
17 | C1BUFPNT1 = 0xFFFF; //messages are received in FIFO buffer |
18 | C1BUFPNT2 = 0xFFFF; |
19 | C1BUFPNT3 = 0xFFFF; |
20 | C1BUFPNT4 = 0x00FF; |
21 | |
22 | C1RXF0SIDbits.SID = 0b00000000001; //Filter 0 |
23 | C1RXF0SIDbits.EID = 0b00; //Filter 0 (Extended Identifier) |
24 | C1RXF0EID = 0x0000; //Filter 0 (Extended Identifier) |
25 | C1RXF1SIDbits.SID = 0b00000000010; //Filter 1 |
26 | C1RXF1SIDbits.EID = 0b00; //Filter 1 (Extended Identifier) |
27 | C1RXF1EID = 0x0000; //Filter 1 (Extended Identifier) |
28 | C1RXF2SIDbits.SID = 0b00000000011; //Filter 2 |
29 | C1RXF2SIDbits.EID = 0b00; //Filter 2 (Extended Identifier) |
30 | C1RXF2EID = 0x0000; //Filter 2 (Extended Identifier) |
31 | C1RXF3SIDbits.SID = 0b00000000100; //Filter 3 |
32 | C1RXF3SIDbits.EID = 0b00; //Filter 3 (Extended Identifier) |
33 | C1RXF3EID = 0x0000; //Filter 3 (Extended Identifier) |
34 | C1RXF4SIDbits.SID = 0b00000000101; //Filter 4 |
35 | C1RXF4SIDbits.EID = 0b00; //Filter 4 (Extended Identifier) |
36 | C1RXF4EID = 0x0000; //Filter 4 (Extended Identifier) |
37 | C1RXF5SIDbits.SID = 0b00000000110; //Filter 5 |
38 | C1RXF5SIDbits.EID = 0b00; //Filter 5 (Extended Identifier) |
39 | C1RXF5EID = 0x0000; //Filter 5 (Extended Identifier) |
40 | C1RXF6SIDbits.SID = 0b00000000111; //Filter 6 |
41 | C1RXF6SIDbits.EID = 0b00; //Filter 6 (Extended Identifier) |
42 | C1RXF6EID = 0x0000; //Filter 6 (Extended Identifier) |
43 | C1RXF7SIDbits.SID = 0b00000001000; //Filter 7 |
44 | C1RXF7SIDbits.EID = 0b00; //Filter 7 (Extended Identifier) |
45 | C1RXF7EID = 0x0000; //Filter 7 (Extended Identifier) |
46 | C1RXF8SIDbits.SID = 0b00000001001; //Filter 8 |
47 | C1RXF8SIDbits.EID = 0b00; //Filter 8 (Extended Identifier) |
48 | C1RXF8EID = 0x0000; //Filter 8 (Extended Identifier) |
49 | C1RXF9SIDbits.SID = 0b00000001010; //Filter 9 |
50 | C1RXF9SIDbits.EID = 0b00; //Filter 9 (Extended Identifier) |
51 | C1RXF9EID = 0x0000; //Filter 9 (Extended Identifier) |
52 | C1RXF10SIDbits.SID = 0b0000001011; //Filter 10 |
53 | C1RXF10SIDbits.EID = 0b00; //Filter 10 (Extended Identifier) |
54 | C1RXF10EID = 0x0000; //Filter 10 (Extended Identifier) |
55 | C1RXF11SIDbits.SID = 0b00000001100; //Filter 11 |
56 | C1RXF11SIDbits.EID = 0b00; //Filter 11 (Extended Identifier) |
57 | C1RXF11EID = 0x0000; //Filter 11 (Extended Identifier) |
58 | C1RXF12SIDbits.SID = 0b00000001101; //Filter 12 |
59 | C1RXF12SIDbits.EID = 0b00; //Filter 12 |
60 | C1RXF12EID = 0x0000; //Filter 12 |
61 | C1RXF13SIDbits.SID = 0b00000001110; //Filter 13 |
62 | C1RXF13SIDbits.EID = 0b00; //Filter 13 (Extended Identifier) |
63 | C1RXF13EID = 0x0000; //Filter 13 (Extended Identifier) |
64 | |
65 | C1FMSKSEL1 = 0x0000; //Mask0 determines the acceptance mask for all used filters |
66 | C1FMSKSEL2 = 0x0000; |
67 | C1RXM0SID = 0xFFF7; //All identifier digits are relevant, standard fames and extended frames are receivable |
68 | C1RXM0EID = 0xFFFF; |
69 | |
70 | C1CTRL1bits.WIN = 0; //buffer window |
71 | C1FCTRLbits.DMABS = 0b100; //16 DMA buffers in RAM |
72 | C1FCTRLbits.FSA = 0b00001; // FIFO area from TRB1 to RB15 |
73 | C1TR01CONbits.TXEN0 = 1; //Set TRB0 as transmit buffer |
74 | IEC4bits.C1TXIE = 0; //deactivate interrpt processing by CPU |
75 | IEC2bits.C1RXIE = 0; |
76 | |
77 | //DMA
|
78 | DMA0CONbits.AMODE = 0b10; //Peripheral indirect mode |
79 | DMA0REQbits.IRQSEL = 0b00100010; //Connect to CAN RX peripheral |
80 | DMA0PAD = (volatile unsigned int) &C1RXD; //Read from CAN1 RX register (address) |
81 | IEC0bits.DMA0IE = 1; //Enable interrupt for DMA channel 0 |
82 | DMA0CNT = 7; //8 words to be transmitted |
83 | DMA1CONbits.AMODE = 0b10; //Peripheral indirect mode |
84 | DMA1CONbits.DIR = 1; //Channel 1 reads data from RAM to CAN |
85 | DMA1REQbits.IRQSEL = 0b01000110; //Connect to CAN TX peripheral |
86 | DMA1PAD = (volatile unsigned int) &C1TXD; //Writes to CAN1 TX register (address) |
87 | IEC0bits.DMA1IE = 1; //Enable interrupt for DMA channel 1 |
88 | DMA1CNT = 7; //8 words to be transmitted |
89 | |
90 | DMA0STAL = (unsigned int) &canbuf; //CAN receive FIFO buffer (16 buffer, 8 words each) |
91 | DMA0STAH = 0x0000; |
92 | DMA1STAL = (unsigned int) &canbuf; |
93 | DMA1STAH = 0x0000; |
94 | |
95 | DMA0CONbits.CHEN = 1; //Enable DMA channel 0 for CAN RX |
96 | DMA1CONbits.CHEN = 1; //Enable DMA channel 1 for CAN TX |
97 | |
98 | C1CTRL1bits.REQOP = 0b000; //Switch to normal CAN operation mode |
99 | while(C1CTRL1bits.OPMODE != 0b000); //Wait for opeation mode to change |
100 | |
101 | //MUST be last operation here
|
102 | IFS1bits.CNIF = 0; //Reset all used interrupt flags |
103 | IFS0bits.DMA0IF = 0; |
104 | IFS0bits.DMA1IF = 0; |
105 | IFS0bits.T1IF = 0; |
106 | IFS2bits.C1RXIF = 0; |
107 | IFS4bits.C1TXIF = 0; |
108 | INTCON2bits.GIE = 1; //Global interrupt enable |
Die Funktion die Nachrichten versendet:
1 | bool SendMessage(uint16_t data_bytes[]) |
2 | {
|
3 | /* CAN data frame *
|
4 | * *
|
5 | * Word 0: *
|
6 | * bit 13-15 unimplemented *
|
7 | * bit 2-12 Standard Identifier (SID) *
|
8 | * bit 1 SRR - Substitute Remote Request bit *
|
9 | * 0 (normal message) - 1 (request remote message) *
|
10 | * MUST be 1 for extended message format *
|
11 | * bit 0 IDE bit - Identifier Extension bit *
|
12 | * 0 (standard message format) - 1 (extended message format) *
|
13 | * *
|
14 | * Word 1: *
|
15 | * bit 12-15 unimplemented *
|
16 | * bit 0-11 Extended Identifier (EID) *
|
17 | * *
|
18 | * Word 2: *
|
19 | * bit 10-15 Extended Identifier (EID) *
|
20 | * bit 9 Remote Transmission Request (RTR) *
|
21 | * 0 (normal message) - 1 (request remote transmission) *
|
22 | * IGNORED for standard message format *
|
23 | * bit 8 RB1 bit - MUST be set to 0 *
|
24 | * bit 5-7 unimplemented *
|
25 | * bit 4 RB0 - MUST be set to 0 *
|
26 | * bit 0-3 Data Length Code - Numnber of bytes to send *
|
27 | * *
|
28 | * Word 3: *
|
29 | * bit 8-15 message byte 1 *
|
30 | * bit 0-7 message byte 0 *
|
31 | * *
|
32 | * Word 4: *
|
33 | * bit 8-15 message byte 3 *
|
34 | * bit 0-7 message byte 2 *
|
35 | * *
|
36 | * Word 5: *
|
37 | * bit 8-15 message byte 5 *
|
38 | * bit 0-7 message byte 4 *
|
39 | * *
|
40 | * Word 6: *
|
41 | * bit 8-15 message byte 7 *
|
42 | * bit 0-7 message byte 6 *
|
43 | * *
|
44 | * Word 7: *
|
45 | * bit 0-15 unimplemented *
|
46 | * */
|
47 | |
48 | |
49 | unsigned int i, k, n; |
50 | unsigned int j = 0; |
51 | unsigned int number_of_bytes = sizeof(data_bytes)+1; |
52 | |
53 | n = (number_of_bytes/8)+1; //determine how many messages are needed |
54 | if(number_of_bytes % 8 == 0) n--; |
55 | for(k=0;k<n;k++) //send n messages |
56 | {
|
57 | for(i=0;i<8;i++) canbuf[0][i] = 0; //reset send buffer |
58 | |
59 | //save message to buffer
|
60 | canbuf[0][0] = (SID_OF_MAIN_CONTROLLER << 2) | 0x0003; //SID and send extended message |
61 | canbuf[0][1] = 0x000; //write EID |
62 | if((number_of_bytes - k*8) <= 8) canbuf[0][2] = number_of_bytes; |
63 | else canbuf[0][2] = 0x0008; //number of bytes to send |
64 | |
65 | if(canbuf[0][2] % 2 != 0) //if odd number of bytes to send write highest one out of normal flow |
66 | {
|
67 | canbuf[0][3+(canbuf[0][2]/2)] = data_bytes[number_of_bytes - 1]; |
68 | }
|
69 | |
70 | for(i=0;i<(canbuf[0][2]/2);i++) |
71 | {
|
72 | canbuf[0][i+3] = data_bytes[j+1] << 8; //place upper byte |
73 | canbuf[0][i+3] = canbuf[0][i+3] | (data_bytes[j] & 0x00FF); //place lower byte |
74 | j = j+2; |
75 | }
|
76 | |
77 | C1TR01CONbits.TXREQ0 = 1; //request message sending |
78 | |
79 | while(C1TR01CONbits.TXREQ0 == 1 && C1ECbits.TERRCNT == 0); //wait for transmission |
80 | if(C1TR01CONbits.TXABT0 != 0 || C1ECbits.TERRCNT != 0) |
81 | {
|
82 | C1ECbits.TERRCNT = 0; |
83 | C1TR01CONbits.TXABT0 = 0; |
84 | return false; |
85 | }
|
86 | }
|
87 | |
88 | return true; //messages sent without errors |
89 | }
|
Und zu guter Letzt die relevanten ISRs:
1 | void __attribute__((interrupt, no_auto_psv)) _DMA0Interrupt(void) |
2 | {
|
3 | if(DMAPWCbits.PWCOL0 == 1) //write collision detect |
4 | {
|
5 | DMAPWCbits.PWCOL0 = 0; //clear write collison bit |
6 | }
|
7 | |
8 | else if(DMARQCbits.RQCOL0 == 1) //user force and interrupt based collision detect |
9 | {
|
10 | DMARQCbits.RQCOL0 == 0; //clear error bit |
11 | }
|
12 | |
13 | else if(C1RXOVF1 != 0) //tried to write to already full FIFO buffer |
14 | {
|
15 | C1RXOVF1 = 0; //reset overflow flag |
16 | }
|
17 | |
18 | else if(C1ECbits.RERRCNT != 0) //receive error bit counter |
19 | {
|
20 | C1ECbits.RERRCNT = 0; //reset counter |
21 | }
|
22 | |
23 | else //message received correctly |
24 | {
|
25 | canmsg = true; |
26 | |
27 | }
|
28 | |
29 | IFS0bits.DMA0IF = 0; // Clear the DMA0 Interrupt Flag |
30 | return; |
31 | }
|
32 | |
33 | void __attribute__((interrupt, no_auto_psv)) _DMA1Interrupt(void) |
34 | {
|
35 | IFS0bits.DMA1IF = 0; |
36 | return; |
37 | }
|