Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 21 of 21

Thread: How to use CAN bus on Teensy 4.1, 4.0 and 3.2 ?

  1. #1
    Junior Member
    Join Date
    Nov 2020
    Posts
    6

    How to use CAN bus on Teensy 4.1, 4.0 and 3.2 ?

    Hi everyone,

    I would like to communicate with a CAN bus between 3 teensy board (4.1, 4.0 and 3.2).
    The only information that i found about Teensy and the CAN bus, is that the connection isn't native and i need a CAN Transceiver and a CAN receiver at least for the Teensy 3.2. Is that right ? Or can i directly wire it and use it like other connection ?
    I couldn't find any more information about T4.0 and T4.1 concerning this port, if you have any documentation or knowledge about this, i will gladly read them.

    Thanks !

  2. #2
    Junior Member
    Join Date
    Apr 2019
    Posts
    4
    See https://forum.pjrc.com/threads/40966...le-CAN-library
    The boards you mentioned have a CAN controller so you can use existing libraries to read the bus, but if you want to send messages you'll need a transceiver.
    Not sure how to configure the transceiver, I'm using the MCP2515 in another project.

  3. #3
    Senior Member PaulS's Avatar
    Join Date
    Apr 2015
    Location
    Netherlands
    Posts
    767
    All Teensy boards you mention have a CAN Controller onboard.
    See this picture from Wikipedia:

    Click image for larger version. 

Name:	CAN_Node.png 
Views:	168 
Size:	22.1 KB 
ID:	22322

    The only thing you need to add is a CAN bus transceiver like this one:

    Click image for larger version. 

Name:	TI SN65HVD230 CAN-bus transceiver module.png 
Views:	400 
Size:	226.6 KB 
ID:	22323

    Google for "TI SN65HVD230 CAN-bus transceiver module".
    No configuration needed for this transceiver, just hookup the CRX & CTX pins to the appropriate Teensy CAN bus pins.

    Paul

  4. #4
    Junior Member
    Join Date
    Nov 2020
    Posts
    6
    Thanks for your answer !
    I just need to add one transceiver for each Teens that will transmit with CAN, if i am right.

  5. #5
    Senior Member PaulS's Avatar
    Join Date
    Apr 2015
    Location
    Netherlands
    Posts
    767
    You're right.
    Paul

  6. #6
    Junior Member
    Join Date
    Nov 2020
    Posts
    7
    I have a question regarding the transceiver.
    I have a project where similar communication is required between a 3.6 and 3.2. To summarize what I have done so far is I am running a CAN node that is sending data and one that is attempting to receive it. I have gotten it to send data, however it stops updating it after 10 attempts (simple check with setting Can0.write() equal to an int). It is consistently cutting off after 10 attempts and is repeatable, but I can't find a buffer that is causing this cutout so I am not sure why this is. The system IS sending data though, as the receiving node does display the first sent data point through the serial port. Also to confirm that the data received is in fact from the first Teensy I filled an 8 byte buffer full of random data and it was 100% accurate on the other teensy, as long as it was not changed during runtime.
    I really want to understand CAN networks better so I have a few questions to follow up where I am at:
    If the transceiver is required, how is it the first data frame is able to make it to the receiving side?
    Is it possible that it times out after 10 attempts is that it is trying to write the first message over and over again but see's a reflection in the data which causes it to reset? I only 1 120 ohm resistor hooked up to it and that resistance seems to be to allow it to function (no resistor doesn't function)
    Any help provided is appreciated, and if there is any lacking information let me know!
    Thanks

  7. #7
    Member
    Join Date
    Oct 2020
    Location
    Berks UK
    Posts
    34
    I’m about to start out with CAN a on the Teensy 4.1. I’ve got both MCP2515 boards and some 3.3v transceiver chips too. I started out interested in using the 2515 as I found a fair amount of code out there online. Data rates will be fairly low so speed and overheads are a non-issue either way. I’m thinking now that there’s no real advantage to using the microchip part over Teensy hardware CAN via the transceiver alone. Though I’d welcome any comments to the contrary?

    Steve

  8. #8
    Senior Member PaulS's Avatar
    Join Date
    Apr 2015
    Location
    Netherlands
    Posts
    767
    Quote Originally Posted by dresio View Post
    and if there is any lacking information let me know!
    Thanks
    Hi Dresio, could you post both pieces of code [TX node & RX node]. And perhaps a photo of your setup?

    Quote Originally Posted by SteveW View Post
    I Iím thinking now that thereís no real advantage to using the microchip part over Teensy hardware CAN via the transceiver alone.
    Hi Steve, correct, why use an external CAN controller when it's already present in the Teensy? And software support is also available.

    Paul

  9. #9
    Member
    Join Date
    Oct 2020
    Location
    Berks UK
    Posts
    34
    Thanks Paul, the FlexCAN library looks as if will be useful!

    Steve

  10. #10
    Junior Member
    Join Date
    Nov 2020
    Posts
    7
    Both bits of code on the nodes are just slightly modified from the object oriented examples.
    Here is the receive node:
    Code:
    #include <FlexCAN.h>
    
    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 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');
    }
    
    bool ExampleClass::frameHandler(CAN_message_t &frame, int mailbox, uint8_t controller)
    {
        printFrame(frame, mailbox);
    
        return true;
    }
    
    ExampleClass exampleClass;
    
    // -------------------------------------------------------------
    void setup(void)
    {
      delay(1000);
      Serial.println(F("Hello Teensy Single CAN Receiving Example With Objects."));
    
      Can0.begin(100000);  
    
    
      Can0.attachObj(&exampleClass);
      exampleClass.attachGeneralHandler();
    }
    
    
    // -------------------------------------------------------------
    void loop(void)
    {
      delay(1000);
      Serial.write('.');
    }
    And here is the send node:
    Code:
    #include <FlexCAN.h>
    
    #ifndef __MK66FX1M0__
      #error "Teensy 3.6 runs this code"
    #endif
    
    
    CAN_message_t msg;
    static uint8_t hex[17] = "0123456789abcdef";
    
    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 ExampleClass::printFrame(CAN_message_t &frame, int mailbox)
    {
       Serial.print("ID: ");
       Serial.print(frame.id, HEX);
       Serial.print(", MB: ");
       Serial.print(mailbox);
       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');
    }
    
    bool ExampleClass::frameHandler(CAN_message_t &frame, int mailbox, uint8_t controller)
    {
        printFrame(frame, mailbox);
    
        return true;
    }
    
    ExampleClass exampleClass;
    
    // -------------------------------------------------------------
    void setup(void)
    {
      delay(1000);
      Serial.println(F("Hello Teensy 3.6 dual CAN Test With Objects."));
    
      Can0.begin(100000);  
    
      //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);
    
      Can0.attachObj(&exampleClass);
      exampleClass.attachGeneralHandler();
    
      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]++;
      int temp = Can0.write(msg);
      Serial.println(temp);
      delay(20);
    }
    Here is a picture of the setup:
    Click image for larger version. 

Name:	Setup.jpg 
Views:	337 
Size:	84.3 KB 
ID:	22359

    Breadboard wires were too unstable so this is a modified PCB I found laying around. I am looking over it now and I think that I may of been off one pin in the socketing so the tx on the 3.6 was streaming directly to the rx pin on the 3.2, which would explain why I am seeing data on the 3.2, but I am still confused on why it is only receiving the first message.

  11. #11
    Senior Member PaulS's Avatar
    Join Date
    Apr 2015
    Location
    Netherlands
    Posts
    767
    Hi Dresio,
    I got a bit confused with the object oriented examples so I crafted a slightly different piece of code for the receiver:
    Code:
    // https://github.com/collin80/FlexCAN_Library
    // https://en.wikipedia.org/wiki/CAN_bus
    
    #include <FlexCAN.h>                 // CAN transceiver: CTX pin 3, CRX pin 4
    
    static CAN_message_t msg;
    static CAN_filter_t allPassFilter;
    
    void setup() {
      pinMode(LED_BUILTIN, OUTPUT);
      Serial.begin(115200);
      while (!Serial) ;       // wait for serial monitor
      
      allPassFilter.flags.extended = 1;  // 1 for extended/29 bit IDs
      Can0.begin(100000, allPassFilter); // init CAN bus @ 100kbps
      Serial.println("CAN initialized and listening");
    }
    
    void loop() {
      if (Can0.read(msg)) {
        digitalWrite(LED_BUILTIN, HIGH);
        Serial.printf("0x%08X", msg.id); Serial.print(" ");
        Serial.printf("0x%04X", msg.timestamp); Serial.print(" ");
        Serial.printf("0x%02X", msg.flags); Serial.print(" ");
        Serial.printf("0x%02X", msg.len); Serial.print(" ");
        for (byte i = 0; i < sizeof(msg.buf); i++) {
          Serial.printf("0x%02X", msg.buf[i]); Serial.print(" ");
        }
        Serial.println("");
        digitalWrite(LED_BUILTIN, LOW);
      }
    }
    When running this code on a Teensy 3.2, I was able to receive lots of CAN frames without any problem from my USB CAN analyzer.

    Paul

  12. #12
    Senior Member PaulS's Avatar
    Join Date
    Apr 2015
    Location
    Netherlands
    Posts
    767
    I just realized that the issue you are seeing [only receiving the first message] is perhaps caused by the fact that the transmitting node does not see the ACK generated by the receiving node when a correct CAN message is received. In the case of a missing ACK, it may stop transmitting subsequent CAN frames.

    Here is a logic analyzer snapshot showing the ACK inserted by the receiver:

    Click image for larger version. 

Name:	CAN message.png 
Views:	433 
Size:	29.1 KB 
ID:	22362
    "CAN RX src" is measured on pin 4 of the T3.2, "CAN TX src" on pin 3. [by the way, this snapshot shows the CAN bus running at 250kbps]
    CAN RX and CAN TX are ofcourse merged when you look at the actual CANL and CANH lines.

    I'm also wondering whether you do need to use an actual transceiver such that the transmitter can check whether the ACK is given in the right time slot.

    Paul

  13. #13
    Check out this linked doc on how to connect TX to RX and still have proper ACK function.
    https://forum.pjrc.com/threads/56035...406#post254406

  14. #14
    I try to setup filter for can bus. This does not work:

    Code:
    #include <FlexCAN.h>
    
    void setup() {
    
      CAN_filter_t defaultFilter;
      
      defaultFilter.ext = 0;
      defaultFilter.rtr = 0;
      defaultFilter.id = 0x700;
      for (int c = 4; c < 16; c++){
        Can0.setMask(0xFFFF,c);
        Can0.setFilter(defaultFilter, c); // */
      }
    
      
      Can0.begin(500000);
    
      Serial.println("Init done");
    
    }
    
    void loop() {
    
       while ( Can0.read(rxmsg) ) {
        Serial.printf("%08X",rxmsg.id);for(byte i=0;i<8;i++){Serial.printf(" %02X",rxmsg.buf[i]);}Serial.printf(" time:%d \n\r",millis());
    
       }
      
    }
    any directions, what I need to change, to receive only 0x700 frames?

  15. #15
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    4,033
    Shouldn't you set the filter only after running begin()?

  16. #16
    Senior Member PaulS's Avatar
    Join Date
    Apr 2015
    Location
    Netherlands
    Posts
    767
    Hi jblaze, I modified your sketch since it compiled with an error ['rxmsg' was not declared in this scope]
    Here is the modified code:
    Code:
    #include <FlexCAN.h>
    
    static CAN_message_t rxmsg;
    static CAN_filter_t defaultFilter;
    
    void setup() {
      defaultFilter.id = 0x0700;
      defaultFilter.flags.extended = 0;       // this filter works, it blocks extended frames and vice-versa
      defaultFilter.flags.remote = 0;
    
      //  for (uint8_t c = 0; c = 13; c++) {    // 0-13 are RX mailbox, 14 & 15 are TX mailbox
      //    Can0.setMask(0x0700, c);
      //    Can0.setFilter(defaultFilter, c);
      //  }
      //  Can0.begin(500000);
    
      Can0.begin(500000, defaultFilter);   // uncomment when using for-loop to set mask
      Serial.println("Init done");
    }
    
    void loop() {
      if (Can0.read(rxmsg)) {
        Serial.printf("%08X", rxmsg.id);
        for (byte i = 0; i < 8; i++) {
          Serial.printf(" %02X", rxmsg.buf[i]);
        }
        Serial.printf(" time:%d \n\r", millis());
      }
    }
    Long story short: I did not get it to filter using setMask. That is to say: ALL frames are blocked.
    With the for-loop uncommented as above, it does filter on extended/standard frames though.
    Even when setting the masks after Can0.begin(500000); as tonton81 suggested, it did not work.

    Tried a lot things the last 2 hours but I'm stuck now. Maybe I get another idea after a night's sleep.

    Paul

  17. #17
    Junior Member
    Join Date
    Jan 2022
    Posts
    1
    Hi everyone. I see that is is an old thread, but i'll shoot my shot:

    Is there a specific CAN-bus transciever one need to buy in order to use CAN FD and Teensy 4.1 / 4.0? The "TI SN65HVD230 CAN-bus transceiver module" seems very simple and good, but does that work with CAN FD, or is there a specific type of CAN-bus transcievers that works with CAN FD?

    Also, what is the difference between using an IC as MCP2515 versus using something more user-friendly as the "TI SN65HVD230 CAN-bus transceiver module"?

    Ole

  18. #18
    Senior Member PaulS's Avatar
    Join Date
    Apr 2015
    Location
    Netherlands
    Posts
    767
    The SN65HVD230 supports speeds up to 1Mbit/s. For CAN FD you need a higher speed chip like the MCP2562FD.
    See a suitable board here.

    By the way, in the meantime I have solved the filtering issue that I referred to in msg #16.
    You need to set a 29 bit mask, an 11 bit mask doesn't work.

    Code:
    void setup() {
      defaultFilter.flags.extended = 0;
      Can0.begin(500000, defaultFilter);
     
      defaultFilter.id = 0x0700;          // pass only ID 0x0700
      for (int m = 0; m < 14; m++) {      // set mask & filter for RX mailbox 0-13 [14 & 15 are TX mailbox]
        Can0.setMask(0x1FFFFFFF, m);      // set 29 bit mask, 11 bit mask doesn't work
        Can0.setFilter(defaultFilter, m);
      }
      Serial.println("Init done");
    }
    Paul

  19. #19
    Junior Member
    Join Date
    Jan 2022
    Posts
    1
    Hi , I want to use all 3 CAN ports of teensy4.0 but I don't want to use the FD protocol. Is it possible to implement CAN2.0 on the CAN FD port too?

    Also , I had a basic doubt. Since we are using an external transceiver can't we use any set of TX/RX pins (like RX1,TX1) on teensy4.0 for CAN communication?

    Click image for larger version. 

Name:	teensy4_pinout.png 
Views:	52 
Size:	372.7 KB 
ID:	27306

  20. #20
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    4,033
    CAN3 supports CAN2.0 legacy OR CANFD, so yes you can use CAN2.0 on all 3 with identical code

    the CAN pins are PINK on the card, don't confuse them for the serial ports, you can't install the transceiver on any pins other than the pink labelled ones as theyre the pins linked to the onboard CAN controller

  21. #21
    Senior Member
    Join Date
    Jan 2015
    Location
    UK
    Posts
    195
    Quote Originally Posted by Arush View Post
    Hi , I want to use all 3 CAN ports of teensy4.0 but I don't want to use the FD protocol. Is it possible to implement CAN2.0 on the CAN FD port too?

    Also , I had a basic doubt. Since we are using an external transceiver can't we use any set of TX/RX pins (like RX1,TX1) on teensy4.0 for CAN communication?

    Click image for larger version. 

Name:	teensy4_pinout.png 
Views:	52 
Size:	372.7 KB 
ID:	27306
    The pinout picture is for Teensy 3.2 not Teensy 4.0

Posting Permissions

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