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

Support for Teensy 3.5 and 3.6 (dual CAN) + alternative CAN pins #19

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
154 changes: 98 additions & 56 deletions 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"
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)
{
#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
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,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;
Expand All @@ -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;
Expand All @@ -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;
}
Expand All @@ -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
}
Expand All @@ -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;
Expand Down
6 changes: 4 additions & 2 deletions 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__
Expand All @@ -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()
{
Expand Down
Binary file added FlexCAN_pins_35.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added FlexCAN_pins_36.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added FlexCAN_pins_alt.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 32 additions & 11 deletions README.md
@@ -1,27 +1,48 @@
##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)
- 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)

###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)<br>Teensy 3.6: **0** (CAN0), 1 (CAN1)
| txAlt | Alternative TX pin | Teensy 3.1/3.2: **0** (PIN3), 1 (PIN32)<br>Teensy 3.5/3.6 CAN0: **0** (PIN3), 1 (PIN29)<br>Teensy 3.6 CAN1: **0** (PIN33)
| rxAlt | Alternative RX pin | Teensy 3.1/3.2: **0** (PIN4), 1 (PIN25)<br>Teensy 3.5/3.6 CAN0: **0** (PIN4), 1 (PIN30)<br>Teensy 3.6 CAN1: **0** (PIN34)

**begin()**
Enable the CAN to start actively participating on the CANbus.

Expand All @@ -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.

Expand All @@ -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.
Expand All @@ -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.