1 | /*********************************************************************
|
2 | *
|
3 | * This file contains CAN drivers for PIC18Fxx8 devices
|
4 | *
|
5 | *********************************************************************
|
6 | * FileName: CAN.C
|
7 | * Dependencies: CAN.H, PIC18.H or P18CXXX.H
|
8 | * Processor: PIC18FXX8
|
9 | * Compiler: MCC18 v2.20 or higher
|
10 | * HITECH PICC-18 v8.20PL4 or higher
|
11 | * Linker:
|
12 | * Company: Microchip Technology, Inc.
|
13 | *
|
14 | * Software License Agreement
|
15 | *
|
16 | * The software supplied herewith by Microchip Technology Incorporated
|
17 | * (the "Company") is intended and supplied to you, the Companys
|
18 | * customer, for use solely and exclusively with products manufactured
|
19 | * by the Company.
|
20 | *
|
21 | * The software is owned by the Company and/or its supplier, and is
|
22 | * protected under applicable copyright laws. All rights are reserved.
|
23 | * Any use in violation of the foregoing restrictions may subject the
|
24 | * user to criminal sanctions under applicable laws, as well as to
|
25 | * civil liability for the breach of the terms and conditions of this
|
26 | * license.
|
27 |
|
28 | * THIS SOFTWARE IS PROVIDED IN AN "AS IS" CONDITION. NO WARRANTIES,
|
29 | * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
|
30 | * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
31 | * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
|
32 | * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
|
33 | * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
|
34 | *
|
35 | *
|
36 | *
|
37 | *
|
38 | * Author Date Comment
|
39 | *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
40 | * Thomas Castmo 06/07/2003 Initial release
|
41 | * Thomas Castmo 07/07/2003 Cleared up a bit and implemented
|
42 | * the window function CANCON<3:1>
|
43 | * for interrupts
|
44 | * Thomas Castmo 16/07/2003 Added support for the Microchip
|
45 | * MPLAB C18 compiler
|
46 | *
|
47 | ********************************************************************/
|
48 | #include "can.h"
|
49 |
|
50 | #if defined(HI_TECH_C)
|
51 | #if defined(_MPC_)
|
52 | #define HITECH_C18
|
53 | #else
|
54 | #error "Unknown part is selected."
|
55 | #endif
|
56 | #else
|
57 | #define MCHP_C18
|
58 | #endif
|
59 |
|
60 | #if defined(MCHP_C18) && defined(HITECH_C18)
|
61 | #error "Invalid Compiler selection."
|
62 | #endif
|
63 |
|
64 | #if !defined(MCHP_C18) && !defined(HITECH_C18)
|
65 | #error "Compiler not supported."
|
66 | #endif
|
67 |
|
68 |
|
69 | #if defined(HITECH_C18)
|
70 | #include <pic18.h>
|
71 |
|
72 | #elif defined(MCHP_C18)
|
73 | #include <p18cxxx.h>
|
74 |
|
75 | #define TRISB2 TRISBbits.TRISB2
|
76 | #define TRISB3 TRISBbits.TRISB3
|
77 | #define TXB0REQ TXB0CONbits.TXREQ
|
78 | #define RXB0FUL RXB0CONbits.RXFUL
|
79 | #define RXB0RTRRO RXB0CONbits.RXRTRRO
|
80 |
|
81 | #define RXB0IF PIR3bits.RXB0IF
|
82 | #define RXB1IF PIR3bits.RXB1IF
|
83 | #define TXB0IF PIR3bits.TXB0IF
|
84 | #define TXB1IF PIR3bits.TXB1IF
|
85 | #define TXB2IF PIR3bits.TXB2IF
|
86 | #define ERRIF PIR3bits.ERRIF
|
87 | #define WAKIF PIR3bits.WAKIF
|
88 |
|
89 | #define RXB0IE PIE3bits.RXB0IE
|
90 | #define RXB1IE PIE3bits.RXB1IE
|
91 | #define TXB0IE PIE3bits.TXB0IE
|
92 | #define TXB1IE PIE3bits.TXB1IE
|
93 | #define TXB2IE PIE3bits.TXB2IE
|
94 | #define ERRIE PIE3bits.ERRIE
|
95 | #define WAKIE PIE3bits.WAKIE
|
96 |
|
97 |
|
98 | #endif
|
99 |
|
100 |
|
101 |
|
102 | #define CONFIG_MODE 0x9F
|
103 | #define LISTEN_MODE 0x7F
|
104 | #define LOOPBACK_MODE 0x5F
|
105 | #define DISABLE_MODE 0x3F
|
106 | #define NORMAL_MODE 0x1F
|
107 | #define MODE_MASK 0xE0
|
108 |
|
109 | #define NoInterrupt 0x00
|
110 | #define ErrorInterrupt 0x02
|
111 | #define TXB2Interrupt 0x04
|
112 | #define TXB1Interrupt 0x06
|
113 | #define TXB0Interrupt 0x08
|
114 | #define RXB1Interrupt 0x0A
|
115 | #define RXB0Interrupt 0x0C
|
116 | #define WakeUpInterrupt 0x0E
|
117 |
|
118 |
|
119 | #ifdef CAN_ERROR_HANDLER_ENABLE
|
120 | extern void CANErrorHandler(void);
|
121 | #define CAN_INT_BITS 0x3F //CAN interrupts which should be enabled, simply what PIE3 is to be loaded with (Note all TXB IE will be set regardless of this value)
|
122 | #else
|
123 | #define CAN_INT_BITS 0x1F //CAN interrupts which should be enabled, simply what PIE3 is to be loaded with (Note all TXB IE will be set regardless of this value)
|
124 | #endif
|
125 |
|
126 | union RXBuffer { //Receive buffer structure
|
127 | unsigned char Data[14]; //It has to be a bit messy/strict for
|
128 | struct { //it to go trough the PICC18 compiler
|
129 | union {
|
130 | unsigned char Byte;
|
131 | struct {
|
132 | unsigned FILHIT0:1;
|
133 | unsigned JTOFF:1;
|
134 | unsigned RXB0DBEN:1;
|
135 | unsigned RXRTRRO:1;
|
136 | unsigned :1;
|
137 | unsigned RXM0:1;
|
138 | unsigned RXM1:1;
|
139 | unsigned RXFUL:1;
|
140 | } Bits;
|
141 | } RXBCON;
|
142 | union {
|
143 | unsigned char Byte;
|
144 | } RXBSIDH;
|
145 | union {
|
146 | unsigned char Byte;
|
147 | struct {
|
148 | unsigned EID16:1;
|
149 | unsigned EID17:1;
|
150 | unsigned :1;
|
151 | unsigned EXID:1;
|
152 | unsigned SRR:1;
|
153 | unsigned SID0:1;
|
154 | unsigned SID1:1;
|
155 | unsigned SID2:1;
|
156 | } Bits;
|
157 | } RXBSIDL;
|
158 | union {
|
159 | unsigned char Byte;
|
160 | } RXBEIDH;
|
161 | union {
|
162 | unsigned char Byte;
|
163 | } RXBEIDL;
|
164 | union {
|
165 | unsigned char Byte;
|
166 | struct {
|
167 | unsigned DLC0:1;
|
168 | unsigned DLC1:1;
|
169 | unsigned DLC2:1;
|
170 | unsigned DLC3:1;
|
171 | unsigned RB0:1;
|
172 | unsigned RB1:1;
|
173 | unsigned RXRTR:1;
|
174 | unsigned :1;
|
175 | } Bits;
|
176 | } RXBDLC;
|
177 | union {
|
178 | unsigned char Array[8];
|
179 | struct {
|
180 | unsigned char RXBD0;
|
181 | unsigned char RXBD1;
|
182 | unsigned char RXBD2;
|
183 | unsigned char RXBD3;
|
184 | unsigned char RXBD4;
|
185 | unsigned char RXBD5;
|
186 | unsigned char RXBD6;
|
187 | unsigned char RXBD7;
|
188 | } Bytes;
|
189 | } RXBD;
|
190 | } Specific;
|
191 | };
|
192 |
|
193 | union TXBuffer { //Transmit buffer structure
|
194 | unsigned char Data[14];
|
195 | struct {
|
196 | union {
|
197 | unsigned char Byte;
|
198 | struct {
|
199 | unsigned TXPRI0:1;
|
200 | unsigned TXPRI1:1;
|
201 | unsigned :1;
|
202 | unsigned TXREQ:1;
|
203 | unsigned TXERR:1;
|
204 | unsigned TXLARB:1;
|
205 | unsigned TXABT:1;
|
206 | } Bits;
|
207 | } TXBCON;
|
208 | union {
|
209 | unsigned char Byte;
|
210 | } TXBSIDH;
|
211 | union {
|
212 | unsigned char Byte;
|
213 | struct {
|
214 | unsigned EID16:1;
|
215 | unsigned EID17:1;
|
216 | unsigned :1;
|
217 | unsigned EXIDE:1;
|
218 | unsigned :1;
|
219 | unsigned SID0:1;
|
220 | unsigned SID1:1;
|
221 | unsigned SID2:1;
|
222 | } Bits;
|
223 | } TXBSIDL;
|
224 | union {
|
225 | unsigned char Byte;
|
226 | } TXBEIDH;
|
227 | union {
|
228 | unsigned char Byte;
|
229 | } TXBEIDL;
|
230 | union {
|
231 | unsigned char Byte;
|
232 | struct {
|
233 | unsigned DLC0:1;
|
234 | unsigned DLC1:1;
|
235 | unsigned DLC2:1;
|
236 | unsigned DLC3:1;
|
237 | unsigned :1;
|
238 | unsigned :1;
|
239 | unsigned TXRTR:1;
|
240 | unsigned :1;
|
241 | } Bits;
|
242 | } TXBDLC;
|
243 | union {
|
244 | unsigned char Array[8];
|
245 | struct {
|
246 | unsigned char TXBD0;
|
247 | unsigned char TXBD1;
|
248 | unsigned char TXBD2;
|
249 | unsigned char TXBD3;
|
250 | unsigned char TXBD4;
|
251 | unsigned char TXBD5;
|
252 | unsigned char TXBD6;
|
253 | unsigned char TXBD7;
|
254 | } Bytes;
|
255 | } TXBD;
|
256 | } Specific;
|
257 | };
|
258 | union RXBuffer RXMessage[RXBUF]; //Received messages FIFO buffer
|
259 | union TXBuffer TXMessage[TXBUF]; //Pending messages to transmit FIFO buffer
|
260 | char RXRPtr = 0; //Read pointer for RXMessage buffer
|
261 | char RXWPtr = 0; //Write pointer for RXMessage buffer
|
262 | char TXRPtr = 0; //Read pointer for TXMessage buffer
|
263 | char TXWPtr = 0; //Write pointer for TXMessage buffer
|
264 |
|
265 |
|
266 | /*********************************************************************
|
267 | * Function: void CANGetMessage(void)
|
268 | *
|
269 | * PreCondition: <WIN2:WIN0> in the CANCON register has to set
|
270 | * to reflect the desired RXB registers
|
271 | *
|
272 | * Input: None
|
273 | *
|
274 | * Output: None
|
275 | *
|
276 | * Side Effects: Will modify the RX FIFO Write pointer (RXWPtr)
|
277 | *
|
278 | * Overview: Gets the registers for a RXB and puts them in the
|
279 | * CAN Receive buffer
|
280 | *
|
281 | * Note: Care is not taken if buffer is full
|
282 | ********************************************************************/
|
283 | void CANGetMessage(void);
|
284 |
|
285 | /*********************************************************************
|
286 | * Function: char CANPutMessage(void)
|
287 | *
|
288 | * PreCondition: <WIN2:WIN0> in the CANCON register has to set
|
289 | * to reflect the desired TXB registers
|
290 | *
|
291 | * Input: None
|
292 | *
|
293 | * Output: 0 -> A new message has been put in the transmit queue
|
294 | * 1 -> There was no messages in the TX buffer to send
|
295 | *
|
296 | * Side Effects: Will modify the TX buffer´s Read pointer (TXRPtr)
|
297 | *
|
298 | * Overview: Checks if there is any messages to transmit and if so
|
299 | * place it in the registers reflected by <WIN2:WIN0>
|
300 | *
|
301 | * Note: None
|
302 | ********************************************************************/
|
303 | char CANPutMessage(void);
|
304 |
|
305 | /*********************************************************************
|
306 | * Function: char CANOpen(void)
|
307 | *
|
308 | * PreCondition: None
|
309 | *
|
310 | * Input: Values to be written into BRGCON1 -> BRGCON3
|
311 | *
|
312 | * Output: 0 -> Initialasation succeeded
|
313 | *
|
314 | * Side Effects: None
|
315 | *
|
316 | * Overview: Sets up the appropriate register for the device to act
|
317 | * as a CAN node
|
318 | *
|
319 | * Note: Input values 0x03, 0xAA, 0x05 at Fosc = 16MHz works with
|
320 | * the default firmware at nodeB on the CAN I/O expander board.
|
321 | ********************************************************************/
|
322 | char CANOpen(unsigned char CONFIG1, unsigned char CONFIG2, unsigned char CONFIG3)
|
323 | {
|
324 | TRISB2 = 0;
|
325 | TRISB3 = 1;
|
326 | PIE3 = 0; //Disable all CAN interrupts
|
327 | PIR3 = 0; //and clear all CAN interrupt flags
|
328 | CANCON = (CONFIG_MODE & MODE_MASK) | (CANCON & 0x3F); //Set configuration mode
|
329 | while((CANSTAT & MODE_MASK) != (CONFIG_MODE & MODE_MASK)); //Wait until config mode is set
|
330 |
|
331 | BRGCON1 = CONFIG1;
|
332 | BRGCON2 = CONFIG2;
|
333 | BRGCON3 = CONFIG3;
|
334 |
|
335 | RXB0CON = 0x04; //Receive all valid messages receive buffer overflow
|
336 | RXB1CON = 0x00; //writes to RXB1
|
337 |
|
338 | //Set the acceptance filters for all the filters
|
339 | #ifdef ACCEPT_STANDARD_FILTER_0
|
340 | RXF0SIDL = (unsigned char)(ACCEPTANCE_FILTER_0 << 5);
|
341 | RXF0SIDH = (unsigned char)(ACCEPTANCE_FILTER_0 >> 3);
|
342 | #else
|
343 | RXF0EIDL = (unsigned char)(ACCEPTANCE_FILTER_0 & 0xFF);
|
344 | RXF0EIDH = (unsigned char)((ACCEPTANCE_FILTER_0 >> 8) & 0xFF);
|
345 | RXF0SIDL = (unsigned char)((ACCEPTANCE_FILTER_0 >> 16) & 0x03) | (unsigned char)((ACCEPTANCE_FILTER_0 >> 13) & 0xE0) | 0x08;
|
346 | RXF0SIDH = (unsigned char)((ACCEPTANCE_FILTER_0 >> 21) & 0xFF);
|
347 | #endif
|
348 | #ifdef ACCEPT_STANDARD_FILTER_1
|
349 | RXF1SIDL = (unsigned char)(ACCEPTANCE_FILTER_1 << 5);
|
350 | RXF1SIDH = (unsigned char)(ACCEPTANCE_FILTER_1 >> 3);
|
351 | #else
|
352 | RXF1EIDL = (unsigned char)(ACCEPTANCE_FILTER_1 & 0xFF);
|
353 | RXF1EIDH = (unsigned char)((ACCEPTANCE_FILTER_1 >> 8) & 0xFF);
|
354 | RXF1SIDL = (unsigned char)((ACCEPTANCE_FILTER_1 >> 16) & 0x03) | (unsigned char)((ACCEPTANCE_FILTER_1 >> 13) & 0xE0) | 0x08;
|
355 | RXF1SIDH = (unsigned char)((ACCEPTANCE_FILTER_1 >> 21) & 0xFF);
|
356 | #endif
|
357 |
|
358 | #ifdef ACCEPT_STANDARD_FILTER_2
|
359 | RXF2SIDL = (unsigned char)(ACCEPTANCE_FILTER_2 << 5);
|
360 | RXF2SIDH = (unsigned char)(ACCEPTANCE_FILTER_2 >> 3);
|
361 | #else
|
362 | RXF2EIDL = (unsigned char)(ACCEPTANCE_FILTER_2 & 0xFF);
|
363 | RXF2EIDH = (unsigned char)((ACCEPTANCE_FILTER_2 >> 8) & 0xFF);
|
364 | RXF2SIDL = (unsigned char)((ACCEPTANCE_FILTER_2 >> 16) & 0x03) | (unsigned char)((ACCEPTANCE_FILTER_2 >> 13) & 0xE0) | 0x08;
|
365 | RXF2SIDH = (unsigned char)((ACCEPTANCE_FILTER_2 >> 21) & 0xFF);
|
366 | #endif
|
367 |
|
368 | #ifdef ACCEPT_STANDARD_FILTER_3
|
369 | RXF3SIDL = (unsigned char)(ACCEPTANCE_FILTER_3 << 5);
|
370 | RXF3SIDH = (unsigned char)(ACCEPTANCE_FILTER_3 >> 3);
|
371 | #else
|
372 | RXF3EIDL = (unsigned char)(ACCEPTANCE_FILTER_3 & 0xFF);
|
373 | RXF3EIDH = (unsigned char)((ACCEPTANCE_FILTER_3 >> 8) & 0xFF);
|
374 | RXF3SIDL = (unsigned char)((ACCEPTANCE_FILTER_3 >> 16) & 0x03) | (unsigned char)((ACCEPTANCE_FILTER_3 >> 13) & 0xE0) | 0x08;
|
375 | RXF3SIDH = (unsigned char)((ACCEPTANCE_FILTER_3 >> 21) & 0xFF);
|
376 | #endif
|
377 |
|
378 | #ifdef ACCEPT_STANDARD_FILTER_4
|
379 | RXF4SIDL = (unsigned char)(ACCEPTANCE_FILTER_4 << 5);
|
380 | RXF4SIDH = (unsigned char)(ACCEPTANCE_FILTER_4 >> 3);
|
381 | #else
|
382 | RXF4EIDL = (unsigned char)(ACCEPTANCE_FILTER_4 & 0xFF);
|
383 | RXF4EIDH = (unsigned char)((ACCEPTANCE_FILTER_4 >> 8) & 0xFF);
|
384 | RXF4SIDL = (unsigned char)((ACCEPTANCE_FILTER_4 >> 16) & 0x03) | (unsigned char)((ACCEPTANCE_FILTER_4 >> 13) & 0xE0) | 0x08;
|
385 | RXF4SIDH = (unsigned char)((ACCEPTANCE_FILTER_4 >> 21) & 0xFF);
|
386 | #endif
|
387 |
|
388 | #ifdef ACCEPT_STANDARD_FILTER_5
|
389 | RXF5SIDL = (unsigned char)(ACCEPTANCE_FILTER_5 << 5);
|
390 | RXF5SIDH = (unsigned char)(ACCEPTANCE_FILTER_5 >> 3);
|
391 | #else
|
392 | RXF5EIDL = (unsigned char)(ACCEPTANCE_FILTER_5 & 0xFF);
|
393 | RXF5EIDH = (unsigned char)((ACCEPTANCE_FILTER_5 >> 8) & 0xFF);
|
394 | RXF5SIDL = (unsigned char)((ACCEPTANCE_FILTER_5 >> 16) & 0x03) | (unsigned char)((ACCEPTANCE_FILTER_4 >> 13) & 0xE0) | 0x08;
|
395 | RXF5SIDH = (unsigned char)((ACCEPTANCE_FILTER_5 >> 21) & 0xFF);
|
396 | #endif
|
397 |
|
398 | //Set the acceptance masks
|
399 | RXM0EIDL = (unsigned char)(ACCEPTANCE_MASK_0_1 & 0xFF);
|
400 | RXM0EIDH = (unsigned char)((ACCEPTANCE_MASK_0_1 >> 8) & 0xFF);
|
401 | RXM0SIDL = (unsigned char)((ACCEPTANCE_MASK_0_1 >> 16) & 0x03) | (unsigned char)((ACCEPTANCE_MASK_0_1 >> 13) & 0xE0) | 0x08;
|
402 | RXM0SIDH = (unsigned char)((ACCEPTANCE_MASK_0_1 >> 21) & 0xFF);
|
403 | RXM1EIDL = (unsigned char)(ACCEPTANCE_MASK_2_5 & 0xFF);
|
404 | RXM1EIDH = (unsigned char)((ACCEPTANCE_MASK_2_5 >> 8) & 0xFF);
|
405 | RXM1SIDL = (unsigned char)((ACCEPTANCE_MASK_2_5 >> 16) & 0x03) | (unsigned char)((ACCEPTANCE_MASK_2_5 >> 13) & 0xE0) | 0x08;
|
406 | RXM1SIDH = (unsigned char)((ACCEPTANCE_MASK_2_5 >> 21) & 0xFF);
|
407 |
|
408 | CIOCON = 0x20; //Drive TX pin Vdd when recessive, disable capture
|
409 |
|
410 | #ifdef CAN_LOW_INT
|
411 | IPR3 = 0x00;
|
412 | #else
|
413 | IPR3 = 0xFF;
|
414 | #endif
|
415 |
|
416 | #ifdef USE_LOOPBACK_MODE
|
417 | CANCON = (LOOPBACK_MODE & MODE_MASK) | (CANCON & (MODE_MASK ^ 0xFF)); //Set loopback mode for debug purposes only
|
418 | while((CANSTAT & MODE_MASK) != (LOOPBACK_MODE & MODE_MASK)); //Wait until loopback mode is set
|
419 | #else
|
420 | CANCON = (NORMAL_MODE & MODE_MASK) | (CANCON & (MODE_MASK ^ 0xFF)); //Set normal mode
|
421 | while((CANSTAT & MODE_MASK) != (NORMAL_MODE & MODE_MASK)); //Wait until normal mode is set
|
422 | #endif
|
423 | PIE3 = CAN_INT_BITS & 0xE3; //Enable CAN interrupts except TX interrupts
|
424 | // PIR3 = 0x18; //Set TXB1 & TXB2 int flags
|
425 | PIR3 = 0x0; //Set TXB1 & TXB2 int flags
|
426 |
|
427 | //Send my address to notify our presence
|
428 | #ifdef MY_ADDRESS_IS_STANDARD
|
429 | TXB0SIDL = (unsigned char)(MY_ADDRESS_IDENTIFIER << 5);
|
430 | TXB0SIDH = (unsigned char)(MY_ADDRESS_IDENTIFIER >> 3); //Load address with MY_ADDRESS_IDENTIFIER standard identifier
|
431 | TXB0DLC = 0x00; //0 data bytes to send
|
432 | TXB0CON = 0x00; //Initiate transmission
|
433 | TXB0REQ = 1;
|
434 | #else
|
435 | TXB0EIDL = (unsigned char)(MY_ADDRESS_IDENTIFIER & 0xFF); //Load address with MY_ADDRESS_IDENTIFIER extended identifier
|
436 | TXB0EIDH = (unsigned char)((MY_ADDRESS_IDENTIFIER >> 8) & 0xFF);
|
437 | TXB0SIDL = (unsigned char)((MY_ADDRESS_IDENTIFIER >> 16) & 0x03) | (unsigned char)((ACCEPTANCE_FILTER_2 >> 13) & 0xE0) | 0x08;
|
438 | TXB0SIDH = (unsigned char)((MY_ADDRESS_IDENTIFIER >> 21) & 0xFF);
|
439 | TXB0DLC = 0x00; //0 data bytes to send
|
440 | TXB0CON = 0x00; //Initiate transmission
|
441 | TXB0REQ = 1;
|
442 | #endif
|
443 |
|
444 | return 0;
|
445 | }
|
446 |
|
447 |
|
448 | /*********************************************************************
|
449 | * Function: void CANISR(void)
|
450 | *
|
451 | * PreCondition: None
|
452 | *
|
453 | * Input: None
|
454 | *
|
455 | * Output: None
|
456 | *
|
457 | * Side Effects: Will modify the RX/TX interrupt flags
|
458 | * and interrupt enable bits
|
459 | *
|
460 | * Overview: Checks if a CAN reception/transmission was complete
|
461 | * and if so write/read to the CAN RX/TX FIFO buffers
|
462 | *
|
463 | * Note: This function is supposed to be called from the ISR
|
464 | ********************************************************************/
|
465 | void CANISR(void)
|
466 | {
|
467 | unsigned char TempCANCON;
|
468 |
|
469 | if(PIR3 & PIE3)
|
470 | {
|
471 | TempCANCON = CANCON;
|
472 |
|
473 | if(RXB0IF && RXB0IE)
|
474 | {
|
475 | RXB0IF = 0; //Clear interrupt flag
|
476 | CANCON = CANCON & 0xF0 | RXB0Interrupt;
|
477 | CANGetMessage();
|
478 | }
|
479 | else if(RXB1IF && RXB1IE)
|
480 | {
|
481 | RXB1IF = 0; //Clear interrupt flag
|
482 | CANCON = CANCON & 0xF0 | RXB1Interrupt;
|
483 | CANGetMessage();
|
484 | }
|
485 | else if(TXB0IF && TXB0IE)
|
486 | {
|
487 | CANCON = CANCON & 0xF0 | TXB0Interrupt;
|
488 | if(CANPutMessage())
|
489 | TXB0IE = 0;
|
490 | else
|
491 | TXB0IF = 0;
|
492 | }
|
493 | else if(TXB1IF && TXB1IE)
|
494 | {
|
495 | CANCON = CANCON & 0xF0 | TXB1Interrupt;
|
496 | if(CANPutMessage())
|
497 | TXB1IE = 0;
|
498 | else
|
499 | TXB1IF = 0;
|
500 | }
|
501 | else if(TXB2IF && TXB2IE)
|
502 | {
|
503 | CANCON = CANCON & 0xF0 | TXB2Interrupt;
|
504 | if(CANPutMessage()) //if there wasn't any more messages to send
|
505 | TXB2IE = 0; //disable interrupts for TXB2 and leave TXB2IF
|
506 | else //still on so PutCAN() can reenable the interrupt and instantly vector to ISR
|
507 | TXB2IF = 0; //message was sent, just clear the interrupt flag.
|
508 | }
|
509 | else if(ERRIF && ERRIE)
|
510 | {
|
511 | ERRIF = 0; //Clear interrupt flag
|
512 | #ifdef CAN_ERROR_HANDLER_ENABLE
|
513 | CANErrorHandler();
|
514 | #endif
|
515 | //No error handler implemented!!!
|
516 | }
|
517 | else if(WAKIF && WAKIE)
|
518 | {
|
519 | WAKIF = 0; //Clear interrupt flag
|
520 | }
|
521 |
|
522 | CANCON = TempCANCON;
|
523 | }
|
524 | }
|
525 |
|
526 |
|
527 | /*********************************************************************
|
528 | * Function: void CANGetMessage(void)
|
529 | *
|
530 | * PreCondition: <WIN2:WIN0> in the CANCON register has to set
|
531 | * to reflect the desired RXB registers
|
532 | *
|
533 | * Input: None
|
534 | *
|
535 | * Output: None
|
536 | *
|
537 | * Side Effects: Will modify the RX FIFO Write pointer (RXWPtr)
|
538 | *
|
539 | * Overview: Gets the registers for a RXB and puts them in the
|
540 | * CAN Receive buffer
|
541 | *
|
542 | * Note: Care is not taken if buffer is full
|
543 | ********************************************************************/
|
544 | void CANGetMessage(void)
|
545 | {
|
546 | unsigned char i;
|
547 | if(++RXWPtr >= RXBUF) //If pointer overflowed
|
548 | RXWPtr = 0; //Clear it
|
549 |
|
550 | for(i=0;i<14;i++)
|
551 | {
|
552 | RXMessage[RXWPtr].Data[i] = *(unsigned char *)(0xF60+i);
|
553 | }
|
554 | RXB0FUL = 0;
|
555 | }
|
556 |
|
557 |
|
558 | /*********************************************************************
|
559 | * Function: char CANPutMessage(void)
|
560 | *
|
561 | * PreCondition: <WIN2:WIN0> in the CANCON register has to set
|
562 | * to reflect the desired TXB registers
|
563 | *
|
564 | * Input: None
|
565 | *
|
566 | * Output: 0 -> A new message has been put in the transmit queue
|
567 | * 1 -> There was no messages in the TX buffer to send
|
568 | *
|
569 | * Side Effects: Will modify the TX buffer´s Read pointer (TXRPtr)
|
570 | *
|
571 | * Overview: Checks if there is any messages to transmit and if so
|
572 | * place it in the registers reflected by <WIN2:WIN0>
|
573 | *
|
574 | * Note: None
|
575 | ********************************************************************/
|
576 | char CANPutMessage(void)
|
577 | {
|
578 | unsigned char i;
|
579 | if(TXWPtr != TXRPtr) //If there are any more data to send
|
580 | {
|
581 | if(++TXRPtr >= TXBUF) //then increment the TX read pointer
|
582 | TXRPtr = 0;
|
583 | for(i=0;i<14;i++)
|
584 | *(unsigned char *)(0xF60+i) = TXMessage[TXRPtr].Data[i];
|
585 | RXB0RTRRO = 1; //TXREQ = 1;
|
586 | return 0;
|
587 | }
|
588 | else
|
589 | return 1;
|
590 | }
|
591 |
|
592 |
|
593 | /*********************************************************************
|
594 | * Function: char CANPut(struct CANMessage Message)
|
595 | *
|
596 | * PreCondition: None
|
597 | *
|
598 | * Input: A CAN message
|
599 | *
|
600 | * Output: 1 -> Failed to put a CAN on the buffer, buffer is full
|
601 | * 0 -> The CAN message is put on the buffer and will be
|
602 | * transmitted eventually
|
603 | *
|
604 | * Side Effects: Will modify the TX Buffer register´s Write pointer
|
605 | *
|
606 | * Overview: Initially checks if at least one buffer slot is available
|
607 | * and if so push the requested message in the buffer.
|
608 | * Checks if the TX modules are idle and if they are, reactivate one.
|
609 | *
|
610 | * Note: None
|
611 | ********************************************************************/
|
612 | char CANPut(struct CANMessage Message)
|
613 | {
|
614 | unsigned char TempPtr, i;
|
615 | if(TXWPtr == TXRPtr-1 || (TXWPtr == TXBUF-1 && TXRPtr == 0)) //if all transmit buffers are full return 1
|
616 | return 1;
|
617 |
|
618 | //Do not modify the TX pointer until the message has been successfully copied so the CANISR don't
|
619 | //send a message that isn't ready
|
620 | if(TXWPtr >= TXBUF-1) //check if transmit write pointer will overflow
|
621 | {
|
622 | TempPtr = 0; //and post clear write pointer
|
623 | }
|
624 | else
|
625 | {
|
626 | TempPtr = TXWPtr+1; //and postincrement write pointer
|
627 | }
|
628 |
|
629 | if(Message.NoOfBytes > 8) //Ensure we don't handle more than 8 bytes
|
630 | Message.NoOfBytes = 8;
|
631 |
|
632 | TXMessage[TempPtr].Specific.TXBDLC.Byte = Message.NoOfBytes; //Set the data count
|
633 |
|
634 | if(!Message.Remote) //If dataframe
|
635 | {
|
636 | TXMessage[TempPtr].Specific.TXBDLC.Bits.TXRTR = 0; //Clear the Remote Transfer Request bit
|
637 |
|
638 | for(i = 0; i < Message.NoOfBytes; i++) //Load data registers
|
639 | {
|
640 | TXMessage[TempPtr].Specific.TXBD.Array[i] = Message.Data[i];
|
641 | }
|
642 | }
|
643 | else //Remote frame
|
644 | {
|
645 | TXMessage[TempPtr].Specific.TXBDLC.Bits.TXRTR = 1; //Set TXRTR bit
|
646 | }
|
647 | if(Message.Ext) //Extended identifier
|
648 | {
|
649 | TXMessage[TempPtr].Specific.TXBEIDL.Byte = (unsigned char)(Message.Address & 0xFF); // Put address <7:0> in EIDL
|
650 | TXMessage[TempPtr].Specific.TXBEIDH.Byte = (unsigned char)((Message.Address >> 8) & 0xFF); // Put address <15:8> in EIDH
|
651 | TXMessage[TempPtr].Specific.TXBSIDL.Byte = (unsigned char)((Message.Address >> 16) & 0x03) | (unsigned char)((Message.Address >> 13) & 0xE0);
|
652 | TXMessage[TempPtr].Specific.TXBSIDH.Byte = (unsigned char)((Message.Address >> 21) & 0xFF);
|
653 | TXMessage[TempPtr].Specific.TXBSIDL.Bits.EXIDE = 1;
|
654 | }
|
655 | else //Standard identifier
|
656 | {
|
657 | TXMessage[TempPtr].Specific.TXBSIDL.Byte = (unsigned char)((Message.Address << 5) & 0xFF); //Put address <2:0> in SIDL
|
658 | TXMessage[TempPtr].Specific.TXBSIDH.Byte = (unsigned char)((Message.Address >> 3) & 0xFF); //Put address <10:3> in SIDH
|
659 | TXMessage[TempPtr].Specific.TXBSIDL.Bits.EXIDE = 0;
|
660 | }
|
661 | TXMessage[TempPtr].Specific.TXBCON.Byte = Message.Priority & 0x03; //Set the internal priority of the data frame
|
662 |
|
663 | TXWPtr = TempPtr;
|
664 |
|
665 | //Reenable an interrupt if it is idle, it doesn't matter if another TX source caught the pending message
|
666 | //before the source that is enabled here does since the interrupt CHECKS if there are any messages pending
|
667 | //and if the buffer is empty, it will disable itself again.
|
668 | if(!TXB0IE) //TXB0 is idle
|
669 | TXB0IE = 1; //enable TXB0 to fire an interrupt to send the pending message
|
670 | else if(!TXB1IE) //else if TXB1 is idle
|
671 | TXB1IE = 1; //same procedure
|
672 | else if(!TXB2IE) //finally try TXB2
|
673 | TXB2IE = 1;
|
674 |
|
675 | return 0;
|
676 | }
|
677 |
|
678 |
|
679 | /*********************************************************************
|
680 | * Function: char CANRXMessageIsPending(void)
|
681 | *
|
682 | * PreCondition: None
|
683 | *
|
684 | * Input: None
|
685 | *
|
686 | * Output: 1 -> At least one received message is pending in the RX buffer
|
687 | * 0 -> No received messages are pending
|
688 | *
|
689 | * Side Effects: None
|
690 | *
|
691 | * Overview: Checks if the RX Write pointer is equal to RX Read pointer and
|
692 | * if so returns 0, else returns 1
|
693 | *
|
694 | * Note: Since no care is taken if the buffer overflow
|
695 | * this function has to be polled frequently to
|
696 | * prevent a software receive buffer overflow
|
697 | ********************************************************************/
|
698 | char CANRXMessageIsPending(void)
|
699 | {
|
700 | if(RXWPtr != RXRPtr)
|
701 | return 1;
|
702 | else
|
703 | return 0;
|
704 | }
|
705 |
|
706 |
|
707 |
|
708 | /*********************************************************************
|
709 | * Function: struct CANMessage CANGet(void)
|
710 | *
|
711 | * PreCondition: An unread message has to be in the buffer
|
712 | * use RXCANMessageIsPending(void) prior to
|
713 | * calling this function in order to determine
|
714 | * if an unread message is pending.
|
715 | *
|
716 | * Input: None
|
717 | *
|
718 | * Output: The received message
|
719 | *
|
720 | * Side Effects: Will modify the RX Buffer register´s Read pointer
|
721 | *
|
722 | * Overview: Pops the the first message of the RX buffer
|
723 | *
|
724 | * Note: None
|
725 | ********************************************************************/
|
726 | struct CANMessage CANGet(void)
|
727 | {
|
728 | struct CANMessage ReturnMessage;
|
729 | unsigned char TempPtr, i;
|
730 |
|
731 | /*Do not modify the RX pointer until the message has been successfully
|
732 | copied to prevent ISR to overwrite it (Note. this is not implemented in the ISR yet)*/
|
733 | if(RXRPtr >= RXBUF-1) //Check if pointer will overflow
|
734 | {
|
735 | TempPtr = 0;
|
736 | }
|
737 | else
|
738 | {
|
739 | TempPtr = RXRPtr+1;
|
740 | }
|
741 |
|
742 | ReturnMessage.NoOfBytes = RXMessage[TempPtr].Specific.RXBDLC.Byte & 0x0F; //copy data count
|
743 | if(RXMessage[TempPtr].Specific.RXBCON.Bits.RXRTRRO) //Remote frame request
|
744 | {
|
745 | ReturnMessage.Remote = 1;
|
746 | }
|
747 | else //Data frame
|
748 | {
|
749 | ReturnMessage.Remote = 0; //Clear remote flag
|
750 | for(i = 0; i < ReturnMessage.NoOfBytes; i++) //copy data content
|
751 | ReturnMessage.Data[i] = RXMessage[TempPtr].Specific.RXBD.Array[i];
|
752 | }
|
753 | CANCON = CANCON & 0xF0;
|
754 |
|
755 | ReturnMessage.Address = (unsigned int)(RXMessage[TempPtr].Specific.RXBSIDH.Byte) << 3; //Load the standard identifier into the address
|
756 | ReturnMessage.Address |= (RXMessage[TempPtr].Specific.RXBSIDL.Byte >> 5);
|
757 |
|
758 | if(RXMessage[TempPtr].Specific.RXBSIDL.Bits.EXID) //Extended identifier
|
759 | {
|
760 | ReturnMessage.Ext = 1; //Set the extended identifier flag
|
761 | ReturnMessage.Address = (ReturnMessage.Address << 2) | (RXMessage[TempPtr].Specific.RXBSIDL.Byte & 0x03);
|
762 | ReturnMessage.Address = ReturnMessage.Address << 16; //and copy the extended address
|
763 | ReturnMessage.Address |= (unsigned int)(RXMessage[TempPtr].Specific.RXBEIDH.Byte) << 8;
|
764 | ReturnMessage.Address |= RXMessage[TempPtr].Specific.RXBEIDL.Byte;
|
765 | }
|
766 | else //Standard identifier
|
767 | {
|
768 | ReturnMessage.Ext = 0; //clear the extended identifier flag
|
769 | }
|
770 |
|
771 | RXRPtr = TempPtr;
|
772 | return ReturnMessage;
|
773 | }
|
774 |
|
775 |
|
776 | /*********************************************************************
|
777 | * Function: void CANSetMode(unsigned char Mode)
|
778 | *
|
779 | * PreCondition: None
|
780 | *
|
781 | * Input: Desired CAN Mode
|
782 | * (CAN_LISTEN_MODE, CAN_LOOPBACK_MODE
|
783 | * CAN_DISABLE_MODE, CAN_NORMAL_MODE)
|
784 | *
|
785 | * Output: None
|
786 | *
|
787 | * Side Effects: None
|
788 | *
|
789 | * Overview: Requests to set the desired mode and waits until
|
790 | * the mode has been set.
|
791 | *
|
792 | * Note: If USE_LOOPBACK_MODE is defined the requested
|
793 | * mode will be loopback mode if the input is
|
794 | * Normal mode
|
795 | ********************************************************************/
|
796 | void CANSetMode(unsigned char Mode)
|
797 | {
|
798 | #ifdef USE_LOOPBACK_MODE
|
799 | if(Mode == NORMAL_MODE)
|
800 | {
|
801 | CANCON = (LOOPBACK_MODE & MODE_MASK) | (CANCON & (MODE_MASK ^ 0xFF));
|
802 | while((CANSTAT & MODE_MASK) != (LOOPBACK_MODE & MODE_MASK));
|
803 | }
|
804 | else
|
805 | #endif
|
806 | {
|
807 | CANCON = (Mode & MODE_MASK) | (CANCON & (MODE_MASK ^ 0xFF));
|
808 | while((CANSTAT & MODE_MASK) != (Mode & MODE_MASK));
|
809 | }
|
810 |
|
811 | }
|