Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

very unreliable CAN bus reading #9

Open
wt70707 opened this issue Jan 31, 2019 · 13 comments
Open

very unreliable CAN bus reading #9

wt70707 opened this issue Jan 31, 2019 · 13 comments

Comments

@wt70707
Copy link

wt70707 commented Jan 31, 2019

Hello Collin,
Thanks for open a window for asking your expert help. I am trying to build communication on CAN bus using your library.

My system: on one side, NVidia TX2 (with CAN controller CAN MCP2515T-I/ML and transceiver TJA1051TK/3); the other side Teensy 3.6 with "Dual CAN-Bus adapter for Teensy 3.5, 3.6" (https://www.tindie.com/products/Fusion/dual-can-bus-adapter-for-teensy-35-36/) which uses transceiver SN65HVD230D.

My first question is in the example "CANtest", as I understand it is same setup as me, why the enable pin is set to HIGH (which as Pawelsky point out the transceiver SN65HVD230D is in sleep mode)? Is slope mode you are using? Should I put pull down resistor for the enable pin?

I put an oscilloscope on the CANH and CANL, here is a picture of what I got:
one catch of can

If the hardware is of no problem. My problem is the communication on CAN bus always fails after some seconds. I had tried both teachtop's library and your library; I also tried your library and examples. Now I only succeed in the CANtest example with loopback.

On the TX2 side, CAN socket is used. I use a timer (40hz) to send command to read I2C altimeter (LW20/C): send command to CAN bus; delay 1ms; read CAN bus.

On the Teensy 3.6 side, I tried both scan mode and interrupt mode; interrupt mode will be a little bit better, but also failed after some reading the CAN bus (TX2 side). I will attach the code for the interrupt mode in the end. From the debug, it seems the mailboxes (TX) at the Teensy side are not released or the the data wrote to CAN bus from Teensy 3.6 is not read out from the TX2 side. I see there is a "txHandler", how to use it and what is this for? What is the event for this handler?

There are two extra headers for the LED and altimeter I work with. I put the function to read distance here. After this function is the main() of the Teensy 3.6.

static uint8_t getDefaultMedianDistance(byte addr, uint8_t **strCAN)
{
int i = 0;
uint8_t count = 0;
uint8_t str[8];

Wire.beginTransmission(addr);
Wire.write("?LD\r\n");
Wire.endTransmission();

delay(2); //must have a delay even only 1ms, or a lot of mess up

Wire.requestFrom(addr, (byte)12); // general call
while( Wire.available() ) {
char c = Wire.read();
//Serial.print(c);
if(i >= 5 && c != '\r' && c != '\n' && c != ' ' && c != '\0')
{
str[i - 5] = c;
count++;
}
i++;
}
//Serial.print('\n');

*strCAN = str;

return count;
}

The following is the main() of Teensy 3.6:
// -------------------------------------------------------------
// 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 <Time.h>
#include "FlexCAN.h"
//#include <Wire.h>
#include <i2c_t3.h> // for multiple i2c ports

#include "BlinkM_funcs.h"
byte addr_BlinkM = 0x09; // address of BlinkM

#include "lw20_funcs.h"
byte addr_lw20 = 0x66;

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

class ExampleClass : public CANListener
{
public:
void printFrame(CAN_message_t &frame, int mailbox);
bool frameHandler(CAN_message_t &frame, int mailbox, uint8_t controller); //overrides the parent version so we can actually do something
void txHandler (int mailbox, uint8_t controller);

bool tx_completed_ = false;
};

void ExampleClass::printFrame(CAN_message_t &frame, int mailbox)
{
Serial.print("ID: ");
Serial.print(frame.id, HEX);
Serial.print(" Data: ");
for (int c = 0; c < frame.len; c++)
{
Serial.print(frame.buf[c], HEX);
Serial.write(' ');
}
Serial.write('\r');
Serial.write('\n');

Serial.print("mailbox: ");
Serial.print(mailbox);
Serial.write('\r');
Serial.write('\n');
}

void ExampleClass::txHandler (int mailbox, uint8_t controller)
{
tx_completed_ = true;
Serial.print("One write for mailbox and controller: ");
Serial.println(mailbox);
//Serial.print(", ");
//Serial.println(controller);
}

bool ExampleClass::frameHandler(CAN_message_t &frame, int mailbox, uint8_t controller)
{
CAN_message_t outMsg;

//printFrame(frame, mailbox);

switch (frame.id)
{
case 0x00: //BlinkM LED
{
switch (frame.buf[1])
{
case 'n':
{
BlinkM_setRGB(frame.buf[0], frame.buf[2], frame.buf[3], frame.buf[4]);

      break;
    }
    case 'c':
    {
      break;
    }
    case 'h':
    {
      break;
    }
    case 'C':
    {
      break;
    }
    case 'H':
    {
      break;
    }
    case 'p':
    {
      break;
    }
    case 'o':
    {
      break;
    }
    case 'f':
    {
      break;
    }
    case 't':
    {
      break;
    }
    case 'W':
    {
      break;
    }
    case 'L':
    {
      break;
    }
    case 'A':
    {
      break;
    }
    case 'a':
    {
      outMsg.buf[0] = addr_BlinkM;
      outMsg.buf[1] = BlinkM_getAddress(addr_BlinkM);
      
      outMsg.ext = 0;
      outMsg.id = 0x00;
      //outMsg.timeout = 100;
      outMsg.len = 2;
      //tx_completed_ = false;
      Can1.write(outMsg);
      //while (!tx_completed_);
      Serial.print("Address of BlinkM: 0x");
      Serial.println(outMsg.buf[1]);
  
      break;
    }
    case 'B':
    {
      break;
    }
    case 'Z':
    {
      int ver = BlinkM_getVersion(addr_BlinkM);
      outMsg.buf[0] = addr_BlinkM;
      outMsg.buf[1] = (ver >> 8) & 0xff;
      outMsg.buf[2] = ver & 0xff;
      
      outMsg.ext = 0;
      outMsg.id = 0x00;
      //outMsg.timeout = 100;
      outMsg.len = 3;
      //tx_completed_ = false;
      Can1.write(outMsg);
      //while (!tx_completed_);
      Serial.print("BlinkM version: 0x");
      Serial.print(outMsg.buf[1], HEX);
      Serial.println(outMsg.buf[2], HEX);
      
      break;
    }
    case 'R':
    {
      break;
    }
    case 'g':
    {
      byte r=0, g=0, b=0;
      BlinkM_getRGBColor(addr_BlinkM, &r, &g, &b);
      outMsg.buf[0] = addr_BlinkM;
      outMsg.buf[1] = r;
      outMsg.buf[2] = g;
      outMsg.buf[3] = b;
      Serial.print("r: 0x");
      Serial.print(r, HEX);
      Serial.print(", g: 0x");
      Serial.print(g, HEX);
      Serial.print(", b: 0x");
      Serial.println(b, HEX);
      
      outMsg.ext = 0;
      outMsg.id = 0x00;
      //outMsg.timeout = 100;
      outMsg.len = 4;
      //tx_completed_ = false;
      Can1.write(outMsg);
      //while (!tx_completed_);
      
      break;
    }
    default:
    {
      break;
    }
  }
  break;
}
case 0x01: // LW20 altimeter
{
  String lw20CanCmd = "";
  uint8_t *strCAN;
  uint8_t strCANLen;
  for(int i = 1; i < frame.len; i++)
    lw20CanCmd += (char)frame.buf[i];
  //Serial.print(lw20CanCmd);
  //Serial.print('\n');
  
  if(lw20CanCmd == "?LD")
  {        
    strCANLen = getDefaultMedianDistance(addr_lw20, &strCAN) + 1;
    //Serial.print("\noutMsg.buf: ");
    for(int i = 1; i < strCANLen; i++)
    {
      outMsg.buf[i] = strCAN[i-1];
    //  Serial.print(outMsg.buf[i]);
    }
    //Serial.print('\n');
  }
  else if(lw20CanCmd == "?PN")
  {
    strCANLen = getProductName(addr_lw20, &strCAN) + 1;
    //Serial.print("\noutMsg.buf: ");
    for(int i = 1; i < strCANLen; i++)
    {
      outMsg.buf[i] = strCAN[i-1];
    //  Serial.print(outMsg.buf[i]);
    }
    //Serial.print('\n');
  }
  else if(lw20CanCmd == "?PS")
  {
    strCANLen = getSoftwareRev(addr_lw20, &strCAN) + 1;
    //Serial.print("\noutMsg.buf: ");
    for(int i = 1; i < strCANLen; i++)
    {
      outMsg.buf[i] = strCAN[i-1];
    //  Serial.print(outMsg.buf[i]);
    }
    //Serial.print('\n');
  }
  else if(lw20CanCmd == "?PF")
  {
    strCANLen = getFirmwareRev(addr_lw20, &strCAN) + 1;
    //Serial.print("\noutMsg.buf: ");
    for(int i = 1; i < strCANLen; i++)
    {
      outMsg.buf[i] = strCAN[i-1];
    //  Serial.print(outMsg.buf[i]);
    }
    //Serial.print('\n');
  }

  outMsg.ext = 0;
  outMsg.id = 0x01;
  //outMsg.timeout = 100;
  outMsg.buf[0] = addr_lw20;
  outMsg.len = strCANLen;
  //tx_completed_ = false;
  Can1.write(outMsg);
  //while (!tx_completed_);

// Serial.print("outMsg.buf: ");
// for(int i = 1; i < strCANLen; i++)
// {
// Serial.print((char)outMsg.buf[i]);
// }
// Serial.print('\t');
// Serial.print("Length:");
// Serial.print(strCANLen);
// Serial.print('\n');

  break;
}
default:
{
  break;
}

}

return true;
}

ExampleClass exampleClass;

// -------------------------------------------------------------
void setup(void)
{
//Can0.setNumTxBoxes(8);
Can1.setNumTxBoxes(8);
//Can0.begin(1000000);
Can1.begin(1000000);

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

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

//Can0.attachObj(&exampleClass);
Can1.attachObj(&exampleClass);
exampleClass.attachGeneralHandler();
//exampleClass.attachMBHandler(2);
//exampleClass.attachMBHandler(14);

Wire.begin();

Serial.begin(115200);
delay(2000);
Serial.println(F("Teensy 3.6 dual CAN, BlinkM and LW20 altimeter."));

// init BlinkM funcs
BlinkM_begin();
BlinkM_off(addr_BlinkM);
// print address of BlinkMs
Serial.print("Address of BlinkM: 0x");
Serial.print(BlinkM_getAddress(addr_BlinkM), HEX);
Serial.println();
}

uint8_t j = 0;
uint32_t clk_count = 0;
unsigned long old_millis = 0;
unsigned long current_millis;

// -------------------------------------------------------------
void loop(void)
{
clk_count++;
if (clk_count > 1000000)
{
//Serial.println(now());//Returns the number of seconds since Jan 1 1970
current_millis = millis(); //Number of milliseconds since the program started (unsigned long)
Serial.println(millis() - old_millis);
old_millis = current_millis;
clk_count = 0;
}
//CAN_message_t inMsg, outMsg;

/*outMsg.buf[0] = 0x00;
outMsg.buf[1] = BlinkM_getAddress(0x09);

outMsg.ext = 0;
outMsg.id = 0x00;
//outMsg.timeout = 100;
outMsg.len = 2;
Can1.write(outMsg);

for(uint8_t i = 0; i < 8; i++, j++)
outMsg.buf[i] = j;
outMsg.ext = 0;
outMsg.id = 0x01;
//outMsg.timeout = 100;
outMsg.len = 8;
Can1.write(outMsg);*/

/*while (Can1.available())
//if (Can1.available())
{

}*/
}

@szotyi007
Copy link

I am using this library for more than a year without a problem. I think it is hardware problem.
https://www.kmpdrivetrain.com/paddleshift/practical-tips-can-bus/
"The most common CAN-Bus issue is too much or too little termination resistance"...

@wt70707
Copy link
Author

wt70707 commented Feb 1, 2019

Thanks szotyi007,

120 Ohms on end of bus (only 2x 120 Ohms): there is a sold on 120 Ohms on "Dual CAN-Bus adapter for Teensy 3.5, 3.6" and I put a 120 Ohms on the TX2 side; measured is 60 Ohms.
Make sure all devices have the same bitrate speed: on TX2 side it is set to "bitrate of 1000000 and sample-point of 0.75". I think sample-point of 0.75 is the standard. On Teensy 3.6 side as you can see in the above code, it is set to 1000000.
Measure voltage of CAN-High and CAN-Low: both of CAN-High and CAN-Low are 2.43V.

Also I put the "Dual CAN-Bus adapter for Teensy 3.5, 3.6" on top of Teensy 3.6 board instead of previously I put the transceiver on a breadboard and wired it to Teensy 3.6. I doubt it is more sensitive of the TX and RX signals of CAN controller, so I make this revision.

I am also thinking about to twist the wire (about 32cm or 13 inches) from the transceiver to TX2. But from the oscilloscope, the signals are good.

Best Regards,
Tao Wang

@collin80
Copy link
Owner

collin80 commented Feb 1, 2019

I have never used the 230 transceiver. I use the 234 where Rs is the slope control and the special pin is an enable pin that can be used to turn the transceiver on and off. For fast CAN you want to essentially ground the Rs pin to go into fast mode. You can't really do slope control at 1M or likely even at 500k. You need the transceiver to slam the digital signal to the proper level as fast as it can. It seems for your 230 transceiver the extra pin is Vref instead of enable. You will need to leave that pin alone. If it is connected to a pin on your processor then set that processor pin to input or you're going to have a bad time.

@wt70707
Copy link
Author

wt70707 commented Feb 1, 2019

Thanks Collins.

I tried to remove the line "digitalWrite(35, LOW);", and it is the same behavior and the measurement of pin 35 is always 0. I then remove the line "pinMode(35, OUTPUT);", no difference. At last I define pin 35 as input, the CAN totally doesn't work.

I checked the spec of 230. It says "Rs: SN65HVD230 and SN65HVD231: Mode select pin: strong pull down to GND = high speed mode, strong pull up to VCC = low power mode, 10kΩ to 100kΩ pull down to GND = slope control mode". It seem the same feature as of 234. And 230 have another pin Vref.

@wt70707
Copy link
Author

wt70707 commented Feb 1, 2019

This is the spec of 230:
image

This is the spec of 234:
image

@szotyi007
Copy link

What if you take out the NVidia TX2? And try to connect the two can bus of the teensy? You send a message from Can0 to Can1.. and you print out the received data on Can1?
To be sure that part is working...

@wt70707
Copy link
Author

wt70707 commented Feb 1, 2019

Thanks szotyi007, I had tested that example, it works fine.

@wt70707
Copy link
Author

wt70707 commented Feb 1, 2019

Hello Coliin,

I just notice in your CAN_message_t, there is no "timeout", is it just removed or it is implemented in other way?

And for the new "flags.extended" and "flags.remote", should I explicitly set them to 0 for standard CAN frame and normal frames? For the new "flags.overun", how can I use it?

For the tx mailbox, as I understand if exact order is required, it should be set to 1. However, when I set it, the CAN bus never works. Also I saw somewhere, it should be set before the begin() function, however it is even after the begin() function, it still works.

@wt70707
Copy link
Author

wt70707 commented Feb 1, 2019

I set "flags.extended", "flags.remote" and "flags.overrun" to zero, it works much better. But still CAN bus seems freeze after some time. From oscilloscope TX2 still send out CAN frames, but it seems Teensy not answer anything. In the Serial Monitor, all the Serial.print() in the loop is not executed.

@wt70707
Copy link
Author

wt70707 commented Feb 3, 2019

It seems I solve my problem. "flags.overrun" should not be set to zero each time write something to CAN bus. I got it works in the morning. But in the afternoon, the system will freeze after some running. In this situation, Teensy requires reset to work again. With some print out, it seems "loop" and "interrupt handlers" are not working. Should I suspect the hardware? As I use breadboard for the test now, so a lot of flying wires.

@collin80
Copy link
Owner

collin80 commented Feb 3, 2019

It is possible that hardware issues could cause it. Intermittent freezes after a long time are pretty much the hardest thing to track down. There are many reasons that something like that could occur. With interrupts one very suspect reason would be race conditions. They could be exceedingly rare and hard to trigger but when you're running for hours straight and through millions of loops they can pop up seemingly at random. So, it's difficult to say for sure what the cause is for you. Usually a purpose built PCB will be more reliable though.

@wt70707
Copy link
Author

wt70707 commented Feb 3, 2019

As I tried both interrupt mode and poll mode, so it should not be race conditions. When it happens, it will stop running both interrupt loops and the main loop. It should be mostly the hardware problem. I will try to use less the breadboard.

@wt70707
Copy link
Author

wt70707 commented Feb 6, 2019

Thanks szotyi007, collin80,
I got the CAN bus works the whole day, after wired the sensors directly without going through the breadboard.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants