Forum Rule: Always post complete source code & details to reproduce any issue!
Page 20 of 46 FirstFirst ... 10 18 19 20 21 22 30 ... LastLast
Results 476 to 500 of 1130

Thread: FlexCAN_T4 - FlexCAN for Teensy 4

  1. #476
    Junior Member
    Join Date
    Jan 2021
    Location
    Japan
    Posts
    18
    Thank you tonton81,
    I am so stupid, I could not see the whole codes but stuck around CAN setting.
    must correct basic logic coding part first before asking question.....

  2. #477
    Hello tonton81,

    We have been using Teensy 3.X boards for a while now with Collin80's FlexCan_Library. In his library there is a CANListener class that has a frameHandler function that can be declared in a user defined class so that the user's own library can have access to the received frames.

    We have just started using a Teensy 4.0 on our setup and we had the need to switch to your library which from what I read here it is really well maintained!

    In order to implement a similar behaviour to what we had before I think that we should use one of the ext_output functions. I have checked your TeensyCan library also but I can't seem to understand how should I implement this in my own class.

    Below is the way we used to do it with Collin80's library:
    Code:
    class TSB_CAN : public CANListener 
    {    
    public:
        TSB_CAN();
        void receive_Message(CAN_message_t &frame);
        bool frameHandler(CAN_message_t &frame, int mailbox, uint8_t controller); //overrides the parent version so we can actually do something
    };
    
    bool TSB_CAN::frameHandler(CAN_message_t &frame, int mailbox, uint8_t controller)
    {
    		//printFrame(frame, mailbox);
    		receive_Message(frame);
    		return true;
    }
    
    void TSB_CAN::receive_Message(CAN_message_t &frame)
    {
        switch(frame.id) {
    	case 0x609:
        	    //save message payload
    	break; 
        }
    }
    Then on the main sketch we did something like this:
    Code:
    TSB_CAN canMessageHandler;
    void setup(void){
      Can0.begin(1000000); // Inicialise CAN BUS with 1 Mb/s speed
      Can0.attachObj(&canMessageHandler);
      canMessageHandler.attachGeneralHandler();
    }
    
    void loop(void)
    {
      // If you want to print something that is avalible on the CAN Bus check the CAN_TSB.h to see the structer used.
      // As an example lets print the battery current
      Serial.println(canMessageHandler.device.variable); 
    }

  3. #478
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    4,077
    just add this to your library after including flexcan header:
    Code:
    void ext_output1(const CAN_message_t &msg) {
      //do whatever with message
    }
    and enable MB/FIFO interrupts in setup, the function will receive all frames, unless you use filters, then the mailbox/fifo will only stream your filtered IDs

    If it's for a library, thats the way to go. If you are doing it from the sketch like above, either works. you can use onRecieve to set your sketch callback, but the background handler is always unused until you define it like i mentioned, either in sketch or library

    don't forget, to differentiate which bus the frame came from, use msg.bus and it will return 1,2 or 3, depending on what you setup (CAN1, CAN2, CAN3)

  4. #479
    What if I want that function to be part of my own C++ class so that I can do an Object Oriented Callback Interface? Is there any possibility to do so with this library?
    Last edited by tecnico.solarboat; 01-23-2021 at 02:49 PM.

  5. #480
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    4,077
    sorry i dont understand how that works, but maybe i can look at how Collin did it and see if i can port it over

  6. #481
    If you can have a look that would be nice, check this example.

  7. #482
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    4,077
    Can you try this patch? Originally it only supported 31 mailboxes max, as Teensy 3.x had 16 mailboxes, bit 31 was used for the global handler. Now it should support up to 64 mailboxes with a general handler.
    Also if the mailbox handler was specified the generalhandler wouldn't fire, in case you did specify both ways, both will activate now.

    Serial monitor:
    Code:
    ID: FADE Data: 80 40 0 3 7 1 1  <------------------- CANListener
    
    MB 99 OVERRUN: 0 LEN: 7 EXT: 1 TS: 58671 ID: FADE Buffer: 80 40 0 3 7 1 1  <------- FlexCAN_T4 callback
    
    ID: FADE Data: 81 0 1 0 9 1 1 
    
    MB 99 OVERRUN: 0 LEN: 7 EXT: 1 TS: 5044 ID: FADE Buffer: 81 0 1 0 9 1 1 
    
    ID: FADE Data: 80 80 7 4 0 1 1 
    
    MB 99 OVERRUN: 0 LEN: 7 EXT: 1 TS: 53021 ID: FADE Buffer: 80 80 7 4 0 1 1 
    
    ID: FADE Data: 80 40 0 A 0 1 1 
    
    MB 99 OVERRUN: 0 LEN: 7 EXT: 1 TS: 7888 ID: FADE Buffer: 80 40 0 A 0 1 1 
    
    ID: FADE Data: 80 80 0 A 0 1 1 
    
    MB 99 OVERRUN: 0 LEN: 7 EXT: 1 TS: 36067 ID: FADE Buffer: 80 80 0 A 0 1 1 
    
    ID: FADE Data: 80 80 2 0 8 1 1 
    
    MB 99 OVERRUN: 0 LEN: 7 EXT: 1 TS: 2446 ID: FADE Buffer: 80 80 2 0 8 1 1 
    
    ID: FADE Data: 80 40 9 0 1 1 1 
    
    MB 99 OVERRUN: 0 LEN: 7 EXT: 1 TS: 23012 ID: FADE Buffer: 80 40 9 0 1 1 1 
    
    ID: FADE Data: 81 0 8 2 0 1 1 
    
    MB 99 OVERRUN: 0 LEN: 7 EXT: 1 TS: 35028 ID: FADE Buffer: 81 0 8 2 0 1 1

  8. #483
    First of all thank you very much for you willingness to help! I can confirm that this works in a Teensy 3.5 with a Kvaser generating random CAN data. I have another Teensy 3.2 board with me but the transceiver on it is not working... When I'm able to test it with other boards I can let you know, but I'm pretty sure that if it works on 3.5 and 4.X (I suppose you test on that) it will work on the rest of them as well.

    Can you explain what is the diference between using FIFO and Mailboxes? I think that with FIFO we can assume that the messages are in order. On the other hand with MB this is not guaranteed. Is this line of though right? I have tested this patched version with both and it worked with both also.

    Will this patched version be added to the TeensyDuino?

    On another note I noticed that the library allows to define CAN1 on Teensy 3.2 and 3.5, I think that the following code (FlexCAN_T4 line 53) should be made in 2 ifs one for 3.2 and 3.5 and another for the 3.6:
    Code:
    #if defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
      if ( _bus == CAN1 ) _CAN1 = this;
      if ( _bus == CAN0 ) _CAN0 = this;
    #endif
    Once again THAK YOU VERY MUCH!!

  9. #484
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    4,077
    for the define, thats just a pointer, _CAN1 wont compile on T3.2 anyways

    FIFO allows ordered receptions, mailboxes can receive in any order as long as a slot is empty. you can have FIFO and mailboxes combined for example, assign a mailbox to receive a filtered ID in it's own callback, so a separate callback will fire when your critical frame is received. with fifo alone you have only 1 callback essentially. In either case Teensy is fast enough to receive all critical frames without filters unless you are in non interrupt mode or your loop code is causing delays..

  10. #485
    At least for me, with Paltformio if I declare
    Code:
    FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> Can0;
    it compiles for Teensy 3.2 and 3.5 but it obviously does not do anything.


    Thank you very much for the explanation!

  11. #486
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    4,077
    Indeed, it compiled in the arduino IDE as well I see, I just don't wanna add much code bloat. Going ahead after compilation should result in undefined behaviour though should the wrong one be used. I suppose a cleaner solution is to ifdef and give a warning if _bus is not identified in hardware rather than sprinkle more ifdef else's all over the place

  12. #487
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    4,077
    You can try this?


    added checks:
    Code:
    #if defined(__MK20DX256__) || defined(__MK64FX512__)
      static_assert(_bus == CAN0, "Only CAN0 works on Teensy 3.2/3.5");
    #endif
    #if defined(__MK66FX1M0__)
      static_assert(_bus == CAN0 || _bus == CAN1, "Only CAN0 & CAN1 works on Teensy 3.6");
    #endif
    #if defined(__IMXRT1062__)
      static_assert(_bus == CAN1 || _bus == CAN2 || _bus == CAN3, "Only CAN1 & CAN2 & CAN3 works on Teensy 4.0/4.1");
    #endif

  13. #488
    It works as expected! Both on Teensy 3.2 and 3.5.

    Compiler throws:
    Only CAN0 works on Teensy 3.2/3.5
    static_assert(_bus == CAN0, "Only CAN0 works on Teensy 3.2/3.5");
    ^

    *** [.pio/build/teensy35/src/main.cpp.o] Error 1

    By the way, trying to declare CAN2 on T3.6 although it gives an error it is not the same fancy error as in the other case. But for me it is fine, as long as we get an error it's fine. It just says that "CAN2 was not declared in this scope".

  14. #489
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    4,077
    Yeah, that would require defining CAN2, CAN3, asserts should work as is:

    Code:
    typedef enum CAN_DEV_TABLE {
    #if defined(__IMXRT1062__)
      CAN0 = (uint32_t)0x0,   <------------- This was added to support the static_assert instead of a compiler crash saying it wasn't in scope for T4.x
      CAN1 = (uint32_t)0x401D0000,
      CAN2 = (uint32_t)0x401D4000,
      CAN3 = (uint32_t)0x401D8000
    #endif
    #if defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
      CAN0 = (uint32_t)0x40024000,
      CAN1 = (uint32_t)0x400A4000,  <-------- CAN2 could be added after here like above, like so 
      CAN2 = (uint32_t)0x0,
      CAN3 = (uint32_t)0x0,
    #endif
    } CAN_DEV_TABLE;
    Just added em, try to break CANListener and if you can't I will update it on github :P
    Last edited by tonton81; 01-23-2021 at 09:41 PM.

  15. #490
    Junior Member
    Join Date
    Jan 2021
    Location
    Japan
    Posts
    18
    Thank you, tonton81,
    Since I could not do a good job with FIFO, I went back to mail box stuff anyway.
    So far I can send and receive OBD CAN message with extended 29 bit CAN communication.
    Nevertheless, my goal is not getting PID parameters such as engine speed, engine coolant temperature, but longer messages which requires multi-frame (ISO-15765-2).
    In order to handle multi-frame stuff, Teensy has to receive a multiple consecutive frames after sending flow control from Teensy.
    Therefore I probably have to go back to FIFO again. I will read through FlexCAN_T4 library and try to understand how to use.

    Anyway following code works with my vehicle.

    Code:
    // 29bit extended OBD CAN Sketch
    //  get Service$01 PID$0C Engine Speed
    //
    
    #include <FlexCAN_T4.h>
    #include <SPI.h>
    #include <Wire.h>
    #include <Adafruit_GFX.h>
    #include <Adafruit_SSD1306.h>
    #include <ADC.h>
    
    #define SCREEN_WIDTH 128 // OLED display width, in pixels
    #define SCREEN_HEIGHT 64 // OLED display height, in pixels
    
    // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
    #define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
    Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
    
    #define NUMFLAKES     10 // Number of snowflakes in the animation example
    
    FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_16> can2;
    
    #define LOGO_HEIGHT   16
    #define LOGO_WIDTH    16
    
    static const unsigned char PROGMEM logo_bmp[] =
    { B00000000, B11000000,
      B00000001, B11000000,
      B00000001, B11000000,
      B00000011, B11100000,
      B11110011, B11100000,
      B11111110, B11111000,
      B01111110, B11111111,
      B00110011, B10011111,
      B00011111, B11111100,
      B00001101, B01110000,
      B00011011, B10100000,
      B00111111, B11100000,
      B00111111, B11110000,
      B01111100, B11110000,
      B01110000, B01110000,
      B00000000, B00110000 };
    
    
    int engineCoolantTemp = 0; // Save the data here
    int engineRPM = 0;// Save the data here
    
    
    void setup(){
      while (!Serial && millis() < 5000);
      // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
      if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
    
        delay(200);
        
        Serial.println(F("SSD1306 allocation failed"));
        
        for(;;); // Don't proceed, loop forever
      }
      
      Serial.begin(115200);
      can2.begin();
      can2.setBaudRate(500000);
      //can2.setFIFOFilter(REJECT_ALL);
      //can2.setFIFOFilter(0, 0x18DAF111, EXT); // Extended CANID  Target address F1(Tester), Sender 11(ENG ECU)
      can2.setMB(MB10,TX,EXT); // Set mailbox as transmit
      can2.setMB(MB4,RX,EXT); // Set mailbox as receiving extended frames.
      can2.setMaxMB(16);
      can2.mailboxStatus(); // view current configuration
      
      //can2.enableFIFO();
      //can2.enableFIFOInterrupt();
      can2.enableMBInterrupt(MB4);
      can2.onReceive(canSniff);
    
    }
    
    const long loopDelay1 = 50; // Make a request every 500ms
    unsigned long timeNow1 = 0;
    
    void loop(){
    
    can2.events();
     
      if (millis() > timeNow1 + loopDelay1)
        {
          timeNow1 = millis();
          canTx_OBD(); // Query data from CAN BUS via OBD
          //canTx_UDS(); // Query data from CAN BUS via UDS
    
        }
    }
    
    
    void canSniff (const CAN_message_t &msg){ // Global callback to catch any CAN frame coming in
    
       
          if (msg.buf[1] == 0x41){
            if (msg.buf[2] ==0x0C){
    
               // SID$01 PID$0C Engine Speed
               //engineCoolantTemp = msg.buf[3] - 40;           // Offset -40(degC)
               engineRPM = (msg.buf[3]*0x100 + msg.buf[4]) /4;
               Serial.println(" ");
               //Serial.printf("OBD: Engine Coolant Temp: %d c", engineCoolantTemp);
               Serial.printf("OBD: Engine Speed: %d rpm", engineRPM);
    
            }
          }
        
        
            display.setTextColor(WHITE);
            display.clearDisplay();
    
            display.setTextSize(1);      // Normal 1:1 pixel scale
            display.setTextColor(SSD1306_WHITE); // Draw white text
            display.setCursor(0, 0);     // Start at top-left corner
            display.println(F("CAN_ID:"));
            display.setCursor(60,0);
            display.setTextColor(WHITE);
            display.print(msg.id, HEX);
    
        
            for ( uint8_t i = 0; i < 8; i++ ) {
               display.setCursor(15*i ,15);
               display.print(msg.buf[i],HEX);  Serial.print(" ");
            }
    
            display.setTextSize(2);      // Normal 1:1 pixel scale
            display.setCursor(10, 35);
           //display.print(engineCoolantTemp,DEC);
            display.print(engineRPM, DEC);
            display.setCursor(70, 35);
           //display.print("degC");
            display.print("RPM");
            display.display(); 
    
    }
    
    
    void canTx_OBD(){ // Request function to ask for Engine Coolant Temp via OBD request
      CAN_message_t msgTx, msgRx;
        msgTx.buf[0] = 0x02;     // Data Length 2byte
        msgTx.buf[1] = 0x01;     // Service$01
        msgTx.buf[2] = 0x0C;     // PID $05 Engine Coolant Temperature
        msgTx.buf[3] = 0x55;        // Padding
        msgTx.buf[4] = 0x55;
        msgTx.buf[5] = 0x55; 
        msgTx.buf[6] = 0x55;
        msgTx.buf[7] = 0x55;
        msgTx.len = 8;            // number of bytes in request
        //msgTx.flags.extended = 0; // 11 bit header, not 29 bit 
        msgTx.flags.extended = 1; // 29 bit header, not 11 bit 
        msgTx.flags.remote = 0;
        
        //msgTx.id = 0x7E0; // request header for OBD           // Physical Addressing Request to Engine ECU
        msgTx.id = 0x18DB33F1; // request header for OBD Functional Addressing request to all emission related ECUs.
        can2.write(msgTx);
        Serial.println("canTx_OBD REQ sent"); 
      }
    
     void canTx_UDS(){ // Request function to ask for Engine Coolant Temp via UDS request
      CAN_message_t msgTx, msgRx;
        msgTx.buf[0] = 0x03;      // Data Length
        msgTx.buf[1] = 0x22;      // SID$22 Request parameter by Data Identifier
        msgTx.buf[2] = 0xf4;      // 
        msgTx.buf[3] = 0x05;      // PID$05 is Engine Coolant Temperature
        msgTx.buf[4] = 0;
        msgTx.buf[5] = 0; 
        msgTx.buf[6] = 0; 
        msgTx.buf[7] = 0;
        msgTx.len = 8;            // number of bytes in request
        //msgTx.flags.extended = 0; // 11 bit header, not 29 bit
        msgTx.flags.extended = 1; // 29 bit header, not 11 bit
        
        msgTx.flags.remote = 0;
        //msgTx.id = 0x7E0; // request header for OBD
        msgTx.id = 0x18DB33F1; // request header for OBD Functional Addressing request to all emission related ECUs.
        can2.write(msgTx); 
        Serial.println("canTx_UDS REQ sent"); 
      }
    
    
    
    void testdrawchar(void) {
      display.clearDisplay();
    
      display.setTextSize(1);      // Normal 1:1 pixel scale
      display.setTextColor(SSD1306_WHITE); // Draw white text
      display.setCursor(0, 0);     // Start at top-left corner
      display.cp437(true);         // Use full 256 char 'Code Page 437' font
    
      // Not all the characters will fit on the display. This is normal.
      // Library will draw what it can and the rest will be clipped.
      for(int16_t i=0; i<256; i++) {
        if(i == '\n') display.write(' ');
        else          display.write(i);
      }
    
      display.display();
      delay(2000);
    }

  16. #491
    So it does look like the SDHC basic write speed I've tried with test sketches is better than OK, but only if I keep the file open. The easy method is the too slow method, where you open a file, write, and close it on every write burst.

    I would like to be able to get the SD file object to be global, so that I can write to it from various functions. I instantiated the object before the setup() function, and it surprisingly compiled, but it's not accessible by any function. If I instantiate the file in the setup function, which is kind of where it logically belongs, it's not accessible even in the loop(). Any hints on that?

  17. #492
    Quote Originally Posted by tonton81 View Post

    Just added em, try to break CANListener and if you can't I will update it on github :P
    I have missed this post yesterday. I'm happy to tell you that I has not able to break it! Everything looks to be working as expected. Nice work! Thank you very much!

  18. #493
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    4,077
    Quote Originally Posted by Zweisteinjp View Post
    Thank you, tonton81,
    Since I could not do a good job with FIFO, I went back to mail box stuff anyway.
    So far I can send and receive OBD CAN message with extended 29 bit CAN communication.
    Nevertheless, my goal is not getting PID parameters such as engine speed, engine coolant temperature, but longer messages which requires multi-frame (ISO-15765-2).
    In order to handle multi-frame stuff, Teensy has to receive a multiple consecutive frames after sending flow control from Teensy.
    Therefore I probably have to go back to FIFO again. I will read through FlexCAN_T4 library and try to understand how to use.

    Anyway following code works with my vehicle.

    Code:
    // 29bit extended OBD CAN Sketch
    //  get Service$01 PID$0C Engine Speed
    //
    
    #include <FlexCAN_T4.h>
    #include <SPI.h>
    #include <Wire.h>
    #include <Adafruit_GFX.h>
    #include <Adafruit_SSD1306.h>
    #include <ADC.h>
    
    #define SCREEN_WIDTH 128 // OLED display width, in pixels
    #define SCREEN_HEIGHT 64 // OLED display height, in pixels
    
    // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
    #define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
    Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
    
    #define NUMFLAKES     10 // Number of snowflakes in the animation example
    
    FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_16> can2;
    
    #define LOGO_HEIGHT   16
    #define LOGO_WIDTH    16
    
    static const unsigned char PROGMEM logo_bmp[] =
    { B00000000, B11000000,
      B00000001, B11000000,
      B00000001, B11000000,
      B00000011, B11100000,
      B11110011, B11100000,
      B11111110, B11111000,
      B01111110, B11111111,
      B00110011, B10011111,
      B00011111, B11111100,
      B00001101, B01110000,
      B00011011, B10100000,
      B00111111, B11100000,
      B00111111, B11110000,
      B01111100, B11110000,
      B01110000, B01110000,
      B00000000, B00110000 };
    
    
    int engineCoolantTemp = 0; // Save the data here
    int engineRPM = 0;// Save the data here
    
    
    void setup(){
      while (!Serial && millis() < 5000);
      // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
      if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
    
        delay(200);
        
        Serial.println(F("SSD1306 allocation failed"));
        
        for(;;); // Don't proceed, loop forever
      }
      
      Serial.begin(115200);
      can2.begin();
      can2.setBaudRate(500000);
      //can2.setFIFOFilter(REJECT_ALL);
      //can2.setFIFOFilter(0, 0x18DAF111, EXT); // Extended CANID  Target address F1(Tester), Sender 11(ENG ECU)
      can2.setMB(MB10,TX,EXT); // Set mailbox as transmit
      can2.setMB(MB4,RX,EXT); // Set mailbox as receiving extended frames.
      can2.setMaxMB(16);
      can2.mailboxStatus(); // view current configuration
      
      //can2.enableFIFO();
      //can2.enableFIFOInterrupt();
      can2.enableMBInterrupt(MB4);
      can2.onReceive(canSniff);
    
    }
    
    const long loopDelay1 = 50; // Make a request every 500ms
    unsigned long timeNow1 = 0;
    
    void loop(){
    
    can2.events();
     
      if (millis() > timeNow1 + loopDelay1)
        {
          timeNow1 = millis();
          canTx_OBD(); // Query data from CAN BUS via OBD
          //canTx_UDS(); // Query data from CAN BUS via UDS
    
        }
    }
    
    
    void canSniff (const CAN_message_t &msg){ // Global callback to catch any CAN frame coming in
    
       
          if (msg.buf[1] == 0x41){
            if (msg.buf[2] ==0x0C){
    
               // SID$01 PID$0C Engine Speed
               //engineCoolantTemp = msg.buf[3] - 40;           // Offset -40(degC)
               engineRPM = (msg.buf[3]*0x100 + msg.buf[4]) /4;
               Serial.println(" ");
               //Serial.printf("OBD: Engine Coolant Temp: %d c", engineCoolantTemp);
               Serial.printf("OBD: Engine Speed: %d rpm", engineRPM);
    
            }
          }
        
        
            display.setTextColor(WHITE);
            display.clearDisplay();
    
            display.setTextSize(1);      // Normal 1:1 pixel scale
            display.setTextColor(SSD1306_WHITE); // Draw white text
            display.setCursor(0, 0);     // Start at top-left corner
            display.println(F("CAN_ID:"));
            display.setCursor(60,0);
            display.setTextColor(WHITE);
            display.print(msg.id, HEX);
    
        
            for ( uint8_t i = 0; i < 8; i++ ) {
               display.setCursor(15*i ,15);
               display.print(msg.buf[i],HEX);  Serial.print(" ");
            }
    
            display.setTextSize(2);      // Normal 1:1 pixel scale
            display.setCursor(10, 35);
           //display.print(engineCoolantTemp,DEC);
            display.print(engineRPM, DEC);
            display.setCursor(70, 35);
           //display.print("degC");
            display.print("RPM");
            display.display(); 
    
    }
    
    
    void canTx_OBD(){ // Request function to ask for Engine Coolant Temp via OBD request
      CAN_message_t msgTx, msgRx;
        msgTx.buf[0] = 0x02;     // Data Length 2byte
        msgTx.buf[1] = 0x01;     // Service$01
        msgTx.buf[2] = 0x0C;     // PID $05 Engine Coolant Temperature
        msgTx.buf[3] = 0x55;        // Padding
        msgTx.buf[4] = 0x55;
        msgTx.buf[5] = 0x55; 
        msgTx.buf[6] = 0x55;
        msgTx.buf[7] = 0x55;
        msgTx.len = 8;            // number of bytes in request
        //msgTx.flags.extended = 0; // 11 bit header, not 29 bit 
        msgTx.flags.extended = 1; // 29 bit header, not 11 bit 
        msgTx.flags.remote = 0;
        
        //msgTx.id = 0x7E0; // request header for OBD           // Physical Addressing Request to Engine ECU
        msgTx.id = 0x18DB33F1; // request header for OBD Functional Addressing request to all emission related ECUs.
        can2.write(msgTx);
        Serial.println("canTx_OBD REQ sent"); 
      }
    
     void canTx_UDS(){ // Request function to ask for Engine Coolant Temp via UDS request
      CAN_message_t msgTx, msgRx;
        msgTx.buf[0] = 0x03;      // Data Length
        msgTx.buf[1] = 0x22;      // SID$22 Request parameter by Data Identifier
        msgTx.buf[2] = 0xf4;      // 
        msgTx.buf[3] = 0x05;      // PID$05 is Engine Coolant Temperature
        msgTx.buf[4] = 0;
        msgTx.buf[5] = 0; 
        msgTx.buf[6] = 0; 
        msgTx.buf[7] = 0;
        msgTx.len = 8;            // number of bytes in request
        //msgTx.flags.extended = 0; // 11 bit header, not 29 bit
        msgTx.flags.extended = 1; // 29 bit header, not 11 bit
        
        msgTx.flags.remote = 0;
        //msgTx.id = 0x7E0; // request header for OBD
        msgTx.id = 0x18DB33F1; // request header for OBD Functional Addressing request to all emission related ECUs.
        can2.write(msgTx); 
        Serial.println("canTx_UDS REQ sent"); 
      }
    
    
    
    void testdrawchar(void) {
      display.clearDisplay();
    
      display.setTextSize(1);      // Normal 1:1 pixel scale
      display.setTextColor(SSD1306_WHITE); // Draw white text
      display.setCursor(0, 0);     // Start at top-left corner
      display.cp437(true);         // Use full 256 char 'Code Page 437' font
    
      // Not all the characters will fit on the display. This is normal.
      // Library will draw what it can and the rest will be clipped.
      for(int16_t i=0; i<256; i++) {
        if(i == '\n') display.write(' ');
        else          display.write(i);
      }
    
      display.display();
      delay(2000);
    }
    for ordered frames you need FIFO, otherwise you'll have to build your own frame re-assembly code for multiframe (you can build both ways, but FIFO would make the rebuilding easier, also remove events() from the loop().


    for ordered frames you need FIFO, otherwise you'll have to build your own frame re-assembly code for multiframe (you can build both ways, but FIFO would make the rebuilding easier, also remove events() from the loop().

  19. #494
    Quote Originally Posted by Major7 View Post
    So it does look like the SDHC basic write speed I've tried with test sketches is better than OK, but only if I keep the file open. The easy method is the too slow method, where you open a file, write, and close it on every write burst.

    I would like to be able to get the SD file object to be global, so that I can write to it from various functions. I instantiated the object before the setup() function, and it surprisingly compiled, but it's not accessible by any function. If I instantiate the file in the setup function, which is kind of where it logically belongs, it's not accessible even in the loop(). Any hints on that?
    Sorry I figured it out. Declared only above setup() instantiated in setup(), wrote and closed in loop(). That seems to work for me.

  20. #495
    Hi tonton81 - Couple of questions from the FIFO Interrupts example - loop code below.

    1. How often does CAN.events() have to be called? I want to put some other code in loop() but it's not clear when things start to go south.
    2. What's the purpose of the timeout routine?
    3. Why isn't this thread a sticky?



    void loop() {
    Can0.events();

    static uint32_t timeout = millis();
    if ( millis() - timeout > 200 ) {
    CAN_message_t msg;
    msg.id = random(0x1,0x7FE);
    for ( uint8_t i = 0; i < 8; i++ ) msg.buf[i] = i + 1;
    Can0.write(msg);
    timeout = millis();
    }

  21. #496
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    4,077
    events() dequeues while the interrupt queues. so depending on your delays, if you let the queue build up to max you'll just be tossing frames after. you could also do a while(Can0.events()); and it'll dequeue everything in queue before continuing loop.

    timeout means after 200ms the transmit repeats

    if you dont want to rely on your loop() code if its got delays, remove the events() call and you will get the messages directly in callback without using the queue method

  22. #497
    Junior Member
    Join Date
    Jan 2021
    Posts
    4
    Hello,

    Apologies if this has already been answered but I'm struggling to send or receive when the baud rate is set to 95,000 bps. I've tried all of the clock speeds using setClock (8,16,20,24,...) but still without success. Other speeds such as 33,333 and 500,000 work just fine. I really can't see what I'm doing wrong. Any help would be greatly appreciated. Many thanks!

    Code:
    #include <FlexCAN_T4.h>
    
    FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_16> can2;  // can2 port
    FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> can1;  // can1 port 
    
    int led = 13;
    IntervalTimer timer;
    uint8_t d=0;
    
    
    void setup(void) {
      pinMode(led, OUTPUT);   
      digitalWrite(led,HIGH);
      Serial.begin(115200); delay(1000);
      Serial.println("Teensy 4.0 Triple CAN test");
      digitalWrite(led,LOW);
      
      can2.begin();
      can2.setClock(CLK_60MHz);
      can2.setBaudRate(95000);       // 95kbps data rate
      can2.enableFIFO();
      can2.enableFIFOInterrupt();
      can2.onReceive(FIFO, canSniff20);
      can2.mailboxStatus();
      
      can1.begin();
      can2.setClock(CLK_60MHz);
      can1.setBaudRate(95000);     // 95kbps data rate
      can1.enableFIFO();
      can1.enableFIFOInterrupt();
      can1.onReceive(FIFO, canSniff20);
      can1.mailboxStatus();
    
      timer.begin(sendframe, 500000); // Send frame every 500ms 
    }
    
    void sendframe()
    {
      
      CAN_message_t msg2;
      msg2.id = 0x401;
      
      for ( uint8_t i = 0; i < 8; i++ ) {
        msg2.buf[i] = i + 1;
      }
      
      msg2.buf[0] = d++;
      msg2.seq = 1;
      can2.write(MB15, msg2); // write to can2
    
      msg2.id = 0x402;
      msg2.buf[1] = d++;
      can1.write(msg2);       // write to can1
    
    }
    
    
    void canSniff20(const CAN_message_t &msg) { // global callback
      Serial.print("T4: ");
      Serial.print("MB "); Serial.print(msg.mb);
      Serial.print(" OVERRUN: "); Serial.print(msg.flags.overrun);
      Serial.print(" BUS "); Serial.print(msg.bus);
      Serial.print(" LEN: "); Serial.print(msg.len);
      Serial.print(" EXT: "); Serial.print(msg.flags.extended);
      Serial.print(" REMOTE: "); Serial.print(msg.flags.remote);
      Serial.print(" TS: "); Serial.print(msg.timestamp);
      Serial.print(" ID: "); Serial.print(msg.id, HEX);
      Serial.print(" IDHIT: "); Serial.print(msg.idhit);
      Serial.print(" Buffer: ");
      for ( uint8_t i = 0; i < msg.len; i++ ) {
        Serial.print(msg.buf[i], HEX); Serial.print(" ");
      } Serial.println();
    }
    
    
    
    void loop() {
      
      can2.events();
      can1.events();
      
    }

  23. #498
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    4,077
    Try this:

    Code:
      can1.setClock(CLK_60MHz);
      can1.setBaudRate(95238);
    I made an ESP32 version of this CAN library and the closest match it shows on the ESP32 is 95238. So when I put that on teensy @ 60MHz peripheral clock, they're both talking to each other
    Last edited by tonton81; 01-29-2021 at 03:20 PM.

  24. #499
    Junior Member
    Join Date
    Jan 2021
    Posts
    4
    Thank you so much tonton81! I would have never figured this out.

    Quote Originally Posted by tonton81 View Post
    Try this:

    Code:
      can1.setClock(CLK_60MHz);
      can1.setBaudRate(95238);
    I made an ESP32 version of this CAN library and the closest match it shows on the ESP32 is 95238. So when I put that on teensy @ 60MHz peripheral clock, they're both talking to each other

  25. #500
    Junior Member
    Join Date
    Jan 2021
    Location
    Japan
    Posts
    18
    Instead of using MailBox, I started using FIFO and it seems to be working.
    Therefore I started to handle with multi-frame messages. Since my vehicle does not support VIN (Vehicle Identification Number), Calibration ID is selected for the beginning.
    Calibration ID is Service$09 InfoType$04. Calibration ID consists of 16 ASCII characters and response message from ECU requires multi-frame because of the message length.
    With the Vehicle Spy software ISO-15765-2 option usage, Teensy can receive multi-frame message, but with the actual vehicle Teensy cannot. Teensy can only receive First Frame response message and Teensy sends Flow Control but cannot receive Consecutive message from the ECU. My FIFO handling for the consecutive message may be wrong.


    Code:
     /*********************************************************************************
     *   Teensy4.0 + MCP2562 CAN Transceiver + Adafruit OLED
     *   500kbps CAN communication speed
     *   2021 JAN 30
     *
     *   Service$09 InfoType$04 CALID Read
     *   
     *   
     ********************************************************************************/
    
    #include <FlexCAN_T4.h>
    #include <SPI.h>
    #include <Wire.h>
    #include <Adafruit_GFX.h>
    #include <Adafruit_SSD1306.h>
    #include <ADC.h>
    #include <ADC_util.h>
    #include <Bounce.h>  // Bounce library makes button change detection easy
    
    
    const int channel = 1;
    
    int Req_msgTxid;
    int val6, val7, val8, val9;
    int Stat_FC=0;  // Flow Control request status
    int disp_mode;
    int seq_Num=0;
    int CF_Num;
    int CF_Max;
    int sid09inftyp=0;
    int f_sid09calid_multi;
    String str_A;
    String dtc_buf6pre;
    String calid_buf1, calid_buf2, calid_buf3, calid_buf4, calid_buf5, calid_buf6, calid_buf7, calid_buf8;
    String calid_buf9, calid_buf10, calid_buf11, calid_buf12, calid_buf13, calid_buf14, calid_buf15, calid_buf16, calid_buf17;
    
    String cal_buf1, cal_buf2, cal_buf3, cal_buf4, cal_buf5, cal_buf6, cal_buf7, cal_buf8, cal_buf9, cal_buf10;
    String cal_buf11,cal_buf12, cal_buf13, cal_buf14, cal_buf15, cal_buf16;  // CALID is maximum 16 ASCC characters.
    
    #define SCREEN_WIDTH 128 // OLED display width, in pixels
    #define SCREEN_HEIGHT 64 // OLED display height, in pixels
    
    // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
    #define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
    Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
    
    #define NUMFLAKES     10 // Number of snowflakes in the animation example
    unsigned long curr, prev, next, interval;
    
    #define LOGO_HEIGHT   16
    #define LOGO_WIDTH    16
    
    FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> can1;
    FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_16> can2;
    CAN_message_t msg;
    
    static const unsigned char PROGMEM logo_bmp[] =
    { B00000000, B11000000,
      B00000001, B11000000,
      B00000001, B11000000,
      B00000011, B11100000,
      B11110011, B11100000,
      B11111110, B11111000,
      B01111110, B11111111,
      B00110011, B10011111,
      B00011111, B11111100,
      B00001101, B01110000,
      B00011011, B10100000,
      B00111111, B11100000,
      B00111111, B11110000,
      B01111100, B11110000,
      B01110000, B01110000,
      B00000000, B00110000 };
    
    void setup(void) {
      prev = 0;         // Initialize previous execution time
      interval = 1000;   // reset execution interval
      
      // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
      if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
        Serial.println(F("SSD1306 allocation failed"));
        for(;;); // Don't proceed, loop forever
      }
    
     while (!Serial && millis() < 5000);
      Serial.begin(115200);
      can2.begin();
      can2.setBaudRate(500000);
      //can2.setMBFilter(REJECT_ALL);
      can2.setFIFOFilter(REJECT_ALL);
      can2.setFIFOFilter(0, 0x18DAF111, EXT); // Extended CANID  Target address F1(Tester), Sender 11(ENG ECU)
      can2.setMB(MB10,TX); // Set mailbox as transmit
      can2.setMaxMB(16);
      can2.mailboxStatus(); // view current configuration
      
      can2.enableFIFO();
      can2.enableFIFOInterrupt();
      //can2.enableMBInterrupt(MB4);
       
      can2.onReceive(FIFO, canSniff);
    }
    
    const long loopDelay1 =500;
    unsigned long timeNow1 = 0;
    unsigned long timeNow2 = 0;
    
    void loop() {
    
    
      /*
       * Requesting Serivice Identifier routine
       */
      if (millis() > timeNow1 + loopDelay1) // Send the request every 100ms
        {
                 timeNow1 = millis();
                 if(Stat_FC ==0){
                   can_SID09_TX();
                
                 }
    
        }
    
       if(Stat_FC ==1){
                delay(10);
                can_FC_TX();
            }
            else if(Stat_FC ==2){
                
                 // consider doing something
            }
    
        if ( can2.read(msg)) {
        
          Serial.print("CAN2 "); 
          Serial.print("MB: "); Serial.print(msg.mb);
          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(" DATA: ");
          for ( uint8_t i = 0; i < 8; i++ ) {
             Serial.print(msg.buf[i]); Serial.print(" ");
          }
          Serial.print("  TS: "); Serial.println(msg.timestamp);
       }
      
    }
    
    void testdrawchar(void) {
      display.clearDisplay();
    
      display.setTextSize(1);      // Normal 1:1 pixel scale
      display.setTextColor(SSD1306_WHITE); // Draw white text
      display.setCursor(0, 0);     // Start at top-left corner
      display.cp437(true);         // Use full 256 char 'Code Page 437' font
    
      // Not all the characters will fit on the display. This is normal.
      // Library will draw what it can and the rest will be clipped.
      for(int16_t i=0; i<256; i++) {
        if(i == '\n') display.write(' ');
        else          display.write(i);
      }
      display.display();
    }
    
    
    // Response Message process routine 
    // 
    void canSniff (const CAN_message_t &msg){ // Global callback - prints out the received message in HEX + saves TW into a global variable
      if(msg.id == 0x18DAF111){
         Serial.println(" ");
         Serial.print("MB: ");
         Serial.print(msg.mb);
         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(" DATA: ");
     
          for (uint8_t i = 0; i < 8; i++)
             {
                Serial.print(msg.buf[i], HEX);
                Serial.print(" ");
             }
          }
          if (msg.buf[0] > 0x0F & msg.buf[2] == 0x49){    // Service$09 Positive Response message  and First Frame.
             CF_Max = 2;
             f_sid09calid_multi = 1;   // SID$09 calid process
              
             if(msg.buf[3] == 4){   // Means Info Type == 02 calid. InfoType == 04 CALID.
                // ignore msg.buf[4]. because this buffer is always 0x01.Number of data item.
                 calid_buf1 = msg.buf[5];
                 calid_buf2 = msg.buf[6];
                 calid_buf3 = msg.buf[7];  // calid buffer is fixed 17 byte. 
                 Stat_FC = 1; 
               
             }
             
          }
          else if(f_sid09calid_multi ==1 & msg.buf[0] > 0x20 & Stat_FC ==2 ){     // Means CF: Consecutive Frame and Buf[0] is sequence number
            seq_Num = msg.buf[0]; //
                 if(seq_Num == 0x21){   // Sequence Number is 1.
                    calid_buf4  = msg.buf[1];
                    calid_buf5  = msg.buf[2];
                    calid_buf6  = msg.buf[3];
                    calid_buf7  = msg.buf[4];
                    calid_buf8  = msg.buf[5];
                    calid_buf9  = msg.buf[6];
                    calid_buf10 = msg.buf[7];
                    CF_Num = 1;
                  }
                  if(seq_Num == 0x22 ){  // Sequence Number is 2.
                    calid_buf11 = msg.buf[1];
                    calid_buf12 = msg.buf[2];
                    calid_buf13 = msg.buf[3];
                    calid_buf14 = msg.buf[4];
                    calid_buf15 = msg.buf[5];
                    calid_buf16 = msg.buf[6];
                    calid_buf17 = msg.buf[7];
                    CF_Num = 2;
                   }
                  if( CF_Num == CF_Max){
                     if(Stat_FC == 2){
                        Stat_FC=0;
                        CF_Num = 0;
                        f_sid09calid_multi = 0;               
                     }
               
                  }
        
            } 
      
    
      if(msg.id == 0x18DAF111){
        display.setTextColor(WHITE);
        display.clearDisplay();
    
        display.setTextSize(1);      // Normal 1:1 pixel scale
        display.setTextColor(SSD1306_WHITE); // Draw white text
        display.setCursor(0, 0);     // Start at top-left corner
        display.println(F("CAN_ID:"));
        display.setCursor(60,0);
        display.setTextColor(WHITE);
        display.print(msg.id, HEX);
      }
        
      for ( uint8_t i = 0; i < 8; i++ ) {
         display.setCursor(15*i ,15);
         display.print(msg.buf[i],HEX);  Serial.print(" ");
      }
         
           display.display();
    
          display.setCursor(0, 30);
          display.print(calid_buf1);
          display.setCursor(6, 30);
          display.print(calid_buf2);
          display.setCursor(12, 30);
          display.print(calid_buf3);
          display.setCursor(18, 30);
          display.print(calid_buf4); 
          display.setCursor(24, 30);
          display.print(calid_buf5);
          display.setCursor(30, 30);
          display.print(calid_buf6); 
          display.setCursor(36, 30);
          display.print(calid_buf7); 
          display.setCursor(42, 30);
          display.print(calid_buf8);
          display.setCursor(48, 30);
          display.print(calid_buf9); 
          display.setCursor(54, 30);
          display.print(calid_buf10);
          display.setCursor(60, 30);
          display.print(calid_buf11); 
          display.setCursor(66, 30);
          display.print(calid_buf12);
          display.setCursor(72, 30);
          display.print(calid_buf13); 
          display.setCursor(78, 30);
          display.print(calid_buf14); 
          display.setCursor(84, 30);
          display.print(calid_buf15);
          display.setCursor(90, 30);
          display.print(calid_buf16); 
          //display.setCursor(96, 30);
          //display.print(calid_buf17); 
          
          display.display();   
      
    }
    
    
    
    void can_SID09_TX(){  // Sendo a request to get calid from ECU
        
        CAN_message_t msgTx, msgRx;
        msgTx.buf[0] = 0x02; 
        msgTx.buf[1] = 0x09; // SID$09 Request Info Type$02 calid
        msgTx.buf[2] = 0x04; // 02 is Info Type $02 CALID $04
        msgTx.buf[3] = 0x55; // 0x55 is padding
        msgTx.buf[4] = 0x55;
        msgTx.buf[5] = 0x55; 
        msgTx.buf[6] = 0x55;
        msgTx.buf[7] = 0x55;
        msgTx.len = 8; // number of bytes in request
        msgTx.flags.extended = 1; // 11 bit header, not 29 bit
        msgTx.flags.remote = 0;
        //msgTx.id = 0x7E0;   // requesting Service$09 use only 7E0 for testing Toyota
        //msgTx.id = 0x18DA11F1;  // Honda
        msgTx.id = 0x18DB33F1;
    
        can2.write(msgTx); 
    }
    
    
    void can_FC_TX(){ // Flow Control Command
      CAN_message_t msgTx, msgRx;
        msgTx.buf[0] = 0x30;     // Flow Control 
        msgTx.buf[1] = 0x00;     // Block Size
        msgTx.buf[2] = 0x00;     // STMin
        msgTx.buf[3] = 0x00;        // Padding
        msgTx.buf[4] = 0x00;
        msgTx.buf[5] = 0x00; 
        msgTx.buf[6] = 0x00;
        msgTx.buf[7] = 0x00;
        msgTx.len = 8;            // number of bytes in request
        //msgTx.flags.extended = 0; // 11 bit header, not 29 bit 
        msgTx.flags.extended = 1; // 29 bit header, not 11 bit 
        msgTx.flags.remote = 0;
        
        //msgTx.id = 0x7E0; // request header for OBD           // Physical Addressing Request to Engine ECU
        msgTx.id = 0x18DB33F1; // request header for OBD Functional Addressing request to all emission related ECUs.
        can2.write(msgTx);
        Stat_FC = 2;  // Flow Control sent
        
        //Serial.println("canTx_OBD FC sent"); 
      }

Posting Permissions

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