How to configure Teensy 4.0's CAN controller with a CAN transceiver

soban

Member
Hey guys,

I have recently bought a BLDC actuator that uses CAN communication. Its working perfectly fine using an MCP2515 CAN module with an Arduino Mega. However, due to my application, I require it to work with Teensy 4.0 as it has a greater computational power.

Since Teensy 4.0 has a built in CAN controller therefore, I decided to use THREE different CAN transceiver modules with it ( including TJA1050, MCP2551 and SNHVD230 ) . Unfortunately, I have been unable to make the motor run. The motor uses an MIT mini cheetah driver which requires a certain command to enable its motor mode. Thats all I have been trying to implement using teensy so far, not even anything complex.

Could someone please help me out?

The pin configuration for Teensy 4.0 with SN65hvd230 is mentioned below:

CAN transceiver VCC -----> 3V on Teensy 4.0

GND--->GND on the Teensy.

CAN TX (D): Connected to the Teensy's CAN TX pin, which is pin 22.

CAN RX (R): Connected to the Teensy's CAN RX pin, which is pin 23.

CANH and CANL of tranceiver connected to the CANH/CANL of the motor.


Im using FlexCAN_T4 library. And the code is as mentioned below:

#include <FlexCAN_T4.h>

FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> can1;

void setup() {
Serial.begin(115200);
while (!Serial);

can1.begin();
can1.setBaudRate(1000000); // Set baud rate to 1Mbps(motor requirement)

Serial.println("CAN bus initialized.");
}

void loop() {
CAN_message_t msg;

// Define the message
msg.id = 0x00B; // CAN ID
msg.len = 8; // Data length code (8 bytes)
msg.buf[0] = 0xFF;
msg.buf[1] = 0xFF;
msg.buf[2] = 0xFF;
msg.buf[3] = 0xFF;
msg.buf[4] = 0xFF;
msg.buf[5] = 0xFF;
msg.buf[6] = 0xFF;
msg.buf[7] = 0xFC;

// Send the message
if (can1.write(msg)) {
Serial.println("Message sent successfully");
} else {
Serial.println("Error sending message");
}

delay(1000); // Wait for 1s
}


Please help me out. Its very important.
 
Had a look at your code and compared it to a working sketch on my machine and it seems OK.
You may want to have a look at this thread for more info.

One thing to be aware of is that some cheapo SN65HVD230 CAN-bus transceiver modules have a wrong silkscreen print on the backside!
Here are 2 examples on my desk:
IMG_20241106_205114.jpg


So if you happen to have these, I hope you connected them correctly.
Can you show us a clear photo of your setup?

Paul
 
Last edited:
Hello sir, thankyou so much for your reply. Actually I ordered three different transceivers like I mentioned earlier , the results were pretty similar on each.
I tried a different approach right now based on your suggested thread, and tried communication between 2 CAN transceivers ( mcp2551 and sn65hvd230) using teensy 4.0's CAN0 and CAN1 using the following code: ( Im using arduino IDE 2.3.2 and teensy board ver. 1.59.0)
Code:
#include <FlexCAN_T4.h>
FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> myCan1;  // CAN0
FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_16> myCan2;  // CAN1
void setup() {
  Serial.begin(115200);
  while (!Serial);  // Wait for Serial Monitor to open
  pinMode(LED_BUILTIN, OUTPUT);          // LED to show loop activity
  // Initialize each CAN bus
  myCan1.begin();
  myCan2.begin();
  // Set the baud rate for each CAN bus
  myCan1.setBaudRate(1000000);  // Set baud rate to 1 Mbps for CAN0
  myCan2.setBaudRate(1000000);  // Set baud rate to 1 Mbps for CAN1
  Serial.println("CAN buses initialized.");
}
void loop() {
  digitalToggle(LED_BUILTIN);            // Toggle LED to show activity
  // Message to send
  CAN_message_t msg;
  msg.len = 8;
  msg.id = 1;
  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 message on CAN0
  if (myCan1.write(msg)) {
    Serial.println("Message sent on CAN0");
  }
  // Send message on CAN1
  msg.id = 2;
  if (myCan2.write(msg)) {
    Serial.println("Message sent on CAN1");
  }
  // Check for received messages on CAN0
  if (myCan1.read(msg)) {
    Serial.print("Received on CAN0: ID=0x");
    Serial.print(msg.id, HEX);
    Serial.print(" Data=");
    for (int i = 0; i < msg.len; i++) {
      Serial.print(msg.buf[i], HEX);
      Serial.print(" ");
    }
    Serial.println();
  }
  // Check for received messages on CAN1
  if (myCan2.read(msg)) {
    Serial.print("Received on CAN1: ID=0x");
    Serial.print(msg.id, HEX);
    Serial.print(" Data=");
    for (int i = 0; i < msg.len; i++) {
      Serial.print(msg.buf[i], HEX);
      Serial.print(" ");
    }
    Serial.println();
  }
  delay(2000);  // Delay before sending the next message
}

Please look at the following images to check my transceivers aswell as my current setup. once again, thanks alot for your help!
WhatsApp Image 2024-11-07 at 10.28.12 AM.jpeg
WhatsApp Image 2024-11-07 at 10.28.11 AM (1).jpeg
WhatsApp Image 2024-11-07 at 10.28.11 AM.jpeg
WhatsApp Image 2024-11-07 at 10.28.10 AM.jpeg
 
I have also tried checking the signal via an Oscilloscope , however, this is the signal I am getting which isnt correct , despite the communication being successful ( I added another debug to show error in messages in case I removed the CANH/CANL wires from one transceiver )
 

Attachments

  • WhatsApp Image 2024-11-07 at 10.44.56 AM.jpeg
    WhatsApp Image 2024-11-07 at 10.44.56 AM.jpeg
    165.5 KB · Views: 12
Thanks for your pictures. That CANL/CANH(?) signal indeed does not look well.
What happens if you lower the baudrates on both sides to e.g. 125000?
Sorry, the coming 2 days I don't have time to dig into this in detail.

Paul
 
Thanks for your pictures. That CANL/CANH(?) signal indeed does not look well.
What happens if you lower the baudrates on both sides to e.g. 125000?
Sorry, the coming 2 days I don't have time to dig into this in detail.

Paul
Hello Paul, no worries mate! I have managed to make the motor work with my teensy 4.0 and SN65hvd230! I realized that if I called both CAN0 and CAN1 in my code and didnt common the ground of my power supply with the transceiver, the signal became a proper square wave just like CAN is supposed to be, omitted the mcp2551 and then used the exact code on my motor with these changes and it started working!

However, Im still not sure why do I need to call both can0 and can1 even if Im only using a single controller out of these? ( I tried omitting either one but the motor instantly became unresponsive)
 
I realized that if I called both CAN0 and CAN1 in my code and didnt common the ground of my power supply with the transceiver, the signal became a proper square wave just like CAN is supposed to be
This is very strange... When you only use 1 CAN interface of the Teensy to talk to your BLDC motor, you shouldn't need to call another CAN interface on the Teensy to get the first one working.
What do you exactly mean by "didnt common the ground of my power supply with the transceiver"? Can you show us a photo on how your setup/wiring is with the motor attached?
By the way: do you happen to know the partnumber [or have a datasheet] of the BLDC motor controller?

Paul
 
Being puzzled by your remark that both CAN interfaces needed to be called to get it to work, I took your code, stripped out all stuff related to myCan2 [CAN1] and compiled & uploaded it to a Teensy 4 plus SN65HVD230 module connected to a CAN-analyzer.
I setup the CAN-analyzer to auto-reply A0 A1 A2 A3 A4 A5 A6 A7 whenever a frame came in from the Teensy.
That seems to work fine:

1731161997435.png


Here is the modified code:
C++:
#include <FlexCAN_T4.h>
FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> myCan1;  // CAN0

void setup() {
  Serial.begin(115200);
  while (!Serial);  // Wait for Serial Monitor to open
  pinMode(LED_BUILTIN, OUTPUT);          // LED to show loop activity
  // Initialize each CAN bus
  myCan1.begin();
  // Set the baud rate for each CAN bus
  myCan1.setBaudRate(1000000);  // Set baud rate to 1 Mbps for CAN0

  Serial.println("CAN buses initialized.");
}
void loop() {
  digitalToggle(LED_BUILTIN);            // Toggle LED to show activity
  // Message to send
  CAN_message_t msg;
  msg.len = 8;
  msg.id = 1;
  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 message on CAN0
  if (myCan1.write(msg)) {
    Serial.println("Message sent on CAN0");
  }
 
  // Check for received messages on CAN0
  if (myCan1.read(msg)) {
    Serial.print("Received on CAN0: ID=0x");
    Serial.print(msg.id, HEX);
    Serial.print(" Data=");
    for (int i = 0; i < msg.len; i++) {
      Serial.print(msg.buf[i], HEX);
      Serial.print(" ");
    }
    Serial.println();
  }

  delay(2000);  // Delay before sending the next message
}

And the setup:
IMG_20241109_145523.jpg


You may want to have a closer look at your wiring as well.

Paul
 
Back
Top