FlexCAN_T4 - FlexCAN for Teensy 4

In your program, when you want to check if errors exist, you should be able to do something like this:
Code:
void loop() {
  ... some other code ...

  static uint32_t timeout = millis();
  if ( millis() - timeout > 1000 ) {  // Check for errors every 1000 ms
    CAN_error_t err;
    if CAN0.error(err, true) {
      // the "err" structure will be populated with the current errors.
      // Second argument set to true tells the error() function to ...
      // serial.print() the current errors. 
      ... some code to handle errors here ...
    }
  }
  ... some other code ...
}

worked like a champ thank you!
 
FIFO blocks mboxes

Trying to use the FIFO blocks mboxes, both polled and interrupt driven.

Initialization:

Code:
void MCOUSER_ResetCommunication(void){
  int i;

  gTimCnt = GTIMCNT; // Initialize global timer
  canbus1.begin(); // Must be first JGH
  canbus1.setMaxMB(16);
  canbus1.setMBFilter(REJECT_ALL);
  canbus1.setBaudRate(1000*BAUDRATE);
  for(i = 0; i < (NR_OF_RPDOS + 2); i++) { // NMT and SDO will use the first two boxes.
    canbus1.setMB((FLEXCAN_MAILBOX)i, RX, STD);
    if(i > 1){
    canbus1.onReceive((FLEXCAN_MAILBOX)i, canbus_isr); // Get all RPDOs via interrupt. 
    canbus1.enableMBInterrupt((FLEXCAN_MAILBOX)i); 
    }
  }
  for(; i < (NR_OF_RPDOS + NR_OF_TPDOS); i++) {
    canbus1.setMB((FLEXCAN_MAILBOX)i, TX, STD);
  }
  // For sync
  #ifdef SYNC
  canbus1.setMB((FLEXCAN_MAILBOX)i, RX, STD);
  canbus1.setMBFilter((FLEXCAN_MAILBOX)i, 0x080);
  canbus1.onReceive((FLEXCAN_MAILBOX)i, canbus_sync);
  canbus1.enableMBInterrupt((FLEXCAN_MAILBOX)i);
  #endif
  // BAUDRATE,Node_ID,HEARTRATE defined at the top of this file.  JGH
  MCO_Init(BAUDRATE,Node_ID,HEARTRATE);

  // Default base receive COBs are 0x200, 0x300, 0x400, and 0x500
  // Calling MCO_InitRPDO or MCO_InitTPDO with COB-ID 0 results in default
  // RPDO1, default ID (0x200+nodeID), 4 bytes
  MCO_InitRPDO(1, 0, 4, &target_speed); 

  // RPDO2, default ID (0x300+nodeID), 4 bytes
  MCO_InitRPDO(2, 0, 4, &acceleration);
  
  //BYTE PDO_NR,  WORD CAN_ID, WORD event_time, WORD inhibit_time, BYTE len, BYTE offset
  // TPDO1, default ID (0x180+nodeID), 100ms event, 5ms inhibit, 4 bytes
  // Transmit trigger: COS (change-of-state) with 250ms inhibit time
  MCO_InitTPDO(1, 0, 0, 5, 4, &control_word);    

  // TPDO2, default ID (0x280+nodeID), 100ms event, 5ms inhibit, 4 bytes
  // Transmit trigger: COS (change-of-state) with 250ms inhibit time
  MCO_InitTPDO(2, 0, 0, 5, 4, &status_word); 

  // TPDO3, default ID (0x380+nodeID), 100ms event, 5ms inhibit, 4 bytes
  // Transmit trigger: COS with 100ms inhibit time, but if there is no COS within
  // 1000ms, message gets triggered, too
  MCO_InitTPDO(3, 0, 0, 5, 4, &target_speed);

  // TPDO4, default ID (0x480+nodeID), 100ms event, 5ms inhibit, 4 bytes
  // Transmit trigger: COS with 100ms inhibit time, but if there is no COS within
  // 1000ms, message gets triggered, too
  MCO_InitTPDO(4, 0, 0, 5, 4, &acceleration);
}


/**************************************************************************
DOES:    ISR for RPDO mailboxes. Writes message content to the correct PDO
         if the state_machine state permits. JGH
         
RETURNS: nothing
**************************************************************************/
void canbus_isr(const CAN_message_t &msg) {
  int i;
  if(gMCOConfig.heartbeat_msg.BUF[0] != 5) return; // Only receive in operational state.
  i = mbox_to_RPDO[msg.mb]; // This tells us what RPDO this mbox goes with.
  if(gRPDOConfig[i].len != msg.len) return; // Not a valid message.  Should set an error. JGH
  memcpy(gRPDOConfig[i].offset, msg.buf, gRPDOConfig[i].len);
}

Added to experiment with the FIFO:

Code:
  canbus1.enableFIFO();
  canbus1.disableFIFOInterrupt();
  canbus1.setFIFOFilter(REJECT_ALL);
  canbus1.enhanceFilter(FIFO);
  canbus1.setFIFOFilter(7, 0x123, STD);

NMTs (id 0x000) and SDOs (id 0x607) are polled with this:
Code:
BYTE MCOHW_PullMessage(CAN_MSG *pReceiveBuf){
  // pointer to a single message sized buffer to hold the received message
 
  // variable declarations
  BYTE  Length;
  BYTE  i;
  CAN_message_t msg;
  if(canbus1.readMB(msg)){
    pReceiveBuf->ID = msg.id;
    pReceiveBuf->LEN = msg.len;
    // Read data bytes and write to buffer
    for (i=0; i < msg.len; i++){
      // copy bytes
      *(BYTE *)(pReceiveBuf->BUF+i) = msg.buf[i];
    }
    return (1);
  }
  else {
    // return 0, no message received
    return (0);
  }
}

RPDOs are handled by the ISR.

The FIFO is read with this:
Code:
  CAN_message_t mesg;
  if(canbus1.readFIFO(mesg)) {
    
    Serial.print("ID "); Serial.print(mesg.id, HEX);
    Serial.print(" Filter "); Serial.print(mesg.idhit, HEX);
    Serial.print(" LEN: "); Serial.print(mesg.len);
    Serial.print(" Buffer: ");
    for ( uint8_t i = 0; i < mesg.len; i++ ) {
      Serial.print(mesg.buf[i], HEX); Serial.print(" ");
    } Serial.println();
    
  }

Everything works fine with the experimental FIFO stuff commented out. The FIFO code works as expected but when it's enabled all mboxes are blocked.
Uncommenting just the FIFO initialization blocks the mboxes.
 
Last edited:
Hi

I have taken a lot of time to find a solution for my problem. I didn't find it.

I use the following filter:

Can.setFIFOFilter(0, 0x18DAF100, EXT);

How is it possible to erase this filter to get all messages? I need this filter only for a short time.

First - filter then all messages

Thanx
Gary
 
Gary, based on looking at the library, try:
Code:
Can.setFIFOFilter(Accept_All);
Also, in case you weren't aware,
Code:
Can.MailboxStatus();
is an easy way to see what's going on with the mailboxes and filters.
 
Hello,

I am trying to run a Teensy 4.1 with two SN65HVD230 transceivers to talk to two can networks.

I have no issues with getting CAN1 working on the 125k can network, but I cant get CAN2 to connect to my 83.3k network.

I am using the Flexcan_T4 Library.
 
error() sometimes returns true on transition between "Idle" and Receive"

Example:

FlexCAN State: Idle, FLT_CONF: Error Active
In GetStatus gMCOHW_status = 1
Receive errors = 0
Transmit errors = 0
error.ESR1 = 40080
FlexCAN State: Receiving, FLT_CONF: Error Active
In GetStatus gMCOHW_status = 1
Receive errors = 0
Transmit errors = 0
error.ESR1 = 40008
FlexCAN State: Idle, FLT_CONF: Error Active
In GetStatus gMCOHW_status = 1
Receive errors = 0
Transmit errors = 0
error.ESR1 = 40080

gMCOHW_status = 1 means that the error variable contained no errors.

I'm using a Teensy 3.6 running my heavily-hacked version of Microcanopen (no threads or interrupts: polling only). It is sending a TPDO every millisecond and receiving an RPDO sent by this script:

while true; do sleep .001; cansend can0 307#ffffffff; done

The bus master is canopend from Canopennode running under Linux on a pc connected to the Teensy by an 8devices USB to CAN converter.

The relevant code from the Canopen implementation:

Code:
uint8_t MCOHW_GetStatus(void) {
  CAN_error_t error;
  bool cerr = false, erpa = false, boff = false;
  int state = CO_INTERFACE_ACTIVE; // Is this the right thing to do if no errors?
  gMCOHW_status &= INIT; // Clear CAN status but leave INIT state unchanged
  if(canbus1.error(error, PRINT_ERRORS)){ // PRINT_ERRORS is defined in mco.h
    // Evidently returns zero quickly if there are no errors
    cerr = error.BIT1_ERR || error.BIT0_ERR || error.ACK_ERR || error.CRC_ERR \
      || error.FRM_ERR || error.STF_ERR;
    
    if ((error.ESR1 & 0x30) == 0x0) { // Copied from FlexCAN_T4
      erpa = 0; // Error active
      state = CO_INTERFACE_ACTIVE;
	}
    else if ((error.ESR1 & 0x30) == 0x1) { // Copied from FlexCAN_T4
      erpa = 1; // Error passive
      Serial.println("MCOHW_GetStatus: Error passive");
      state = CO_INTERFACE_LISTEN_ONLY;
    }
    else {
      boff = 1; // Bus off 
      Serial.println("MCOHW_GetStatus: Bus off");
      state = CO_INTERFACE_BUS_OFF;
    }
    gMCOHW_status |= cerr << 1;
    gMCOHW_status |= erpa << 2;
    gMCOHW_status |= error.TX_WRN << 3;
    gMCOHW_status |= error.RX_WRN << 4;
    gMCOHW_status |= boff << 7;
    Serial.print("In GetStatus gMCOHW_status = "); Serial.println(gMCOHW_status, BIN); // JGH debug
    Serial.print("Receive errors = "); Serial.println(error.RX_ERR_COUNTER);
    Serial.print("Transmit errors = "); Serial.println(error.TX_ERR_COUNTER);
    Serial.print("error.ESR1 = "); Serial.println(error.ESR1, HEX);
  }
  if((gMCOConfig.CANinterfaceState == CO_INTERFACE_BUS_OFF) && (state != CO_INTERFACE_BUS_OFF)) {
    Serial.println("MCOHW_GetStatus: Recovered from BUS_OFF");
    MCO_Handle_EMCY(CO_EMC_BUS_OFF_RECOVERED);
  }
  gMCOConfig.CANinterfaceState = state;
  return gMCOHW_status;
}

I'm using the FIFO with 8 filters allocated and with enhanceFilter(FIFO). The other mboxes are configured for transmit with TPDOs being sent via write(). It all works quite well but for this oddity.

I can provide more code, of course, but the total is about 2100 lines.
 
Last edited:
So canbus1.error() returns true, but once the errors print, there are none?
Am I understanding this correctly? If so, can you post the canbus.error() function?
 
The error() function is part of FlexCAN_T4.

Code:
FCTP_FUNC bool FCTP_OPT::error(CAN_error_t &error, bool printDetails) {
  if ( !busESR1.size() ) return 0;
  NVIC_DISABLE_IRQ(nvicIrq);
  error.ESR1 = busESR1.read();
  error.ECR = busECR.read();

  if ( (error.ESR1 & 0x400C8) == 0x40080 ) strncpy((char*)error.state, "Idle", (sizeof(error.state) - 1));
  else if ( (error.ESR1 & 0x400C8) == 0x0 ) strncpy((char*)error.state, "Not synchronized to CAN bus", (sizeof(error.state) - 1));
  else if ( (error.ESR1 & 0x400C8) == 0x40040 ) strncpy((char*)error.state, "Transmitting", (sizeof(error.state) - 1));
  else if ( (error.ESR1 & 0x400C8) == 0x40008 ) strncpy((char*)error.state, "Receiving", (sizeof(error.state) - 1));

  error.BIT1_ERR = (error.ESR1 & (1UL << 15)) ? 1 : 0;
  error.BIT0_ERR = (error.ESR1 & (1UL << 14)) ? 1 : 0;
  error.ACK_ERR = (error.ESR1 & (1UL << 13)) ? 1 : 0;
  error.CRC_ERR = (error.ESR1 & (1UL << 12)) ? 1 : 0;
  error.FRM_ERR = (error.ESR1 & (1UL << 11)) ? 1 : 0;
  error.STF_ERR = (error.ESR1 & (1UL << 10)) ? 1 : 0;
  error.TX_WRN = (error.ESR1 & (1UL << 9)) ? 1 : 0;
  error.RX_WRN = (error.ESR1 & (1UL << 8)) ? 1 : 0;

  if ( (error.ESR1 & 0x30) == 0x0 ) strncpy((char*)error.FLT_CONF, "Error Active", (sizeof(error.FLT_CONF) - 1));
  else if ( (error.ESR1 & 0x30) == 0x1 ) strncpy((char*)error.FLT_CONF, "Error Passive", (sizeof(error.FLT_CONF) - 1));
  else strncpy((char*)error.FLT_CONF, "Bus off", (sizeof(error.FLT_CONF) - 1));

  error.RX_ERR_COUNTER = (uint8_t)(error.ECR >> 8);
  error.TX_ERR_COUNTER = (uint8_t)error.ECR;

  if ( printDetails ) printErrors(error);
  NVIC_ENABLE_IRQ(nvicIrq);
  return 1;
}
 
Getting confused with this library

Hi, I am programming two teensys 4.1 and I am using this library. While I was programming, I was trying to check if there are any CAN messages available in my loop() like this:
void loop() {
// Check if there are any CAN messages available
if (can0.available()) {
// Read the CAN message
CAN_message_t msg;
can0.read(msg);

But there is no function "available()". Is there any function that does what I want to do or if I need to use another approach what would that be?
 
But there is no function "available()". Is there any function that does what I want to do or if I need to use another approach what would that be?

In the Arduino IDE, take a look at the examples under File / Examples / Examples for Teensy 4.1 / FlexCAN_T4. One or more of those should get you started.

Mark J Culross
KD5RXT
 
@jmlima44 mine works like this:

Code:
#include <FlexCAN_T4.h>
CAN_message_t can_fwd_car;
FlexCAN_T4<CAN2, RX_SIZE_32, TX_SIZE_32> can_master;

void setup() {
  // put your setup code here, to run once:
  can_master.begin();
  can_master.setBaudRate(125000);
}

void loop() {
  // put your main code here, to run repeatedly:
  
  if (can_master.read(can_fwd_car)) {
    
    //  do something with the data in can_fwd_car
  
  }

  //  rest of code

}
 
I have no issues with getting CAN1 working on the 125k can network, but I cant get CAN2 to connect to my 83.3k network.
I have also experienced the same. Many other speeds, such as 250k and 500k work nicely for me too. But the 83.3k is not. I have tried all the different clock rates, still no luck. Has someone got the 83.3k speed working with Flexcan library? I am currently browsing other options as I really need this speed in my project.
 
I don't have a device that runs at 83.3k so the following code might not work.

All I can test is on a CAN-bus analyser.

Try this :
Code:
#include <FlexCAN_T4.h>

FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> can1;
uint8_t i;

void setup(void) {
  
  can1.begin();
  can1.setBaudRate(83333);
  can1.enableFIFO();
  can1.enableFIFOInterrupt();
  can1.onReceive(FIFO, canSniff20);
  can1.mailboxStatus();
 
    }


void canSniff20(const CAN_message_t &msg) { // global callback
  Serial.print("T4: ");
  Serial.print("MB "); Serial.print(msg.mb);
  Serial.print(" OVERRUN: "); Serial.print(msg.flags.overrun);
  Serial.print(" BUS "); Serial.print(msg.bus);
  Serial.print(" LEN: "); Serial.print(msg.len);
  Serial.print(" EXT: "); Serial.print(msg.flags.extended);
  Serial.print(" REMOTE: "); Serial.print(msg.flags.remote);
  Serial.print(" TS: "); Serial.print(msg.timestamp);
  Serial.print(" ID: "); Serial.print(msg.id, HEX);
  Serial.print(" IDHIT: "); Serial.print(msg.idhit);
  Serial.print(" Buffer: ");
  for ( uint8_t i = 0; i < msg.len; i++ ) {
    Serial.print(msg.buf[i], HEX); Serial.print(" ");
  } Serial.println();
}
 
void loop() {
  CAN_message_t msg1;

  msg1.id = 0x7df;
  msg1.buf[0] = i++;
  can1.write(msg1);
  
  delay(100);
}

CAN-bus analyser show is it working at 83.33k
Cursor_and_192_168_1_28.jpg
 
I don't have a device that runs at 83.3k so the following code might not work.

All I can test is on a CAN-bus analyser.

Try this :

Hi. Now tested this with a car. Even it works at PCAN analyser fine, but it does not work with real car env. Actually, plugging in the Teensy to the car canbus, it jams the bus completely. Even if there is no power on the Teeensy yet. I am thinking it might be a CAN tranceiver likely. To verify this, I have tested this with two different tranceivers SN65HVD230 (cheap aliexpress one) and TCAN330 (Fusion Tech manufactured dual can tranceiver for T4). Both of these work with other speeds, such 500k just prefectly, but for 83.3k, bus is stalling completely.

Some other boards with CAN tranceivers work fine with the 83.3k speed, such as Seeedstudio I2C can adapter hooked to Wemos mini (or any other).

I would love to use Teensy4 in my project due to need of 3 buses, but it looks I need to look other directions. The car with the challenging CANBUS speed of 83.3k is Jeep Patriot 2011.

All tips are welcomed. Thanks!
 
If you have a known working transceiver then the speed shouldn't really matter as long as it is 1Mbps or below.

I would use your CAN-bus analyser, set it to 83.3k and connect it to your car to see if any data on PCAN-View.

If you don't see any data that means it is not quite 83.3k

If you see data that means your Teensy/transceiver/wiring/termination is not quite right.
 
If you have a known working transceiver then the speed shouldn't really matter as long as it is 1Mbps or below.

I would use your CAN-bus analyser, set it to 83.3k and connect it to your car to see if any data on PCAN-View.

If you don't see any data that means it is not quite 83.3k

If you see data that means your Teensy/transceiver/wiring/termination is not quite right.

Thanks for your advice. This is actually the mystery here. My PCAN analyser sees all the traffic at bus set to 83.3k and the same Teensy 4.0 with the tranceiver can be hooked to a 500k bus in the same car. And works beautifully. So the only variable left here is the termination of which I have tried with and without. Still no luck.

As a side comment to my findings. if the T4 and PCAN analyser are plugged in, the car bus goes silent, but if I send some frames with the PCAN analyser to the bus, the T4 sees these fine. Even if the frames are previously captured from the bus while it was live.

Loosing my faith with this.
 
If you plug the T4 and PCAN analyser in and the car bus goes silent.

If the bitrate is set correctly then it could be that the CAN_H and CAN_L are swapped.
 
If you plug the T4 and PCAN analyser in and the car bus goes silent.

If the bitrate is set correctly then it could be that the CAN_H and CAN_L are swapped.

Appreciate your help in this. Went back to garage to double check things again. And I am affraid all wiring was fine. I even tested again with the Seeedstudio I2C adapter + Wemos mini and it listens the bus nicely and has no interference to the traffic in bus. But then while plugging in the Teensy 4 based board (with either previously mentioned tranceivers), the bus goes silent. Wiring is triple checked and correct. tested with and without of terminator resistor. Something really weird it is.
 
Hi, I am trying to use Teensy 4.1 with MCP2551 powered by Vdd=3.3V, but I can't get it to send/read data on the CAN bus. Is the problem the Vdd voltage, must it be 5V? Can I just replace MCP2551 with SN65HVD233SJD running at Vdd=3.3V? Or is it the code that is missing something? Thank you.

Code:
// Using Teensy 4.1 here with MCP2551 at Vdd=3.3V
// Other end of CANbus is ArduinoDue with Seeed Studio, CAN-bus Shield V2
// Other end of CANbus is working well with other CAN-bus transceivers, but not Teensy/MCP2551 here 

#include <FlexCAN_T4.h>
FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> Can1;
static CAN_message_t msg;

void setup(void) {
  Serial.begin(115200);
  delay(100);

  Can1.begin();
  Can1.setBaudRate(250000); 

  msg.id = 0x100;
  msg.len = 8;
  msg.flags.extended = 0;
  msg.flags.remote   = 0;
  msg.flags.overrun  = 0;
  msg.flags.reserved = 0;
  msg.buf[0] = 10;
  msg.buf[1] = 20;
  msg.buf[2] = 0;
  msg.buf[3] = 100;
  msg.buf[4] = 128;
  msg.buf[5] = 64;
  msg.buf[6] = 32;
  msg.buf[7] = 16;
}

void loop(void) {
  CAN_message_t inMsg;
  while (Can1.read(inMsg) != 0) 
    Serial.print("Received a message"); // this is not printing

  msg.buf[0]++;
  Can1.write(msg);
  Serial.println("Sending a message"); // this is printing
  delay(2000);
}

can Large.jpg
 
Back
Top