CAN communication problems

Status
Not open for further replies.

WarPig

Member
Hello everyone. I have been trying to set up a CAN communication between two teensy 3.6. I have been using a TJA1051T/3 (link) can transiver. I have connected the Vref pin to 3.3V, Tx to Tx and Rx to Rx, CANH to CANH and CANL to CANL. Using two 60ohm resistors with a cap to ground for each termination. Both microcontrollers and the transivers share a common ground.

First I tried using the example code found of the FlexCAN library. The second teensy never received any message and the CAN1.available condition was never met. I have also tried measuring the voltage on the can bus lines using an oscilloscope and no signal was measured. The Tx pin on the transmitting teensy instead presented some PWM signal. The RX pin on the receiving is stuck at one.

I have also tried some other codes found online (such as this one and the result was the same. I am quite confused on what I'm doing wrong so any help is appreciated!

PS: I don't have pictures of wiring/signal readings right now. If needed I can add them on Monday.
 
You need to post the schematic. Can't see a Vref pin on the TJA1051T/3.
Thank you for your answer.
You are right, I meant V_io, which is a reference voltage for the Tx and Rx pins, where Vtx and Vrx = V_io - 0.4.
I'll add a schematic tomorrow morning.
 
Make sure both transceivers have their "S" pin pulled low. Also, just to be certain, you are supplying the transceivers with 5v?
 
UPDATE:
I am adding some pictures to make the question more clear:
Schematic:
schematic.jpg

Tx Teensy output:
View attachment TEK0000.BMP

Rx Teensy input:
View attachment TEK0001.BMP

CanH when no other transceiver is connected:
View attachment TEK0002.BMP

CanH when 2nd transceiver (listener/no code - same result) is connected:
View attachment TEK0003.BMP

2nd teensy Rx pin:
View attachment TEK0004.BMP

Make sure both transceivers have their "S" pin pulled low. Also, just to be certain, you are supplying the transceivers with 5v?
Yes both S pin is pulled to ground and we are supplying 5V to Vcc
 
Okay, thanks.
Here is the code, it is the same for both Teensy s, but I also tried running it with no code uploaded on the 2nd teensy.

Code:
// -------------------------------------------------------------
// CANtest for Teensy 3.1
// by teachop
//
// This test is talking to a single other echo-node on the bus.
// 6 frames are transmitted and rx frames are counted.
// Tx and rx are done in a way to force some driver buffering.
// Serial is used to print the ongoing status.
//

#include <Metro.h>
#include <FlexCAN.h>

Metro sysTimer = Metro(1);// milliseconds

int led = 13;
//FlexCAN Can1(500000);
static CAN_message_t msg,rxmsg;
static uint8_t hex[17] = "0123456789abcdef";

int txCount,rxCount;
unsigned int txTimer,rxTimer;


// -------------------------------------------------------------
static void hexDump(uint8_t dumpLen, uint8_t *bytePtr)
{
  uint8_t working;
  while( dumpLen-- ) {
    working = *bytePtr++;
    Serial.write( hex[ working>>4 ] );
    Serial.write( hex[ working&15 ] );
  }
  Serial.write('\r');
  Serial.write('\n');
}


// -------------------------------------------------------------
void setup(void)
{
  Can1.begin(1000000);
  pinMode(led, OUTPUT);
  pinMode(32,  OUTPUT);
  

  delay(1000);
  Serial.println(F("Hello Teensy 3.1 CAN Test."));

  sysTimer.reset();
}


// -------------------------------------------------------------
void loop(void)
{
  digitalWrite(32, HIGH);
  digitalWrite(led, 1);
  // service software timers based on Metro tick
  if ( sysTimer.check() ) {
    if ( txTimer ) {
      --txTimer;
    }
    if ( rxTimer ) {
      --rxTimer;
    }
  }

  // if not time-delayed, read CAN messages and print 1st bit
  if ( !rxTimer ) {
    while ( Can1.read(rxmsg) ) {
      //hexDump( sizeof(rxmsg), (uint8_t *)&rxmsg );
      Serial.write(rxmsg.buf[0]);
      rxCount++;
    }
  }

  // insert a time delay between transmissions
  if ( !txTimer ) {
    // if frames were received, print the count
    if ( rxCount ) {
      Serial.write('=');
      Serial.print(rxCount);
      rxCount = 0;
    }
    txTimer = 100;//milliseconds
    msg.len = 8;
    msg.id = 0x222;
    /*for( int idx=0; idx<8; ++idx ) {
      msg.buf[idx] = '1';
    }*/
    msg.buf[0] = '0';
    msg.buf[1] = '0';
    msg.buf[2] = '0';
    msg.buf[3] = '0';
    msg.buf[4] = '0';
    msg.buf[5] = '0';
    msg.buf[6] = '0';
    msg.buf[7] = '0';
   
    // send 6 at a time to force tx buffering
    txCount = 6;
    digitalWrite(led, 1);
    Serial.println("sending...");
    while ( txCount-- ) {
      Can1.write(msg);
      msg.buf[0]++;
    }
    digitalWrite(led, 0);
    // time delay to force some rx data queue use
    rxTimer = 3;//milliseconds
  }

}

Other codes that I tried:
Transmitter:
Code:
// -------------------------------------------------------------
// CANtest for Teensy 3.6 dual CAN bus
// by Collin Kidder, Based on CANTest by Pawelsky (based on CANtest by teachop)
//
// Both buses are left at default 250k speed and the second bus sends frames to the first
// to do this properly you should have the two buses linked together. This sketch
// also assumes that you need to set enable pins active. Comment out if not using
// enable pins or set them to your correct pins.
//
// This sketch tests both buses as well as interrupt driven Rx and Tx. There are only
// two Tx buffers by default so sending 5 at a time forces the interrupt driven system
// to buffer the final three and send them via interrupts. All the while all Rx frames
// are internally saved to a software buffer by the interrupt handler.
//

#include <FlexCAN.h>

#ifndef __MK66FX1M0__
  #error "Teensy 3.6 with dual CAN bus is required to run this example"
#endif

static CAN_message_t msg;
static uint8_t hex[17] = "0123456789abcdef";

// -------------------------------------------------------------
static void hexDump(uint8_t dumpLen, uint8_t *bytePtr)
{
  uint8_t working;
  while( dumpLen-- ) {
    working = *bytePtr++;
    Serial.write( hex[ working>>4 ] );
    Serial.write( hex[ working&15 ] );
  }
  Serial.write('\r');
  Serial.write('\n');
}


// -------------------------------------------------------------
void setup(void)
{
  delay(1000);
  Serial.println(F("Hello Teensy 3.6 dual CAN Test."));

  Can0.begin();  
  Can1.begin();

  //if using enable pins on a transceiver they need to be set on
  pinMode(13, OUTPUT);
  pinMode(35, OUTPUT);

  digitalWrite(13, HIGH);
  digitalWrite(35, HIGH);

  msg.ext = 0;
  msg.id = 0x100;
  msg.len = 8;
  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)
{
  
  msg.buf[0]++;
  Can1.write(msg);
  msg.buf[0]++;
  Can1.write(msg);
  msg.buf[0]++;
  Can1.write(msg);
  msg.buf[0]++;
  Can1.write(msg);
  msg.buf[0]++;
  Can1.write(msg);  
  delay(20);
}

Receiver:
Code:
// -------------------------------------------------------------
// CANtest for Teensy 3.6 dual CAN bus
// by Collin Kidder, Based on CANTest by Pawelsky (based on CANtest by teachop)
//
// Both buses are left at default 250k speed and the second bus sends frames to the first
// to do this properly you should have the two buses linked together. This sketch
// also assumes that you need to set enable pins active. Comment out if not using
// enable pins or set them to your correct pins.
//
// This sketch tests both buses as well as interrupt driven Rx and Tx. There are only
// two Tx buffers by default so sending 5 at a time forces the interrupt driven system
// to buffer the final three and send them via interrupts. All the while all Rx frames
// are internally saved to a software buffer by the interrupt handler.
//

#include <FlexCAN.h>

#ifndef __MK66FX1M0__
  #error "Teensy 3.6 with dual CAN bus is required to run this example"
#endif

static CAN_message_t msg;
static uint8_t hex[17] = "0123456789abcdef";

// -------------------------------------------------------------
static void hexDump(uint8_t dumpLen, uint8_t *bytePtr)
{
  uint8_t working;
  while( dumpLen-- ) {
    working = *bytePtr++;
    Serial.write( hex[ working>>4 ] );
    Serial.write( hex[ working&15 ] );
  }
  Serial.write('\r');
  Serial.write('\n');
}


// -------------------------------------------------------------
void setup(void)
{
  delay(1000);
  Serial.println(F("Hello Teensy 3.6 dual CAN Test."));

  Can0.begin();  
  Can1.begin();

  //if using enable pins on a transceiver they need to be set on
  pinMode(2, OUTPUT);
  pinMode(35, OUTPUT);

  digitalWrite(2, HIGH);
  digitalWrite(35, HIGH);


}


// -------------------------------------------------------------
void loop(void)
{
  CAN_message_t inMsg;
  while (Can1.available()) 
  {
    Can1.read(inMsg);
    Serial.print("CAN bus 0: "); hexDump(8, inMsg.buf);
  }
 
}

using the last codes no signal was measured on the canH/canL wires

EDIT: an additional note: if in the first code the can1.write() function is commented for one teensy so that it only reads, the signal is gone for both teensys in the Tx pin
 
Last edited:
Your schematic on the Teensy doesn't show which pins you have used. There are two CAN ports on the 3.6.

Show how you wired up CAN_TX and CAN_RX.
 
I am using pin 34 and 35 on the teensy 3.6, just a wire connection to Tx and Rx in the transceiver.

While I was waiting for an answer I fixed one connection on the chip were the soldering tin didn't stick properly. Now the signal on the Tx pin is propagated to the Rx of the same teensy, on the CanH line, the complementary on CanL line, also with the proper DC bias at 2.5V, but still nothing is received at the Rx of the 2nd teensy.
 
In the Transmitter and Receiver you need to specify the baud rate like this:

Can1.begin(500000);

In the receiver try this:
Code:
void loop() {
 CAN_message_t rxmsg;

  while(Can1.read(rxmsg))
  { 
     String CANStr(""); 
     for (int i=0; i < 8; i++) {     

         CANStr += String(rxmsg.buf[i],HEX);
         CANStr += (" ") ;
     }
     Serial.print(rxmsg.id,HEX); 
     Serial.print(' '); 
     Serial.print(rxmsg.len,HEX); 
     Serial.print(' ');
     Serial.println(CANStr);  
   

     
  }
}
 
First of all thank you for the quick answers and dedication, I really appreciate it!
I'm using your code now, and a signal is measured on the receiving Rx pin. On the other hand, the Can1.available condition is never true, and nothing is printed on the serial.
I am thinking that the PWM signal of the teensy Tx pin is not correct, as it is the same regardless of the message (see figure above, where there is one initial longer Low-pulse, and then a bunch of shorter low-pulses)
 
Lets rule out the software, put this on both your Teensy 3.6's pins 34 and 35, itll read and write to the bus and both serial monitors will be scrolling data

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(500000);
  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 > 200 ) {
    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();
  }

}

if it still doesnt work, check your wiring
 
Status
Not open for further replies.
Back
Top