Teensy 4.1 CAN Bus Problems

shaneb

New member
I’m trying to get my Teensy 4.1 to communicate over CAN but running into issues with the CAN_TX signal.

Setup:

  • Teensy 4.1 connected to a breadboard
  • Dupont wires connecting to an SN65HVD230 CAN transceiver breakout board
  • Tested with and without a 120Ω termination resistor

Issue:

I’m using an example sketch to test. Before sending a message, CAN_TX sits at a steady 3.3V. However, after the first transmission attempt, CAN_TX starts oscillating between 0V and 3.3V (as shown in the video). I’ve also probed CANH and CANL but still can’t get proper communication.

Any ideas on what might be causing this issue?

Video:

Code:

Code:
#include <FlexCAN_T4.h>
FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> Can0;

void setup(void) {
  Serial.begin(115200); delay(400);
  pinMode(6, OUTPUT); digitalWrite(6, LOW); /* optional tranceiver enable pin */
  Can0.begin();
  Can0.setBaudRate(1000000);
  Can0.setMaxMB(16);
  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[i], HEX); Serial.print(" ");
  } Serial.println();
}

void loop() {
  Can0.events();

  static uint32_t timeout = millis();
  if ( millis() - timeout > 5000 ) {
    Serial.printf("Sending Message\n");
    CAN_message_t msg;
    msg.id = random(0x1,0x7FE);
    for ( uint8_t i = 0; i < 8; i++ ) msg.buf[i] = i + 1;
    Can0.write(msg);
    timeout = millis();
  }

}
 
No there wasn't for the above demo. The ultimate goal is to communicate with a motor over CAN bus. When I have connected it to a motor, the motor wasn't receiving or processing the messages, although I was sending the correct motor ID and a valid command.
 
not too long ago, I used the following script to time the canbus transmission, you may find it useful, by printing the message in the msg.buf field

For my test, I connected one of the can module to CAN1, and the other to CAN2. If you see that the sent and recieved messages are same, then you know the problem lies else where

C++:
#include <FlexCAN_T4.h>
#include <motctrl_prot.h>
#include <cstring>
#include <IntervalTimer.h>
FlexCAN_T4<CAN1, RX_SIZE_8, TX_SIZE_8> Can1;
FlexCAN_T4<CAN2, RX_SIZE_8, TX_SIZE_8> Can2;
IntervalTimer sendTimer;


volatile uint32_t can1_send_time, can2_send_time, can1_recv_time, can2_recv_time;
volatile bool can_event;
CAN_message_t can_message;
volatile int can1_counter, can2_counter;
void setup()
{
  can_event = false;
  Serial.begin(115200);
  while (!Serial)
    delay(1000);
  Can1.begin();
  Can1.setBaudRate(500000);
  Can1.setMaxMB(16);
  Can1.enableFIFO();
  Can1.enableFIFOInterrupt();
  // Can1.onReceive(canSniff);
  delay(1000);
  Can2.begin();
  Can2.setBaudRate(500000);
  Can2.setMaxMB(16);
  Can2.enableFIFO();
  Can2.enableFIFOInterrupt();
  // Can2.onReceive(canSniff);
  delay(1000);
  sendTimer.begin(Can1Send, 1000);  // 1s = 1 millon microseconds
}
void loop()
{
  // Can1.events();
  // Can2.events();
  if (can_event)
  {
    can_event = false;
    if (can1_counter != 0 && can2_counter != 0)
    {
      Serial.print("1:");
      Serial.print(can1_recv_time - can1_send_time);
      Serial.print(", 2:");
      Serial.println(can2_recv_time - can2_send_time);
    }
  }
}

void Can1Send()
{
  can1_send_time = micros();
  CAN_message_t msgs;
  msgs.id = 0x2;
  msgs.len = MOTCTRL_FRAME_SIZE;
  MCReqStopMotor(msgs.buf);
  Can1.write(msgs);
  can1_counter++;
  // Serial.print("w1:");
  // Serial.println(micros() - can1_send_time);
}

void Can2Send()
{
  can2_send_time = micros();
  CAN_message_t msgs;
  msgs.id = 0x1;
  msgs.len = MOTCTRL_FRAME_SIZE;
  MCReqStartMotor(msgs.buf);
  Can2.write(msgs);
  can2_counter++;

  // Serial.print("w2:");
  // Serial.println(micros() - can2_send_time);
}
// void canSniff(const CAN_message_t &msg)
void ext_output1(const CAN_message_t &msg)
{

  can_event = true;
  if (msg.bus == 1)
  {
    can2_recv_time = micros();
    can1_counter--;
  }
  else if (msg.bus == 2)
  {
    can1_recv_time = micros();
    Can2Send();
    can1_counter--;
  }
  else
  {
    Serial.println("ERR!");
  }
  // printCanMsg(msg);
}


void printCanMsg(const CAN_message_t &msg)
{
  char buffer[64];

  // Format the first part of the message
  sprintf(buffer,
          "TS: %u  ID: %lu  RMT: %d  BUS: %d.",
          msg.timestamp, msg.id, msg.flags.remote, msg.bus);
  Serial.print(buffer);

  // Print buffer separately to avoid overflowing sprintf buffer
  Serial.print(" MSG : ");
  for (uint8_t i = 0; i < msg.len - 7; i++)
  {
    sprintf(buffer, "%02X ", msg.buf[i]);
    Serial.print(buffer);
  }
  Serial.println();
}
 
No there wasn't for the above demo. The ultimate goal is to communicate with a motor over CAN bus. When I have connected it to a motor, the motor wasn't receiving or processing the messages, although I was sending the correct motor ID and a valid command.

Connect the motor. Then put your scope on the CAN_RX pin. If your scope does CAN decoding that would be great otherwise it's going to be harder to figure things out. At the very end of the transmitted message is an ACK bit that the motor should be asserting. If it is not ACKing the frame then either your speed is wrong, your termination is wrong, the motor isn't working properly, or the wiring is faulty. But, what you want to normally see is that the CAN_TX and CAN_RX pins have essentially the same signals on them, with CAN-RX delayed a little and also with RX having the ACK bit asserted when some other node accepts it.
 
Back
Top