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

Thread: FlexCAN_T4 - FlexCAN for Teensy 4

  1. #476
    Junior Member
    Join Date
    Jan 2021
    Location
    Japan
    Posts
    18
    Things are going back and forth. Since engine coolant temperature changes slow, I used PID$0C engine speed.
    I let Teensy4.0 transmit the SID$01 PID$0C request messages every 200ms but can receive only sometimes as you can see from the Arduino Log and Vehecile Spy Log.
    From Vehicle Spy Log ECU send the response message every 200ms, but Teesnsy cannot pick up the response message every 200ms.
    Is there any missing setting for FIFO?


    Click image for larger version. 

Name:	Teensy4_PID0C_IDE.png 
Views:	53 
Size:	41.6 KB 
ID:	23348

    Click image for larger version. 

Name:	Teensy4_PID0C_PICT.png 
Views:	56 
Size:	48.1 KB 
ID:	23349




    Code:
    #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
    unsigned long curr, prev, next, interval;
    int TW =0;
    
    #define LOGO_HEIGHT   16
    #define LOGO_WIDTH    16
    
    FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_16> can2;
    
    
    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(2000);
        
        Serial.println(F("SSD1306 allocation failed"));
        
        for(;;); // Don't proceed, loop forever
      }
      Serial.begin(115200);
      can2.begin();
      can2.setBaudRate(500000);
      can2.setMBFilter(REJECT_ALL);
     // can2.setMBFilter(MB1, 0x7E8); // Standard CANID  ENG ECU -> TESTER
      can2.setMBFilter(MB7, 0x18DB33F1, EXT); // Extended CANID  ENG ECU -> TESTER (Physical Addressing)
      can2.setFIFOFilter(0, 0x18DAF111,EXT); // Extended CANID  Target address F1(Tester), Sender 11(ENG ECU)
    
      can2.setMaxMB(16);
      can2.enableFIFO();
      can2.enableFIFOInterrupt();
      
      //can2.enableMBInterrupt(MB4);
      can2.onReceive(canSniff);
    
    }
    
    const long loopDelay1 = 200; // 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.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[1] == 0x41 && msg.buf[2] == 0x0C){     // SID$01 PID$05 Engine Coolant Temperature, PID$0C Engine Speed
            //engineCoolantTemp = msg.buf[3] - 40;           // Offset -40(degC)
            engineRPM = (msg.buf[3] * 0x100 + msg.buf[4])/4;   // Engine Speed 2byte 1/4 bit per rpm
            
            Serial.println(" ");
            //Serial.printf("OBD: Engine Coolant Temp: %d c", engineCoolantTemp);
            Serial.printf("OBD Engine Speed; %d rpm", engineRPM);
        }
    
    
        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.setTextSize(2);      // Normal 1:1 pixel scale
           display.setCursor(10, 30);
         //display.print(engineCoolantTemp,DEC);
          display.print(engineRPM, DEC);
          display.setCursor(70, 30);
         //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 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);
    }

  2. #477
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,903
    remove EXT from setMBFilter (that function doesn't use that), remove events() from loop, and you enabled FIFO last in setup, which makes your filters not effective, also MB7 is a TX mailbox, so that function never runs and just exits, transmit mailboxes don't have filters.

  3. #478
    Junior Member
    Join Date
    May 2018
    Posts
    15
    This software worked like a champ after I changed my wiring to CAN1 on the Teensy 3.6. I'm using the Teensy 3.6 DIN rail adapter, and the Waveshare transceiver. I'd say this setup is one of the hidden GEMs in CAN World.

    I'd developed a car data logger for IGN and Batt to SDHC, and now I'd like to shuttle off the CAN data to the SDHC as well so that I can log timestamped CAN and battery voltage side by side. Any hints or pitfalls with this approach?

    I'm not sure how I can contribute here, but I think I can. I've been developing automotive electronics since the mid 80's, mostly at an upper management level, so I know a fair amount about vehicle electrical systems, including CAN bus architectures. I haven't spent a lot of time until now directly pulling data off a CAN bus as a listener. Looking forward to getting further into this project.

    Thank you for making this functionality available on a great platform (Teensy/Arduino).

  4. #479
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,903
    only pitfall may be the SD latency if any. What most people do is fill a 512 buffer in ram then write that to SD while you continue logging to a different 512 buffer. You can do this with a standard array, or the built-in Circular_Buffer library included and used with FlexCAN_T4.

    if you want a challenge, you could do a circular buffer 1024byte and after size() returns >= 512, pop 512bytes of the contents out to the file while the same buffer is being populated

  5. #480
    Junior Member
    Join Date
    Jan 2021
    Location
    Japan
    Posts
    18
    Meanwhile I am trying to figure out the FIFO and mailboxes behavior, but there is still a lot of things to understand.
    Most of the reason why the software does not work properly may come from setup().

    Current behavior is, when the teensy is connected to the vehicle, teensy keeps sending request to the ECU, but teensy cannot pick the positive response from the ECU though the ECU is sending the response message. When teensy is disconnected from the ECU, Teensy picks once or twice the positive response message.
    For starting the building the software, I made a simple dummy ECU (PIC18F) which responds to the teensy request messages and sends some meaningless data. But the actual vehicle CAN network bus load is much higher and there are a lot of data coming into the Teensy's buffer.

    Code:
    // 29bit extended OBD CAN Sketch
    //
    //  2012 Honda FIT
    //  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(MB9,TX); // Set mailbox as transmit
      //can2.setMB(MB10,RX,EXT); // Set mailbox as receiving extended frames.
      can2.setMaxMB(16);
      can2.mailboxStatus(); // view current configuration
      
      can2.enableFIFO();
      can2.enableFIFOInterrupt();
      
      can2.onReceive(canSniff);
    
    }
    
    const long loopDelay1 = 100; // 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.id == 0x18DAF111 & msg.buf[1] == 0x41 & msg.buf[2] == 0x0C){     // SID$01 PID$05 Engine Coolant Temperature
            //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);
        }
    
        if (msg.buf[1] == 0x62 && msg.buf[2] == 0xf4 && msg.buf[3] == 0x05){     // Checking positive reponse
            engineCoolantTemp = msg.buf[4] - 40;
            Serial.println(" ");
            Serial.printf("UDS: Engine Coolant Temp: %d c", engineCoolantTemp);
        }
            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);
    }

  6. #481
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,903
    dont set filters BEFORE calling enableFIFO

    and by the way.....
    Code:
    msg.id == 0x18DAF111 & msg.buf[1] == 0x41 & msg.buf[2]
    & is not &&

    essentially you are asking:
    Code:
    msg.id == (0x18DAF111 & msg.buf[1]) == (0x41 & msg.buf[2]).....
    which would result in 0 in the end, which is why the condition is never met
    Last edited by tonton81; 01-21-2021 at 04:03 PM.

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

  8. #483
    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); 
    }

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

  10. #485
    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.

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

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

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

  14. #489
    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!!

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

  16. #491
    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!

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

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

  19. #494
    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".

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

  21. #496
    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);
    }

  22. #497
    Junior Member
    Join Date
    May 2018
    Posts
    15
    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?

  23. #498
    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!

  24. #499
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,903
    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().

  25. #500
    Junior Member
    Join Date
    May 2018
    Posts
    15
    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.

Posting Permissions

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