Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Patch 3 #21

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
165 changes: 109 additions & 56 deletions FlexCAN.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// -------------------------------------------------------------
// a simple Arduino Teensy3.1 CAN driver
// a simple Arduino Teensy 3.1/3.2/3.6 CAN driver
// by teachop
// dual CAN support for MK66FX1M0 by Pawelsky
//
#include "FlexCAN.h"
#include "kinetis_flexcan.h"
Expand All @@ -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)
{
#ifdef __MK66FX1M0__
// 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
Expand All @@ -70,35 +112,35 @@ 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))
;
}


// -------------------------------------------------------------
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);
}
}

Expand All @@ -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);
}
}
}
Expand All @@ -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;
}


Expand All @@ -140,15 +182,16 @@ 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.rtr = (FLEXCANb_MBn_CS(flexcanBase, rxb) & FLEXCAN_MB_CS_RTR)? 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;
Expand All @@ -157,7 +200,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;
Expand All @@ -171,7 +214,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;
}
Expand All @@ -187,7 +230,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
}
Expand All @@ -205,20 +248,30 @@ 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;
if(msg.rtr) {
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 | FLEXCAN_MB_CS_RTR;
} else {
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);
if(msg.rtr) {
FLEXCANb_MBn_CS(flexcanBase, buffer) = FLEXCAN_MB_CS_CODE(FLEXCAN_MB_CODE_TX_ONCE)
| FLEXCAN_MB_CS_LENGTH(msg.len) | FLEXCAN_MB_CS_RTR;
} else {
FLEXCANb_MBn_CS(flexcanBase, buffer) = FLEXCAN_MB_CS_CODE(FLEXCAN_MB_CODE_TX_ONCE)
| FLEXCAN_MB_CS_LENGTH(msg.len);
}
}

return 1;
Expand Down
7 changes: 5 additions & 2 deletions FlexCAN.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// -------------------------------------------------------------
// a simple Arduino Teensy3.1 CAN driver
// a simple Arduino Teensy 3.1/3.2/3.6 CAN driver
// by teachop
// dual CAN support for MK66FX1M0 by Pawelsky
//
#ifndef __FLEXCAN_H__
#define __FLEXCAN_H__
Expand All @@ -10,6 +11,7 @@
typedef struct CAN_message_t {
uint32_t id; // can identifier
uint8_t ext; // identifier is extended
uint8_t rtr; // remote transmission request packet type
uint8_t len; // length of data
uint16_t timeout; // milliseconds, zero will disable waiting
uint8_t buf[8];
Expand All @@ -26,9 +28,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()
{
Expand Down
Binary file added FlexCAN_pins_36.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 13 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
##CANbus Library for Teensy 3.1
##CANbus Library for Teensy 3.1, 3.2 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.
FlexCAN is a serial communication driver for the CAN peripherial built into the Teensy CPUs. Versions 3.1 and 3.2 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 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)

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.
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 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, 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.6 to a CAN network.

Even though the Teensy 3.1/3.2 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.

Expand All @@ -20,6 +27,7 @@ Please add parts you are using successfully with Teensy 3.1 to this list.
- NXP TJA1050T/VM,118 on the same 5V supply as the Teensy. (1MBPS)
- Microchip MCP2551 on 5V (reported at 500KBPS)
- Linear LT1796 on 5V (not speedtested)
- Microchip MCP2562 with VIO on 3.3V (tested on Teensy 3.2 and 3.6)

###Driver API
**begin()**
Expand Down
Loading