Assistance with CAN FD Communication Setup in Senior Design Project Using Teensy 4.1

AustinECEStudent

Active member
I’m currently working on a Senior Design project that involves real-time motor control using a Teensy microcontroller and CAN FD communication. Here's a brief overview of the project and my setup:



### Project Overview:

Our project focuses on controlling a motor via an Escon motor controller, which is interfaced with a Teensy microcontroller. The system includes a torque meter for measuring torque generated by the motor, which outputs an analog signal that is converted to digital for processing by the Teensy. The ultimate goal is to enable real-time control and monitoring of the motor through a laptop application using CAN FD (Controller Area Network Flexible Data-rate) communication.



### Setup Details:

- **Teensy Microcontroller**: Acts as the main control unit, receiving signals from the motor controller and transmitting data to the laptop via CAN FD.

- **Escon Motor Controller**: Interfaces with the Teensy to control the motor based on PWM signals.

- **Torque Meter**: Measures torque and sends analog signals, which are converted and read by the Teensy.

- **CAN FD Communication**: Implemented to allow real-time data exchange between the Teensy and a laptop application. The CAN FD protocol was chosen for its high data rate, error correction capabilities, and scalability.



### Code and Current Output:

I’ve written the following code to initialize the CAN FD communication and periodically send random CAN frames:



```cpp

#include <FlexCAN_T4.h>

FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_16> Can0;



void setup(void) {

Serial.begin(115200); delay(400);

pinMode(2, OUTPUT); digitalWrite(2, LOW); // enable transceiver

Can0.begin();

Can0.setBaudRate(500000);

Can0.setMaxMB(16); // up to 64 max for T4, not important in FIFO mode, unless you want to use additional mailboxes with FIFO

Can0.enableFIFO();

Can0.enableFIFOInterrupt();

Can0.onReceive(canSniff);

Can0.mailboxStatus();

}



void canSniff(const CAN_message_t &msg) {

Serial.print("MB "); Serial.print(msg.mb);

Serial.print(" OVERRUN: "); Serial.print(msg.flags.overrun);

Serial.print(" LEN: "); Serial.print(msg.len);

Serial.print(" EXT: "); Serial.print(msg.flags.extended);

Serial.print(" TS: "); Serial.print(msg.timestamp);

Serial.print(" ID: "); Serial.print(msg.id, HEX);

Serial.print(" Buffer: ");

for ( uint8_t i = 0; i < msg.len; i++ ) {

Serial.print(msg.buf, HEX); Serial.print(" ");

} Serial.println();

}



void loop() {

Can0.events();



static uint32_t timeout = millis();

if ( millis() - timeout > 20 ) { // send random frame every 20ms

CAN_message_t msg;

msg.id = random(0x1,0x7FE);

for ( uint8_t i = 0; i < 8; i++ ) msg.buf = i + 1;

Can0.write(msg);

timeout = millis();

}

}

```



The output I’m currently seeing is:



- **FIFO Enabled → Interrupt Enabled**

- **FIFO Filters in use: 8**

- **Remaining Mailboxes: 8**

- **MB8 code: TX_INACTIVE**

- **MB9 code: TX_INACTIVE**

- **MB10 code: TX_INACTIVE**

- **MB11 code: TX_INACTIVE**

- **MB12 code: TX_INACTIVE**

- **MB13 code: TX_INACTIVE**

- **MB14 code: TX_INACTIVE**

- **MB15 code: TX_INACTIVE**

- **CAN FD communication started.**



### Issue:

The output doesn’t match my expectations, especially with all the mailboxes showing as inactive. I’m unsure if this indicates a problem with the CAN FD communication setup or the way the mailboxes are configured.



Could you please provide guidance on why this might be happening and suggest any steps I can take to debug or correct the issue? Your expertise and advice would be greatly appreciated.



Also how can I make sure that CAN FD messages are actually being sent because I am not sure whats happening as I am a beginner and totally new to this protocol.



Thank you for your assistance!
 
My setup using CAN waveshare (SN65HVD230-CAN-Board), CAN FD pcan cable, and teensy 4.1.
 

Attachments

  • CanSetup.jpg
    CanSetup.jpg
    79.2 KB · Views: 26
OK, start with the basics:
Do you have a terminating resistor on your CAN bus? You need ~120 ohms between CAN high and CAN low. You can get away with less and depending on the speed often more if you are limited in what parts are available.

Is your bus correctly configured? You say CAN-FD but then your configuration implies a classic CAN 2.0 bus setup rather than CAN FD.

Your Tx code looks reasonable and should work but you should be setting the message length field of msg otherwise you could be sending a 0 byte packet (which is valid but not much use if you want to send data). Also a random number for CAN ID is a bit odd, not wrong but not normal. The ID sets the packet priority and is normally an indication of what data the packet contains, not something that you would want to set at random.

For reference here's some code I use that looks for CAN packets that can either be CAN 2.0 at 500 kBaud or CAN-FD at 500k with data rate switching to 2 Mbaud.

Rather than polling this is interrupt based, ext_outputFD1 is called every time a packet is received.
I just stripped most of the rest of the code out, all it does is count the number of packets with the CAN ID specified and output the total once every 5 seconds.

Code:
#include <FlexCAN_T4.h>
 
FlexCAN_T4FD<CAN3, RX_SIZE_1024, TX_SIZE_16> IntCAN;
const int CANID_TO_USE = 0x301;

volatile uint32_t CANCount;

void setup() {
  Serial.begin(115200);
  Serial.printf("Startup\r\n\r\n");
  Serial.printf("Looking for CAN ID 0x%X\r\n", CANID_TO_USE);
  initCAN();
}
 
void initCAN() {
  CANFD_timings_t config;
  uint32_t rate = 500*1000;
  uint32_t fdRate = 2*1000*1000;
  config.clock = CLK_24MHz;
  config.baudrate = rate;
  config.baudrateFD = fdRate;
  config.propdelay = 190;
  config.bus_length = 1;
  config.sample = 85;
  Serial.printf("Set baud to %lu / %lu \r\n", rate, fdRate);
  IntCAN.begin();
  IntCAN.setBaudRate(config);
  IntCAN.setRegions(64);
  IntCAN.enableMBInterrupts();
}

void ext_outputFD1(const CANFD_message_t &msg) {
  if ((msg.id == CANID_TO_USE)) {
    CANCount++;
  }
}

uint32_t lastOutput = 0;

void loop () {
  if ((millis() - lastOutput) > (5*1000)) { // 5 seconds
    lastOutput = millis();
    Serial.printf("Seen %d Packets of ID %X\r\n",CANCount,CANID_TO_USE);
  }
}
 
Last edited:
#include <FlexCAN_T4.h>
//// CAN TEST TO BLINK BASED ON WHAT CAN MESSAGES ARE BEING SENT AND USED.
const int ledPin = LED_BUILTIN; // Use the built-in LED pin
bool done = false; // Flag to stop the loop after one complete run
FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> myCan1;
FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_16> myCan2;
FlexCAN_T4<CAN3, RX_SIZE_256, TX_SIZE_16> myCan3;
void setup() {
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
myCan1.begin();
myCan2.begin();
myCan3.begin();
myCan1.setBaudRate(250*1000);
myCan2.setBaudRate(250*1000);
myCan3.setBaudRate(250*1000);
}
void loop() {
if (!done) {
CAN_message_t msg;
msg.len = 8;
msg.buf[0] = 1;
msg.buf[1] = 2;
msg.buf[2] = 3;
msg.buf[3] = 4;
msg.buf[4] = 5;
msg.buf[5] = 6;
msg.buf[6] = 7;
msg.buf[7] = 8;
// Send and blink for CAN1
msg.id = 1;
myCan1.write(msg);
Serial.print("Message sent on CAN1 with ID: 0x");
Serial.println(msg.id, HEX);
blinkLED(1000); // Blink LED for 1 second
delay(2000); // Standby for 2 seconds
// Send and blink for CAN2
msg.id = 2;
myCan2.write(msg);
Serial.print("Message sent on CAN2 with ID: 0x");
Serial.println(msg.id, HEX);
blinkLED(2000); // Blink LED for 2 seconds
delay(3000); // Standby for 3 seconds
// Send and blink for CAN3
msg.id = 3;
myCan3.write(msg);
Serial.print("Message sent on CAN3 with ID: 0x");
Serial.println(msg.id, HEX);
blinkLED(3000); // Blink LED for 3 seconds
delay(4000); // Standby for 4 seconds
done = true; // Set the flag to true to stop the loop
}
}
void blinkLED(int duration) {
unsigned long startMillis = millis();
while (millis() - startMillis < duration) {
digitalWrite(ledPin, HIGH); // Turn the LED on
delay(250); // Wait for 250 milliseconds
digitalWrite(ledPin, LOW); // Turn the LED off
delay(250); // Wait for 250 milliseconds
}
}
I changed my code and tried this with the terminating resistors and I got an output that says .
1725557652694.png

I guess my problem now is why I can not see these messages sent on the PCAN VIEW
 
The photo of the wiring connection doesn't look right.

Looks like you are using pin 24 and 25. Those are UART pins, not CAN.

You need to use pin 0,1 for can2. pin 30,31 for can3 and pin 23,22 for can1
 
You need to use the CAN port of the Teensy. On the card it is shown in pink.

So you need to wire up like this:
For CAN port can1
CRX1 on pin 23
CTX1 on pin 22

For CAN port can2
CRX2 on pin 0
CTX2 on pin 1

For CAN port can3
CRX3 on pin 30
CTX3 on pin 31

So the RX pin of your CAN transceiver need to connect CRX1 pin 23 of the Teensy
TX pin of your CAN transceiver need to connect CTX1 pin 22 of the Teensy
 
Thank you. I will rewire and see if I can see the output of at least CAN1,CAN2 or CAN3 on PCAN view.
You need to use the CAN port of the Teensy. On the card it is shown in pink.

So you need to wire up like this:
For CAN port can1
CRX1 on pin 23
CTX1 on pin 22

For CAN port can2
CRX2 on pin 0
CTX2 on pin 1

For CAN port can3
CRX3 on pin 30
CTX3 on pin 31

So the RX pin of your CAN transceiver need to connect CRX1 pin 23 of the Teensy
TX pin of your CAN transceiver need to connect CTX1 pin 22 of the Teensy
 
Considering my aim to send can fd messages
You keep saying CAN-FD however all of your code and packets you are trying to send are CAN 2.0.
Only CAN3 supports CAN-FD, all 3 CAN interfaces support CAN 2.0B.

CAN 2.0B is the interface that is normally meant these days when someone says CAN. That is 11 or 29 bit IDs, up to 8 bytes of data and baud rates up to 1 Mbit/s
CAN-FD is backwards compatible with CAN 2.0B and can send/receive CAN 2.0B format packets but adds the ability to send up to 64 bytes of data in a single packet and to increase the baud rate during the data portion of the packet up to 8 Mbit/s (although lots of parts are limited to around 5 Mbits/s).

So which is it? Because if you need CAN FD then you need to configure things like what the higher data baud rate is and you need to ensure you're on the FD capable CAN port with a CAN transceiver chip that can handle the higher data rates.
If you don't need FD then you should probably stop stating that as a requirement.
 
You keep saying CAN-FD however all of your code and packets you are trying to send are CAN 2.0.
Only CAN3 supports CAN-FD, all 3 CAN interfaces support CAN 2.0B.

CAN 2.0B is the interface that is normally meant these days when someone says CAN. That is 11 or 29 bit IDs, up to 8 bytes of data and baud rates up to 1 Mbit/s
CAN-FD is backwards compatible with CAN 2.0B and can send/receive CAN 2.0B format packets but adds the ability to send up to 64 bytes of data in a single packet and to increase the baud rate during the data portion of the packet up to 8 Mbit/s (although lots of parts are limited to around 5 Mbits/s).

So which is it? Because if you need CAN FD then you need to configure things like what the higher data baud rate is and you need to ensure you're on the FD capable CAN port with a CAN transceiver chip that can handle the higher data rates.
If you don't need FD then you should probably stop stating that as a requirement.
Hi sorry for the confusion I do need FD but my code didn’t work for some reason using canFD I’m not sure maybe a library issue so that’s why I started just trying to use CAN just to problem solve and see that data on the PCAN view which I still haven’t managed to do
 
Code:
#include <FlexCAN_T4.h>  // Include the FlexCAN_T4 library

FlexCAN_T4<CAN1, CAN2, TX_SIZE, RX_SIZE> Can1;  // Initialize CAN1 object with TX and RX buffer sizes

// Initialize CAN bus at 500 kbps
void setup() {
  Can1.begin();
  Can1.setBaudRate(500000);
}

void loop() {
  uint8_t data[8] = {1, 2, 3, 4, 5, 6, 7, 8};  // Sample data to be sent
  sendCANFDMessage(0x123, data, 8);  // Send CAN FD message with ID 0x123 and data array
  delay(1000);  // Delay for 1 second before sending the next message
}

// Function to send CAN FD message
void sendCANFDMessage(uint32_t id, uint8_t* data, uint8_t length) {
  CANFD_message_t msg;  // Create CAN FD message object
  msg.id = id;  // Set message ID
  msg.len = length;  // Set message length
  for (int i = 0; i < length; i++) {
    msg.buf[i] = data[i];  // Copy data to message buffer
  }
  msg.flags.extended = 0;  // Set message as standard (not extended)
  msg.flags.rtr = 0;  // Set message as data frame (not remote request)
  msg.flags.brs = 1;  // Set BRS (Bit Rate Switch) to enable higher data rate for CAN FD
  msg.flags.fd = 1;  // Enable CAN FD mode (if supported by library version)
  Can1.write(msg);  // Send the message
}
Code:
#include <FlexCAN_T4.h>  // Include the FlexCAN_T4 library

FlexCAN_T4<CAN1, CAN2, TX_SIZE, RX_SIZE> Can1;  // Initialize CAN1 object with TX and RX buffer sizes

void setup() {
  Can1.begin();
  Can1.setBaudRate(500000);  // Initialize CAN bus at 500 kbps
  Can1.enableFIFO();  // Enable FIFO for receiving messages
}

void loop() {
  if (Can1.available()) {  // Check if there are any messages available
    CANFD_message_t msg;  // Create CAN FD message object
    Can1.read(msg);  // Read the received message
    processCANFDMessage(msg);  // Process the received message
  }
  delay(10);  // Small delay to avoid busy-waiting
}

// Function to process received CAN FD message
void processCANFDMessage(CANFD_message_t& msg) {
  Serial.print("Received message with ID: ");  // Print message ID
  Serial.println(msg.id);
  Serial.print("Data: ");
  for (int i = 0; i < msg.len; i++) {
    Serial.print(msg.buf[i]);  // Print each byte of data
    Serial.print(" ");
  }
  Serial.println();
}
 
Code:
#include <FlexCAN_T4.h>  // Include the FlexCAN_T4 library

FlexCAN_T4<CAN1, CAN2, TX_SIZE, RX_SIZE> Can1;  // Initialize CAN1 object with TX and RX buffer sizes

// Initialize CAN bus at 500 kbps
void setup() {
  Can1.begin();
  Can1.setBaudRate(500000);
}

void loop() {
  uint8_t data[8] = {1, 2, 3, 4, 5, 6, 7, 8};  // Sample data to be sent
  sendCANFDMessage(0x123, data, 8);  // Send CAN FD message with ID 0x123 and data array
  delay(1000);  // Delay for 1 second before sending the next message
}

// Function to send CAN FD message
void sendCANFDMessage(uint32_t id, uint8_t* data, uint8_t length) {
  CANFD_message_t msg;  // Create CAN FD message object
  msg.id = id;  // Set message ID
  msg.len = length;  // Set message length
  for (int i = 0; i < length; i++) {
    msg.buf[i] = data[i];  // Copy data to message buffer
  }
  msg.flags.extended = 0;  // Set message as standard (not extended)
  msg.flags.rtr = 0;  // Set message as data frame (not remote request)
  msg.flags.brs = 1;  // Set BRS (Bit Rate Switch) to enable higher data rate for CAN FD
  msg.flags.fd = 1;  // Enable CAN FD mode (if supported by library version)
  Can1.write(msg);  // Send the message
}
Code:
#include <FlexCAN_T4.h>  // Include the FlexCAN_T4 library

FlexCAN_T4<CAN1, CAN2, TX_SIZE, RX_SIZE> Can1;  // Initialize CAN1 object with TX and RX buffer sizes

void setup() {
  Can1.begin();
  Can1.setBaudRate(500000);  // Initialize CAN bus at 500 kbps
  Can1.enableFIFO();  // Enable FIFO for receiving messages
}

void loop() {
  if (Can1.available()) {  // Check if there are any messages available
    CANFD_message_t msg;  // Create CAN FD message object
    Can1.read(msg);  // Read the received message
    processCANFDMessage(msg);  // Process the received message
  }
  delay(10);  // Small delay to avoid busy-waiting
}

// Function to process received CAN FD message
void processCANFDMessage(CANFD_message_t& msg) {
  Serial.print("Received message with ID: ");  // Print message ID
  Serial.println(msg.id);
  Serial.print("Data: ");
  for (int i = 0; i < msg.len; i++) {
    Serial.print(msg.buf[i]);  // Print each byte of data
    Serial.print(" ");
  }
  Serial.println();
}
@AndyA with your code and suggestions I have tried to modify code and made adjustments with the layout.
My two pieces of code: one for transmitting and one for receiving messages.

The transmitter initializes the CAN bus at 500 kbps and uses a `sendCANFDMessage` function to construct and send messages with a specified ID and data. It sends a message every second.

The receiver also initializes the CAN bus at 500 kbps and enables FIFO mode to receive messages. It continuously checks for incoming messages and prints the ID and data to the Serial Monitor when a message is received.

Both codes seem to follow the library's structure, but I’m having trouble getting them to work as expected. Any suggestions would be helpful! This is the error I am receieving.
1726510457595.png
 
You are trying to send messages of type CANFD_message_t on CAN1
Only CAN3 support CAN_FD.

Change the line at the start of your code to

FlexCAN_T4FD<CAN3, RX_SIZE_512, TX_SIZE_512> can1;

so that you are using the correct CAN peripheral, you will of course need to change the physical pins you are using to match.
 
You are trying to send messages of type CANFD_message_t on CAN1
Only CAN3 support CAN_FD.

Change the line at the start of your code to

FlexCAN_T4FD<CAN3, RX_SIZE_512, TX_SIZE_512> can1;

so that you are using the correct CAN peripheral, you will of course need to change the physical pins you are using to match.
On my CANFD Send code :
FlexCAN_T4FD<CAN3, RX_SIZE_1024, TX_SIZE_16> can3;

On my CANFD receive code:
FlexCAN_T4FD<CAN3, RX_SIZE_1024, TX_SIZE_16> IntCAN;

Would this work?
 
On my CANFD Send code :
FlexCAN_T4FD<CAN3, RX_SIZE_1024, TX_SIZE_16> can3;

On my CANFD receive code:
FlexCAN_T4FD<CAN3, RX_SIZE_1024, TX_SIZE_16> IntCAN;

Would this work?
It should. You aren't sending huge amounts of data so the sizes of the buffers don't matter much.
The name on the end can be anything you like as long as you are consistent what you call it in your code.
 
It should. You aren't sending huge amounts of data so the sizes of the buffers don't matter much.
The name on the end can be anything you like as long as you are consistent what you call it in your code.
Thank you for your continued support. While my code had some initial errors, I've made several adjustments, and it now runs successfully. The PCAN cable blinks, indicating that messages are being transmitted or received. However, the messages are not yet visible in PCAN-View, and I'm not sure what might be causing the issue. I'd appreciate any advice or suggestions for resolving this problem.
Thank you in advance!
 
Code:
#include <FlexCAN_T4.h>

// Define the CAN object for CAN3 with buffer sizes
FlexCAN_T4FD<CAN3, RX_SIZE_1024, TX_SIZE_16> can3;

const int CANID_TO_USE = 0x301;  // ID should match the receiver's expected ID

void setup() {
  Serial.begin(115200);
  Serial.println("CAN FD Transmitter Initialized");
  initCAN();
}

void initCAN() {
  CANFD_timings_t config;
  uint32_t rate = 500 * 1000;       // CAN baud rate 500 kbps
  uint32_t fdRate = 2 * 1000 * 1000; // CAN FD data rate 2 Mbps
  config.clock = CLK_24MHz;
  config.baudrate = rate;
  config.baudrateFD = fdRate;
  config.propdelay = 190;
  config.bus_length = 1;
  config.sample = 85;
  can3.begin();
  can3.setBaudRate(config);
  can3.setRegions(64);
}

void sendCANFDMessage(uint32_t id, uint8_t* data, uint8_t dataSize) {
  CANFD_message_t msg;
 
  msg.id = id;
  msg.len = dataSize;
  msg.flags.extended = 0;  // Standard ID (11-bit)
  msg.flags.fd = 1;        // CAN FD enabled

  for (uint8_t i = 0; i < dataSize; i++) {
    msg.buf[i] = data[i];
  }

  can3.write(msg);
 
  Serial.print("Sent CAN FD Message with ID: ");
  Serial.println(id, HEX);
}

void loop() {
  // Create a data array containing 8 bytes
  uint8_t data1[] = {
    static_cast<uint8_t>(count),     // First byte set to `count`
    static_cast<uint8_t>(count + 1), // Second byte set to `count + 1`
    static_cast<uint8_t>(count + 2), // Third byte set to `count + 2`
    static_cast<uint8_t>(count + 3), // Fourth byte set to `count + 3`
    static_cast<uint8_t>(count + 4), // Fifth byte set to `count + 4`
    static_cast<uint8_t>(count + 5), // Sixth byte set to `count + 5`
    static_cast<uint8_t>(count + 6), // Seventh byte set to `count + 6`
    static_cast<uint8_t>(count + 7)  // Eighth byte set to `count + 7`
  };

  // Send the CAN FD message with ID 0x301 (to match receiver's ID)
  sendCANFDMessage(CANID_TO_USE, data1, sizeof(data1));

  count++;
  delay(1000);
}
 
First your code doesn't compile. You need to add:
uint8_t count;

Just comment out
msg.flags.fd = 1;

As can3 is already has CAN FD.

On PCAN-View you should see something like this:
Cursor_and_192_168_1_28.jpg


With your error on PCAN-View, it could be your wiring to the CAN transceiver is not right.
Which CAN transceiver are you using ? Is it CAN FD compliant ?
Post a photo of your setup.
 
Back
Top