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