Forum Rule: Always post complete source code & details to reproduce any issue!
Page 41 of 41 FirstFirst ... 31 39 40 41
Results 1,001 to 1,015 of 1015

Thread: FlexCAN_T4 - FlexCAN for Teensy 4

  1. #1001
    Junior Member
    Join Date
    Apr 2022
    Posts
    6
    Thanks for your response!

    The example you gave me is for CAN as far as I know, but I want to use CAN-FD. So is this correct?

    Code:
    #include <FlexCAN_T4.h>
    
    FlexCAN_T4FD<CAN3, RX_SIZE_256, TX_SIZE_16> can3;
    IntervalTimer timer;
    int SILENT = 9;
    
    uint8_t a=0;
    void setup(void) {
    
      pinMode(SILENT,OUTPUT); 
    
      digitalWrite(SILENT,LOW);
      
      can3.begin();
    
      CANFD_timings_t config;
      config.clock = CLK_24MHz;
      config.baudrate = 500000;
      config.baudrateFD = 500000;
      config.propdelay = 190;
      config.bus_length = 1;
      config.sample = 70;
    
      can3.setBaudRate(config);
      can3.setMaxMB(16);
      can3.enableFIFO();
      can3.enableFIFOInterrupt();
      can3.onReceive(canSniff);
      can3.mailboxStatus();
    
      
      timer.begin(sendframe, 100000); // Send frame every 500ms
    }
    
    
    void canSniff(const CAN_message_t &msg) {
      Serial.print("MB "); Serial.print(msg.mb);
      Serial.print("  OVERRUN: "); Serial.print(msg.flags.overrun);
      Serial.print("  LEN: "); Serial.print(msg.len);
      Serial.print(" EXT: "); Serial.print(msg.flags.extended);
      Serial.print(" TS: "); Serial.print(msg.timestamp);
      Serial.print(" ID: "); Serial.print(msg.id, HEX);
      Serial.print(" Buffer: ");
      for ( uint8_t i = 0; i < msg.len; i++ ) {
        Serial.print(msg.buf[i], HEX); Serial.print(" ");
      } Serial.println();
    }
    
    void sendframe()
    {
    
      CANFD_message_t msg;
      
      msg.id = 0x7df;
    
      msg.buf[0] = a++;     // Pot 1 value
      msg.buf[1] = 0;
      msg.buf[2] = 0;
      msg.buf[3] = 0;
      msg.buf[4] = 0;  // SW1 value
      msg.buf[5] = 0;
      msg.buf[6] = 0;
      msg.buf[7] = 0;
    
      msg.len = 8;
      msg.seq = 1;
      can3.write(MB15, msg);
     
    }
    void loop() {
    
      can3.events();
      
    
    }

    Also could you explain why the SILENT Pin is necessary and what it does?

  2. #1002
    Senior Member
    Join Date
    Jan 2015
    Location
    UK
    Posts
    195
    Best to get Classic CAN going first to prove the cabling is correct, then move to CAN FD.

    The SILENT pin is to control the CAN transceiver. That is to disable the silent mode.

  3. #1003
    Junior Member
    Join Date
    Apr 2022
    Posts
    6
    CAN Communication works! Thank you!

    Now want do I have to do to get CAN-FD working in a similar way?

    -Alex

  4. #1004
    Senior Member
    Join Date
    Jan 2015
    Location
    UK
    Posts
    195
    There are some CAN FD examples in the library.

    You can also try this:

    Code:
    #include <FlexCAN_T4.h>
    
    FlexCAN_T4FD<CAN3, RX_SIZE_256, TX_SIZE_16> FD;
    IntervalTimer timer;
    int SILENT = 9;
    
    uint8_t a=0;
    void setup(void) {
    
      pinMode(SILENT,OUTPUT); 
    
      digitalWrite(SILENT,LOW);
      
      FD.begin();
      CANFD_timings_t config;
      config.clock = CLK_24MHz;
      config.baudrate =   500000;     // 500kbps Nominal data rate
      config.baudrateFD = 2000000;    // 2000kpbs Data rate
      config.propdelay = 190;
      config.bus_length = 1;
      config.sample = 75;
      FD.setRegions(64);
      FD.setBaudRate(config);
    
    
      FD.setMBFilter(ACCEPT_ALL);
      FD.setMBFilter(MB13, 0x1);
      FD.setMBFilter(MB12, 0x1, 0x3);
      FD.setMBFilterRange(MB8, 0x1, 0x04);
      FD.enableMBInterrupt(MB8);
      FD.enableMBInterrupt(MB12);
      FD.enableMBInterrupt(MB13);
      FD.enhanceFilter(MB8);
      FD.enhanceFilter(MB10);
      FD.distribute();
      FD.mailboxStatus();
    
      timer.begin(sendframe, 100000); // Send frame every 500ms
    }
    
    
    void canSniff(const CAN_message_t &msg) {
      Serial.print("MB "); Serial.print(msg.mb);
      Serial.print("  OVERRUN: "); Serial.print(msg.flags.overrun);
      Serial.print("  LEN: "); Serial.print(msg.len);
      Serial.print(" EXT: "); Serial.print(msg.flags.extended);
      Serial.print(" TS: "); Serial.print(msg.timestamp);
      Serial.print(" ID: "); Serial.print(msg.id, HEX);
      Serial.print(" Buffer: ");
      for ( uint8_t i = 0; i < msg.len; i++ ) {
        Serial.print(msg.buf[i], HEX); Serial.print(" ");
      } Serial.println();
    }
    
    void sendframe()
    {
    
      CANFD_message_t msg;
      msg.len = 64;           // Set frame length to 64 bytes
      msg.id = 0x321;
      msg.seq = 1;
      msg.buf[0] = a++;       // Pot 1 value
      msg.buf[1] = 0;
      msg.buf[2] = 0;
      msg.buf[3] = 04;
      msg.buf[4] = 0;  // SW1 value
      msg.buf[5] = 0;
      msg.buf[6] = 0;
      msg.buf[7] = 0;
      FD.write( msg);
     
    }
    void loop() {
      CANFD_message_t msg;
      FD.events();
      if (FD.readMB(msg))
      {
          Serial.print("MB: "); Serial.print(msg.mb);
          Serial.print("  OVERRUN: "); Serial.print(msg.flags.overrun);
          Serial.print("  ID: 0x"); Serial.print(msg.id, HEX );
          Serial.print("  EXT: "); Serial.print(msg.flags.extended );
          Serial.print("  LEN: "); Serial.print(msg.len);
          Serial.print("  BRS: "); Serial.print(msg.brs);
          Serial.print(" DATA: ");
          for ( uint8_t i = 0; i <msg.len ; i++ ) {
            Serial.print(msg.buf[i]); Serial.print(" ");
          }
          Serial.print("  TS: "); Serial.println(msg.timestamp);
        
      }
    
    }

  5. #1005
    Junior Member
    Join Date
    Apr 2022
    Posts
    6
    Thank you for your answer! I actually managed to get the two teensy boards to communicate via CAN-FD!

    Now I wanted to monitor the communication via CANalyzer but sadly I get this error:
    Click image for larger version. 

Name:	Unbenannt.png 
Views:	25 
Size:	13.0 KB 
ID:	28053

    The code I am using right now ist just the example of your previous answer.

    Thank you very much for your helpful support!

  6. #1006
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    4,032
    have you tried other baudrates? tried changing the clock to 60?

    collink had same if not similar issue with 500000/2000000 specifically, while 1000000/2000000 was fine

  7. #1007
    Junior Member
    Join Date
    Apr 2022
    Posts
    6
    Actually I was sending with baudrate 1000000/2000000 as this error occured. Ealier I had the ECU connected with the Vector Box + CANalyzer and my Teensy Board only as listener on the bus. There everything with baudrate 1000000/2000000 was fine.

    But what occured to me just now is, that I had a config loaded whilest this experiment, and the config may altered the baudrate and the clock to the functioning 1000000/2000000 and 60! And later when I wanted to start sending with the teensy and for debugging just connected the teensy to the CANalyzer but without a config and the default values of CANalyzer may vary! So I will look into this next week!

    Much Thanks for your help and patience with me!

    But still I'm a bit confused, because I was also trying to get the teensy board sending directly to the ECU, which should have the correct baudrate/clock because I was able to read the messages earlier (Or did I just read the ones from the CANalyzer script? Gotta check), but the ECU didnt answer. And it should answer once it gets some messages, so this could be that the messages I was sending were not the one the ECU expected or some other problem...

    I will continue to try and keep you updated / will come back for help! Thank you very much!

  8. #1008
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    4,032
    there are also multiple timing parameters for FD in the Advanced setbaudrate config menu, it displays all the timings for the same bitrate so you can pick one from the list, by default it uses the first match. The debug output list is printed to serial monitor. Each rate can have multiple selections at different clock speeds,

  9. #1009
    Junior Member
    Join Date
    May 2022
    Posts
    2
    Hello,

    Does someone know about documentation on changes made to ARM Flexcan module between Teensy3 and Teensy4? If I understand correctly they went from ARM Cortex-M4 to M7.

    The goal is to write CanOpenNode drivers for Teensy4 based on this code for Teensy3. Unfortunately, I don't have prior experience with ARM-chips. So I was hoping to find more sources of information on thoose changes, other than the highly technical manual for i.MX RT1060 processor.

    On 07-29-2020, there were a few references on CanOpen on Teensy3 in this thread but they didn't help much.

    Many thanks!


    I wasn't sure if I should start a thread in "Project guidance". I guess, one should do so if there is a broader interest on the "CanOpen on Teensy4" topic.

  10. #1010
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    4,032
    the registers should be fine to port the older library to t4, however if you look at flexcan_t4's begin() you'll see the initialization routines needed, and you'll need to remap the address of can0 and can1 to that of teensy4 (can1 and can2), the other registers are just offsets of that. it can get a bit complex, but flexcan_t4 was made to work with all t3.x and 4.x processors. You'll probably have a better chance porting that library to flexcan_t4.

    EDIT, thats not a library that is a driver itself, take what you can from flexcan_t4 because you'll need to fix up that code or find another library that is based off the previous flexcan.h libraries...

  11. #1011
    Junior Member
    Join Date
    May 2022
    Posts
    2
    Thanks for the help. I think the remapping of addresses worked. I'm able to e.g. set FRZ bit and read back the ACK bit, which is then set.

    I'm not quite sure what you mean by "porting that library to flexcan_t4".

    If I understand correctly, you recommend to take as much as possible from your T4 library, right?

    At the moment, the Teensy is trying to send CAN messages, until some buffer in CANopenNode is full. Next goal is now, to figure out, why those messages aren't send. At least, they don't show up on the wire.

  12. #1012
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    4,032
    most libraries depended on the original flexcan.h, however the one you are using is custom and accesses the hardware directly without depending on flexcan.h. Once you remap the addresses and figure out the initialization routine in flexcan_t4 source begin() functor, it *should* just work, also take note of the setRX and setTX functors, those pin configurations matter as well.

    You can get the CAN addresses in the H files

  13. #1013
    Junior Member
    Join Date
    Dec 2020
    Posts
    10
    Hello,

    Could someone please clarify how the interrupts for this library work?

    I am trying to recognize a button press in my vehicle, and create an interrupt that increments a counter every time a particular can message is received.

    Code:
    // New can object using can bus 0 on teensy.
    FlexCAN_T4<CAN0, RX_SIZE_256, TX_SIZE_16> can1;
    
    CAN_message_t canMsg;
    CAN_message_t msgInt;
    
    void initCanT4(void){
    
      can1.begin();
      can1.setBaudRate(100E3);
      can1.setMaxMB(1);
    
      can1.setMB(MB0, RX, STD);
    
      //REJECT ANY CAN MESSAGE THAT IS NOT IN THE LIST
      can1.setMBFilter(REJECT_ALL);
    
      // MAILBOX 0 Acts as a hardware interrupt (For button presses ONLY)
      can1.enableMBInterrupt(MB0, true);
    
      //Every time there is a new message, sniff the packet
      can1.onReceive(MB0,canInterruptSniff);
    
      
      can1.setMBFilter(MB0, 0x1D6); // Hardware interrupt, steering wheel button
    
    }

    Code:
    void canInterruptSniff(const CAN_message_t &msgInt) {
    
        Serial.print("INTERRUPTED CAN1 "); 
        Serial.print("MB: "); Serial.print(msgInt.mb);
        Serial.print("  ID: 0x"); Serial.print(msgInt.id, HEX );
        Serial.print("  EXT: "); Serial.print(msgInt.flags.extended );
        Serial.print("  LEN: "); Serial.print(msgInt.len);
        Serial.print(" DATA: ");
        for ( uint8_t i = 0; i < 8; i++ ) {
          Serial.print(msgInt.buf[i]); Serial.print(" ");
        }
        Serial.print("  TS: "); Serial.println(msgInt.timestamp);
    
      Serial.println("END READ INTERRUPT CAN MSG");
      
      if (lastClickTime - millis() > 800) { //Essentially, this is to eliminate "bouncing of the button press"
        parseCanInterruptedMessage(msgInt.id, msgInt.buf, msgInt.len);
      }
    
    }
    Code:
    unsigned volatile long lastClickTime = 0;
    volatile int clickCount = 0;
    static uint32_t STEERING_WHEEL_ID = 470; //1D6 HEX
    
    void parseCanInterruptedMessage(uint32_t id, const uint8_t message[], uint8_t messageLength){
    
        if (id == STEERING_WHEEL_ID){
        Serial.println("STEERING WHEEL BUTTON!!!!!");   
            if (message[0] == 192 && message[1] == 13 && lastClickTime - millis() > 800){ // IF the particular voice button is pressed...
                lastClickTime = millis();  // Reset button press timer
                Serial.println("STEERING WHEEL BUTTON!!!!!****************PRESSED!");   
                clickCount += 1;
            }
        }
    }

    So I want to run the above two functions whenever a can bus message with ID 470 is received, no matter what the microcontroller is doing. In this case, the interrupt would increment a counter, and the teensy would be running a while loop checking for the number of clicks. The interrupt should increment the number of clicks. My current code does not trigger an interrupt to increment the counter though.

    Code:
    void checkNumClicks(void){
    static unsigned long max_delay = 3000;
    
          Serial.println("");
          Serial.print("internal Fn click Counter: ");
          Serial.println(clickCount);
    
          while((millis() - lastClickTime < max_delay) && clickCount == 1){
              if (clickCount >= 2){
                //returnVal = 2;
                clickCount = 0;
                Serial.println("DOUBLECLICK************************");
                lastClickTime = millis();
                break;
                }
          }
          if ((clickCount == 1) && (millis() - lastClickTime >= max_delay)){
              clickCount = 0;
              Serial.println("***********************SINGLECLICK");
              advanceScreen();
              lastClickTime = millis();
    
              //returnVal = 1;
              //lastClickTime = millis();
          }
    }
    I am hoping there is a very simple solution I am overlooking. The code works perfectly with a traditional "pin rising" interrupt and a standard button.

  14. #1014
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    4,032
    I can't see all your code but just remove events() from the loop() if you have it so the callback will fire directly rather from the events() queue system, this will disable the RX queue system and fire directly to the callback

    polling: read() // (without enableMBInterrupts())

    interrupt queue // (with events(), stores all messages to the queue, where events() will process one queue at a time to the callback. depending on where you put events() in your code, the latency depends on your code processing obviously

    interrupts direct firing to callback, (without events(), disables the RX queue and processes the callback immediately when a message arrives


    Also, do not forget some modules repeat frames, maybe every 100ms, it's different per vehicle. If you have repetitive frames, have a static local variable keep track if the bit/byte changes and only proceed to process it if it changed from last value. That's how i keep track of held down keyfob buttons and touched buttons.

    Code:
    static uint8_t last_value = msg.buf[4];
    if ( msg.buf[4] != last_value ) {
      // DoSomething()
      last_value = msg.buf[4]
    }
    if, of course, multiple bits are changing and you're only interested in one bit, mask it:
    if ( (msg.buf[4] & 0x4) != last_value ) { ........
    Last edited by tonton81; 05-12-2022 at 10:48 AM.

  15. #1015
    Junior Member
    Join Date
    Dec 2020
    Posts
    10
    Quote Originally Posted by tonton81 View Post
    I can't see all your code but just remove events() from the loop() if you have it so the callback will fire directly rather from the events() queue system, this will disable the RX queue system and fire directly to the callback

    polling: read() // (without enableMBInterrupts())

    interrupt queue // (with events(), stores all messages to the queue, where events() will process one queue at a time to the callback. depending on where you put events() in your code, the latency depends on your code processing obviously

    interrupts direct firing to callback, (without events(), disables the RX queue and processes the callback immediately when a message arrives


    Also, do not forget some modules repeat frames, maybe every 100ms, it's different per vehicle. If you have repetitive frames, have a static local variable keep track if the bit/byte changes and only proceed to process it if it changed from last value. That's how i keep track of held down keyfob buttons and touched buttons.

    Code:
    static uint8_t last_value = msg.buf[4];
    if ( msg.buf[4] != last_value ) {
      // DoSomething()
      last_value = msg.buf[4]
    }
    if, of course, multiple bits are changing and you're only interested in one bit, mask it:
    if ( (msg.buf[4] & 0x4) != last_value ) { ........
    Yup. Removing events() from the main loop fixed everything. Haha, took longer to undo all of my debugging code. Thanks for your help!

    Also, all of your suggestions are great. Looking forward to making my project cleaner/more efficient.

Posting Permissions

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