PIC24 Support Libraries
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pic24_ecan.c
Go to the documentation of this file.
1 /*
2  * "Copyright (c) 2008 Robert B. Reese, Bryan A. Jones, J. W. Bruce ("AUTHORS")"
3  * All rights reserved.
4  * (R. Reese, reese_AT_ece.msstate.edu, Mississippi State University)
5  * (B. A. Jones, bjones_AT_ece.msstate.edu, Mississippi State University)
6  * (J. W. Bruce, jwbruce_AT_ece.msstate.edu, Mississippi State University)
7  *
8  * Permission to use, copy, modify, and distribute this software and its
9  * documentation for any purpose, without fee, and without written agreement is
10  * hereby granted, provided that the above copyright notice, the following
11  * two paragraphs and the authors appear in all copies of this software.
12  *
13  * IN NO EVENT SHALL THE "AUTHORS" BE LIABLE TO ANY PARTY FOR
14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
15  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE "AUTHORS"
16  * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17  *
18  * THE "AUTHORS" SPECIFICALLY DISCLAIMS ANY WARRANTIES,
19  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20  * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21  * ON AN "AS IS" BASIS, AND THE "AUTHORS" HAS NO OBLIGATION TO
22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
23  *
24  * Please maintain this header in its entirety when copying/modifying
25  * these files.
26  *
27  *
28  */
29 
30 #include "pic24_ecan.h"
31 
32 // Only include if this module exists.
33 #if (NUM_ECAN_MODS >= 1)
34 
35 
36 // Documentation for this file. If the \file tag is not present,
37 // this file will not be documented.
38 // Note: place this comment below the #if NUM_ECAN_MODS so Doxygen
39 // will only see it once.
40 /** \file
41  * ECAN support functions. \see pic24_ecan.h for details.
42  */
43 
44 
45 
46 #ifndef ECAN_1TIME_CODE_DEFS
47 
48 /**
49 Format a standard data frame \em u8_n for TX
50 \param p_ecanmsg pointer to message buffer (ECANMSG* )
51 \param u16_id Standard Identifier (11-bit)
52 \param u8_len Number of data bytes in the message
53 */
54 
55 
56 void formatStandardDataFrameECAN (ECANMSG* p_ecanmsg, uint16_t u16_id, uint8_t u8_len) {
57  p_ecanmsg->w0.IDE = 0;
58  p_ecanmsg->w0.SRR = 0;
59  p_ecanmsg->w0.SID = u16_id;
60  p_ecanmsg->w1.EID17_6 = 0;
61  p_ecanmsg->w2.EID5_0 = 0;
62  p_ecanmsg->w2.RTR = 0;
63  p_ecanmsg->w2.RB1 = 0;
64  p_ecanmsg->w2.RB0 = 0;
65  p_ecanmsg->w2.DLC = u8_len; //length of the message
66 }
67 
68 
69 /**
70 Format an extended data frame \em u8_n for TX
71 \param p_ecanmsg pointer to message buffer (ECANMSG* )
72 \param u32_id Standard Identifier (11-bit)
73 \param u8_len Number of data bytes in the message
74 */
75 
76 void formatExtendedDataFrameECAN (ECANMSG* p_ecanmsg, uint32_t u32_id, uint8_t u8_len) {
77 
78  p_ecanmsg->w0.IDE = 1;
79  p_ecanmsg->w0.SRR = 0;
80  p_ecanmsg->w0.SID = (u32_id >> 18) & 0x7FF;
81  p_ecanmsg->w1.EID17_6 = (u32_id >> 6) & 0xFFF;
82  p_ecanmsg->w2.EID5_0 = u32_id & 0x3F;
83  p_ecanmsg->w2.RTR = 0;
84  p_ecanmsg->w2.RB1 = 0;
85  p_ecanmsg->w2.RB0 = 0;
86  p_ecanmsg->w2.DLC = u8_len; //length of the message
87 }
88 
89 /**
90 Extract the 29-bit message id from an extended data frame
91 \param p_ecanmsg pointer to RX message buffer (ECANMSG* )
92 \return 29-bit message id
93 */
94 
95 uint32_t getIdExtendedDataFrameECAN (ECANMSG* p_ecanmsg) {
96  uint32_t u32_id, u32_tmp;
97  u32_tmp = p_ecanmsg->w0.SID;
98  u32_id = u32_tmp << 18;
99  u32_tmp = p_ecanmsg->w1.EID17_6;
100  u32_id = u32_id | (u32_tmp << 6) | p_ecanmsg->w2.EID5_0;
101  return u32_id;
102 }
103 
104 #define ECAN_1TIME_CODE_DEFS
105 #endif
106 
107 /**
108 Configure ECANx peripheral to run at 1Mbps.
109 
110 \todo Get this working on the E family. Current code is broken.
111 */
112 void configBaudECAN1(void) {
113 #ifdef __dsPIC33E__
114  // Microchip added CANCKS to the CiCTRL1 registers for the dsPIC33E family in
115  // March 2011. This bit has a different meaning from the CANCKS bit that was
116  // removed from the datasheets in the older PIC24/dsPIC families.
117  //
118  // Set the ECAN Module Clock to FCY
119  C1CTRL1bits.CANCKS = ECAN_FCAN_IS_FP;
120 #endif
121 
122 #if FCY == GET_FCY(FRCPLL_FCY40MHz) // <- This needs to be reverified! - rnn13
123  // Clock config taken from the PIC24H FRM ECAN datasheet (DS70226B,
124  // Example 21-9). Produces data rate of 1 Mbps assuming FCY = 40 MHz,
125  // quanta = 20, Prescale = 2.
126  //
127  // FCAN = FCY = 40 MHz, TQ = 20. Prescale = 2.
128  // CAN Data Rate = FCAN/(TQ * pre) = 40MHz/40 = 1 MBps.
129  // 20 TQ for a bit time. 20 = Sync(1) + Seg1 (8) + Seg2 (6) + Prop seg (5)
130  C1CFG2 = ECAN_NO_WAKEUP |
131  ECAN_SAMPLE_3TIMES | //sample three times at sample point
132  ECAN_SEG1PH_8TQ | //seg1 = 8 TQ
133  ECAN_SEG2_PROGRAMMABLE | //seg2 is programmable
134  ECAN_SEG2PH_6TQ | //seg2 = 6 TQ
135  ECAN_PRSEG_5TQ; //propagation delay segment = 5 TQ
136 
137  C1CFG1 = ECAN_SYNC_JUMP_4 | //use maximum sync jump width
138  ECAN_PRE_2x1; //prescalers to 2x1 = 2
139 
140 #elif FCY == GET_FCY(FRCPLL_FCY60MHz)
141  // As of April 2015, this section is still under development and has not
142  // been proven functional.
143  //
144  // What seems to be missing: per DS70353C, page 21-33, the peripheral starts
145  // up in configuration mode. This code never switches it to normal operation
146  // mode. The sample code in DS70353C, page 21-35 to 26 does this. It also
147  // configures several other parts of the CAN and DMA before switching to
148  // normal mode. This will probably take some re-writing to sandwitch all the
149  // config code (spread over this function and at least the
150  // configTxRxBufferECAN1) with the switch to config / switch to normal
151  // sequence.
152  //
153  // FCAN = FCY = 60 MHz, Use TQ = 15, Prescale = 4.
154  // CAN Data Rate = FCAN/(TQ * Prescale) = 60MHz/60 = 1 MBps.
155  // Bit Time 15TQ = SyncSeg(1) + PropSeg(4) + Seg1(4) + Seg2 (6)
156  C1CFG2 = ECAN_NO_WAKEUP |
157  ECAN_SAMPLE_3TIMES | //sample three times at sample point
158  ECAN_SEG1PH_4TQ | //seg1 = 4 TQ
159  ECAN_SEG2_PROGRAMMABLE | //seg2 is programmable
160  ECAN_SEG2PH_6TQ | //seg2 = 6 TQ
161  ECAN_PRSEG_4TQ; //propagation delay segment = 4 TQ
162 
163  C1CFG1 = ECAN_SYNC_JUMP_4 | //use maximum sync jump width
164  ECAN_PRE_2x2; //prescalers to 2x2 = 4
165 #else
166 #warning "ECAN module not configured for current processor frequency! Edit function configECAN1()."
167 #endif
168 }
169 
170 
171 /**
172 Clear full bit of buffer \em u8_bufNum
173 \param u8_bufNum buffer number of full bit to clear (0 to 31)
174 */
175 
176 void clrRxFullFlagECAN1(uint8_t u8_bufNum) {
177  u8_bufNum &= 0x1F; //0-31
178  if (u8_bufNum > 15) {
179  u8_bufNum = u8_bufNum - 16;
180  C1RXFUL2 = C1RXFUL2 & ~(1<<u8_bufNum);
181  } else {
182  C1RXFUL1 = C1RXFUL1 & ~(1<<u8_bufNum);
183  }
184 }
185 
186 /**
187 Get full bit of buffer \em u8_bufNum, zero if empty, non-zero if ull
188 \param u8_bufNum buffer number of full bit to read(0 to 31)
189 */
190 
192  u8_bufNum &= 0x1F; //0-31
193  if (u8_bufNum > 15) {
194  u8_bufNum = u8_bufNum - 16;
195  return(C1RXFUL2 & (1<<u8_bufNum));
196  } else {
197  return(C1RXFUL1 & (1<<u8_bufNum));
198  }
199 }
200 
201 /**
202 Operation: Clear all of the full and overflow RX flags.
203 */
205  C1RXFUL1=0x0000;
206  C1RXFUL2=0x0000;
207  C1RXOVF1=0x0000;
208  C1RXOVF2=0x0000;
209 }
210 
211 /**
212 Configure a buffer as either RX or TX buffer, only has to be done for first 8 buffers.
213 \param u8_bufNum buffer number (0 to 7)
214 \param u8_type buffer type (0 - receive, 1 transmit)
215 \param u8_priority only used for TX, priority (0-3)
216 */
217 void configTxRxBufferECAN1(uint8_t u8_bufNum, uint8_t u8_type, uint8_t u8_priority ) {
218  u8_bufNum &= 0x07; //0-7
219  switch (u8_bufNum) {
220  case 0:
221  C1TR01CONbits.TXEN0 = u8_type;
222  C1TR01CONbits.TX0PRI = u8_priority;
223  break;
224  case 1:
225  C1TR01CONbits.TXEN1 = u8_type;
226  C1TR01CONbits.TX1PRI = u8_priority;
227  break;
228  case 2:
229  C1TR23CONbits.TXEN2 = u8_type;
230  C1TR23CONbits.TX2PRI = u8_priority;
231  break;
232  case 3:
233  C1TR23CONbits.TXEN3 = u8_type;
234  C1TR23CONbits.TX3PRI = u8_priority;
235  break;
236  case 4:
237  C1TR45CONbits.TXEN4 = u8_type;
238  C1TR45CONbits.TX4PRI = u8_priority;
239  break;
240  case 5:
241  C1TR45CONbits.TXEN5 = u8_type;
242  C1TR45CONbits.TX5PRI = u8_priority;
243  break;
244  case 6:
245  C1TR67CONbits.TXEN6 = u8_type;
246  C1TR67CONbits.TX6PRI = u8_priority;
247  break;
248  default:
249  C1TR67CONbits.TXEN7 = u8_type;
250  C1TR67CONbits.TX7PRI = u8_priority;
251  break;
252  }
253 }
254 
255 /**
256 Start Transmit for buffer \em u8_bufNum
257 \param u8_bufNum buffer number (0 to 7)
258 **/
259 void startTxECAN1(uint8_t u8_bufNum) {
260  u8_bufNum &= 0x07; //0-7
261  switch (u8_bufNum) {
262  case 0:
263  C1TR01CONbits.TXREQ0 = 1;
264  break;
265  case 1:
266  C1TR01CONbits.TXREQ1 = 1;
267  break;
268  case 2:
269  C1TR23CONbits.TXREQ2 = 1;
270  break;
271  case 3:
272  C1TR23CONbits.TXREQ3 = 1;
273  break;
274  case 4:
275  C1TR45CONbits.TXREQ4 = 1;;
276  break;
277  case 5:
278  C1TR45CONbits.TXREQ5 = 1;
279  break;
280  case 6:
281  C1TR67CONbits.TXREQ6 = 1;
282  break;
283  default:
284  C1TR67CONbits.TXREQ7 = 1;
285  break;
286  }
287 }
288 
289 /**
290 Start Transmit for buffer \em u8_bufNum
291 \param u8_bufNum buffer number (0 to 7)
292 **/
294  u8_bufNum &= 0x07; //0-7
295  switch (u8_bufNum) {
296  case 0:
297  return(C1TR01CONbits.TXREQ0);
298  case 1:
299  return(C1TR01CONbits.TXREQ1);
300  case 2:
301  return(C1TR23CONbits.TXREQ2);
302  case 3:
303  return(C1TR23CONbits.TXREQ3);
304  case 4:
305  return(C1TR45CONbits.TXREQ4);
306  case 5:
307  return(C1TR45CONbits.TXREQ5);
308  case 6:
309  return(C1TR67CONbits.TXREQ6);
310  default:
311  return(C1TR67CONbits.TXREQ7);
312  }
313 }
314 
315 
316 
317 
318 /**
319 Configure an acceptance Filter
320 \param u8_filtNum filter number (0 to 15)
321 \param u32_id identifier, either SID (11 bits) or EID (29 bits)
322 \param u8_idType ID type (0: SID, nonzero: EID)
323 \param u8_bufnum RX buffer (0-14) to use for filter , if 15, then use FIFO
324 \param u8_maskReg Mask register (0-2) to use for filter
325 */
326 void configRxFilterECAN1(uint8_t u8_filtNum, uint32_t u32_id, uint8_t u8_idType, uint8_t u8_bufnum, uint8_t u8_maskReg) {
327  uint16_t *pu16_CxRXFySID,*pu16_CxRXFyEID, *pu16_CxFMSKSEL1, *pu16_CxBUFPNT1;
328  uint16_t u16_sid;
329  uint16_t u16_eid15_0;
330  uint16_t u16_eid17_16;
331  uint16_t u16_mask;
332  uint8_t u8_startPos;
333 
334  u8_filtNum &= 0xF; //0-15
335  u8_bufnum &= 0xF; //0-15
336  u8_maskReg &= 0x07; //0-7
337 
338  pu16_CxRXFySID = (uint16_t*) &C1RXF0SID + (u8_filtNum << 1);
339  pu16_CxRXFyEID = pu16_CxRXFySID + 1;
340  pu16_CxFMSKSEL1 = (uint16_t*) &C1FMSKSEL1 + (u8_filtNum >> 3);
341  pu16_CxBUFPNT1 = (uint16_t*) &C1BUFPNT1 + (u8_filtNum >> 2);
342 
343  C1CTRL1bits.WIN=1; //select filter register window
344 
345 //write to the CxRXFySID, CxRXFyEID registers
346  if(u8_idType) { // EID
347  u16_sid = (u32_id >> 18) & 0x7FF;
348  u16_eid17_16 = (u32_id >>16) & 0x3;
349  u16_eid15_0 = u32_id & 0xFFFF;
350  *pu16_CxRXFySID =(u16_sid <<5) | ECAN_MATCH_EID | u16_eid17_16;
351  *pu16_CxRXFyEID = u16_eid15_0;
352  } else { //SID
353  u16_sid = u32_id & 0x7FF;
354  *pu16_CxRXFySID = u16_sid <<5;
355  *pu16_CxRXFyEID = 0;
356  }
357 
358 //point the filter to the RX buffer (modify CxBUFPNT1 register)
359  u8_startPos = 4 * (u8_filtNum & 0x3); //starting bit position to mask
360  u16_mask = ~ ( 0xF << u8_startPos);
361  *pu16_CxBUFPNT1 = (*pu16_CxBUFPNT1 & u16_mask) | (u8_bufnum << u8_startPos);
362 
363 //point the filter to the mask register (modify CxFMSKSEL1 register)
364  u8_startPos = 2 * (u8_filtNum & 0x7);
365  u16_mask = ~ ( 0x3 << u8_startPos);
366  *pu16_CxFMSKSEL1 = (*pu16_CxFMSKSEL1 & u16_mask) | (u8_maskReg << u8_startPos);
367 
368  C1FEN1 = C1FEN1 | (1 << u8_filtNum) ; // Enable the filter
369 
370  C1CTRL1bits.WIN=0;
371 
372 }
373 
374 /**
375 Configure an acceptance MASK
376 \param u8_maskNum mask number (0 to 3; 0 to 2 specifies mask register, 3 then no mask is used)
377 \param u32_idMask mask for the identifier, either SID mask (11 bits) or EID mask (29 bits)
378 \param u8_idType ID type (0: SID, nonzero: EID)
379 \param u8_matchType Match type; if zero match either SID or EID addresses if filter matches
380 (i.e, match if (Filter SID == Message SID) || (Filter SID:EID = Message SID:EID)) )
381 If nonzero, match only message types as specified by the filter (either SID or SID:EID).
382 */
383 
384 void configRxMaskECAN1(uint8_t u8_maskNum, uint32_t u32_idMask, uint8_t u8_idType, uint8_t u8_matchType) {
385  uint16_t *pu16_CxRXMySID,*pu16_CxRXMyEID;
386  uint16_t u16_msid;
387  uint16_t u16_meid15_0;
388  uint16_t u16_meid17_16;
389 
390  pu16_CxRXMySID =(uint16_t*) &C1RXM0SID + (u8_maskNum << 1);
391  pu16_CxRXMyEID = pu16_CxRXMySID + 1;
392 
393  C1CTRL1bits.WIN=1; //select filter register window
394 
395 //write to the CxRXMySID, CxRXMyEID registers
396  if(u8_idType) { // EID
397  u16_msid = (u32_idMask >> 18) & 0x7FF;
398  u16_meid17_16 = (u32_idMask >>16) & 0x3;
399  u16_meid15_0 = u32_idMask & 0xFFFF;
400  if (u8_matchType) *pu16_CxRXMySID =(u16_msid <<5) | ECAN_MATCH_EID | u16_meid17_16;
401  else *pu16_CxRXMySID =(u16_msid <<5) | u16_meid17_16;
402  *pu16_CxRXMyEID = u16_meid15_0;
403  } else {
404  u16_msid = u32_idMask & 0x7FF;
405  if (u8_matchType) *pu16_CxRXMySID = (u16_msid <<5) | ECAN_MATCH_EID ;
406  else *pu16_CxRXMySID = (u16_msid <<5);
407  *pu16_CxRXMyEID = 0;
408  }
409  C1CTRL1bits.WIN=0;
410 }
411 
412 #endif // #if (NUM_ECAN_MODS >= ${x})
413 
414 
415 
416 
417 
418 /*
419  * "Copyright (c) 2008 Robert B. Reese, Bryan A. Jones, J. W. Bruce ("AUTHORS")"
420  * All rights reserved.
421  * (R. Reese, reese_AT_ece.msstate.edu, Mississippi State University)
422  * (B. A. Jones, bjones_AT_ece.msstate.edu, Mississippi State University)
423  * (J. W. Bruce, jwbruce_AT_ece.msstate.edu, Mississippi State University)
424  *
425  * Permission to use, copy, modify, and distribute this software and its
426  * documentation for any purpose, without fee, and without written agreement is
427  * hereby granted, provided that the above copyright notice, the following
428  * two paragraphs and the authors appear in all copies of this software.
429  *
430  * IN NO EVENT SHALL THE "AUTHORS" BE LIABLE TO ANY PARTY FOR
431  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
432  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE "AUTHORS"
433  * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
434  *
435  * THE "AUTHORS" SPECIFICALLY DISCLAIMS ANY WARRANTIES,
436  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
437  * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
438  * ON AN "AS IS" BASIS, AND THE "AUTHORS" HAS NO OBLIGATION TO
439  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
440  *
441  * Please maintain this header in its entirety when copying/modifying
442  * these files.
443  *
444  *
445  */
446 
447 #include "pic24_ecan.h"
448 
449 // Only include if this module exists.
450 #if (NUM_ECAN_MODS >= 2)
451 
452 
453 // Documentation for this file. If the \file tag is not present,
454 // this file will not be documented.
455 // Note: place this comment below the #if NUM_ECAN_MODS so Doxygen
456 // will only see it once.
457 /** \file
458  * ECAN support functions. \see pic24_ecan.h for details.
459  */
460 
461 
462 
463 #ifndef ECAN_1TIME_CODE_DEFS
464 
465 /**
466 Format a standard data frame \em u8_n for TX
467 \param p_ecanmsg pointer to message buffer (ECANMSG* )
468 \param u16_id Standard Identifier (11-bit)
469 \param u8_len Number of data bytes in the message
470 */
471 
472 
473 void formatStandardDataFrameECAN (ECANMSG* p_ecanmsg, uint16_t u16_id, uint8_t u8_len) {
474  p_ecanmsg->w0.IDE = 0;
475  p_ecanmsg->w0.SRR = 0;
476  p_ecanmsg->w0.SID = u16_id;
477  p_ecanmsg->w1.EID17_6 = 0;
478  p_ecanmsg->w2.EID5_0 = 0;
479  p_ecanmsg->w2.RTR = 0;
480  p_ecanmsg->w2.RB1 = 0;
481  p_ecanmsg->w2.RB0 = 0;
482  p_ecanmsg->w2.DLC = u8_len; //length of the message
483 }
484 
485 
486 /**
487 Format an extended data frame \em u8_n for TX
488 \param p_ecanmsg pointer to message buffer (ECANMSG* )
489 \param u32_id Standard Identifier (11-bit)
490 \param u8_len Number of data bytes in the message
491 */
492 
493 void formatExtendedDataFrameECAN (ECANMSG* p_ecanmsg, uint32_t u32_id, uint8_t u8_len) {
494 
495  p_ecanmsg->w0.IDE = 1;
496  p_ecanmsg->w0.SRR = 0;
497  p_ecanmsg->w0.SID = (u32_id >> 18) & 0x7FF;
498  p_ecanmsg->w1.EID17_6 = (u32_id >> 6) & 0xFFF;
499  p_ecanmsg->w2.EID5_0 = u32_id & 0x3F;
500  p_ecanmsg->w2.RTR = 0;
501  p_ecanmsg->w2.RB1 = 0;
502  p_ecanmsg->w2.RB0 = 0;
503  p_ecanmsg->w2.DLC = u8_len; //length of the message
504 }
505 
506 /**
507 Extract the 29-bit message id from an extended data frame
508 \param p_ecanmsg pointer to RX message buffer (ECANMSG* )
509 \return 29-bit message id
510 */
511 
512 uint32_t getIdExtendedDataFrameECAN (ECANMSG* p_ecanmsg) {
513  uint32_t u32_id, u32_tmp;
514  u32_tmp = p_ecanmsg->w0.SID;
515  u32_id = u32_tmp << 18;
516  u32_tmp = p_ecanmsg->w1.EID17_6;
517  u32_id = u32_id | (u32_tmp << 6) | p_ecanmsg->w2.EID5_0;
518  return u32_id;
519 }
520 
521 #define ECAN_1TIME_CODE_DEFS
522 #endif
523 
524 /**
525 Configure ECANx peripheral to run at 1Mbps.
526 
527 \todo Get this working on the E family. Current code is broken.
528 */
529 void configBaudECAN2(void) {
530 #ifdef __dsPIC33E__
531  // Microchip added CANCKS to the CiCTRL1 registers for the dsPIC33E family in
532  // March 2011. This bit has a different meaning from the CANCKS bit that was
533  // removed from the datasheets in the older PIC24/dsPIC families.
534  //
535  // Set the ECAN Module Clock to FCY
536  C2CTRL1bits.CANCKS = ECAN_FCAN_IS_FP;
537 #endif
538 
539 #if FCY == GET_FCY(FRCPLL_FCY40MHz) // <- This needs to be reverified! - rnn13
540  // Clock config taken from the PIC24H FRM ECAN datasheet (DS70226B,
541  // Example 21-9). Produces data rate of 1 Mbps assuming FCY = 40 MHz,
542  // quanta = 20, Prescale = 2.
543  //
544  // FCAN = FCY = 40 MHz, TQ = 20. Prescale = 2.
545  // CAN Data Rate = FCAN/(TQ * pre) = 40MHz/40 = 1 MBps.
546  // 20 TQ for a bit time. 20 = Sync(1) + Seg1 (8) + Seg2 (6) + Prop seg (5)
547  C2CFG2 = ECAN_NO_WAKEUP |
548  ECAN_SAMPLE_3TIMES | //sample three times at sample point
549  ECAN_SEG1PH_8TQ | //seg1 = 8 TQ
550  ECAN_SEG2_PROGRAMMABLE | //seg2 is programmable
551  ECAN_SEG2PH_6TQ | //seg2 = 6 TQ
552  ECAN_PRSEG_5TQ; //propagation delay segment = 5 TQ
553 
554  C2CFG1 = ECAN_SYNC_JUMP_4 | //use maximum sync jump width
555  ECAN_PRE_2x1; //prescalers to 2x1 = 2
556 
557 #elif FCY == GET_FCY(FRCPLL_FCY60MHz)
558  // As of April 2015, this section is still under development and has not
559  // been proven functional.
560  //
561  // What seems to be missing: per DS70353C, page 21-33, the peripheral starts
562  // up in configuration mode. This code never switches it to normal operation
563  // mode. The sample code in DS70353C, page 21-35 to 26 does this. It also
564  // configures several other parts of the CAN and DMA before switching to
565  // normal mode. This will probably take some re-writing to sandwitch all the
566  // config code (spread over this function and at least the
567  // configTxRxBufferECAN2) with the switch to config / switch to normal
568  // sequence.
569  //
570  // FCAN = FCY = 60 MHz, Use TQ = 15, Prescale = 4.
571  // CAN Data Rate = FCAN/(TQ * Prescale) = 60MHz/60 = 1 MBps.
572  // Bit Time 15TQ = SyncSeg(1) + PropSeg(4) + Seg1(4) + Seg2 (6)
573  C2CFG2 = ECAN_NO_WAKEUP |
574  ECAN_SAMPLE_3TIMES | //sample three times at sample point
575  ECAN_SEG1PH_4TQ | //seg1 = 4 TQ
576  ECAN_SEG2_PROGRAMMABLE | //seg2 is programmable
577  ECAN_SEG2PH_6TQ | //seg2 = 6 TQ
578  ECAN_PRSEG_4TQ; //propagation delay segment = 4 TQ
579 
580  C2CFG1 = ECAN_SYNC_JUMP_4 | //use maximum sync jump width
581  ECAN_PRE_2x2; //prescalers to 2x2 = 4
582 #else
583 #warning "ECAN module not configured for current processor frequency! Edit function configECAN1()."
584 #endif
585 }
586 
587 
588 /**
589 Clear full bit of buffer \em u8_bufNum
590 \param u8_bufNum buffer number of full bit to clear (0 to 31)
591 */
592 
593 void clrRxFullFlagECAN2(uint8_t u8_bufNum) {
594  u8_bufNum &= 0x1F; //0-31
595  if (u8_bufNum > 15) {
596  u8_bufNum = u8_bufNum - 16;
597  C2RXFUL2 = C2RXFUL2 & ~(1<<u8_bufNum);
598  } else {
599  C2RXFUL1 = C2RXFUL1 & ~(1<<u8_bufNum);
600  }
601 }
602 
603 /**
604 Get full bit of buffer \em u8_bufNum, zero if empty, non-zero if ull
605 \param u8_bufNum buffer number of full bit to read(0 to 31)
606 */
607 
608 uint8_t getRxFullFlagECAN2(uint8_t u8_bufNum) {
609  u8_bufNum &= 0x1F; //0-31
610  if (u8_bufNum > 15) {
611  u8_bufNum = u8_bufNum - 16;
612  return(C2RXFUL2 & (1<<u8_bufNum));
613  } else {
614  return(C2RXFUL1 & (1<<u8_bufNum));
615  }
616 }
617 
618 /**
619 Operation: Clear all of the full and overflow RX flags.
620 */
621 void clrRxFullOvfFlagsECAN2(void) {
622  C2RXFUL1=0x0000;
623  C2RXFUL2=0x0000;
624  C2RXOVF1=0x0000;
625  C2RXOVF2=0x0000;
626 }
627 
628 /**
629 Configure a buffer as either RX or TX buffer, only has to be done for first 8 buffers.
630 \param u8_bufNum buffer number (0 to 7)
631 \param u8_type buffer type (0 - receive, 1 transmit)
632 \param u8_priority only used for TX, priority (0-3)
633 */
634 void configTxRxBufferECAN2(uint8_t u8_bufNum, uint8_t u8_type, uint8_t u8_priority ) {
635  u8_bufNum &= 0x07; //0-7
636  switch (u8_bufNum) {
637  case 0:
638  C2TR01CONbits.TXEN0 = u8_type;
639  C2TR01CONbits.TX0PRI = u8_priority;
640  break;
641  case 1:
642  C2TR01CONbits.TXEN1 = u8_type;
643  C2TR01CONbits.TX1PRI = u8_priority;
644  break;
645  case 2:
646  C2TR23CONbits.TXEN2 = u8_type;
647  C2TR23CONbits.TX2PRI = u8_priority;
648  break;
649  case 3:
650  C2TR23CONbits.TXEN3 = u8_type;
651  C2TR23CONbits.TX3PRI = u8_priority;
652  break;
653  case 4:
654  C2TR45CONbits.TXEN4 = u8_type;
655  C2TR45CONbits.TX4PRI = u8_priority;
656  break;
657  case 5:
658  C2TR45CONbits.TXEN5 = u8_type;
659  C2TR45CONbits.TX5PRI = u8_priority;
660  break;
661  case 6:
662  C2TR67CONbits.TXEN6 = u8_type;
663  C2TR67CONbits.TX6PRI = u8_priority;
664  break;
665  default:
666  C2TR67CONbits.TXEN7 = u8_type;
667  C2TR67CONbits.TX7PRI = u8_priority;
668  break;
669  }
670 }
671 
672 /**
673 Start Transmit for buffer \em u8_bufNum
674 \param u8_bufNum buffer number (0 to 7)
675 **/
676 void startTxECAN2(uint8_t u8_bufNum) {
677  u8_bufNum &= 0x07; //0-7
678  switch (u8_bufNum) {
679  case 0:
680  C2TR01CONbits.TXREQ0 = 1;
681  break;
682  case 1:
683  C2TR01CONbits.TXREQ1 = 1;
684  break;
685  case 2:
686  C2TR23CONbits.TXREQ2 = 1;
687  break;
688  case 3:
689  C2TR23CONbits.TXREQ3 = 1;
690  break;
691  case 4:
692  C2TR45CONbits.TXREQ4 = 1;;
693  break;
694  case 5:
695  C2TR45CONbits.TXREQ5 = 1;
696  break;
697  case 6:
698  C2TR67CONbits.TXREQ6 = 1;
699  break;
700  default:
701  C2TR67CONbits.TXREQ7 = 1;
702  break;
703  }
704 }
705 
706 /**
707 Start Transmit for buffer \em u8_bufNum
708 \param u8_bufNum buffer number (0 to 7)
709 **/
710 uint8_t getTxInProgressECAN2(uint8_t u8_bufNum) {
711  u8_bufNum &= 0x07; //0-7
712  switch (u8_bufNum) {
713  case 0:
714  return(C2TR01CONbits.TXREQ0);
715  case 1:
716  return(C2TR01CONbits.TXREQ1);
717  case 2:
718  return(C2TR23CONbits.TXREQ2);
719  case 3:
720  return(C2TR23CONbits.TXREQ3);
721  case 4:
722  return(C2TR45CONbits.TXREQ4);
723  case 5:
724  return(C2TR45CONbits.TXREQ5);
725  case 6:
726  return(C2TR67CONbits.TXREQ6);
727  default:
728  return(C2TR67CONbits.TXREQ7);
729  }
730 }
731 
732 
733 
734 
735 /**
736 Configure an acceptance Filter
737 \param u8_filtNum filter number (0 to 15)
738 \param u32_id identifier, either SID (11 bits) or EID (29 bits)
739 \param u8_idType ID type (0: SID, nonzero: EID)
740 \param u8_bufnum RX buffer (0-14) to use for filter , if 15, then use FIFO
741 \param u8_maskReg Mask register (0-2) to use for filter
742 */
743 void configRxFilterECAN2(uint8_t u8_filtNum, uint32_t u32_id, uint8_t u8_idType, uint8_t u8_bufnum, uint8_t u8_maskReg) {
744  uint16_t *pu16_CxRXFySID,*pu16_CxRXFyEID, *pu16_CxFMSKSEL1, *pu16_CxBUFPNT1;
745  uint16_t u16_sid;
746  uint16_t u16_eid15_0;
747  uint16_t u16_eid17_16;
748  uint16_t u16_mask;
749  uint8_t u8_startPos;
750 
751  u8_filtNum &= 0xF; //0-15
752  u8_bufnum &= 0xF; //0-15
753  u8_maskReg &= 0x07; //0-7
754 
755  pu16_CxRXFySID = (uint16_t*) &C2RXF0SID + (u8_filtNum << 1);
756  pu16_CxRXFyEID = pu16_CxRXFySID + 1;
757  pu16_CxFMSKSEL1 = (uint16_t*) &C2FMSKSEL1 + (u8_filtNum >> 3);
758  pu16_CxBUFPNT1 = (uint16_t*) &C2BUFPNT1 + (u8_filtNum >> 2);
759 
760  C2CTRL1bits.WIN=1; //select filter register window
761 
762 //write to the CxRXFySID, CxRXFyEID registers
763  if(u8_idType) { // EID
764  u16_sid = (u32_id >> 18) & 0x7FF;
765  u16_eid17_16 = (u32_id >>16) & 0x3;
766  u16_eid15_0 = u32_id & 0xFFFF;
767  *pu16_CxRXFySID =(u16_sid <<5) | ECAN_MATCH_EID | u16_eid17_16;
768  *pu16_CxRXFyEID = u16_eid15_0;
769  } else { //SID
770  u16_sid = u32_id & 0x7FF;
771  *pu16_CxRXFySID = u16_sid <<5;
772  *pu16_CxRXFyEID = 0;
773  }
774 
775 //point the filter to the RX buffer (modify CxBUFPNT1 register)
776  u8_startPos = 4 * (u8_filtNum & 0x3); //starting bit position to mask
777  u16_mask = ~ ( 0xF << u8_startPos);
778  *pu16_CxBUFPNT1 = (*pu16_CxBUFPNT1 & u16_mask) | (u8_bufnum << u8_startPos);
779 
780 //point the filter to the mask register (modify CxFMSKSEL1 register)
781  u8_startPos = 2 * (u8_filtNum & 0x7);
782  u16_mask = ~ ( 0x3 << u8_startPos);
783  *pu16_CxFMSKSEL1 = (*pu16_CxFMSKSEL1 & u16_mask) | (u8_maskReg << u8_startPos);
784 
785  C2FEN1 = C2FEN1 | (1 << u8_filtNum) ; // Enable the filter
786 
787  C2CTRL1bits.WIN=0;
788 
789 }
790 
791 /**
792 Configure an acceptance MASK
793 \param u8_maskNum mask number (0 to 3; 0 to 2 specifies mask register, 3 then no mask is used)
794 \param u32_idMask mask for the identifier, either SID mask (11 bits) or EID mask (29 bits)
795 \param u8_idType ID type (0: SID, nonzero: EID)
796 \param u8_matchType Match type; if zero match either SID or EID addresses if filter matches
797 (i.e, match if (Filter SID == Message SID) || (Filter SID:EID = Message SID:EID)) )
798 If nonzero, match only message types as specified by the filter (either SID or SID:EID).
799 */
800 
801 void configRxMaskECAN2(uint8_t u8_maskNum, uint32_t u32_idMask, uint8_t u8_idType, uint8_t u8_matchType) {
802  uint16_t *pu16_CxRXMySID,*pu16_CxRXMyEID;
803  uint16_t u16_msid;
804  uint16_t u16_meid15_0;
805  uint16_t u16_meid17_16;
806 
807  pu16_CxRXMySID =(uint16_t*) &C2RXM0SID + (u8_maskNum << 1);
808  pu16_CxRXMyEID = pu16_CxRXMySID + 1;
809 
810  C2CTRL1bits.WIN=1; //select filter register window
811 
812 //write to the CxRXMySID, CxRXMyEID registers
813  if(u8_idType) { // EID
814  u16_msid = (u32_idMask >> 18) & 0x7FF;
815  u16_meid17_16 = (u32_idMask >>16) & 0x3;
816  u16_meid15_0 = u32_idMask & 0xFFFF;
817  if (u8_matchType) *pu16_CxRXMySID =(u16_msid <<5) | ECAN_MATCH_EID | u16_meid17_16;
818  else *pu16_CxRXMySID =(u16_msid <<5) | u16_meid17_16;
819  *pu16_CxRXMyEID = u16_meid15_0;
820  } else {
821  u16_msid = u32_idMask & 0x7FF;
822  if (u8_matchType) *pu16_CxRXMySID = (u16_msid <<5) | ECAN_MATCH_EID ;
823  else *pu16_CxRXMySID = (u16_msid <<5);
824  *pu16_CxRXMyEID = 0;
825  }
826  C2CTRL1bits.WIN=0;
827 }
828 
829 #endif // #if (NUM_ECAN_MODS >= ${x})
830 
831 
832 
833 
834