Forum Rule: Always post complete source code & details to reproduce any issue!
Page 1 of 2 1 2 LastLast
Results 1 to 25 of 27

Thread: Teensy 3.6 - FlexCAN - Listen and respond

  1. #1

    Teensy 3.6 - FlexCAN - Listen and respond

    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

  2. #2
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,133
    Its 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?

  3. #3
    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.

  4. #4
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,133
    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

  5. #5
    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?

  6. #6
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,133
    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

  7. #7
    Thank you. I will give it a go and get back here. =)

  8. #8
    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: 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.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....

  9. #9
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,133
    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);

  10. #10
    Thank you for your response.

    How do I read the date without going thru hexdump? And what is hexdump actually doing?

  11. #11
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,133
    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]...

  12. #12
    Ok! Let me experiment a bit and see how I go.

  13. #13
    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

  14. #14
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,133
    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

  15. #15
    Quote Originally Posted by tonton81 View Post
    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.

  16. #16
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,133
    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;

  17. #17
    Thank you. Does this mean that the library accepts DEC as standard when populating the msg.id and buf?

  18. #18
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,133
    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


  19. #19
    You live, you learn. Thanks alot for your quick replys!

    Quote Originally Posted by tonton81 View Post
    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


  20. #20
    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"


    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.



    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.

  21. #21
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,133
    the leading 0s are not printed is normal, you need to use printf or sprintf for that

  22. #22
    Member
    Join Date
    Sep 2019
    Location
    UK
    Posts
    22
    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');
      }
     }

  23. #23
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,133
    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.

  24. #24
    Member
    Join Date
    Sep 2019
    Location
    UK
    Posts
    22
    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

  25. #25
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,133
    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

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •