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

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

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

    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
    533
    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:	32 
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:	52 
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
    5
    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
    533
    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
    533
    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 Im thinking now that theres 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:	75 
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
    533
    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
    533
    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:	94 
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
    3,692
    Shouldn't you set the filter only after running begin()?

  16. #16
    Senior Member PaulS's Avatar
    Join Date
    Apr 2015
    Location
    Netherlands
    Posts
    533
    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

Posting Permissions

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