Teensy 3.6 - FlexCAN - Listen and respond

Status
Not open for further replies.

Tobbera

Member
Hi!

A few weeks ago I posted a question in the project guidance forum but never received any feedback. Thought it might be the wrong place so I give it a try here instead.


My goal is rather simple. I want the Teensy to respond to a frame when its detected on the bus. But I don't know how to implement it with the help of the FlexCAN library examples. I have a Teensy 3.6 and a CAN transceiver module SN65HVD230.


Pseudo code
Code:
loop() {
Listen on CAN bus for certain frame.
If frame == "t568101" detected..
then 
send on CAN bus "t5653001511" in decimal format.
}


Have anyone done something similar and can post an example snipped of code?


Code:
#include <FlexCAN.h>


void setup() {
delay(1000);
Serial.println(F("Starting up..."));
Can0.begin(500000);   
}

void loop() {
}


Regards
Tobias
 
It’s definately possible to do, a received frame ID would update the msg.id with the CAN ID of the frame.

But what do you mean frame id is “t568101”?, that is not valid, are you looking at the data field?
 
Thank you for taking time to look at my project tonton.

The "t568101” is a frame as I have read it on my CANbus with a canbus sniffer device. According to my research in translates into:
t = transmit
568 = frame hex ID
101 = payload in hex.
 
irregardless, you will have no issue identifying that frame when you see it, 568 will be populating the msg.id variable and your payload will appear in msg.buf[x];

sorry I didn’t catch your last post I would have definately helped you out

You can try out my IFCT library, there are simple examples included with it
 
Thank you. Looking at your library now.

So what I need to do is create an IF statement on the content of msg.id variable and msg.buf[x] compared to the ID and string I'm looking for?
 
pretty much yeah :)

but start it easy first, let it show what it sees on the serial monitor when the transmissions occur, the rest will come to you easily
 
Hi again.

I have now done some dumping on the bus with the following code, which is an altered version of the test code supplied with the library.

Dump code:
Code:
#include <FlexCAN.h> // by Collin Kidder, Based on CANTest by Pawelsky (based on CANtest by teachop)


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(500000); 
   pinMode(13, OUTPUT);    
  digitalWrite(13, HIGH);
}  

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

Code:
18:05:39.604 -> CAN bus 0: 1384, 0100000000000000
18:05:39.604 -> CAN bus 0: 1304, 0000000000000000
18:05:39.604 -> CAN bus 0: 1328, 0000000000000c00
18:05:39.604 -> CAN bus 0: [B]1384, 0100000000000000[/B]
18:05:39.604 -> CAN bus 0: 1304, 0000000000000000
18:05:39.604 -> CAN bus 0: 1328, 0000000000000c00
18:05:39.604 -> CAN bus 0: 1384, 0100000000000000
18:05:39.604 -> CAN bus 0: 1304, 0000000000000000
18:05:39.604 -> CAN bus 0: 1328, 0000000000000c00
18:05:39.604 -> CAN bus 0: 1384, 0100000000000000
18:05:39.604 -> CAN bus 0: 1304, 0000000000000000
18:05:39.604 -> CAN bus 0: 1328, 0000000000000c00
18:05:39.604 -> CAN bus 0: 1384, 0100000000000000
18:05:39.604 -> CAN bus 0: 1304, 0000000000000000
18:05:39.604 -> CAN bus 0: 1328, 0000000000000c00
18:05:39.650 -> CAN bus 0: 1384, 0100000000000000

Its the "1384, 0100000000000000" I would like to give my reply to on the CANbus, buts its very confusing with the conversion between HEX, DEC and Binary....
 
ok what you can do is for example ignore the hexdump() call in loop and access the data directly.

inMsg.id is your CAN ID
inMsg.buf[x] is your 8 data bytes, where “x” is the indice 0 to 7.

to write a frame you can do this:

CAN_message_t out;
out.len = 8;
out.flags.extended = 1;
out.buf[0] = 0xFF;
out.id = 1384; // or 0x568 in hex
Can0.write(out);
 
Thank you for your response.

How do I read the date without going thru hexdump? And what is hexdump actually doing?
 
hexdump is just a function that prints the data from the buffer (8 bytes)
you dont need that...

you read it like this:

firstByte = inMsg.buf[0];
secondByte = inMsg.buf[1];
etc up to buf[7]...
:)
 
I have experiemented a bit more and being able to detect the frame ID which is great sucess. Now I want to detect the content of the frame and respond with a CAN message as well.

Code:
#include <FlexCAN.h> // by Collin Kidder, Based on CANTest by Pawelsky (based on CANtest by teachop)


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


static uint8_t msg_to_be_checked[8];
//msg_to_be_checked[0] = 1;


void setup(void)
{
  delay(1000);
  Serial.println(F("Hello Teensy 3.6 dual CAN Test."));
  Can0.begin(500000);
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);
}

void loop(void)
{
  CAN_message_t inMsg;

  while (Can0.available())
  {
    Can0.read(inMsg); // Read message into inMsg

    Serial.print("CAN bus 0: ");

    // PRINT TO SERIAL RAW
    Serial.print(inMsg.id);
    Serial.print("  ");
    Serial.print(inMsg.buf[0]);
    Serial.print(" ");
    Serial.print(inMsg.buf[1]);
    Serial.print(" ");
    Serial.print(inMsg.buf[2]);
    Serial.print(" ");
    Serial.print(inMsg.buf[3]);
    Serial.print(" ");
    Serial.print(inMsg.buf[4]);
    Serial.print(" ");
    Serial.print(inMsg.buf[5]);
    Serial.print(" ");
    Serial.print(inMsg.buf[6]);
    Serial.print(" ");
    Serial.print(inMsg.buf[7]);

    Serial.print("\t");

    // PRINT TO SERIAL HEX
    Serial.print(inMsg.id, HEX);
    Serial.print("  ");
    Serial.print(inMsg.buf[0], HEX);
    Serial.print(" ");
    Serial.print(inMsg.buf[1], HEX);
    Serial.print(" ");
    Serial.print(inMsg.buf[2], HEX);
    Serial.print(" ");
    Serial.print(inMsg.buf[3], HEX);
    Serial.print(" ");
    Serial.print(inMsg.buf[4], HEX);
    Serial.print(" ");
    Serial.print(inMsg.buf[5], HEX);
    Serial.print(" ");
    Serial.print(inMsg.buf[6], HEX);
    Serial.print(" ");
    Serial.print(inMsg.buf[7], HEX);

    Serial.print("\t");

    // PRINT TO SERIAL HEXDUMP
    hexDump(8, inMsg.buf);

    if (inMsg.id == 568) {
      Serial.print("568 FRAME DETECTED!");
      Serial.print("\n");
    }

    if (inMsg.id == 1384) {
      Serial.print("1384 FRAME DETECTED!");
      Serial.print("\n");


      msg.ext = 0;
      msg.id = 1385;
      msg.len = 7;
      msg.buf[0] = 3;
      msg.buf[1] = 0;
      msg.buf[2] = 0;
      msg.buf[3] = 1;
      msg.buf[4] = 5;
      msg.buf[5] = 0;
      msg.buf[6] = 0;


      msg.buf[0]++;
      Can0.write(msg);
      msg.buf[0]++;
      Can0.write(msg);
      msg.buf[0]++;
      Can0.write(msg);
      msg.buf[0]++;
      Can0.write(msg);
      msg.buf[0]++;
      Can0.write(msg);
      msg.buf[0]++;
      Can0.write(msg);
      msg.buf[0]++;
      Can0.write(msg);
    }
  }
}

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');
}

Serial output
Code:
14:35:02.740 -> CAN bus 0: 1328  0 0 0 0 0 0 12 0	530  0 0 0 0 0 0 C 0	0000000000000c00
14:35:02.740 -> CAN bus 0: 520  0 0 0 0 11 10 0 0	208  0 0 0 0 B A 0 0	000000000b0a0000
14:35:02.786 -> CAN bus 0: 1384  1 0 0 0 0 0 0 0	568  1 0 0 0 0 0 0 0	0100000000000000
14:35:02.786 -> 1384 FRAME DETECTED!	
14:35:02.786 -> CAN bus 0: 1304  0 0 0 0 0 0 0 0	518  0 0 0 0 0 0 0 0	0000000000000000
14:35:02.786 -> CAN bus 0: 1328  0 0 0 0 0 0 12 0	530  0 0 0 0 0 0 C 0	0000000000000c00
14:35:02.786 -> CAN bus 0: 520  0 0 0 0 11 10 0 0	208  0 0 0 0 B A 0 0	000000000b0a0000
14:35:02.786 -> CAN bus 0: 1384  1 0 0 0 0 0 0 0	568  1 0 0 0 0 0 0 0	0100000000000000
14:35:02.786 -> 1384 FRAME DETECTED!	
14:35:02.786 -> CAN bus 0: 1304  0 0 0 0 0 0 0 0	518  0 0 0 0 0 0 0 0	0000000000000000
14:35:02.786 -> CAN bus 0: 1328  0 0 0 0 0 0 12 0	530  0 0 0 0 0 0 C 0	0000000000000c00
14:35:02.786 -> CAN bus 0: 520  0 0 0 0 11 10 0 0	208  0 0 0 0 B A 0 0	000000000b0a0000
14:35:02.786 -> CAN bus 0: 1384  1 0 0 0 0 0 0 0	568  1 0 0 0 0 0 0 0	0100000000000000
 
you see where your always incrementing indice [0] and Can0.writing it? If thats what your doing than thats pretty much all you have to do for sending :)

You will NOT see what you are sending that is normal, but your other device will see it
 
you see where your always incrementing indice [0] and Can0.writing it? If thats what your doing than thats pretty much all you have to do for sending :)

I'm note sure this is correct at all to be honest... Is it enought to do:
Code:
    Serial.print("WRITING TO CAN0");
    Serial.print("\n");
    msg.ext = 0;
   msg.id = 1385;
   // msg.id = 569;
    msg.len = 3;
    msg.buf[0] = 00;
    msg.buf[1] = 15;
    msg.buf[2] = 00;
    //  "t5693001500"
    Can0.write(msg);
    framedetected = false;
    Serial.print("WRITING DONE.");
    Serial.print("\n");

?


Another thing I cant get my head around is how to format the outgoing CAN msg. Shall it be in HEX or DEC? Depending on how I read the CANbus with different tools and settings, the same CAN msg shows up in different formats.

These are the same frames in different format.
Code:
00 15 00
00 21 00
ff 15 00

And the frame ID can be both 569 and 1385 depending on if its HEX or DEC.
 
hex or dec doesnt matter, the value is the same result. you can view the data (read variable) in hex or dec or even binary, your choice

Serial.print( (HEX) msg.buf[0] );

just use casting HEX, DEC, BIN

if you wanna use HEX for setting a variable, you MUST specify 0x

msg.id = 0x568;
 
this is normal accross all C/C++ programming.

putting buf[0] = 1234; is always decimal
to specify HEX, use 0x1234
to specify 3 in binary you put: 0b11

:)
 
Alright, I'm stepping this game up a couple of notches. =)

I've learned a lot during the last few days and its getting really fun.

With the following program I've made, I have been able to print in both DEC, HEX and BIN to serial console. This to give greater insight to what is happening on the bus. But, first and foremost the serial print in BIN format gives me a bit of grief because it leaves out beginning zeroes, which makes it hard to read which 1 and 0 belongs where on the payload.

Code:
#include <FlexCAN.h> // by Collin Kidder, Based on CANTest by Pawelsky (based on CANtest by teachop)

/*
  putting buf[0] = 1234; is always decimal
  to specify HEX, use 0x1234
  to specify DEC 3 in binary you put: 0b11
*/


static CAN_message_t msg;
static uint8_t hex[17] = "0123456789abcdef";
boolean framedetected = false;
int rawrmp;
int displayrpm;

void setup(void)
{
  delay(1000);
  Serial.println(F("Hello Teensy 3.6 dual CAN Test."));
  Can0.begin(500000);
  pinMode(13, OUTPUT);
  digitalWrite(13, HIGH);
  Serial.print("\n");

  Serial.print("DEC");
  Serial.print("\t");
  Serial.print("HEX");
  Serial.print("\t");
  Serial.print("HEXDUMP");
  Serial.print("\t");
  Serial.print("BIN");
  Serial.print("\n");

}

void loop(void)
{
  CAN_message_t inMsg;

  while (Can0.available())
  {
    Can0.read(inMsg); // Read message into inMsg
    if (inMsg.id == 1344) {
      // PRINT TO SERIAL RAW
      Serial.print(inMsg.id);
      Serial.print(" ");
      Serial.print(inMsg.buf[0]);
      Serial.print(" ");
      Serial.print(inMsg.buf[1]);
      Serial.print(" ");
      Serial.print(inMsg.buf[2]);
      Serial.print(" ");
      Serial.print(inMsg.buf[3]);
      Serial.print(" ");
      Serial.print(inMsg.buf[4]);
      Serial.print(" ");
      Serial.print(inMsg.buf[5]);
      Serial.print(" ");
      Serial.print(inMsg.buf[6]);
      Serial.print(" ");
      Serial.print(inMsg.buf[7]);

      Serial.print("\t");

      // PRINT TO SERIAL HEX
      Serial.print(inMsg.id, HEX);
      Serial.print(" ");
      Serial.print(inMsg.buf[0], HEX);
      Serial.print(" ");
      Serial.print(inMsg.buf[1], HEX);
      Serial.print(" ");
      Serial.print(inMsg.buf[2], HEX);
      Serial.print(" ");
      Serial.print(inMsg.buf[3], HEX);
      Serial.print(" ");
      Serial.print(inMsg.buf[4], HEX);
      Serial.print(" ");
      Serial.print(inMsg.buf[5], HEX);
      Serial.print(" ");
      Serial.print(inMsg.buf[6], HEX);
      Serial.print(" ");
      Serial.print(inMsg.buf[7], HEX);

      Serial.print("\t");

      // PRINT TO SERIAL HEXDUMP
 //     hexDump(8, inMsg.buf);
 //     Serial.print("\t");

      // PRINT TO SERIAL BIN
      Serial.print(inMsg.id, BIN);
      Serial.print(" ");
      Serial.print(inMsg.buf[0], BIN);
      Serial.print(" ");
      Serial.print(inMsg.buf[1], BIN);
      Serial.print(" ");
      Serial.print(inMsg.buf[2], BIN);
      Serial.print(" ");
      Serial.print(inMsg.buf[3], BIN);
      Serial.print(" ");
      Serial.print(inMsg.buf[4], BIN);
      Serial.print(" ");
      Serial.print(inMsg.buf[5], BIN);
      Serial.print(" ");
      Serial.print(inMsg.buf[6], BIN);
      Serial.print(" ");
      Serial.print(inMsg.buf[7], BIN);

      Serial.print("\n");
}
}
}


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');
}

Red = DEC, Blue = HEX, Green = BIN. You can see the bytes that is just one "0" instead of "00000000"
dlQciFw.png


Secondly, I have found that the nodes on the CANbus is packing multiple data into one byte. This is where the BIN readout comes in very handy. With this I have verified the following.

zxovJOH.png


But! How do read this out to understandable variables in an easy way? Lets say I want to populate the variables

Code:
int GearNumber
boolean standPostion 
boolean ABSLight
boolean neutralLight

from the CANBus frame "10101000000 00100101 101100 1 0 0 0 0 0"? From my table above, this frame means ID 1344 (DEC), 2nd gear, Side stand Up, Neutral Light Off, ABS light On.

Somehow I will have to read out the individual BIN data and make sense out of it.
 
Hi Tobbera and tonton81

I'm glad I found your thread as it is very similar to what I am trying to achieve. Canbus is a steep learning curve and the last few hours have started to make my head hurt! Your discussions and code snippets have been very helpful though.

I'm also using the Collin80 FlexCAN code, but a version that has been specifically forked and adapted for integration with a marine NMEA2000 network that I am trying to communicate with. My goal is to read rpm, temperature and boost from the engine canbus on my boat and get this onto the navigation canbus which has been reverse engineered by a clever chap named Timo Lappalainen. To date I have successfully connected to the engine canbus and displayed the frames on serial monitor using Collin80's Rx test sketch. I have also separately managed to get dummy information onto the navigation bus. What I now need to do is join the two up which will involve extracting some of the data bytes from the engine, applying formulas and putting the data onto the nav bus. The only high level guidance I've got is to use interrupts to get the canbus data and then poll for the information I need. Easier said than done as far as I'm concerned!

I don't yet full understand the difference or finer details of object oriented v interrupt v polling but have cobbled together the below code. As getting to my boat to test it is not very easy at present it would be great to know whether there is anything obviously out of place. My test code here is to simply read the 0x288 frames and display the second byte of data in hex (coolant temp). Will it work do you think, it compiles fine?

Code:
// -------------------------------------------------------------
// Development sketch to read VW marine can bus and filter relevant data
// using interrupts
//
// by Collin Kidder, Based on CANTest by Pawelsky (based on CANtest by teachop)
//
// This sketch uses interrupt driven Rx. 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";

/*might need int not uint8_t
uint8_t coolant; //unsigned integer coolant temp
uint16_t rpm; //unsigned integer rpm
uint8_t boost; //unsigned integer boost pressure
uint8_t iat; //unsigned integer intake air temp*/

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

  Can0.begin(500000);  
  
  //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 (Can0.available()) 
  {
    Can0.read(inMsg); //read message into inMsg
    if (inMsg.id == 0x288)
    Serial.print("CAN bus 0: "); 
    Serial.print(inMsg.id, HEX);
    Serial.print(", ");
    Serial.print (inMsg.buf[1], HEX);
    Serial.write('\r');
    Serial.write('\n');
  }
 }
 
This is just polling, nothing object oriented or interrupt, although you shouldnt read the inMsg frame unless .read() returns 1. Tobbera posted some code that should work, my recommendation is don't check for a specific frame (0x288) until you at least see all other frames in stream scrolling in your monitor, just to confirm your seeing data on the bus first.
 
Hi tonton81
Thank you for your helpful advice. I have searched lots of sample code but cannot find any examples of how or where to use the .read() function. Can you perhaps help me here.

Also, I think I understand how to identify code that is using object oriented method but what gives the game away that something is using interrupt rather than polling?

Finally, I don't want my code to send any ack to the can bus. I want it to listen only. Do I need to set anything for this?
Thanks again
 
You can put the hardware into listen only mode, i dont know if it can be done with the library though, by calling read() you are basically polling, whereas an interrupt would fire the callback when a specific frame(s) drops into the mailbox
 
Status
Not open for further replies.
Back
Top