diff --git a/FlexCAN.cpp b/FlexCAN.cpp index 7ad1312..cced508 100644 --- a/FlexCAN.cpp +++ b/FlexCAN.cpp @@ -1,6 +1,7 @@ // ------------------------------------------------------------- -// a simple Arduino Teensy3.1 CAN driver +// a simple Arduino Teensy 3.1/3.2/3.5/3.6 CAN driver // by teachop +// dual CAN support for MK66FX1M0 and updates for MK64FX512 by Pawelsky // #include "FlexCAN.h" #include "kinetis_flexcan.h" @@ -9,54 +10,95 @@ static const int txb = 8; // with default settings, all buffers before this are static const int txBuffers = 8; static const int rxb = 0; +#define FLEXCANb_MCR(b) (*(vuint32_t*)(b)) +#define FLEXCANb_CTRL1(b) (*(vuint32_t*)(b+4)) +#define FLEXCANb_RXMGMASK(b) (*(vuint32_t*)(b+0x10)) +#define FLEXCANb_IFLAG1(b) (*(vuint32_t*)(b+0x30)) +#define FLEXCANb_RXFGMASK(b) (*(vuint32_t*)(b+0x48)) +#define FLEXCANb_MBn_CS(b, n) (*(vuint32_t*)(b+0x80+n*0x10)) +#define FLEXCANb_MBn_ID(b, n) (*(vuint32_t*)(b+0x84+n*0x10)) +#define FLEXCANb_MBn_WORD0(b, n) (*(vuint32_t*)(b+0x88+n*0x10)) +#define FLEXCANb_MBn_WORD1(b, n) (*(vuint32_t*)(b+0x8C+n*0x10)) +#define FLEXCANb_IDFLT_TAB(b, n) (*(vuint32_t*)(b+0xE0+(n*4))) + // ------------------------------------------------------------- -FlexCAN::FlexCAN(uint32_t baud) +FlexCAN::FlexCAN(uint32_t baud, uint8_t id, uint8_t txAlt, uint8_t rxAlt) { - // set up the pins, 3=PTA12=CAN0_TX, 4=PTA13=CAN0_RX - CORE_PIN3_CONFIG = PORT_PCR_MUX(2); - CORE_PIN4_CONFIG = PORT_PCR_MUX(2);// | PORT_PCR_PE | PORT_PCR_PS; + flexcanBase = FLEXCAN0_BASE; +#ifdef __MK66FX1M0__ + if(id > 0) flexcanBase = FLEXCAN1_BASE; +#endif + + // set up the pins + if(flexcanBase == FLEXCAN0_BASE) + { +#if defined(__MK66FX1M0__) || defined(__MK64FX512__) + // 3=PTA12=CAN0_TX, 4=PTA13=CAN0_RX (default) + // 29=PTB18=CAN0_TX, 30=PTB19=CAN0_RX (alternative) + if(txAlt == 1) CORE_PIN29_CONFIG = PORT_PCR_MUX(2); else CORE_PIN3_CONFIG = PORT_PCR_MUX(2); + if(rxAlt == 1) CORE_PIN30_CONFIG = PORT_PCR_MUX(2); else CORE_PIN4_CONFIG = PORT_PCR_MUX(2);// | PORT_PCR_PE | PORT_PCR_PS; +#else + // 3=PTA12=CAN0_TX, 4=PTA13=CAN0_RX (default) + // 32=PTB18=CAN0_TX, 25=PTB19=CAN0_RX (alternative) + if(txAlt == 1) CORE_PIN32_CONFIG = PORT_PCR_MUX(2); else CORE_PIN3_CONFIG = PORT_PCR_MUX(2); + if(rxAlt == 1) CORE_PIN25_CONFIG = PORT_PCR_MUX(2); else CORE_PIN4_CONFIG = PORT_PCR_MUX(2);// | PORT_PCR_PE | PORT_PCR_PS; +#endif + } +#ifdef __MK66FX1M0__ + else if(flexcanBase == FLEXCAN1_BASE) + { + // 33=PTE24=CAN1_TX, 34=PTE25=CAN1_RX (default) + // NOTE: Alternative CAN1 pins are not broken out on Teensy 3.6 + CORE_PIN33_CONFIG = PORT_PCR_MUX(2); + CORE_PIN34_CONFIG = PORT_PCR_MUX(2);// | PORT_PCR_PE | PORT_PCR_PS; + } +#endif + // select clock source 16MHz xtal OSC0_CR |= OSC_ERCLKEN; - SIM_SCGC6 |= SIM_SCGC6_FLEXCAN0; - FLEXCAN0_CTRL1 &= ~FLEXCAN_CTRL_CLK_SRC; + if(flexcanBase == FLEXCAN0_BASE) SIM_SCGC6 |= SIM_SCGC6_FLEXCAN0; +#ifdef __MK66FX1M0__ + else if(flexcanBase == FLEXCAN1_BASE) SIM_SCGC3 |= SIM_SCGC3_FLEXCAN1; +#endif + FLEXCANb_CTRL1(flexcanBase) &= ~FLEXCAN_CTRL_CLK_SRC; // enable CAN - FLEXCAN0_MCR |= FLEXCAN_MCR_FRZ; - FLEXCAN0_MCR &= ~FLEXCAN_MCR_MDIS; - while(FLEXCAN0_MCR & FLEXCAN_MCR_LPM_ACK) + FLEXCANb_MCR(flexcanBase) |= FLEXCAN_MCR_FRZ; + FLEXCANb_MCR(flexcanBase) &= ~FLEXCAN_MCR_MDIS; + while(FLEXCANb_MCR(flexcanBase) & FLEXCAN_MCR_LPM_ACK) ; // soft reset - FLEXCAN0_MCR ^= FLEXCAN_MCR_SOFT_RST; - while(FLEXCAN0_MCR & FLEXCAN_MCR_SOFT_RST) + FLEXCANb_MCR(flexcanBase) ^= FLEXCAN_MCR_SOFT_RST; + while(FLEXCANb_MCR(flexcanBase) & FLEXCAN_MCR_SOFT_RST) ; // wait for freeze ack - while(!(FLEXCAN0_MCR & FLEXCAN_MCR_FRZ_ACK)) + while(!(FLEXCANb_MCR(flexcanBase) & FLEXCAN_MCR_FRZ_ACK)) ; // disable self-reception - FLEXCAN0_MCR |= FLEXCAN_MCR_SRX_DIS; + FLEXCANb_MCR(flexcanBase) |= FLEXCAN_MCR_SRX_DIS; //enable RX FIFO - FLEXCAN0_MCR |= FLEXCAN_MCR_FEN; + FLEXCANb_MCR(flexcanBase) |= FLEXCAN_MCR_FEN; // segment splits and clock divisor based on baud rate - if ( 50000 == baud ) { - FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(1) - | FLEXCAN_CTRL_PSEG1(7) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(19)); + if ( 50000 == baud ) { + FLEXCANb_CTRL1(flexcanBase) = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(1) + | FLEXCAN_CTRL_PSEG1(7) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(19)); } else if ( 100000 == baud ) { - FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(1) - | FLEXCAN_CTRL_PSEG1(7) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(9)); + FLEXCANb_CTRL1(flexcanBase) = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(1) + | FLEXCAN_CTRL_PSEG1(7) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(9)); } else if ( 250000 == baud ) { - FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(1) - | FLEXCAN_CTRL_PSEG1(7) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(3)); + FLEXCANb_CTRL1(flexcanBase) = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(1) + | FLEXCAN_CTRL_PSEG1(7) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(3)); } else if ( 500000 == baud ) { - FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(1) - | FLEXCAN_CTRL_PSEG1(7) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(1)); + FLEXCANb_CTRL1(flexcanBase) = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(1) + | FLEXCAN_CTRL_PSEG1(7) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(1)); } else if ( 1000000 == baud ) { - FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(0) - | FLEXCAN_CTRL_PSEG1(1) | FLEXCAN_CTRL_PSEG2(1) | FLEXCAN_CTRL_PRESDIV(1)); + FLEXCANb_CTRL1(flexcanBase) = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(0) + | FLEXCAN_CTRL_PSEG1(1) | FLEXCAN_CTRL_PSEG2(1) | FLEXCAN_CTRL_PRESDIV(1)); } else { // 125000 - FLEXCAN0_CTRL1 = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(1) - | FLEXCAN_CTRL_PSEG1(7) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(7)); + FLEXCANb_CTRL1(flexcanBase) = (FLEXCAN_CTRL_PROPSEG(2) | FLEXCAN_CTRL_RJW(1) + | FLEXCAN_CTRL_PSEG1(7) | FLEXCAN_CTRL_PSEG2(3) | FLEXCAN_CTRL_PRESDIV(7)); } // Default mask is allow everything @@ -70,8 +112,8 @@ FlexCAN::FlexCAN(uint32_t baud) void FlexCAN::end(void) { // enter freeze mode - FLEXCAN0_MCR |= (FLEXCAN_MCR_HALT); - while(!(FLEXCAN0_MCR & FLEXCAN_MCR_FRZ_ACK)) + FLEXCANb_MCR(flexcanBase) |= (FLEXCAN_MCR_HALT); + while(!(FLEXCANb_MCR(flexcanBase) & FLEXCAN_MCR_FRZ_ACK)) ; } @@ -79,26 +121,26 @@ void FlexCAN::end(void) // ------------------------------------------------------------- void FlexCAN::begin(const CAN_filter_t &mask) { - FLEXCAN0_RXMGMASK = 0; + FLEXCANb_RXMGMASK(flexcanBase) = 0; //enable reception of all messages that fit the mask if (mask.ext) { - FLEXCAN0_RXFGMASK = ((mask.rtr?1:0) << 31) | ((mask.ext?1:0) << 30) | ((mask.id & FLEXCAN_MB_ID_EXT_MASK) << 1); + FLEXCANb_RXFGMASK(flexcanBase) = ((mask.rtr?1:0) << 31) | ((mask.ext?1:0) << 30) | ((mask.id & FLEXCAN_MB_ID_EXT_MASK) << 1); } else { - FLEXCAN0_RXFGMASK = ((mask.rtr?1:0) << 31) | ((mask.ext?1:0) << 30) | (FLEXCAN_MB_ID_IDSTD(mask.id) << 1); + FLEXCANb_RXFGMASK(flexcanBase) = ((mask.rtr?1:0) << 31) | ((mask.ext?1:0) << 30) | (FLEXCAN_MB_ID_IDSTD(mask.id) << 1); } // start the CAN - FLEXCAN0_MCR &= ~(FLEXCAN_MCR_HALT); + FLEXCANb_MCR(flexcanBase) &= ~(FLEXCAN_MCR_HALT); // wait till exit of freeze mode - while(FLEXCAN0_MCR & FLEXCAN_MCR_FRZ_ACK); + while(FLEXCANb_MCR(flexcanBase) & FLEXCAN_MCR_FRZ_ACK); // wait till ready - while(FLEXCAN0_MCR & FLEXCAN_MCR_NOT_RDY); + while(FLEXCANb_MCR(flexcanBase) & FLEXCAN_MCR_NOT_RDY); //set tx buffers to inactive for (int i = txb; i < txb + txBuffers; i++) { - FLEXCAN0_MBn_CS(i) = FLEXCAN_MB_CS_CODE(FLEXCAN_MB_CODE_TX_INACTIVE); + FLEXCANb_MBn_CS(flexcanBase, i) = FLEXCAN_MB_CS_CODE(FLEXCAN_MB_CODE_TX_INACTIVE); } } @@ -108,9 +150,9 @@ void FlexCAN::setFilter(const CAN_filter_t &filter, uint8_t n) { if ( 8 > n ) { if (filter.ext) { - FLEXCAN0_IDFLT_TAB(n) = ((filter.rtr?1:0) << 31) | ((filter.ext?1:0) << 30) | ((filter.id & FLEXCAN_MB_ID_EXT_MASK) << 1); + FLEXCANb_IDFLT_TAB(flexcanBase, n) = ((filter.rtr?1:0) << 31) | ((filter.ext?1:0) << 30) | ((filter.id & FLEXCAN_MB_ID_EXT_MASK) << 1); } else { - FLEXCAN0_IDFLT_TAB(n) = ((filter.rtr?1:0) << 31) | ((filter.ext?1:0) << 30) | (FLEXCAN_MB_ID_IDSTD(filter.id) << 1); + FLEXCANb_IDFLT_TAB(flexcanBase, n) = ((filter.rtr?1:0) << 31) | ((filter.ext?1:0) << 30) | (FLEXCAN_MB_ID_IDSTD(filter.id) << 1); } } } @@ -120,7 +162,7 @@ void FlexCAN::setFilter(const CAN_filter_t &filter, uint8_t n) int FlexCAN::available(void) { //In FIFO mode, the following interrupt flag signals availability of a frame - return (FLEXCAN0_IFLAG1 & FLEXCAN_IMASK1_BUF5M)? 1:0; + return (FLEXCANb_IFLAG1(flexcanBase) & FLEXCAN_IMASK1_BUF5M)? 1:0; } @@ -140,15 +182,15 @@ int FlexCAN::read(CAN_message_t &msg) } // get identifier and dlc - msg.len = FLEXCAN_get_length(FLEXCAN0_MBn_CS(rxb)); - msg.ext = (FLEXCAN0_MBn_CS(rxb) & FLEXCAN_MB_CS_IDE)? 1:0; - msg.id = (FLEXCAN0_MBn_ID(rxb) & FLEXCAN_MB_ID_EXT_MASK); + msg.len = FLEXCAN_get_length(FLEXCANb_MBn_CS(flexcanBase, rxb)); + msg.ext = (FLEXCANb_MBn_CS(flexcanBase, rxb) & FLEXCAN_MB_CS_IDE)? 1:0; + msg.id = (FLEXCANb_MBn_ID(flexcanBase, rxb) & FLEXCAN_MB_ID_EXT_MASK); if(!msg.ext) { msg.id >>= FLEXCAN_MB_ID_STD_BIT_NO; } // copy out message - uint32_t dataIn = FLEXCAN0_MBn_WORD0(rxb); + uint32_t dataIn = FLEXCANb_MBn_WORD0(flexcanBase, rxb); msg.buf[3] = dataIn; dataIn >>=8; msg.buf[2] = dataIn; @@ -157,7 +199,7 @@ int FlexCAN::read(CAN_message_t &msg) dataIn >>=8; msg.buf[0] = dataIn; if ( 4 < msg.len ) { - dataIn = FLEXCAN0_MBn_WORD1(rxb); + dataIn = FLEXCANb_MBn_WORD1(flexcanBase, rxb); msg.buf[7] = dataIn; dataIn >>=8; msg.buf[6] = dataIn; @@ -171,7 +213,7 @@ int FlexCAN::read(CAN_message_t &msg) } //notify FIFO that message has been read - FLEXCAN0_IFLAG1 = FLEXCAN_IMASK1_BUF5M; + FLEXCANb_IFLAG1(flexcanBase) = FLEXCAN_IMASK1_BUF5M; return 1; } @@ -187,7 +229,7 @@ int FlexCAN::write(const CAN_message_t &msg) // find an available buffer int buffer = -1; for ( int index = txb; ; ) { - if ((FLEXCAN0_MBn_CS(index) & FLEXCAN_MB_CS_CODE_MASK) == FLEXCAN_MB_CS_CODE(FLEXCAN_MB_CODE_TX_INACTIVE)) { + if ((FLEXCANb_MBn_CS(flexcanBase, index) & FLEXCAN_MB_CS_CODE_MASK) == FLEXCAN_MB_CS_CODE(FLEXCAN_MB_CODE_TX_INACTIVE)) { buffer = index; break;// found one } @@ -205,20 +247,20 @@ int FlexCAN::write(const CAN_message_t &msg) } // transmit the frame - FLEXCAN0_MBn_CS(buffer) = FLEXCAN_MB_CS_CODE(FLEXCAN_MB_CODE_TX_INACTIVE); + FLEXCANb_MBn_CS(flexcanBase, buffer) = FLEXCAN_MB_CS_CODE(FLEXCAN_MB_CODE_TX_INACTIVE); if(msg.ext) { - FLEXCAN0_MBn_ID(buffer) = (msg.id & FLEXCAN_MB_ID_EXT_MASK); + FLEXCANb_MBn_ID(flexcanBase, buffer) = (msg.id & FLEXCAN_MB_ID_EXT_MASK); } else { - FLEXCAN0_MBn_ID(buffer) = FLEXCAN_MB_ID_IDSTD(msg.id); + FLEXCANb_MBn_ID(flexcanBase, buffer) = FLEXCAN_MB_ID_IDSTD(msg.id); } - FLEXCAN0_MBn_WORD0(buffer) = (msg.buf[0]<<24)|(msg.buf[1]<<16)|(msg.buf[2]<<8)|msg.buf[3]; - FLEXCAN0_MBn_WORD1(buffer) = (msg.buf[4]<<24)|(msg.buf[5]<<16)|(msg.buf[6]<<8)|msg.buf[7]; + FLEXCANb_MBn_WORD0(flexcanBase, buffer) = (msg.buf[0]<<24)|(msg.buf[1]<<16)|(msg.buf[2]<<8)|msg.buf[3]; + FLEXCANb_MBn_WORD1(flexcanBase, buffer) = (msg.buf[4]<<24)|(msg.buf[5]<<16)|(msg.buf[6]<<8)|msg.buf[7]; if(msg.ext) { - FLEXCAN0_MBn_CS(buffer) = FLEXCAN_MB_CS_CODE(FLEXCAN_MB_CODE_TX_ONCE) - | FLEXCAN_MB_CS_LENGTH(msg.len) | FLEXCAN_MB_CS_SRR | FLEXCAN_MB_CS_IDE; + FLEXCANb_MBn_CS(flexcanBase, buffer) = FLEXCAN_MB_CS_CODE(FLEXCAN_MB_CODE_TX_ONCE) + | FLEXCAN_MB_CS_LENGTH(msg.len) | FLEXCAN_MB_CS_SRR | FLEXCAN_MB_CS_IDE; } else { - FLEXCAN0_MBn_CS(buffer) = FLEXCAN_MB_CS_CODE(FLEXCAN_MB_CODE_TX_ONCE) - | FLEXCAN_MB_CS_LENGTH(msg.len); + FLEXCANb_MBn_CS(flexcanBase, buffer) = FLEXCAN_MB_CS_CODE(FLEXCAN_MB_CODE_TX_ONCE) + | FLEXCAN_MB_CS_LENGTH(msg.len); } return 1; diff --git a/FlexCAN.h b/FlexCAN.h index 19e92e8..eb20c0d 100644 --- a/FlexCAN.h +++ b/FlexCAN.h @@ -1,6 +1,7 @@ // ------------------------------------------------------------- -// a simple Arduino Teensy3.1 CAN driver +// a simple Arduino Teensy 3.1/3.2/3.5/3.6 CAN driver // by teachop +// dual CAN support for MK66FX1M0 and updates for MK64FX512 by Pawelsky // #ifndef __FLEXCAN_H__ #define __FLEXCAN_H__ @@ -26,9 +27,10 @@ class FlexCAN { private: struct CAN_filter_t defaultMask; + uint32_t flexcanBase; public: - FlexCAN(uint32_t baud = 125000); + FlexCAN(uint32_t baud = 125000, uint8_t id = 0, uint8_t txAlt = 0, uint8_t rxAlt = 0); void begin(const CAN_filter_t &mask); inline void begin() { diff --git a/FlexCAN_pins_35.png b/FlexCAN_pins_35.png new file mode 100644 index 0000000..4f997dc Binary files /dev/null and b/FlexCAN_pins_35.png differ diff --git a/FlexCAN_pins_36.png b/FlexCAN_pins_36.png new file mode 100644 index 0000000..f8fceff Binary files /dev/null and b/FlexCAN_pins_36.png differ diff --git a/FlexCAN_pins_alt.png b/FlexCAN_pins_alt.png new file mode 100644 index 0000000..bac2fe0 Binary files /dev/null and b/FlexCAN_pins_alt.png differ diff --git a/README.md b/README.md index e94ffd8..74331e5 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,30 @@ -##CANbus Library for Teensy 3.1 +## CANbus Library for Teensy 3.1, 3.2, 3.5 and 3.6 -###Introduction -FlexCAN is a serial communication driver for the CAN0 peripheral built into the Teensy 3.1 CPU. The driver is organized in the Arduino library format. +### Introduction +FlexCAN is a serial communication driver for the CAN peripherial built into the Teensy CPUs. Versions 3.1, 3.2 and 3.5 of the board support single CAN0 controller while version 3.6 supports dual CAN0/CAN1 controllers. The driver is organized in the Arduino library format. -When the FlexCAN object is constructed, Arduino pins Digital 3 and Digital 4 are assigned to CAN functions TX and RX. These should be wired to a 3.3V CAN transceiver TXD and RXD respectively to allow connection of the Teensy 3.1 to a CAN network. +When the FlexCAN object is constructed on Teensy 3.1/3.2, Arduino pins Digital 3 and Digital 4 (or alternatively Digital 32 and Digital 25) are assigned to CAN functions TX and RX. -![Teensy 3.1 CAN Pins, Digital3=TX, Digital4=RX](/FlexCAN_pins.png) +![Teensy 3.1/3.2 CAN Pins, Digital3=TX, Digital4=RX](/FlexCAN_pins.png) ![Teensy 3.1/3.2 Alternative CAN Pins, Digital32=TX, Digital25=RX](/FlexCAN_pins_alt.png) -Even though the Teensy is operating on 3.3V, use of 5V transceivers may be an option if the system has regulated +5V available. The CAN RXD input on the CPU is 5V tolerant and most 5V transceivers will accept the 3V TXD signal. This is a good choice for breadboarding due to availability of thru-hole 5V transceiver parts. +Similarily on Teensy 3.5, the same Arduino pins Digital 3 and Digital 4 (or alternatively Digital 29 and Digital 30) are assigned to CAN functions TX and RX. + +![Teensy 3.5 CAN Pins, Digital3=TX, Digital4=RX (or alternatively Digital29=TX, Digital30=RX)](/FlexCAN_pins_35.png) + +On Teensy 3.6 it is possible to to specify the **id** parameter and select whether CAN0 or CAN1 shall be used. For CAN0 Arduino pins Digital 3 and Digital 4 (or alternatively Digital 29 and Digital 30) are assigned to CAN functions TX and RX. For CAN1 Arduino pins Digital 34 and Digital 33 are assigned to CAN functions TX and RX. + +![Teensy 3.6 CAN Pins, CAN0: Digital3=TX and Digital4=RX (or alternatively Digital29=TX, Digital30=RX), CAN1: Digital34=TX and Digital33=RX](/FlexCAN_pins_36.png) + +CAN RX and TX pins should be wired to a 3.3V CAN transceiver TXD and RXD respectively to allow connection of the Teensy 3.1/3.2/3.5/3.6 to a CAN network. + +Even though the Teensy 3.1/3.2/3.5 is operating on 3.3V, use of 5V transceivers may be an option if the system has regulated +5V available. The CAN RXD input on the CPU is 5V tolerant and most 5V transceivers will accept the 3V TXD signal. This is a good choice for breadboarding due to availability of thru-hole 5V transceiver parts. +**In case of Teensy 3.6 the digital pins are not 5V tolerant, so 3.3V transceivers must be used!** Note that CAN will normally require termination resistors. These are located at the two ends of a CAN bus to prevent reflections. Do not add more terminators when connecting devices to an existing properly terminated CAN bus. Supported baud rates are 50000, 100000, 125000, 250000, 500000, and 1000000 bits per second. If the baud rate is not specified it will default to 125000. -###CAN Transceiver Options +### CAN Transceiver Options Please add parts you are using successfully with Teensy 3.1 to this list. - TI SN65HVD230D on 3.3V (1MBPS) - TI SN65HVD232D / SN65HVD232QDQ1 on 3.3V (1MBPS) @@ -21,7 +32,17 @@ Please add parts you are using successfully with Teensy 3.1 to this list. - Microchip MCP2551 on 5V (reported at 500KBPS) - Linear LT1796 on 5V (not speedtested) -###Driver API +### Driver API +**FlexCAN(baud, id, txAlt, rxAlt)** +Create the FlexCAN object. The table below describes each parameter together with allowed values. Defaults are marked **bold**. When a non-allowed value is used default will be taken instead. + +| Parameter | Description | Allowed values +|-----------|----------------------|---------------------------------------------------------------------------- +| baud | baudrate [bps] | Teensy 3.1/3.2/3.5/3.6: 50000, 100000, **125000**, 250000, 500000, 1000000 +| id | FlexCAN interface ID | Teensy 3.1/3.2/3.5: **0** (CAN0)
Teensy 3.6: **0** (CAN0), 1 (CAN1) +| txAlt | Alternative TX pin | Teensy 3.1/3.2: **0** (PIN3), 1 (PIN32)
Teensy 3.5/3.6 CAN0: **0** (PIN3), 1 (PIN29)
Teensy 3.6 CAN1: **0** (PIN33) +| rxAlt | Alternative RX pin | Teensy 3.1/3.2: **0** (PIN4), 1 (PIN25)
Teensy 3.5/3.6 CAN0: **0** (PIN4), 1 (PIN30)
Teensy 3.6 CAN1: **0** (PIN34) + **begin()** Enable the CAN to start actively participating on the CANbus. @@ -39,7 +60,7 @@ Receive a frame into "message" if available. **read()** will return 1 if a fram **available()** Returns 1 if at least one receive frame is waiting, or 0 if no frame is available. -###Use of Optional RX Filtering +### Use of Optional RX Filtering **begin(mask)** Enable the CAN to start actively participating on the CANbus. Enable reception of all messages that fit the mask. This is a global mask that applies to all the receive filters. @@ -48,7 +69,7 @@ Set the receive filter selected by number, 0-7. When using filters it is requir The mask and filter are **CAN_filter_t** type structures. -###Caller Blocking Support +### Caller Blocking Support Support has been included for wait / blocking in both the **read()** and **write()** calls. When the **CAN_message_t** field **timeout** is given, the **read()** and **write()** calls will wait if needed until the frame transfer can take place. The maximum wait for transfer is specified by **timeout** in milliseconds. If the call times out, it will return 0 as in the non-blocking case. @@ -57,6 +78,6 @@ Setting the timeout field to 0 will make the calls non-blocking. The timeout monitoring mechanism calls **yield()** until a buffer is found or the timeout time is exceeded. -###In-order Transmission +### In-order Transmission Caller blocking can be used to **write()** frames guaranteed in-order to the bus. When caller blocking is selected for **write()** (non-zero timeout specified), a single hardware transmit buffer is used. diff --git a/examples/dualCANtest/dualCANtest.ino b/examples/dualCANtest/dualCANtest.ino new file mode 100644 index 0000000..f042936 --- /dev/null +++ b/examples/dualCANtest/dualCANtest.ino @@ -0,0 +1,62 @@ +// ------------------------------------------------------------- +// CANtest for Teensy 3.6 dual CAN bus +// by Pawelsky (based on CANtest by teachop) +// +// This test transmits all data coming from CAN0 to CAN1 and vice versa (at 1Mbps) +// + +#include + +#ifndef __MK66FX1M0__ + #error "Teensy 3.6 with dual CAN bus is required to run this example" +#endif + +FlexCAN CANbus0(1000000, 0); +FlexCAN CANbus1(1000000, 1); + +static CAN_message_t msg; +static uint8_t hex[17] = "0123456789abcdef"; + + +// ------------------------------------------------------------- +static void hexDump(uint8_t dumpLen, uint8_t *bytePtr) +{ + uint8_t working; + while( dumpLen-- ) { + working = *bytePtr++; + Serial.write( hex[ working>>4 ] ); + Serial.write( hex[ working&15 ] ); + } + Serial.write('\r'); + Serial.write('\n'); +} + + +// ------------------------------------------------------------- +void setup(void) +{ + CANbus0.begin(); + CANbus1.begin(); + + delay(1000); + Serial.println(F("Hello Teensy 3.6 dual CAN Test.")); +} + + +// ------------------------------------------------------------- +void loop(void) +{ + if(CANbus0.available()) + { + CANbus0.read(msg); +// Serial.print("CAN bus 0: "); hexDump(8, msg.buf); + CANbus1.write(msg); + } + + if(CANbus1.available()) + { + CANbus1.read(msg); +// Serial.print("CAN bus 1: "); hexDump(8, msg.buf); + CANbus0.write(msg); + } +} \ No newline at end of file