PropWare  3.0.0.229
C++ objects and CMake build system for Parallax Propeller
mcp2515.h
Go to the documentation of this file.
1 
28 #pragma once
29 
30 #include <PropWare/PropWare.h>
32 
33 /*
34  * Begin mt
35  */
36 #define TIMEOUTVALUE 50
37 #define MCP_SIDH 0
38 #define MCP_SIDL 1
39 #define MCP_EID8 2
40 #define MCP_EID0 3
41 
42 #define MCP_TXB_EXIDE_M 0x08 // In TXBnSIDL
43 #define MCP_DLC_MASK NIBBLE_0
44 #define MCP_RTR_MASK BIT_6
45 
46 #define MCP_RXB_RX_ANY 0x60
47 #define MCP_RXB_RX_EXT 0x40
48 #define MCP_RXB_RX_STD 0x20
49 #define MCP_RXB_RX_STDEXT 0x00
50 #define MCP_RXB_RX_MASK 0x60
51 #define MCP_RXB_BUKT_MASK BIT_2
52 
53 /*
54 ** Bits in the TXBnCTRL registers.
55 */
56 #define MCP_TXB_TXBUFE_M 0x80
57 #define MCP_TXB_ABTF_M 0x40
58 #define MCP_TXB_MLOA_M 0x20
59 #define MCP_TXB_TXERR_M 0x10
60 #define MCP_TXB_TXREQ_M 0x08
61 #define MCP_TXB_TXIE_M 0x04
62 #define MCP_TXB_TXP10_M 0x03
63 
64 #define MCP_TXB_RTR_M 0x40 // In TXBnDLC
65 #define MCP_RXB_IDE_M 0x08 // In RXBnSIDL
66 #define MCP_RXB_RTR_M 0x40 // In RXBnDLC
67 
68 #define MCP_EFLG_RX1OVR BIT_7
69 #define MCP_EFLG_RX0OVR BIT_6
70 #define MCP_EFLG_TXBO BIT_5
71 #define MCP_EFLG_TXEP BIT_4
72 #define MCP_EFLG_RXEP BIT_3
73 #define MCP_EFLG_TXWAR BIT_2
74 #define MCP_EFLG_RXWAR BIT_1
75 #define MCP_EFLG_EWARN BIT_0
76 #define MCP_EFLG_ERRORMASK (0xF8) // 5 MS-Bits
77 
78 
79 #define MCP_TX_INT 0x1C // Enable all transmit interrup ts
80 #define MCP_TX01_INT 0x0C // Enable TXB0 and TXB1 interru pts
81 #define MCP_RX_INT 0x03 // Enable receive interrupts
82 #define MCP_NO_INT 0x00 // Disable all interrupts
83 
84 #define MCP_TX01_MASK 0x14
85 #define MCP_TX_MASK 0x54
86 
87 #define MCP_N_TXBUFFERS (3)
88 
89 #define CANUSELOOP 0
90 
91 #define CANSENDTIMEOUT (200) // milliseconds
92 
93 /*
94  * initial value of gCANAutoProcess
95  */
96 #define CANAUTOPROCESS (1)
97 #define CANAUTOON (1)
98 #define CANAUTOOFF (0)
99 
100 #define CAN_STDID (0)
101 #define CAN_EXTID (1)
102 
103 #define CANDEFAULTIDENT (0x55CC)
104 #define CANDEFAULTIDENTEXT (CAN_EXTID)
105 
106 namespace PropWare {
107 
111 class MCP2515 {
112  public:
113  typedef enum {
114  RXF0SIDH = 0x00,
115  RXF0SIDL = 0x01,
116  RXF0EID8 = 0x02,
117  RXF0EID0 = 0x03,
118  RXF1SIDH = 0x04,
119  RXF1SIDL = 0x05,
120  RXF1EID8 = 0x06,
121  RXF1EID0 = 0x07,
122  RXF2SIDH = 0x08,
123  RXF2SIDL = 0x09,
124  RXF2EID8 = 0x0A,
125  RXF2EID0 = 0x0B,
126  CANSTAT = 0x0E,
127  CANCTRL = 0x0F,
128  RXF3SIDH = 0x10,
129  RXF3SIDL = 0x11,
130  RXF3EID8 = 0x12,
131  RXF3EID0 = 0x13,
132  RXF4SIDH = 0x14,
133  RXF4SIDL = 0x15,
134  RXF4EID8 = 0x16,
135  RXF4EID0 = 0x17,
136  RXF5SIDH = 0x18,
137  RXF5SIDL = 0x19,
138  RXF5EID8 = 0x1A,
139  RXF5EID0 = 0x1B,
140  TEC = 0x1C,
141  REC = 0x1D,
142  RXM0SIDH = 0x20,
143  RXM0SIDL = 0x21,
144  RXM0EID8 = 0x22,
145  RXM0EID0 = 0x23,
146  RXM1SIDH = 0x24,
147  RXM1SIDL = 0x25,
148  RXM1EID8 = 0x26,
149  RXM1EID0 = 0x27,
150  CNF3 = 0x28,
151  CNF2 = 0x29,
152  CNF1 = 0x2A,
153  CANINTE = 0x2B,
154  CANINTF = 0x2C,
155  EFLG = 0x2D,
156  TXB0CTRL = 0x30,
157  TXB1CTRL = 0x40,
158  TXB2CTRL = 0x50,
159  RXB0CTRL = 0x60,
160  RXB0SIDH = 0x61,
161  RXB1CTRL = 0x70,
162  RXB1SIDH = 0x71
163  } RegisterAddress;
164 
165  typedef enum {
166  RX0IF = BIT_0,
167  RX1IF = BIT_1,
168  TX0IF = BIT_2,
169  TX1IF = BIT_3,
170  TX2IF = BIT_4,
171  ERRIF = BIT_5,
172  WAKIF = BIT_6,
173  MERRF = BIT_7
174  } CANINTFBits;
175 
176  typedef enum {
177  WRITE = 0x02,
178  READ = 0x03,
179  BITMOD = 0x05,
180  LOAD_TX0 = 0x40,
181  LOAD_TX1 = 0x42,
182  LOAD_TX2 = 0x44,
183  RTS_TX0 = 0x81,
184  RTS_TX1 = 0x82,
185  RTS_TX2 = 0x84,
186  RTS_ALL = 0x87,
187  READ_RX0 = 0x90,
188  READ_RX1 = 0x94,
189  READ_STATUS = 0xA0,
190  RX_STATUS = 0xB0,
191  RESET = 0xC0
192  } SPIInstructionSet;
193 
194  enum class BufferNumber {
195  BUFFER_0,
196  BUFFER_1
197  };
198 
199  enum class FilterNumber {
200  FILTER_0,
201  FILTER_1,
202  FILTER_2,
203  FILTER_3,
204  FILTER_4,
205  FILTER_5
206  };
207 
208  typedef enum {
209  NORMAL = 0,
210  SLEEP = BIT_5,
211  LOOPBACK = BIT_6,
212  LISTENONLY = BIT_6 | BIT_5,
213  CONFIG = BIT_7,
214  POWERUP = BIT_7 | BIT_6 | BIT_5
215  } Mode;
216 
217  typedef enum {
218  NO_ERROR,
219  MODE_SET_FAILURE,
220  NO_MESSAGE,
221  CONTROL_ERROR,
222  GET_TX_BUFFER_TIMEOUT,
223  SEND_MESSAGE_TIMEOUT,
224  MESSAGE_TOO_LONG,
225  ALLTXBUSY
226  } ErrorCode;
227 
228  static const Mode DEFAULT_MODE = Mode::NORMAL;
229 
230  static const uint8_t MODE_MASK = BIT_7 | BIT_6 | BIT_5;
231 
232 /*
233  * CANCTRL Register Values
234  */
235 #define ABORT_TX 0x10
236 #define MODE_ONESHOT 0x08
237 #define CLKOUT_ENABLE 0x04
238 #define CLKOUT_DISABLE 0x00
239 #define CLKOUT_PS1 0x00
240 #define CLKOUT_PS2 0x01
241 #define CLKOUT_PS4 0x02
242 #define CLKOUT_PS8 0x03
243 
244  enum class BaudRate {
245  BAUD_5KBPS,
246  BAUD_10KBPS,
247  BAUD_20KBPS,
248  BAUD_31K25BPS,
249  BAUD_40KBPS,
250  BAUD_50KBPS,
251  BAUD_80KBPS,
252  BAUD_100KBPS,
253  BAUD_125KBPS,
254  BAUD_200KBPS,
255  BAUD_250KBPS,
256  BAUD_500KBPS,
257  BAUD_1000KBPS
258  };
259 
260  /*
261  * CNF1 Register Values
262  */
263 
264  static const uint8_t SJW1 = NULL_BIT;
265  static const uint8_t SJW2 = BIT_6;
266  static const uint8_t SJW3 = BIT_7;
267  static const uint8_t SJW4 = BIT_7 | BIT_6;
268 
269 
270  /*
271  * CNF2 Register Values
272  */
273 
274  static const uint8_t SAMPLE_1X = NULL_BIT;
275  static const uint8_t SAMPLE_3X = BIT_6;
276  static const uint8_t BTLMODE = BIT_7;
277 
278 
279  /*
280  * CNF3 Register Values
281  */
282 
283  static const uint8_t SOF_ENABLE = 0x80;
284  static const uint8_t SOF_DISABLE = 0x00;
285  static const uint8_t WAKFIL_ENABLE = 0x40;
286  static const uint8_t WAKFIL_DISABLE = 0x00;
287 
288  static const uint8_t CNF1_16MHz_1000kBPS = SJW1;
289  static const uint8_t CNF2_16MHz_1000kBPS = 0xD0;
290  static const uint8_t CNF3_16MHz_1000kBPS = 0x82;
291 
292  static const uint8_t CNF1_16MHz_500kBPS = SJW1;
293  static const uint8_t CNF2_16MHz_500kBPS = 0xF0;
294  static const uint8_t CNF3_16MHz_500kBPS = 0x86;
295 
296  static const uint8_t CNF1_16MHz_250kBPS = SJW2 | 1;
297  static const uint8_t CNF2_16MHz_250kBPS = 0xF1;
298  static const uint8_t CNF3_16MHz_250kBPS = 0x85;
299 
300  static const uint8_t CNF1_16MHz_200kBPS = SJW1 | 1;
301  static const uint8_t CNF2_16MHz_200kBPS = 0xFA;
302  static const uint8_t CNF3_16MHz_200kBPS = 0x87;
303 
304  static const uint8_t CNF1_16MHz_125kBPS = SJW1 | 3;
305  static const uint8_t CNF2_16MHz_125kBPS = 0xF0;
306  static const uint8_t CNF3_16MHz_125kBPS = 0x86;
307 
308  static const uint8_t CNF1_16MHz_100kBPS = SJW1 | 3;
309  static const uint8_t CNF2_16MHz_100kBPS = 0xFA;
310  static const uint8_t CNF3_16MHz_100kBPS = 0x87;
311 
312  static const uint8_t CNF1_16MHz_80kBPS = SJW1 | 3;
313  static const uint8_t CNF2_16MHz_80kBPS = 0xFF;
314  static const uint8_t CNF3_16MHz_80kBPS = 0x87;
315 
316  static const uint8_t CNF1_16MHz_50kBPS = SJW1 | 7;
317  static const uint8_t CNF2_16MHz_50kBPS = 0xFA;
318  static const uint8_t CNF3_16MHz_50kBPS = 0x87;
319 
320  static const uint8_t CNF1_16MHz_40kBPS = SJW1 | 7;
321  static const uint8_t CNF2_16MHz_40kBPS = 0xFF;
322  static const uint8_t CNF3_16MHz_40kBPS = 0x87;
323 
324  static const uint8_t CNF1_16MHz_31k25BPS = SJW1 | 15;
325  static const uint8_t CNF2_16MHz_31k25BPS = 0xF1;
326  static const uint8_t CNF3_16MHz_31k25BPS = 0x85;
327 
328  static const uint8_t CNF1_16MHz_20kBPS = SJW1 | 15;
329  static const uint8_t CNF2_16MHz_20kBPS = 0xFF;
330  static const uint8_t CNF3_16MHz_20kBPS = 0x87;
331 
332  static const uint8_t CNF1_16MHz_10kBPS = SJW1 | 31;
333  static const uint8_t CNF2_16MHz_10kBPS = 0xFF;
334  static const uint8_t CNF3_16MHz_10kBPS = 0x87;
335 
336  static const uint8_t CNF1_16MHz_5kBPS = SJW1 | 63;
337  static const uint8_t CNF2_16MHz_5kBPS = 0xFF;
338  static const uint8_t CNF3_16MHz_5kBPS = 0x87;
339 
343  static const uint8_t MAX_DATA_BYTES = 8;
344 
345  public:
346  MCP2515 (const Pin::Mask cs)
347  : m_spi(&SPI::get_instance()),
348  m_cs(cs, Pin::Dir::OUT) {
349  this->m_cs.set();
350  }
351 
352  MCP2515 (const SPI &spi, const Pin::Mask cs)
353  : m_spi(&spi),
354  m_cs(cs, Pin::Dir::OUT) {
355  this->m_cs.set();
356  }
357 
367  PropWare::ErrorCode start (const BaudRate baudRate, const Mode mode = DEFAULT_MODE) {
368  PropWare::ErrorCode err;
369 
370  this->reset();
371 
372  check_errors(this->set_control_mode(Mode::CONFIG));
373 
374  this->set_baud(baudRate);
375  this->initialize_buffers();
376  // interrupt mode
377  this->set_register(CANINTE, RX0IF | RX1IF);
378 
379 #if (DEBUG_RXANY == 1)
380  // enable both receive-buffers to receive any message and enable rollover
381  this->modifyRegister(RXB0CTRL,
382  MCP_RXB_RX_MASK | MCP_RXB_BUKT_MASK,
383  MCP_RXB_RX_ANY | MCP_RXB_BUKT_MASK);
384  this->modifyRegister(RXB1CTRL, MCP_RXB_RX_MASK, MCP_RXB_RX_ANY);
385 #else
386  // enable both receive-buffers to receive messages with std. and ext. identifiers and enable rollover
387  this->modify_register(RXB0CTRL,
388  MCP_RXB_RX_MASK | MCP_RXB_BUKT_MASK,
389  MCP_RXB_RX_STDEXT | MCP_RXB_BUKT_MASK);
390  this->modify_register(RXB1CTRL, MCP_RXB_RX_MASK, MCP_RXB_RX_STDEXT);
391 #endif
392 
393  /* enter normal mode */
394  this->m_mode = mode;
395  check_errors(this->set_control_mode(this->m_mode));
396 
397  return NO_ERROR;
398  }
399 
400  PropWare::ErrorCode set_mask (const BufferNumber bufferNumber, const uint32_t id,
401  const bool extendedID = false) const {
402  PropWare::ErrorCode err;
403 
404  check_errors(this->set_control_mode(Mode::CONFIG));
405 
406  if (BufferNumber::BUFFER_0 == bufferNumber)
407  this->write_id(RXM0SIDH, id, extendedID);
408  else
409  this->write_id(RXM1SIDH, id, extendedID);
410 
411  return this->set_control_mode(this->m_mode);
412  }
413 
414  PropWare::ErrorCode set_filter (const FilterNumber num,
415  const uint32_t id, const bool extendedID = false) const {
416  PropWare::ErrorCode err;
417  check_errors(this->set_control_mode(Mode::CONFIG));
418 
419  switch (num) {
420  case FilterNumber::FILTER_0:
421  this->write_id(RXF0SIDH, id, extendedID);
422  break;
423  case FilterNumber::FILTER_1:
424  this->write_id(RXF1SIDH, id, extendedID);
425  break;
426  case FilterNumber::FILTER_2:
427  this->write_id(RXF2SIDH, id, extendedID);
428  break;
429  case FilterNumber::FILTER_3:
430  this->write_id(RXF3SIDH, id, extendedID);
431  break;
432  case FilterNumber::FILTER_4:
433  this->write_id(RXF4SIDH, id, extendedID);
434  break;
435  case FilterNumber::FILTER_5:
436  this->write_id(RXF5SIDH, id, extendedID);
437  break;
438  }
439 
440  return this->set_control_mode(this->m_mode);
441  }
442 
451  PropWare::ErrorCode send_message (const uint32_t id, const uint8_t len, const uint8_t buf[],
452  const bool extendedID = false) {
453  this->set_message(id, len, buf, extendedID);
454  return this->send_message();
455  }
456 
467  PropWare::ErrorCode read_message (uint8_t *len, uint8_t *buf) {
468  PropWare::ErrorCode err;
469  check_errors(this->read_message());
470  *len = this->m_dataLength;
471  memcpy(buf, this->m_messageBuffer, this->m_dataLength);
472  return NO_ERROR;
473  }
474 
484  PropWare::ErrorCode read_message (const BufferNumber bufferNumber, uint8_t *len, uint8_t *buf) {
485  PropWare::ErrorCode err;
486  check_errors(this->read_message(bufferNumber));
487  *len = this->m_dataLength;
488  memcpy(buf, this->m_messageBuffer, this->m_dataLength);
489  return NO_ERROR;
490  }
491 
497  bool check_receive_buffer () const {
498  return static_cast<bool>(this->read_status() & (RX0IF | RX1IF));
499  }
500 
508  bool check_receive_buffer (const BufferNumber bufferNumber) const {
509  return static_cast<bool>(this->read_status() & (RX0IF + static_cast<unsigned int>(bufferNumber)));
510  }
511 
512  PropWare::ErrorCode check_error () const {
513  const uint8_t eflg = this->read_register(EFLG);
514 
515  if (eflg & MCP_EFLG_ERRORMASK)
516  return CONTROL_ERROR;
517  else
518  return NO_ERROR;
519  }
520 
521  uint32_t get_id () const {
522  return this->m_id;
523  }
524 
525  private:
526  void reset () const {
527  this->m_cs.clear();
528  this->m_spi->shift_out(8, SPIInstructionSet::RESET);
529  this->m_cs.set();
530  waitcnt(10 * MILLISECOND + CNT);
531  }
532 
533  uint8_t read_register (const uint8_t address) const {
534  uint8_t ret;
535 
536  this->m_cs.clear();
537  this->m_spi->shift_out(8, SPIInstructionSet::READ);
538  this->m_spi->shift_out(8, address);
539  ret = (uint8_t) this->m_spi->shift_in(8);
540  this->m_cs.set();
541 
542  return ret;
543  }
544 
545  void read_registers (const uint8_t address, uint8_t *values, const uint8_t n) {
546  const uint32_t tmp = SPIInstructionSet::READ << 8;
547  const uint32_t combinedBits = tmp | address;
548  this->m_cs.clear();
549  this->m_spi->shift_out(16, combinedBits);
550  // mcp2515 has auto-increment of address-pointer
551  this->m_spi->shift_in_block_mode0_msb_first_fast(values, n);
552  this->m_cs.set();
553  }
554 
555  void set_register (const uint8_t address, const uint8_t value) const {
556  const uint32_t tmp = SPIInstructionSet::WRITE << 16;
557  const uint32_t combinedBits = tmp | (address << 8) | value;
558  this->m_cs.clear();
559  this->m_spi->shift_out(24, combinedBits);
560  this->m_cs.set();
561  }
562 
563  void set_registers (const uint8_t address, const uint8_t values[], const uint8_t n) const {
564  const uint32_t tmp = SPIInstructionSet::WRITE << 8;
565  const uint32_t combinedBits = tmp | address;
566  this->m_cs.clear();
567  this->m_spi->shift_out(16, combinedBits);
568  this->m_spi->shift_out_block_msb_first_fast(values, n);
569  this->m_cs.set();
570  }
571 
572  void initialize_buffers () const {
573  uint8_t i, a1, a2, a3;
574 
575  uint32_t ulMask = 0x00, ulFilt = 0x00;
576 
577 
578  this->write_id(RXM0SIDH, ulMask, true); /*Set both masks to 0 */
579  this->write_id(RXM1SIDH, ulMask, true); /*Mask register ignores ext bit */
580 
581  /* Set all filters to 0 */
582  this->write_id(RXF0SIDH, ulFilt, true); /* RXB0: extended */
583  this->write_id(RXF1SIDH, ulFilt, false); /* RXB1: standard */
584  this->write_id(RXF2SIDH, ulFilt, true); /* RXB2: extended */
585  this->write_id(RXF3SIDH, ulFilt, false); /* RXB3: standard */
586  this->write_id(RXF4SIDH, ulFilt, true);
587  this->write_id(RXF5SIDH, ulFilt, false);
588 
589  /* Clear, deactivate the three */
590  /* transmit buffers */
591  /* TXBnCTRL -> TXBnD7 */
592  a1 = TXB0CTRL;
593  a2 = TXB1CTRL;
594  a3 = TXB2CTRL;
595  for (i = 0; i < 14; i++) { /* in-buffer loop */
596  this->set_register(a1, 0);
597  this->set_register(a2, 0);
598  this->set_register(a3, 0);
599  a1++;
600  a2++;
601  a3++;
602  }
603  this->set_register(RXB0CTRL, 0);
604  this->set_register(RXB1CTRL, 0);
605  }
606 
607  void modify_register (const uint8_t address, const uint8_t mask, const uint8_t data) const {
608  this->m_cs.clear();
609  this->m_spi->shift_out(8, SPIInstructionSet::BITMOD);
610  this->m_spi->shift_out(8, address);
611  this->m_spi->shift_out(8, mask);
612  this->m_spi->shift_out(8, data);
613  this->m_cs.set();
614  }
615 
616  uint8_t read_status () const {
617  this->m_cs.clear();
618  this->m_spi->shift_out(8, SPIInstructionSet::READ_STATUS);
619  const uint8_t i = this->m_spi->shift_in(8);
620  this->m_cs.set();
621  return i;
622  }
623 
624  PropWare::ErrorCode set_control_mode (const Mode mode) const {
625  this->modify_register(CANCTRL, MODE_MASK, mode);
626 
627  const Mode actualMode = static_cast<Mode>(this->read_register(CANCTRL) & MODE_MASK);
628  if (actualMode == mode)
629  return NO_ERROR;
630  else
631  return MODE_SET_FAILURE;
632  }
633 
634  void set_baud (const BaudRate baudRate) const {
635  uint8_t cnf1 = 0;
636  uint8_t cnf2 = 0;
637  uint8_t cnf3 = 0;
638  switch (baudRate) {
639  case BaudRate::BAUD_5KBPS:
640  cnf1 = CNF1_16MHz_5kBPS;
641  cnf2 = CNF2_16MHz_5kBPS;
642  cnf3 = CNF3_16MHz_5kBPS;
643  break;
644  case BaudRate::BAUD_10KBPS:
645  cnf1 = CNF1_16MHz_10kBPS;
646  cnf2 = CNF2_16MHz_10kBPS;
647  cnf3 = CNF3_16MHz_10kBPS;
648  break;
649  case BaudRate::BAUD_20KBPS:
650  cnf1 = CNF1_16MHz_20kBPS;
651  cnf2 = CNF2_16MHz_20kBPS;
652  cnf3 = CNF3_16MHz_20kBPS;
653  break;
654  case BaudRate::BAUD_31K25BPS:
655  cnf1 = CNF1_16MHz_31k25BPS;
656  cnf2 = CNF2_16MHz_31k25BPS;
657  cnf3 = CNF3_16MHz_31k25BPS;
658  break;
659  case BaudRate::BAUD_40KBPS:
660  cnf1 = CNF1_16MHz_40kBPS;
661  cnf2 = CNF2_16MHz_40kBPS;
662  cnf3 = CNF3_16MHz_40kBPS;
663  break;
664  case BaudRate::BAUD_50KBPS:
665  cnf1 = CNF1_16MHz_50kBPS;
666  cnf2 = CNF2_16MHz_50kBPS;
667  cnf3 = CNF3_16MHz_50kBPS;
668  break;
669  case BaudRate::BAUD_80KBPS:
670  cnf1 = CNF1_16MHz_80kBPS;
671  cnf2 = CNF2_16MHz_80kBPS;
672  cnf3 = CNF3_16MHz_80kBPS;
673  break;
674  case BaudRate::BAUD_100KBPS:
675  cnf1 = CNF1_16MHz_100kBPS;
676  cnf2 = CNF2_16MHz_100kBPS;
677  cnf3 = CNF3_16MHz_100kBPS;
678  break;
679  case BaudRate::BAUD_125KBPS:
680  cnf1 = CNF1_16MHz_125kBPS;
681  cnf2 = CNF2_16MHz_125kBPS;
682  cnf3 = CNF3_16MHz_125kBPS;
683  break;
684  case BaudRate::BAUD_200KBPS:
685  cnf1 = CNF1_16MHz_200kBPS;
686  cnf2 = CNF2_16MHz_200kBPS;
687  cnf3 = CNF3_16MHz_200kBPS;
688  break;
689  case BaudRate::BAUD_250KBPS:
690  cnf1 = CNF1_16MHz_250kBPS;
691  cnf2 = CNF2_16MHz_250kBPS;
692  cnf3 = CNF3_16MHz_250kBPS;
693  break;
694  case BaudRate::BAUD_500KBPS:
695  cnf1 = CNF1_16MHz_500kBPS;
696  cnf2 = CNF2_16MHz_500kBPS;
697  cnf3 = CNF3_16MHz_500kBPS;
698  break;
699  case BaudRate::BAUD_1000KBPS:
700  cnf1 = CNF1_16MHz_1000kBPS;
701  cnf2 = CNF2_16MHz_1000kBPS;
702  cnf3 = CNF3_16MHz_1000kBPS;
703  break;
704  }
705 
706  this->set_register(CNF1, cnf1);
707  this->set_register(CNF2, cnf2);
708  this->set_register(CNF3, cnf3);
709  }
710 
711  void write_id (const uint8_t address, const uint32_t id, const bool extendedID) const {
712  uint8_t buffer[4];
713  const uint16_t canIDLow = static_cast<uint16_t>(id & WORD_0);
714 
715  if (extendedID) {
716  const uint16_t canIDHigh = static_cast<uint16_t>(id >> 16);
717 
718  buffer[MCP_EID0] = static_cast<uint8_t>(canIDLow & BYTE_0);
719  buffer[MCP_EID8] = static_cast<uint8_t>(canIDLow >> 8);
720 
721  buffer[MCP_SIDL] = static_cast<uint8_t>(canIDHigh & 0x03);
722  buffer[MCP_SIDL] += static_cast<uint8_t>((canIDHigh & 0x1C) << 3);
723  buffer[MCP_SIDL] |= MCP_TXB_EXIDE_M;
724  buffer[MCP_SIDH] = static_cast<uint8_t>(canIDHigh >> 5);
725  } else {
726  buffer[MCP_SIDH] = static_cast<uint8_t>(canIDLow >> 3);
727  buffer[MCP_SIDL] = static_cast<uint8_t>(canIDLow << 5);
728 
729  buffer[MCP_EID0] = 0;
730  buffer[MCP_EID8] = 0;
731  }
732  this->set_registers(address, buffer, 4);
733  }
734 
735  void read_id (const uint8_t address, uint32_t *id, bool *extendedID) {
736  uint8_t buffer[4];
737 
738  this->read_registers(address, buffer, 4);
739 
740  *id = (buffer[MCP_SIDH] << 3) + (buffer[MCP_SIDL] >> 5);
741  if ((buffer[MCP_SIDL] & MCP_TXB_EXIDE_M) == MCP_TXB_EXIDE_M) {
742  /* extended id */
743  *id = (*id << 2) + (buffer[MCP_SIDL] & 0x03);
744  *id = (*id << 8) + buffer[MCP_EID8];
745  *id = (*id << 8) + buffer[MCP_EID0];
746  *extendedID = true;
747  } else
748  *extendedID = false;
749  }
750 
751  void write_can_message (const uint8_t bufferSIDHAddress) {
752  uint8_t mcp_addr;
753  mcp_addr = bufferSIDHAddress;
754  this->set_registers(mcp_addr + 5, this->m_messageBuffer, this->m_dataLength);
755  if (this->m_rtr == 1)
756  this->m_dataLength |= MCP_RTR_MASK;
757  // write the RTR and DLC
758  this->set_register((mcp_addr + 4), this->m_dataLength);
759  this->write_id(mcp_addr, this->m_id, this->m_extendedID);
760 
761  }
762 
763  void read_can_message (const uint8_t bufferSIDHAddress) {
764  this->read_id(bufferSIDHAddress, &this->m_id, &this->m_extendedID);
765 
766  const uint8_t ctrl = this->read_register(bufferSIDHAddress - 1);
767  this->m_dataLength = this->read_register(bufferSIDHAddress + 4);
768 
769  if ((ctrl & 0x08))
770  this->m_rtr = 1;
771  else
772  this->m_rtr = 0;
773 
774  this->m_dataLength &= MCP_DLC_MASK;
775  read_registers(bufferSIDHAddress + 5, &(this->m_messageBuffer[0]), this->m_dataLength);
776  }
777 
778  void start_transmit (const uint8_t address) {
779  this->modify_register(address - 1, MCP_TXB_TXREQ_M, MCP_TXB_TXREQ_M);
780  }
781 
782  PropWare::ErrorCode get_next_free_tx_buffer (uint8_t *txbuf_n) const {
783  const uint8_t controlRegisters[] = {TXB0CTRL, TXB1CTRL, TXB2CTRL};
784 
785  /* check all 3 TX-Buffers */
786  for (uint_fast8_t i = 0; i < Utility::size_of_array(controlRegisters); i++) {
787  const uint8_t controlValue = read_register(controlRegisters[i]);
788  if ((controlValue & MCP_TXB_TXREQ_M) == 0) {
789  // return SIDH-address of buffer
790  *txbuf_n = static_cast<uint8_t>(controlRegisters[i] + 1);
791  return NO_ERROR;
792  }
793  }
794  return ALLTXBUSY;
795  }
796 
797  uint8_t set_message (const uint32_t id, const uint8_t length, const uint8_t data[], const bool extendedID) {
798  this->m_extendedID = extendedID;
799  this->m_id = id;
800  this->m_dataLength = length;
801 
802  if (MAX_DATA_BYTES < length) {
803  return MESSAGE_TOO_LONG;
804  } else {
805  memcpy(this->m_messageBuffer, data, length);
806  return NO_ERROR;
807  }
808  }
809 
810  void clear_message () {
811  this->m_id = 0;
812  this->m_dataLength = 0;
813  this->m_extendedID = 0;
814  this->m_rtr = 0;
815  memset(this->m_messageBuffer, 0, this->m_dataLength);
816  }
817 
818  PropWare::ErrorCode read_message () {
819  const uint8_t stat = this->read_status();
820 
821  if (Utility::bit_read(stat, (Bit) RX0IF)) {
822  this->read_can_message((RXB0SIDH));
823  this->modify_register(CANINTF, RX0IF, 0);
824  return NO_ERROR;
825  } else if (Utility::bit_read(stat, (Bit) RX1IF)) {
826  this->read_can_message((RXB1SIDH));
827  this->modify_register(CANINTF, RX1IF, 0);
828  return NO_ERROR;
829  } else
830  return NO_MESSAGE;
831  }
832 
833  PropWare::ErrorCode read_message (const BufferNumber bufferNumber) {
834  const uint8_t stat = this->read_status();
835 
836  const Bit interruptFlag = (Bit) (RX0IF + static_cast<uint8_t>(bufferNumber));
837  uint8_t bufferAddress = RXB0SIDH;
838  if (BufferNumber::BUFFER_1 == bufferNumber)
839  bufferAddress += 0x10;
840 
841  if (Utility::bit_read(stat, interruptFlag)) {
842  this->read_can_message(bufferAddress);
843  this->modify_register(CANINTF, interruptFlag, 0);
844  return NO_ERROR;
845  } else
846  return NO_MESSAGE;
847  }
848 
849  PropWare::ErrorCode send_message () {
850  PropWare::ErrorCode err;
851  uint8_t txbuf_n;
852  uint16_t retryCount = 0;
853 
854  do {
855  // info = addr
856  err = this->get_next_free_tx_buffer(&txbuf_n);
857  retryCount++;
858  } while (err == ALLTXBUSY && (TIMEOUTVALUE > retryCount));
859 
860  if (TIMEOUTVALUE == retryCount)
861  return GET_TX_BUFFER_TIMEOUT;
862  else {
863  retryCount = 0;
864  this->write_can_message(txbuf_n);
865  this->start_transmit(txbuf_n);
866 
867  bool messageSent;
868  do {
869  retryCount++;
870 
871  // read send buff ctrl reg
872  messageSent = this->read_register(txbuf_n) & BIT_3;
873  } while (messageSent && (TIMEOUTVALUE > retryCount));
874 
875  if (retryCount == TIMEOUTVALUE)
876  return SEND_MESSAGE_TIMEOUT;
877  else
878  return NO_ERROR;
879  }
880  }
881 
882  private:
883  const SPI *m_spi;
884  const Pin m_cs;
885 
886  Mode m_mode;
887 
893  bool m_extendedID;
894  uint32_t m_id;
895  uint8_t m_dataLength;
896  uint8_t m_messageBuffer[MAX_DATA_BYTES];
897  uint8_t m_rtr;
898 };
899 
900 };
PropWare::MCP2515
Control and communicate with the Microchip MCP2515 CAN bus controller.
Definition: mcp2515.h:111
stat
Definition: types.h:24
PropWare::SPI::shift_in_block_mode0_msb_first_fast
void shift_in_block_mode0_msb_first_fast(const uint8_t *buffer, size_t numberOfBytes) const
Receive an array of data at max transmit speed. Mode is always MODE_0 and data is always MSB first.
Definition: spi.h:317
PropWare::SPI
SPI serial communications library; Core functionality comes from a dedicated assembly cog.
Definition: spi.h:43
PropWare::MCP2515::check_receive_buffer
bool check_receive_buffer(const BufferNumber bufferNumber) const
Determine if a message is ready to be read from the requested buffer.
Definition: mcp2515.h:508
PropWare::SPI::shift_in
uint32_t shift_in(const unsigned int bits) const
Read a value from the MISO line.
Definition: spi.h:242
PropWare::Port::Mask
Mask
Definition: port.h:43
PropWare::MCP2515::read_message
PropWare::ErrorCode read_message(uint8_t *len, uint8_t *buf)
Read a message from either buffer.
Definition: mcp2515.h:467
spi.h
PropWare::MCP2515::check_receive_buffer
bool check_receive_buffer() const
Determine if a message is available for reading on either buffer.
Definition: mcp2515.h:497
PropWare::MCP2515::start
PropWare::ErrorCode start(const BaudRate baudRate, const Mode mode=DEFAULT_MODE)
Initialize the controller.
Definition: mcp2515.h:367
PropWare::Pin
Utility class to handle general purpose I/O pins.
Definition: pin.h:36
PropWare.h
PropWare::SPI::shift_out
void shift_out(uint8_t bits, uint32_t value) const
Send a value out to a peripheral device.
Definition: spi.h:224
PropWare::Port::set
void set() const
Set selected output port high (set all pins to 1)
Definition: port.h:226
PropWare::SPI::shift_out_block_msb_first_fast
void shift_out_block_msb_first_fast(const uint8_t buffer[], size_t numberOfBytes) const
Send an array of data at max transmit speed. Mode is always MODE_0 and data is always MSB first.
Definition: spi.h:270
waitcnt
#define waitcnt(a)
Wait until system counter reaches a value.
Definition: propeller.h:176
PropWare::MCP2515::MAX_DATA_BYTES
static const uint8_t MAX_DATA_BYTES
Definition: mcp2515.h:343
CNT
#define CNT
The system clock count.
Definition: propeller1.h:151
SPI
Definition: SPI.h:11
PropWare::MCP2515::send_message
PropWare::ErrorCode send_message(const uint32_t id, const uint8_t len, const uint8_t buf[], const bool extendedID=false)
Send a message.
Definition: mcp2515.h:451
PropWare
Generic definitions and functions for the Parallax Propeller.
Definition: runnable.h:33
PropWare::Port::clear
void clear() const
Clear selected output port (set it to 0)
Definition: port.h:249
PropWare::Utility::size_of_array
static size_t size_of_array(const T(&array)[N])
Determine the size of an array.
Definition: utility.h:232
PropWare::MCP2515::read_message
PropWare::ErrorCode read_message(const BufferNumber bufferNumber, uint8_t *len, uint8_t *buf)
Read a message from a specific buffer.
Definition: mcp2515.h:484