Forum Rule: Always post complete source code & details to reproduce any issue!
Page 2 of 7 FirstFirst 1 2 3 4 ... LastLast
Results 26 to 50 of 166

Thread: IFCT - Improved Flexcan Teensy Library

  1. #26
    Senior Member+
    Join Date
    Jul 2014
    Location
    New York
    Posts
    3,228
    Ok. Works fine for me now. Two things I messed up on that caused it to stop: 1) left the fifo code in the loop and 2) should have had the onreceive last;

    Now I am getting the following:
    Code:
    *** MB 0  LEN: 8 EXT: 0 REMOTE: 0 TS: 41938 ID: 105 Buffer: 28 44 7F 44 0 0 C4 41 
    Pressure: 0.00  Temperature: 0.00
    *** MB 1  LEN: 8 EXT: 0 REMOTE: 0 TS: 47165 ID: 1 Buffer: 0 3C 1C 46 0 3C 1C 46 
    lat: 0.000000  long: 0.00
    *** MB 1  LEN: 8 EXT: 0 REMOTE: 0 TS: 52356 ID: 2 Buffer: 0 0 40 40 0 0 40 41 
    fType: 0.00  nSV: 0.00
    *** MB 1  LEN: 8 EXT: 0 REMOTE: 0 TS: 57547 ID: 3 Buffer: DC 1 2F 43 B D7 A3 3C 
    head: 0.00  spd: 0.00

  2. #27
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,003
    Your MB0/MB1 callbacks seem to be processing on default variable initialization (0)

    myMSG seems like it supposed to update those vars, because I see the data printout from myMSG being intact, I don't think your conversion routine is setup properly

  3. #28
    Senior Member+
    Join Date
    Jul 2014
    Location
    New York
    Posts
    3,228
    I am not sure what I just did. Was cleaning up code and did something dumb. Now I only getting;
    Code:
    *** MB 0  LEN: 8 EXT: 0 REMOTE: 0 TS: 56905 ID: 105 Buffer: 38 2D 7F 44 B8 1E C7 41 
    Pressure: 0.00  Temperature: 0.00
    *** MB 1  LEN: 8 EXT: 0 REMOTE: 0 TS: 57022 ID: 1 Buffer: 0 0 C6 42 0 0 C6 42 
    lat: 0.000000  long: 0.00
    *** MB 1  LEN: 8 EXT: 0 REMOTE: 0 TS: 57270 ID: 3 Buffer: 0 0 0 0 0 0 0 0 
    head: 0.00  spd: 0.00
    Yeah have to check the conversion routine. Put together on the fly just to test. Wanted to make sure I had CAN working first.

  4. #29
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,003
    T3.5 seems to be "locking" up in your last function, probably an overflow, i put a "return" at the top so it never runs and i can reprogram it fine. If i let it as-is i have to push program button on t3.5
    so there must be an overflow in your last function

  5. #30
    Senior Member+
    Join Date
    Jul 2014
    Location
    New York
    Posts
    3,228
    Hmmm.. Going to check whats going on after diner. Cooking again tonight.

    The last function is the conversion. Was trying to do make a function so that I wouldn't need to repeat it. I am making can_msg_t msg global so I don't have to keep passing. Beside I kept running into conversion errors when I tried

  6. #31
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,003
    you can pass only if you add "const" to the overload

    Code:
    void func(const CAN_message_t &msg) {}

  7. #32
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,003
    You could do it this way:
    Code:
      convert2Float(msg);
    Code:
    void convert2Float(const CAN_message_t &frame) {
      uint8_t data[sizeof(float)];
      uint8_t data1[sizeof(float)];
    
      Serial.print("C2F_FRAME: ");
      for (uint8_t i = 0; i < 8; i++) {
        if ( i < 4 ) data[i] = frame.buf[i];
        else data1[i] = frame.buf[i];
        Serial.print(i); Serial.print(" ");
      }
    }
    the freezes seem to be caused by using memcpy, i commented them out and its running fine... (T3.5)
    Last edited by tonton81; 06-26-2018 at 11:15 PM.

  8. #33
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,003
    You could also use a union, this doesn't freeze:
    Code:
    void convert2Float(const CAN_message_t &frame) {
      union ifct {
        float val;
        uint8_t b[4];
      };
      ifct data, data1;
    
      Serial.print("C2F_FRAME: ");
    
      for (uint8_t i = 0; i < 8; i++) {
        if ( i < 4 ) data[i] = frame.buf[i];
        else data1[i] = frame.buf[i];
        Serial.print(i); Serial.print(" ");
      }
    
      Serial.print("VAL1: "); Serial.print(data.val);
      Serial.print("\tVAL2: "); Serial.println(data1.val);
    }
    OUTPUT:
    Code:
    C2F_FRAME: 227 132 161 195 76 125 169 137 VAL1: -323.04	VAL2: 0.00
    because my code sends random data, i couldnt test the float stuff as its either "ovf" (overflow) on print, an actual float, or plain 0.00.
    However you could do same but in reverse at your master end for sending, create an ifct union and name (ifct data), set the float (data.val = 0.01f), and then send the bytes data.b[0] -> data.b[3] to the node

  9. #34
    Senior Member+
    Join Date
    Jul 2014
    Location
    New York
    Posts
    3,228
    Hi tony

    Gave your union example a shot and its throwing the following error:
    Code:
    C:\Users\CyberPalin\Documents\Arduino\CANFIFO.ino\CANFIFO.ino.ino: In function 'void convert2Float(float, float, const CAN_message_t&)':
    
    C:\Users\CyberPalin\Documents\Arduino\CANFIFO.ino\CANFIFO.ino.ino:141:11: error: no match for 'operator[]' (operand types are 'convert2Float(float, float, const CAN_message_t&)::ifct' and 'uint8_t {aka unsigned char}')
    
           data[i] = frame.buf[i];
    
               ^
    
    C:\Users\CyberPalin\Documents\Arduino\CANFIFO.ino\CANFIFO.ino.ino:144:12: error: no match for 'operator[]' (operand types are 'convert2Float(float, float, const CAN_message_t&)::ifct' and 'uint8_t {aka unsigned char}')
    
           data1[i] = frame.buf[i];
    
                ^
    Exact same function no modes. Any ideas?


    UPDATE: SOLVED. Has to be data.b[I]

    Final UPDATE:
    Had to make a minor change to the functions but it works fine. I also resolved the issue I had with no ID2 coming through. I added a delay(1) between writes. Not major issue since the sensor updates are quite a bit longer anyway.

    Code:
    *** MB 0  LEN: 8 EXT: 0 REMOTE: 0 TS: 56257 ID: 105 Buffer: B2 1E 7F 44 0 0 C8 41 
    C2F_FRAME: Pressure: 1020.48  Temperature: 25.00
    *** MB 1  LEN: 8 EXT: 0 REMOTE: 0 TS: 58263 ID: 1 Buffer: 0 0 C6 42 0 0 C6 42 
    C2F_FRAME: lat: 99.000000  long: 99.00
    *** MB 1  LEN: 8 EXT: 0 REMOTE: 0 TS: 60267 ID: 2 Buffer: 0 0 40 40 0 0 30 41 
    C2F_FRAME: fType: 3.00  nSV: 11.00
    *** MB 1  LEN: 8 EXT: 0 REMOTE: 0 TS: 62271 ID: 3 Buffer: 0 0 0 0 59 39 34 3C 
    C2F_FRAME: head: 0.00  spd: 0.01
    Last edited by mjs513; 06-27-2018 at 01:51 AM.

  10. #35
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,003
    it depends on how fast your handling the MB interrupt, remember your asking for IDs 1-3, so when you send all 3 to a multi-id mailbox, you catch the first, but maybe your not done “processing it” before 2 comes, and no other mailbox is set to capture it, the hardware will “toss it out”. looks like you were getting 1 and 3 fine, so while processing frame #1 you lose frame #2 but you exited fast enough to process frame 3.

  11. #36
    Senior Member+
    Join Date
    Jul 2014
    Location
    New York
    Posts
    3,228
    I added an additional convert function to go from int32's to 4 bytes so I could preserve the accuracy of the of lat and long. So here is my final results:
    Code:
    *** MB 0  LEN: 8 EXT: 0 REMOTE: 0 TS: 46014 ID: 105 Buffer: CA 8F 7E 44 52 B8 BE 41 
    Pressure: 1018.25  Temperature: 23.84
    *** MB 1  LEN: 8 EXT: 0 REMOTE: 0 TS: 48021 ID: 1 Buffer: 8F BB 4D 18 C7 C6 0 D4 
    lat: 40.77474594  long: -73.81465912
    *** MB 1  LEN: 8 EXT: 0 REMOTE: 0 TS: 50025 ID: 2 Buffer: 3 0 0 0 C 0 0 0 
    fType: 3  nSV: 12
    *** MB 1  LEN: 8 EXT: 0 REMOTE: 0 TS: 52029 ID: 3 Buffer: 0 0 0 0 B D7 A3 3D 
    head: 0.00  spd: 0.08

    In case anyone is interested here are the two sketches that I used:

    SENDER:

    Code:
    #include <IFCT.h>
    #include <Wire.h>
    #include "globals.h"
    #include <Adafruit_Sensor.h>
    #include <Adafruit_BME280.h>
    
    #define SEALEVELPRESSURE_HPA (1013.25)
    
    Adafruit_BME280 bme; // I2C
    
    #include <ublox2.h>
    #include "Streaming.h"
    #include <string>
    
    // a uBlox object, which is on Teensy hardware
    // GPS serial port
    UBLOX GPS(GPShwSERIAL);
    
    // the uBlox data structure
    gpsData uBloxData;
    
    struct gps rtk;
    
    CAN_message_t msg; // setup a storage buffer
    
    void setup() {
      Serial.begin(115200);
      delay(5000);
      
        bool status;
        // default settings
        // (you can also pass in a Wire library object like &Wire2)
        status = bme.begin();  
        if (!status) {
            Serial.println("Could not find a valid BME280 sensor, check wiring!");
            while (1);
        }
    
      //GPS SETUP
      // -- AutoBauding test --
      // Try communication with the GPS
      // receiver at 9600 baud, default settings
      // then set GPS UART Baud to 460800
      GPS.begin(9600);
      GPS.SetGPSbaud(460800, true);
      GPS.end();
      GPS.begin(460800);
      
      GPS.SetRATE(200, false);                 // Navigation/Measurement Rate Settings, e.g. 100ms => 10Hz, 200 => 5.00Hz, 1000ms => 1Hz, 10000ms => 0.1Hz
      // Possible Configurations:
      // 60=>16.67Hz, 64=>15.63Hz, 72=>13.89Hz, 80=>12.50Hz, 100=>10.00Hz, 125=>8.00Hz, 200=>5.00Hz, 250=>4.00Hz, 500=>2.00Hz
      // 800=>1.25Hz, 1000=>1.00Hz, 2000=>0.50Hz, 4000=>0.25Hz, 10000=>0.10Hz, 20000=>0.05Hz, 50000=>0.02Hz
    
      // NOTE: Dis_all_NMEA -strongly suggest changing RX buffer to 255 or more,*otherwise you will miss ACKs*on serial monitor
      GPS.Dis_all_NMEA_Child_MSGs(false);       // Disable All NMEA Child Messages Command
    
      GPS.SetNAV5(4, false);                    // Set Dynamic platform model Navigation Engine Settings (0:portable, 2: stationary, 3:pedestrian, Etc)
      // Possible Configurations
      // 0: portable, 2: stationary, 3: pedestrian, 4: automotive, 5: sea, 6: airborne with <1g, 7: airborne with <2g
      // 8: airborne with <4g, 9: wrist worn watch (not supported in protocol v.less than 18)
    
      // ### Periodic auto update ON,OFF Command ###
      GPS.Ena_NAV_PVT(true);                    // Enable periodic auto update NAV_PVT
      //GPS.Dis_NAV_PVT(false);                 // Disable periodic auto update NAV_PVT
    
        Can0.setMB(MB0, TX);  //Add ,IDE for extended frames.
        Can0.setMB(MB1, TX);  //Add ,IDE for extended frames.
    
    
      delay(2500);
        Serial.println("-- Default Test --");
        Serial.println();
    
    }
    
    void loop() {
    
      msg.flags.extended = 0;  //1 = extended frame 
      msg.flags.remote = 0;
      msg.len = 8;
      delay(2);
      //Send Pressure and Temperature from BME280
      msg.id = 0x69;
      //setup two msg buffer (convert float to uint8's
      convertFloat(bme.readPressure()/100.0F, bme.readTemperature());
      Can0.write(MB0, msg);
    
      if(GPS.read(&uBloxData)) {
        rtk.iTOW = uBloxData.iTOW;
        rtk.fixType = uBloxData.fixType;
        rtk.numSV = uBloxData.numSV;
        rtk.pDOP = uBloxData.pDOP * 100;
        rtk.lat1 = uBloxData.lat;
        rtk.lon1 = uBloxData.lon;
        rtk.heading = uBloxData.heading;
        rtk.gSpeed = uBloxData.gSpeed;
        rtk.hMSL = uBloxData.hMSL;
      } 
    
      delay(2);
     //Sends GPS data from the M8N
      //Serial.println(rtk.lat1, 6);
      msg.id = 0x01;
      convertInt(rtk.lat1*1e7, rtk.lon1*1e7);
      //Serial.print("ID1 TX Status:"); 
      //Serial.println(Can0.write(MB1, msg));
      Can0.write(MB1, msg);
    
      delay(2);
      msg.id = 0x02;
      convertInt(rtk.fixType, rtk.numSV); 
      //Serial.print("ID2 TX Status:"); 
      //Serial.println(Can0.write(MB1, msg));
      Can0.write(MB1, msg);
    
      delay(2);
      msg.id = 0x03;
      convertFloat(rtk.heading, (float) rtk.gSpeed);
      //Serial.print("ID3 TX Status:"); 
      //Serial.println(Can0.write(MB1, msg));
      Can0.write(MB1, msg);
    
    
      static uint32_t _timer = millis();
      if ( millis() - _timer > 4000 ) {
        pinMode(13, OUTPUT); digitalWrite(13, !digitalRead(13));
        Serial.print("*HEARTBEAT* "); Serial.println(millis());
        Serial.println(rtk.lat1, 6);
        //Can0.mailboxStatus();
        _timer = millis();
      }
    
    }
    
    void convertFloat(float a, float b){
        char data[sizeof(float)];
        memcpy(data, &a, sizeof a);    // send data
        char data1[sizeof(float)];
        memcpy(data1, &b, sizeof b);    // send data
        for(uint8_t i = 0; i<4; i++){
          msg.buf[i] = data[i];
          msg.buf[i+4] = data1[i];
        }
    }
    
    void convertInt(int32_t a, int32_t b){
        char data[sizeof(int32_t)];
        memcpy(data, &a, sizeof a);    // send data
        char data1[sizeof(int32_t)];
        memcpy(data1, &b, sizeof b);    // send data
        for(uint8_t i = 0; i<4; i++){
          msg.buf[i] = data[i];
          msg.buf[i+4] = data1[i];
        }
    }
    RECEIVER:
    Code:
    #include <IFCT.h>
      float pressure, temp;
      int32_t lat, lon,  fType, nSV;
      float head, spd;
      CAN_message_t msg; // setup a temporary storage buffer
    
    void setup() {
      Serial.begin(115200);
      delay(1000);
    
      Can0.setMB(MB0, RX);  //add ,IDE for extended frames
      Can0.enableMBInterrupt(MB0); // <--- enable per mailbox interrupt
      Can0.setMB(MB1, RX);  //add ,IDE for extended frames
      Can0.enableMBInterrupt(MB1); // <--- enable per mailbox interrupt
    
      //Set up mailbox filters
      Can0.setMBFilter(REJECT_ALL); // blocks all traffic from entering mailbox (ACCEPT_ALL restores default behaviour)
      Can0.setMBFilter(MB0, 0x69);  // MB0 accecpts BME280 data
      Can0.setMBFilterRange(MB1, 0x01, 0x03);  // MB1 accepts GPS data
    
      //Can0.onReceive(myMSG);
      Can0.onReceive(MB0, MB0cb); // set MB0 to receive and use MB0cb interrupt
      Can0.onReceive(MB1, MB1cb);
    
    }
    
    void loop() {
    
      static uint32_t _timer = millis();
      if ( millis() - _timer > 4000 ) {
        pinMode(13, OUTPUT); digitalWrite(13, !digitalRead(13));
        Serial.print("*HEARTBEAT* "); Serial.println(millis());
        _timer = millis();
        Can0.mailboxStatus();
      }
    
    }
    
    void MB1cb(const CAN_message_t &msg) { // <--- mailbox 1 callback
      Serial.print("*** MB "); Serial.print(msg.mb);
      Serial.print("  LEN: "); Serial.print(msg.len);
      Serial.print(" EXT: "); Serial.print(msg.flags.extended);
      Serial.print(" REMOTE: "); Serial.print(msg.rtr);
      Serial.print(" TS: "); Serial.print(msg.timestamp);
      Serial.print(" ID: "); Serial.print(msg.id);
      Serial.print(" Buffer: ");
      for ( uint8_t i = 0; i < msg.len; i++ ) {
        Serial.print(msg.buf[i], HEX); Serial.print(" ");
      } Serial.println();
    
      if(msg.id == 0x01) {
        convert2Int(lat, lon, msg);
        Serial.print("lat: "); Serial.print(lat/1e7,8);
        Serial.print("  long: "); Serial.println(lon/1e7,8);
      } else if(msg.id == 0x02){
        convert2Int(fType, nSV, msg);
        Serial.print("fType: "); Serial.print(fType);
        Serial.print("  nSV: "); Serial.println(nSV);
    
      } else if(msg.id == 0x03) {
        convert2Float(head, spd, msg);
        Serial.print("head: "); Serial.print(head,2);
        Serial.print("  spd: "); Serial.println(spd);
        Serial.println();
      }
    }
    
    void MB0cb(const CAN_message_t &msg) { // <--- mailbox 1 callback
      Serial.print("*** MB "); Serial.print(msg.mb);
      Serial.print("  LEN: "); Serial.print(msg.len);
      Serial.print(" EXT: "); Serial.print(msg.flags.extended);
      Serial.print(" REMOTE: "); Serial.print(msg.rtr);
      Serial.print(" TS: "); Serial.print(msg.timestamp);
      Serial.print(" ID: "); Serial.print(msg.id);
      Serial.print(" Buffer: ");
      for ( uint8_t i = 0; i < msg.len; i++ ) {
        Serial.print(msg.buf[i], HEX); Serial.print(" ");
      } Serial.println();
    
      convert2Float(pressure, temp, msg);
      Serial.print("Pressure: "); Serial.print(pressure,2);
      Serial.print("  Temperature: "); Serial.println(temp);
    }
    
    
    
    void myMSG(const CAN_message_t &msg) { // global callback
      Serial.print("**MB "); Serial.print(msg.mb);
      Serial.print("  LEN: "); Serial.print(msg.len);
      Serial.print(" EXT: "); Serial.print(msg.flags.extended);
      Serial.print(" REMOTE: "); Serial.print(msg.rtr);
      Serial.print(" TS: "); Serial.print(msg.timestamp);
      Serial.print(" ID: "); Serial.print(msg.id);
      Serial.print(" Buffer: ");
      for ( uint8_t i = 0; i < msg.len; i++ ) {
        Serial.print(msg.buf[i], HEX); Serial.print(" ");
      } Serial.println();
    
          convert2Float(pressure, temp, msg);
          Serial.print(pressure);
          Serial.print(", "); Serial.println(temp);
    }
    
    void convert2Float(float &a, float &c, const CAN_message_t &frame) {
      union ifct {
        float val;
        uint8_t b[4];
      };
      ifct data, data1;
    
      //Serial.print("C2F_FRAME: ");
    
      for (uint8_t i = 0; i < 4; i++) {
          data.b[i] = frame.buf[i];
          data1.b[i] = frame.buf[i+4];
      }
    
    
      //Serial.print("VAL1: "); Serial.print(data.val);
      //Serial.print("\tVAL2: "); Serial.println(data1.val);
      a = data.val;
      c = data1.val;
    }
    
    void convert2Int(int32_t &a, int32_t &c, const CAN_message_t &frame) {
      union ifct {
        int32_t val;
        uint8_t b[4];
      };
      ifct data, data1;
    
      //Serial.print("C2F_FRAME: ");
    
      for (uint8_t i = 0; i < 4; i++) {
          data.b[i] = frame.buf[i];
          data1.b[i] = frame.buf[i+4];
      }
    
    
      //Serial.print("VAL1: "); Serial.print(data.val);
      //Serial.print("\tVAL2: "); Serial.println(data1.val);
      a = data.val;
      c = data1.val;
    }

  12. #37
    Senior Member+
    Join Date
    Jul 2014
    Location
    New York
    Posts
    3,228
    Hi Tony,
    I rewrote the sender sketch to only send GPS data when available and BME280 data every 100 ms. I also got rid of the memcpy in the convert functions (finally):
    Code:
    #include <IFCT.h>
    #include <Wire.h>
    #include "globals.h"
    #include <Adafruit_Sensor.h>
    #include <Adafruit_BME280.h>
    
    #define SEALEVELPRESSURE_HPA (1013.25)
    
    Adafruit_BME280 bme; // I2C
    
    #include <ublox2.h>
    #include "Streaming.h"
    #include <string>
    
    // a uBlox object, which is on Teensy hardware
    // GPS serial port
    UBLOX GPS(GPShwSERIAL);
    
    // the uBlox data structure
    gpsData uBloxData;
    
    struct gps rtk;
    
    CAN_message_t msg; // setup a storage buffer
    
    void setup() {
      Serial.begin(115200);
      delay(5000);
      
        bool status;
        // default settings
        // (you can also pass in a Wire library object like &Wire2)
        status = bme.begin();  
        if (!status) {
            Serial.println("Could not find a valid BME280 sensor, check wiring!");
            while (1);
        }
    
      //GPS SETUP
      // -- AutoBauding test --
      // Try communication with the GPS
      // receiver at 9600 baud, default settings
      // then set GPS UART Baud to 460800
      GPS.begin(9600);
      GPS.SetGPSbaud(460800, true);
      GPS.end();
      GPS.begin(460800);
      
      GPS.SetRATE(200, false);                 // Navigation/Measurement Rate Settings, e.g. 100ms => 10Hz, 200 => 5.00Hz, 1000ms => 1Hz, 10000ms => 0.1Hz
      // Possible Configurations:
      // 60=>16.67Hz, 64=>15.63Hz, 72=>13.89Hz, 80=>12.50Hz, 100=>10.00Hz, 125=>8.00Hz, 200=>5.00Hz, 250=>4.00Hz, 500=>2.00Hz
      // 800=>1.25Hz, 1000=>1.00Hz, 2000=>0.50Hz, 4000=>0.25Hz, 10000=>0.10Hz, 20000=>0.05Hz, 50000=>0.02Hz
    
      // NOTE: Dis_all_NMEA -strongly suggest changing RX buffer to 255 or more,*otherwise you will miss ACKs*on serial monitor
      GPS.Dis_all_NMEA_Child_MSGs(false);       // Disable All NMEA Child Messages Command
    
      GPS.SetNAV5(4, false);                    // Set Dynamic platform model Navigation Engine Settings (0:portable, 2: stationary, 3:pedestrian, Etc)
      // Possible Configurations
      // 0: portable, 2: stationary, 3: pedestrian, 4: automotive, 5: sea, 6: airborne with <1g, 7: airborne with <2g
      // 8: airborne with <4g, 9: wrist worn watch (not supported in protocol v.less than 18)
    
      // ### Periodic auto update ON,OFF Command ###
      GPS.Ena_NAV_PVT(true);                    // Enable periodic auto update NAV_PVT
      //GPS.Dis_NAV_PVT(false);                 // Disable periodic auto update NAV_PVT
    
        Can0.setMB(MB0, TX);  //Add ,IDE for extended frames.
        Can0.setMB(MB1, TX);  //Add ,IDE for extended frames.
    
    
      delay(2500);
        Serial.println("-- Default Test --");
        Serial.println();
    
    }
    
    void loop() {
    
      static uint32_t _timer0 = millis();
      if ( millis() - _timer0 > 100 ) {
        msg.flags.extended = 0;  //1 = extended frame 
        msg.flags.remote = 0;
        msg.len = 8;
        //Send Pressure and Temperature from BME280
        msg.id = 0x69;
        //setup two msg buffer (convert float to uint8's
        convertFloat(bme.readPressure()/100.0F, bme.readTemperature(), msg);
        Can0.write(MB0, msg);
        _timer0 = millis();
      }
      
      if(GPS.read(&uBloxData)) {
        rtk.iTOW = uBloxData.iTOW;
        rtk.fixType = uBloxData.fixType;
        rtk.numSV = uBloxData.numSV;
        rtk.pDOP = uBloxData.pDOP * 100;
        rtk.lat1 = uBloxData.lat;
        rtk.lon1 = uBloxData.lon;
        rtk.heading = uBloxData.heading;
        rtk.gSpeed = uBloxData.gSpeed;
        rtk.hMSL = uBloxData.hMSL;
    
        sendGPS();
      } 
    
      static uint32_t _timer = millis();
      if ( millis() - _timer > 4000 ) {
        pinMode(13, OUTPUT); digitalWrite(13, !digitalRead(13));
        Serial.print("*HEARTBEAT* "); Serial.println(millis());
        Serial.println(rtk.lat1, 6);
        //Can0.mailboxStatus();
        _timer = millis();
      }
    
    }
    
    void sendGPS(){
      msg.flags.extended = 0;  //1 = extended frame 
      msg.flags.remote = 0;
      msg.len = 8;
      //Sends GPS data from the M8N
      msg.id = 0x01;
      convertInt(rtk.lat1*1e7, rtk.lon1*1e7, msg);
      //Serial.print("ID1 TX Status:"); 
      //Serial.println(Can0.write(MB1, msg));
      Can0.write(MB1, msg);
    
      delay(2);
      msg.id = 0x02;
      convertInt(rtk.fixType, rtk.numSV, msg);
      //Serial.print("ID2 TX Status:"); 
      //Serial.println(Can0.write(MB1, msg));
      Can0.write(MB1, msg);
    
      delay(2);
      msg.id = 0x03;
      convertFloat(rtk.heading, (float) rtk.gSpeed, msg);
      //Serial.print("ID3 TX Status:"); 
      //Serial.println(Can0.write(MB1, msg));
      Can0.write(MB1, msg);
    
    }
    
    
    void convertFloat(float s_data, float s_data1, CAN_message_t &frame){
      union ifct {
        float val;
        uint8_t b[4];
      };
      ifct data, data1;
    
      //Serial.print("C2F_FRAME: ");
    
      data.val = s_data;
      data1.val = s_data1;
      for (uint8_t i = 0; i < 4; i++) {
          frame.buf[i] = data.b[i];
          frame.buf[i+4] = data1.b[i];
      }
    }
    
    void convertInt(int32_t s_data, int32_t s_data1, CAN_message_t &frame) {
      union ifct {
        int32_t val;
        uint8_t b[4];
      };
      ifct data, data1;
    
      //Serial.print("C2F_FRAME: ");
    
      data.val = s_data;
      data1.val = s_data1;
      for (uint8_t i = 0; i < 4; i++) {
          frame.buf[i] = data.b[i];
          frame.buf[i+4] = data1.b[i];
      }
    }
    Sample output:
    Code:
    *** MB 0  LEN: 8 EXT: 0 REMOTE: 0 TS: 6313 ID: 105 Buffer: D2 A6 7B 44 E1 7A C4 41 
    Pressure: 1006.61  Temperature: 24.56
    *** MB 0  LEN: 8 EXT: 0 REMOTE: 0 TS: 44780 ID: 105 Buffer: 54 AA 7B 44 E1 7A C4 41 
    Pressure: 1006.66  Temperature: 24.56
    *** MB 1  LEN: 8 EXT: 0 REMOTE: 0 TS: 41355 ID: 1 Buffer: FE BD 4D 18 36 C4 0 D4 
    lat: 40.77481079  long: -73.81472778
    *** MB 1  LEN: 8 EXT: 0 REMOTE: 0 TS: 43359 ID: 2 Buffer: 3 0 0 0 9 0 0 0 
    fType: 3  nSV: 9
    *** MB 1  LEN: 8 EXT: 0 REMOTE: 0 TS: 45363 ID: 3 Buffer: 0 0 0 0 A6 9B 44 3C 
    head: 0.00  spd: 0.01
    
    *** MB 0  LEN: 8 EXT: 0 REMOTE: 0 TS: 17709 ID: 105 Buffer: 32 A9 7B 44 66 66 C4 41 
    Pressure: 1006.64  Temperature: 24.55
    *** MB 0  LEN: 8 EXT: 0 REMOTE: 0 TS: 56174 ID: 105 Buffer: 13 AA 7B 44 66 66 C4 41 
    Pressure: 1006.66  Temperature: 24.55
    *** MB 1  LEN: 8 EXT: 0 REMOTE: 0 TS: 45931 ID: 1 Buffer: FF BD 4D 18 33 C4 0 D4 
    lat: 40.77481079  long: -73.81472778
    *** MB 1  LEN: 8 EXT: 0 REMOTE: 0 TS: 47935 ID: 2 Buffer: 3 0 0 0 9 0 0 0 
    fType: 3  nSV: 9
    *** MB 1  LEN: 8 EXT: 0 REMOTE: 0 TS: 49939 ID: 3 Buffer: 0 0 0 0 9E EF 27 3D 
    head: 0.00  spd: 0.04
    
    *** MB 0  LEN: 8 EXT: 0 REMOTE: 0 TS: 29104 ID: 105 Buffer: 93 A8 7B 44 E1 7A C4 41 
    Pressure: 1006.63  Temperature: 24.56
    *** MB 0  LEN: 8 EXT: 0 REMOTE: 0 TS: 2030 ID: 105 Buffer: 32 A9 7B 44 66 66 C4 41 
    Pressure: 1006.64  Temperature: 24.55
    *** MB 1  LEN: 8 EXT: 0 REMOTE: 0 TS: 48478 ID: 1 Buffer: FF BD 4D 18 33 C4 0 D4 
    lat: 40.77481079  long: -73.81472778
    *** MB 1  LEN: 8 EXT: 0 REMOTE: 0 TS: 50482 ID: 2 Buffer: 3 0 0 0 9 0 0 0 
    fType: 3  nSV: 9
    *** MB 1  LEN: 8 EXT: 0 REMOTE: 0 TS: 52486 ID: 3 Buffer: 0 0 0 0 1B 2F DD 3C 
    head: 0.00  spd: 0.03

  13. #38
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,003
    Updates added this week and posted on github:

    1) Can0.read(msg) has been updated to only pull messages from non-interrupt enabled mailboxes.
    2) Can0.events() changes the way the interrupts work when directly handling the data.

    Circular_Buffer library was added to the library which gives you the option to directly fire a callback and have the data be dealt with your callback (unbuffered), or have the ISR buffer the data into the Circular_Buffer arrays for firing from loop() mode

    To switch between both, just use or don't use the .events() in your main loop. .events() will fire the callbacks and read directly from the queue, not using .events() will allow direct message interrupt --> callback functionality without using buffers

    .events() mode will also allow you to continue to queue interrupt based messages even if your routine is slow in your callback

    Tony

  14. #39
    Senior Member+
    Join Date
    Jul 2014
    Location
    New York
    Posts
    3,228
    Ok. Just gave it a try and it works like a charm. One of the problems I was having with GPS Lat/Lon data was precision. Couldn't send as floats or int32. Wrote a function to send as doubles but had to add 2 more messages plus 1 for iTOW. That's 5 ids on one mailbox. I also removed all delays from the sending sketch on the T3.5 and the receiving sketch using events() kept up like a charm. Here is a sample of the new output layout I am using (just to see the data):
    Code:
    Press    Temp      TOW              LAT           LON        FIX       SV      Head    Spd
    1012.45	24.53	1307513066	40.7747196	-73.8146183	3	11	0.00	0.07
    1012.47	24.53	1307513070	40.7747196	-73.8146182	3	11	0.00	0.02
    1012.41	24.53	1307513073	40.7747197	-73.8146182	3	11	0.00	0.01
    1012.44	24.53	1307513076	40.7747198	-73.8146181	3	11	0.00	0.01
    1012.49	24.53	1307513079	40.7747199	-73.8146181	3	11	0.00	0.03
    1012.43	24.53	1307513082	40.7747200	-73.8146181	3	11	0.00	0.03
    1012.50	24.53	1307513098	40.7747205	-73.8146177	3	11	0.00	0.04
    1012.47	24.53	1307513101	40.7747205	-73.8146176	3	11	0.00	0.01
    1012.48	24.53	1307513104	40.7747208	-73.8146175	3	11	0.00	0.02
    1012.44	24.53	1307513107	40.7747209	-73.8146173	3	11	0.00	0.04
    1012.46	24.53	1307513110	40.7747210	-73.8146172	3	11	0.00	0.02
    For reference here are the sketches:
    Sending:
    Code:
    #include <IFCT.h>
    #include <Wire.h>
    #include "globals.h"
    #include <Adafruit_Sensor.h>
    #include <Adafruit_BME280.h>
    
    #define SEALEVELPRESSURE_HPA (1013.25)
    
    Adafruit_BME280 bme; // I2C
    
    #include <ublox2.h>
    #include "Streaming.h"
    #include <string>
    
    // a uBlox object, which is on Teensy hardware
    // GPS serial port
    UBLOX GPS(GPShwSERIAL);
    
    // the uBlox data structure
    gpsData uBloxData;
    
    struct gps rtk;
    
    CAN_message_t msg; // setup a storage buffer
    
    void setup() {
      Serial.begin(115200);
      delay(5000);
      
        bool status;
        // default settings
        // (you can also pass in a Wire library object like &Wire2)
        status = bme.begin();  
        if (!status) {
            Serial.println("Could not find a valid BME280 sensor, check wiring!");
            while (1);
        }
    
      //GPS SETUP
      // -- AutoBauding test --
      // Try communication with the GPS
      // receiver at 9600 baud, default settings
      // then set GPS UART Baud to 460800
      GPS.begin(9600);
      GPS.SetGPSbaud(460800, true);
      GPS.end();
      GPS.begin(460800);
      
      GPS.SetRATE(100, false);                 // Navigation/Measurement Rate Settings, e.g. 100ms => 10Hz, 200 => 5.00Hz, 1000ms => 1Hz, 10000ms => 0.1Hz
      // Possible Configurations:
      // 60=>16.67Hz, 64=>15.63Hz, 72=>13.89Hz, 80=>12.50Hz, 100=>10.00Hz, 125=>8.00Hz, 200=>5.00Hz, 250=>4.00Hz, 500=>2.00Hz
      // 800=>1.25Hz, 1000=>1.00Hz, 2000=>0.50Hz, 4000=>0.25Hz, 10000=>0.10Hz, 20000=>0.05Hz, 50000=>0.02Hz
    
      // NOTE: Dis_all_NMEA -strongly suggest changing RX buffer to 255 or more,*otherwise you will miss ACKs*on serial monitor
      GPS.Dis_all_NMEA_Child_MSGs(false);       // Disable All NMEA Child Messages Command
    
      GPS.SetNAV5(4, false);                    // Set Dynamic platform model Navigation Engine Settings (0:portable, 2: stationary, 3:pedestrian, Etc)
      // Possible Configurations
      // 0: portable, 2: stationary, 3: pedestrian, 4: automotive, 5: sea, 6: airborne with <1g, 7: airborne with <2g
      // 8: airborne with <4g, 9: wrist worn watch (not supported in protocol v.less than 18)
    
      // ### Periodic auto update ON,OFF Command ###
      GPS.Ena_NAV_PVT(true);                    // Enable periodic auto update NAV_PVT
      //GPS.Dis_NAV_PVT(false);                 // Disable periodic auto update NAV_PVT
    
        Can0.setMB(MB0, TX);  //Add ,IDE for extended frames.
        Can0.setMB(MB1, TX);  //Add ,IDE for extended frames.
    
    
      delay(2500);
        Serial.println("-- Default Test --");
        Serial.println();
    
    }
    
    void loop() {
    
      static uint32_t _timer0 = millis();
      if ( millis() - _timer0 > 100 ) {
        msg.flags.extended = 0;  //1 = extended frame 
        msg.flags.remote = 0;
        msg.len = 8;
        //Send Pressure and Temperature from BME280
        msg.id = 0x69;
        //setup two msg buffer (convert float to uint8's
        convertFloat(bme.readPressure()/100.0F, bme.readTemperature(), msg);
        Can0.write(MB0, msg);
        _timer0 = millis();
      }
    
      if(GPS.read(&uBloxData)) {
        rtk.iTOW = uBloxData.iTOW;
        rtk.fixType = uBloxData.fixType;
        rtk.numSV = uBloxData.numSV;
        rtk.pDOP = uBloxData.pDOP * 100;
        rtk.lat1 = uBloxData.lat;
        rtk.lon1 = uBloxData.lon;
        rtk.heading = uBloxData.heading;
        rtk.gSpeed = uBloxData.gSpeed;
        rtk.hMSL = uBloxData.hMSL;
    
        if((rtk.iTOW - rtk.ts) > 0 ) {
          Serial.println(rtk.lat1, 7);
          sendGPS();
        }
    
        rtk.ts = rtk.iTOW;
      } 
    
      static uint32_t _timer = millis();
      if ( millis() - _timer > 4000 ) {
        pinMode(13, OUTPUT); digitalWrite(13, !digitalRead(13));
        Serial.print("*HEARTBEAT* "); Serial.println(millis());
        //Can0.mailboxStatus();
        _timer = millis();
      }
    
    }
    
    void sendGPS(){
      msg.flags.extended = 0;  //1 = extended frame 
      msg.flags.remote = 0;
      msg.len = 8;
      //Sends GPS data from the M8N
      msg.id = 0x01;
      convertDouble(rtk.lat1, msg);
      //Serial.print("ID1 TX Status:"); 
      //Serial.println(Can0.write(MB1, msg));
      Can0.write(MB1, msg);
    
      //delay(2);
      msg.id = 0x02;
      convertDouble(rtk.lon1, msg);
      //Serial.print("ID2 TX Status:"); 
      //Serial.println(Can0.write(MB1, msg));
      Can0.write(MB1, msg);
      
      //delay(2);
      msg.id = 0x03;
      convertInt(rtk.fixType, rtk.numSV, msg);
      //Serial.print("ID2 TX Status:"); 
      //Serial.println(Can0.write(MB1, msg));
      Can0.write(MB1, msg);
    
      //delay(2);
      msg.id = 0x04;
      convertFloat(rtk.heading, (float) rtk.gSpeed, msg);
      //Serial.print("ID3 TX Status:"); 
      //Serial.println(Can0.write(MB1, msg));
      Can0.write(MB1, msg);
    
      //delay(2);
      msg.id = 0x05;
      convertFloat(rtk.iTOW, 0, msg);
      //Serial.print("ID3 TX Status:"); 
      //Serial.println(Can0.write(MB1, msg));
      Can0.write(MB1, msg);
    
    }
    
    
    void convertFloat(float s_data, float s_data1, CAN_message_t &frame){
      union ifct {
        float val;
        uint8_t b[4];
      };
      ifct data, data1;
    
      //Serial.print("C2F_FRAME: ");
    
      data.val = s_data;
      data1.val = s_data1;
      for (uint8_t i = 0; i < 4; i++) {
          frame.buf[i] = data.b[i];
          frame.buf[i+4] = data1.b[i];
      }
    }
    
    void convertInt(int32_t s_data, int32_t s_data1, CAN_message_t &frame) {
      union ifct {
        int32_t val;
        uint8_t b[4];
      };
      ifct data, data1;
    
      //Serial.print("C2F_FRAME: ");
    
      data.val = s_data;
      data1.val = s_data1;
      for (uint8_t i = 0; i < 4; i++) {
          frame.buf[i] = data.b[i];
          frame.buf[i+4] = data1.b[i];
      }
    }
    
    void convertDouble(double s_data, CAN_message_t &frame){
      union ifct {
        double val;
        uint8_t b[8];
      };
      ifct data;
    
      //Serial.print("C2F_FRAME: ");
    
      data.val = s_data;
      for (uint8_t i = 0; i < 8; i++) {
          frame.buf[i] = data.b[i];
      }
    }
    Receiving:
    Code:
    #include <IFCT.h>
      float pressure, temp, head, spd;
      int32_t iTow, fType, nSV, tmp;
      double lat, lon;
      
      CAN_message_t msg; // setup a temporary storage buffer
      uint8_t gps_msg_cmplt = 0;
    
    void setup() {
      Serial.begin(115200);
      delay(1000);
      
      Can0.setMB(MB0, RX);  //add ,IDE for extended frames
      Can0.enableMBInterrupt(MB0); // <--- enable per mailbox interrupt
      Can0.setMB(MB1, RX);  //add ,IDE for extended frames
      Can0.enableMBInterrupt(MB1); // <--- enable per mailbox interrupt
    
      //Set up mailbox filters
      Can0.setMBFilter(REJECT_ALL); // blocks all traffic from entering mailbox (ACCEPT_ALL restores default behaviour)
      Can0.setMBFilter(MB0, 0x69);  // MB0 accecpts BME280 data
      Can0.setMBFilterRange(MB1, 0x01, 0x05);  // MB1 accepts GPS data
    
      //Can0.onReceive(myMSG);
      Can0.onReceive(MB0, MB0cb); // set MB0 to receive and use MB0cb interrupt
      Can0.onReceive(MB1, MB1cb);
    
      Serial.print("Press(mb) \t Temp(degC) \t Lat \t Lon \t fType \t #SV \t Head \t Spd");  
    
    }
    
    void loop() {
      Can0.events();
    
      if(gps_msg_cmplt == 1){
        Serial.print(pressure,2); Serial.print("\t"); Serial.print(temp);
        Serial.print("\t"); Serial.print(iTow);
        Serial.print("\t"); Serial.print(lat,7); Serial.print("\t"); Serial.print(lon,7);
        Serial.print("\t"); Serial.print(fType); Serial.print("\t"); Serial.print(nSV);
        Serial.print("\t"); Serial.print(head,2);Serial.print("\t"); Serial.println(spd);
        gps_msg_cmplt = 0;
      }
      
      static uint32_t _timer = millis();
      if ( millis() - _timer > 4000 ) {
        pinMode(13, OUTPUT); digitalWrite(13, !digitalRead(13));
        //Serial.print("*HEARTBEAT* "); Serial.println(millis());
        _timer = millis();
      }
    }
    
    void MB1cb(const CAN_message_t &msg) { // <--- mailbox 1 callback
    
      //print_msg(msg);
      
      if(msg.id == 0x01) {
        convert2Double(lat, msg);
        //Serial.print("lat: "); Serial.print(lat/1e7,8);
        //Serial.print("  long: "); Serial.println(lon/1e7,8);
      } else if(msg.id == 0x02){
        convert2Double(lon, msg);  
      } else if(msg.id == 0x03){
        convert2Int(fType, nSV, msg);
        //Serial.print("fType: "); Serial.print(fType);
        //Serial.print("  nSV: "); Serial.println(nSV);
      } else if(msg.id == 0x04) {
        convert2Float(head, spd, msg);
        //Serial.print("head: "); Serial.print(head,2);
        //Serial.print("  spd: "); Serial.println(spd);
        //Serial.println();
      } else if(msg.id == 0x05){
        convert2Int(iTow, tmp, msg);
        gps_msg_cmplt = 1;
      }
    }
    
    void MB0cb(const CAN_message_t &msg) { // <--- mailbox 1 callback
    
      //print_msg(msg);
    
      convert2Float(pressure, temp, msg);
      //Serial.print("Pressure: "); Serial.print(pressure,2);
      //Serial.print("  Temperature: "); Serial.println(temp);
    }
    
    
    
    void myMSG(const CAN_message_t &msg) { // global callback
      print_msg(msg);
    }
    
    
    void print_msg(const CAN_message_t &frame){
      Serial.print("*** MB "); Serial.print(frame.mb);
      Serial.print("  LEN: "); Serial.print(frame.len);
      Serial.print(" EXT: "); Serial.print(frame.flags.extended);
      Serial.print(" REMOTE: "); Serial.print(frame.rtr);
      Serial.print(" TS: "); Serial.print(frame.timestamp);
      Serial.print(" ID: "); Serial.print(frame.id);
      Serial.print(" Buffer: ");
      for ( uint8_t i = 0; i < frame.len; i++ ) {
        Serial.print(frame.buf[i], HEX); Serial.print(" ");
      } Serial.println();
    }
    
    void convert2Float(float &a, float &c, const CAN_message_t &frame) {
      union ifct {
        float val;
        uint8_t b[4];
      };
      ifct data, data1;
    
      //Serial.print("C2F_FRAME: ");
    
      for (uint8_t i = 0; i < 4; i++) {
          data.b[i] = frame.buf[i];
          data1.b[i] = frame.buf[i+4];
      }
    
    
      //Serial.print("VAL1: "); Serial.print(data.val);
      //Serial.print("\tVAL2: "); Serial.println(data1.val);
      a = data.val;
      c = data1.val;
    }
    
    void convert2Int(int32_t &a, int32_t &c, const CAN_message_t &frame) {
      union ifct {
        int32_t val;
        uint8_t b[4];
      };
      ifct data, data1;
    
      //Serial.print("C2F_FRAME: ");
    
      for (uint8_t i = 0; i < 4; i++) {
          data.b[i] = frame.buf[i];
          data1.b[i] = frame.buf[i+4];
      }
    
    
      //Serial.print("VAL1: "); Serial.print(data.val);
      //Serial.print("\tVAL2: "); Serial.println(data1.val);
      a = data.val;
      c = data1.val;
    }
    
    void convert2Double(double &a, const CAN_message_t &frame) {
      union ifct {
        double val;
        uint8_t b[8];
      };
      ifct data;
    
      //Serial.print("C2F_FRAME: ");
    
      for (uint8_t i = 0; i < 8; i++) {
          data.b[i] = frame.buf[i];
      }
    
    
      //Serial.print("VAL1: "); Serial.print(data.val);
      //Serial.print("\tVAL2: "); Serial.println(data1.val);
      a = data.val;
    }

  15. #40
    Senior Member+
    Join Date
    Jul 2014
    Location
    New York
    Posts
    3,228

    IFCT and ODD II Implementation?

    I couldn't resist the lure of trying to hook up the Teensy to my car (Hyundai Sonata). So I ordered a ODB cable which should get here today or tomorrow, but in the mean time I started looking at some of the ODB2 implementations out there and of course Wikipedia.

    Based on what I read (I am really new to ODB and CAN) I think the following sketch may work assuming my car uses the same addresses for requesting and receiving data. If you have any suggestions please let me know:

    Code:
    #include <IFCT.h>
    
      CAN_message_t msg_tx; // setup a storage buffer
      CAN_message_t msg_rx; // setup a receive storage buffer
    
    #define ENGINE_COOLANT_TEMP 0x05   //returns 1 bytes, A-40, -40 to 215C 
    #define ENGINE_RPM          0x0C   //2 bytes, (256A+B)/4, 0-16,383.75 RPM
    #define VEHICLE_SPEED       0x0D   //1 byte, 0-255 km/h
    #define OIL_TEMP            0x5C   //calcluated value A-40, returns 1 byte,
                                       //range -40 to 210C, 
    #define ECM_Voltage         0x42   //2 bytes, 0-65.535, (256A+B)/1000
    
    /*
      Response id from wiki article
        "Typically the engine or main ECU responds at ID 7E8h. 
        Other modules, like the hybrid controller or battery controller in a Prius, respond at 07E9, 07EA, 07EB, etc. "
    
      dta: 0x02, 0x01, PID_CODE
      1st byte Number ofadditionaldata bytes (SAE Standard)
      2nd byte is the Mode, for real time data you use Mode 14
      3rd byte is the PID_Code
      Bytes 4-8 value of the specified parameter starting at Byte 0
      
      See https://en.wikipedia.org/wiki/OBD-II_PIDs
    
      For recieve:
      byte 0: Number of additional data bytes: 3 to 6
      byte 1: Custom mode. Same as query, except that 40h is added to 
        the mode value. So: 41h = show current data;
        42h = freeze frame; etc.
      byte 2: PID code (e.g.: 05 = Engine coolant temperature)
      byte 3: value of the specified parameter, byte 0
      byte 4: value, byte 1 (optional)
      byte 5: value, byte 2 (optional)
      byte 6: value, byte 3 (optional)
      byte 7: not used (may be 00h or 55h)
      
    */  
    #define PID_REQUEST    0x7DF
    #define PID_REPLY0     0x7E8
    #define PID_REPLY1     0x7E9
    #define PID_REPLY2     0x7EA
    #define PID_REPLY3     0x7EB
    
    void setup() {
      Serial.begin(115200);
      delay(2000);
    
      Can0.setBaudRate(50000);  //set baud to 500K
      Can0.enableFIFO(1); // turn on fifo
      Can0.enableFIFOInterrupt(0); //  <---- interrupt off, we use pollFIFO // FIFO -------------->>>>>>>>
      Can0.onReceive(myMSG);
    
      msg_tx.flags.extended = 0;
      msg_tx.flags.remote = 0;
      msg_tx.len = 8;
      msg_tx.buf[3] = 0;
      msg_tx.buf[4] = 0;
      msg_tx.buf[5] = 0;
      msg_tx.buf[6] = 0;
      msg_tx.buf[7] = 0;
    
    }
    
    void loop() {
    
      static uint32_t _timer = millis();
      if ( millis() - _timer > 4000 ) {
        pinMode(13, OUTPUT); digitalWrite(13, !digitalRead(13));
        Serial.print("*HEARTBEAT* "); Serial.println(millis());
        _timer = millis();
      }
    
      //Send request for Engine RPMs
      msg_tx.id = PID_REQUEST;
      msg_tx.buf[0] = 0x02;
      msg_tx.buf[1] = 0x01;
      msg_tx.buf[2] = ENGINE_RPM;
    
      int msg_tx_status = Can0.write(msg_tx);
      while(Can0.read(msg_rx)){
        delay(1);
      }
      
    }
    
    void myMSG(const CAN_message_t &msg_rx) { // global callback
      char buffer[30];
      
      Serial.print("MB "); Serial.print(msg_rx.mb);
      Serial.print("  LEN: "); Serial.print(msg_rx.len);
      Serial.print(" EXT: "); Serial.print(msg_rx.flags.extended);
      Serial.print(" REMOTE: "); Serial.print(msg_rx.rtr);
      Serial.print(" TS: "); Serial.print(msg_rx.timestamp);
      Serial.print(" ID: "); Serial.print(msg_rx.id);
      Serial.print(" Buffer: ");
      for ( uint8_t i = 0; i < msg_rx.len; i++ ) {
        Serial.print(msg_rx.buf[i], HEX); Serial.print(" ");
      } Serial.println();
    
      float rpm =  ((msg_rx.buf[3]*256) + msg_rx.buf[4])/4;
      sprintf(buffer,"%d rpm ",(int) rpm);
      
    }
    Again this is just a test to see if it works


    Thanks
    Mike

  16. #41
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,003
    the read() function doesnt goto callback but you should check the id field of return before running sprintf as it could be any id, or the engine which is sending other data not just rpm (in case you did multiple requests)

    you can also request up to 3 engine datas in a single frame as well

    if youll use read() youll need to handle the data where the delay(1) is otherwise enable interrupt on FIFO in setup and you’ll get all car data in callback

  17. #42
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,003
    Update:

    Added FIFO filtering support, with automatic masking capability as well.

    Usage: (by default you have 8 filters for FIFO)
    Code:
    Can0.setFIFOFilter(REJECT_ALL); /* initially, we set all the filters to ignore all traffic */
    Can0.setFIFOFilter(0, 0x2C, STD); /* allow first filter to accept Standard ID 0x2C */
    Can0.setFIFOFilter(1, 0x2C, EXT); /* allow second filter to accept Extended ID 0x2C */
    Can0.setFIFOFilter(2, 1, 3, STD); /* allow 3rd filter to accept IDs 0x01 and 0x03, Standard ID */
    Can0.setFIFOFilterRange(3, 1, 11, EXT); /* allow the 4th filter to accept Extended ID range from 0x01 -> 0x0B */

  18. #43
    Senior Member+
    Join Date
    Jul 2014
    Location
    New York
    Posts
    3,228

    IFCT and ODD II Implementation?

    I did some mods to the sketch as a first test. I should be specifically printing Engine RPM but also dumping out all data in the call back:

    Code:
    #include <IFCT.h>
    
      CAN_message_t msg_tx; // setup a storage buffer
      CAN_message_t msg_rx; // setup a receive storage buffer
    
    #define ENGINE_COOLANT_TEMP 0x05   //returns 1 bytes, A-40, -40 to 215C 
    #define ENGINE_RPM          0x0C   //2 bytes, (256A+B)/4, 0-16,383.75 RPM
    #define VEHICLE_SPEED       0x0D   //1 byte, 0-255 km/h
    #define OIL_TEMP            0x5C   //calcluated value A-40, returns 1 byte,
                                       //range -40 to 210C, 
    #define ECM_Voltage         0x42   //2 bytes, 0-65.535, (256A+B)/1000
    
    char buffer[30];
    
    /*
      Response id from wiki article
        "Typically the engine or main ECU responds at ID 7E8h. 
        Other modules, like the hybrid controller or battery controller in a Prius, respond at 07E9, 07EA, 07EB, etc. "
    
      dta: 0x02, 0x01, PID_CODE
      1st byte Number ofadditionaldata bytes (SAE Standard)
      2nd byte is the Mode, for real time data you use Mode 14
      3rd byte is the PID_Code
      Bytes 4-8 value of the specified parameter starting at Byte 0
      
      See https://en.wikipedia.org/wiki/OBD-II_PIDs
    
      For recieve:
      byte 0: Number of additional data bytes: 3 to 6
      byte 1: Custom mode. Same as query, except that 40h is added to 
        the mode value. So: 41h = show current data;
        42h = freeze frame; etc.
      byte 2: PID code (e.g.: 05 = Engine coolant temperature)
      byte 3: value of the specified parameter, byte 0
      byte 4: value, byte 1 (optional)
      byte 5: value, byte 2 (optional)
      byte 6: value, byte 3 (optional)
      byte 7: not used (may be 00h or 55h)
      
    */  
    #define PID_REQUEST    0x7DF
    #define PID_REPLY0     0x7E8
    #define PID_REPLY1     0x7E9
    #define PID_REPLY2     0x7EA
    #define PID_REPLY3     0x7EB
    
    void setup() {
      Serial.begin(115200);
      delay(2000);
    
    
      Can0.setBaudRate(50000);  //set baud to 500K
      Can0.enableFIFO(1); // turn on fifo
      Can0.enableFIFOInterrupt(1); //  <---- interrupt off, we use pollFIFO // FIFO -------------->>>>>>>>
      Can0.setMB(MB0, TX);
      Can0.setMB(MB1, RX);
      Can0.setMB(MB2, RX);
      Can0.setMB(MB3, RX);
      
      Can0.onReceive(myMSG);
    
      msg_tx.flags.extended = 0;
      msg_tx.flags.remote = 0;
      msg_tx.len = 8;
      msg_tx.buf[3] = 0;
      msg_tx.buf[4] = 0;
      msg_tx.buf[5] = 0;
      msg_tx.buf[6] = 0;
      msg_tx.buf[7] = 0;
    
    }
    
    void loop() {
    
      static uint32_t _timer = millis();
      if ( millis() - _timer > 4000 ) {
        pinMode(13, OUTPUT); digitalWrite(13, !digitalRead(13));
        Serial.print("*HEARTBEAT* "); Serial.println(millis());
        _timer = millis();
      }
    
      //Send request for Engine RPMs
      msg_tx.id = PID_REQUEST;
      msg_tx.buf[0] = 0x02;
      msg_tx.buf[1] = 0x01;
      msg_tx.buf[2] = ENGINE_RPM;
    
      int msg_tx_status = Can0.write(msg_tx);
    
      while(Can0.read(msg_rx)){
        if(msg_rx.buf[2] == ENGINE_RPM){
          float rpm =  ((msg_rx.buf[3]*256) + msg_rx.buf[4])/4;
          sprintf(buffer,"%d rpm \n",(int) rpm);
        }
      }
    }
    
    void myMSG(const CAN_message_t &msg) { // global callback
      Serial.print("**** MB "); Serial.print(msg.mb);
      Serial.print("  LEN: "); Serial.print(msg.len);
      Serial.print(" EXT: "); Serial.print(msg.flags.extended);
      Serial.print(" REMOTE: "); Serial.print(msg.rtr);
      Serial.print(" TS: "); Serial.print(msg.timestamp);
      Serial.print(" ID: "); Serial.print(msg.id);
      Serial.print(" Buffer: ");
      for ( uint8_t i = 0; i < msg_rx.len; i++ ) {
        Serial.print(msg.buf[i], HEX); Serial.print(" ");
      } Serial.println();
     
    }

  19. #44
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,003
    setMB wont work on FIFO unless the MB’s are above or equal to MB8, FIFO takes over the first 8 mailboxes

    your write will actually be going out MB8 since its first transmit mailbox, MB0 wasnt set because its owned by FIFO
    Also because of this, you dont have any actual reception mailboxes, so fifo gets your ids and itll goto the interrupt callback, read() is not actually working at all since it doesnt touch interrupt driven fifo or mailboxes

    what you could do to collect ECU data in a single mailbox is:

    Code:
    Can0.setMB(8,RX); /* standard id collection mailbox */
    Can0.setMBFilterRange(MB8,0x7DF,7EB) /* accept that data range */
    Can0.enableMBInterrupt(MB8); /* enable MB interrupt */
    This would get ECU specific data to your callback before it enters the FIFO

  20. #45
    Senior Member+
    Join Date
    Jul 2014
    Location
    New York
    Posts
    3,228
    setMB wont work on FIFO unless the MB’s are above or equal to MB8, FIFO takes over the first 8 mailboxes
    Ok guess I had it backwards thought it was the other way around. So,
    Code:
     MB 0 - 5 are FIFO
    MB6-7 are for FIFO filter
    and finally
    MB 8-15 are free.

    Think I will do it the way you suggested and give it a whirl. Would recommend using events as well?


    Mike

    EDIT: Guess I will have to remember a couple of other things as well:
    1. setMRP(0) will have FIFO filters processed before mailboxes, 1 has MB processed first which is default
    2. setRFFN sets the number of filters with a max of 32. I'll let u explain this when u implement the function
    Last edited by mjs513; 07-02-2018 at 05:06 PM.

  21. #46
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,003
    yes events() will enable the queue system to clear the mailbox faster in case your callbacks take too long in processing, the design might change a bit but events() most likely will stay.

  22. #47
    Senior Member+
    Join Date
    Jul 2014
    Location
    New York
    Posts
    3,228
    Hi Tony.

    Finally got it working on the receive side now to test the tx side.

    I wrote a small test sketch for the T3.5 that sends the RPM PID every heartbeat and random data every 500ms:
    Code:
    #include <IFCT.h>
    
    CAN_message_t msg; // setup a storage buffer
    
    void setup() {
      Serial.begin(115200);
      delay(2000);
      
        Serial.println("-- ODBII Test --");
        Serial.println();
    
    }
    
    void loop() {
    
      static uint32_t _timer0 = millis();
      if ( millis() - _timer0 > 500 ) {
      delay(20);
    
      msg.flags.extended = 0;
      msg.flags.remote = 0;
      msg.len = 8;
      msg.id = 0x7E8;
      msg.buf[0] = 0x02;
      msg.buf[1] = 0;
      msg.buf[2] = random(0, 255);
      msg.buf[3] = random(0, 255);
      msg.buf[4] = random(0, 255);
      msg.buf[5] = random(0, 255);
      msg.buf[6] = random(0, 255);
      msg.buf[7] = random(0, 255);
      Can0.write(msg);
      _timer0 = millis();
      }
    
      static uint32_t _timer = millis();
      if ( millis() - _timer > 4000 ) {
        pinMode(13, OUTPUT); digitalWrite(13, !digitalRead(13));
        Serial.print("*HEARTBEAT* "); Serial.println(millis());
        //Can0.mailboxStatus();
        msg.flags.extended = 0;
        msg.flags.remote = 0;
        msg.len = 8;
        msg.id = 0x7E8;
        msg.buf[0] = 0x02;
        msg.buf[1] = 0;
        msg.buf[2] = 0x0C;
        msg.buf[3] = 0x10;
        msg.buf[4] = 0x15;
        msg.buf[5] = 0;
        msg.buf[6] = 0;
        msg.buf[7] = 0;
        Can0.write(msg);
        //Can0.mailboxStatus();
        _timer = millis();
      }
    
    }
    On the master side I incorporated your changes:
    Code:
    #include <IFCT.h>
    
      CAN_message_t msg_tx; // setup a storage buffer
      CAN_message_t msg; // setup a receive storage buffer
    
    #define ENGINE_COOLANT_TEMP 0x05   //returns 1 bytes, A-40, -40 to 215C 
    #define ENGINE_RPM          0x0C   //2 bytes, (256A+B)/4, 0-16,383.75 RPM
    #define VEHICLE_SPEED       0x0D   //1 byte, 0-255 km/h
    #define OIL_TEMP            0x5C   //calcluated value A-40, returns 1 byte,
                                       //range -40 to 210C, 
    #define ECM_Voltage         0x42   //2 bytes, 0-65.535, (256A+B)/1000
    
    /*
      Response id from wiki article
        "Typically the engine or main ECU responds at ID 7E8h. 
        Other modules, like the hybrid controller or battery controller in a Prius, respond at 07E9, 07EA, 07EB, etc. "
    
      dta: 0x02, 0x01, PID_CODE
      1st byte Number ofadditionaldata bytes (SAE Standard)
      2nd byte is the Mode, for real time data you use Mode 14
      3rd byte is the PID_Code
      Bytes 4-8 value of the specified parameter starting at Byte 0
      
      See https://en.wikipedia.org/wiki/OBD-II_PIDs
    
      For recieve:
      byte 0: Number of additional data bytes: 3 to 6
      byte 1: Custom mode. Same as query, except that 40h is added to 
        the mode value. So: 41h = show current data;
        42h = freeze frame; etc.
      byte 2: PID code (e.g.: 05 = Engine coolant temperature)
      byte 3: value of the specified parameter, byte 0
      byte 4: value, byte 1 (optional)
      byte 5: value, byte 2 (optional)
      byte 6: value, byte 3 (optional)
      byte 7: not used (may be 00h or 55h)
      
    */  
    #define PID_REQUEST    0x7DF
    #define PID_REPLY0     0x7E8
    #define PID_REPLY1     0x7E9
    #define PID_REPLY2     0x7EA
    #define PID_REPLY3     0x7EB
    
    void setup() {
      Serial.begin(115200);
      delay(2000);
    
      //Can0.setBaudRate(50000);  //set baud to 500K
      Can0.enableFIFO(1);
      Can0.setMB(MB8,RX); /* standard id collection mailbox */
      Can0.setMBFilterRange(MB8,0x7DF,0x7EB); /* accept that data range */
      Can0.enableMBInterrupt(MB8); /* enable MB interrupt */
    
      Can0.onReceive(MB8, myMSG);
    
      msg_tx.flags.extended = 0;
      msg_tx.flags.remote = 0;
      msg_tx.len = 8;
      msg_tx.buf[3] = 0;
      msg_tx.buf[4] = 0;
      msg_tx.buf[5] = 0;
      msg_tx.buf[6] = 0;
      msg_tx.buf[7] = 0;
    
    }
    
    void loop() {
      Can0.events();
      static uint32_t _timer = millis();
      if ( millis() - _timer > 4000 ) {
        pinMode(13, OUTPUT); digitalWrite(13, !digitalRead(13));
        Serial.print("*HEARTBEAT* "); Serial.println(millis());
        _timer = millis();
      }
    
      //Send request for Engine RPMs
      msg_tx.id = PID_REQUEST;
      msg_tx.buf[0] = 0x02;
      msg_tx.buf[1] = 0x01;
      msg_tx.buf[2] = ENGINE_RPM;
    
      //int msg_tx_status = Can0.write(msg_tx);
    
    }
    
    void myMSG(const CAN_message_t &msg) { // global callback
      Serial.print("**** MB "); Serial.print(msg.mb);
      Serial.print("  LEN: "); Serial.print(msg.len);
      Serial.print(" EXT: "); Serial.print(msg.flags.extended);
      Serial.print(" REMOTE: "); Serial.print(msg.rtr);
      Serial.print(" TS: "); Serial.print(msg.timestamp);
      Serial.print(" ID: "); Serial.print(msg.id);
      Serial.print(" Buffer: ");
      for ( uint8_t i = 0; i < msg.len; i++ ) {
        Serial.print(msg.buf[i], HEX); Serial.print(" ");
      } Serial.println();
    
      if(msg.buf[2] == ENGINE_RPM){
          float rpm =  ((msg.buf[3]*256) + msg.buf[4])/4;
          Serial.println(rpm);
      }
    }
    it basically reads the stream data from T3.5 and prints the RPM when it gets encountered.


    Code:
    *HEARTBEAT* 6301
    **** MB 8  LEN: 8 EXT: 0 REMOTE: 0 TS: 25917 ID: 2024 Buffer: 2 0 D 8A 7 C8 EE 35 
    **** MB 8  LEN: 8 EXT: 0 REMOTE: 0 TS: 22636 ID: 2024 Buffer: 2 0 E5 F1 49 A0 36 98 
    **** MB 8  LEN: 8 EXT: 0 REMOTE: 0 TS: 48962 ID: 2024 Buffer: 2 0 C 10 15 0 0 0 
    RPM: 1029.00
    **** MB 8  LEN: 8 EXT: 0 REMOTE: 0 TS: 19354 ID: 2024 Buffer: 2 0 8 FE 47 85 47 E0 
    **** MB 8  LEN: 8 EXT: 0 REMOTE: 0 TS: 16071 ID: 2024 Buffer: 2 0 5 E2 D0 84 24 D7 
    **** MB 8  LEN: 8 EXT: 0 REMOTE: 0 TS: 12789 ID: 2024 Buffer: 2 0 45 FB A5 EF B6 19 
    **** MB 8  LEN: 8 EXT: 0 REMOTE: 0 TS: 9509 ID: 2024 Buffer: 2 0 7 45 1F 86 7A B7 
    **** MB 8  LEN: 8 EXT: 0 REMOTE: 0 TS: 6227 ID: 2024 Buffer: 2 0 5E 58 2B 55 41 E9 
    *HEARTBEAT* 10302
    **** MB 8  LEN: 8 EXT: 0 REMOTE: 0 TS: 2945 ID: 2024 Buffer: 2 0 2C 9F 1F E4 33 FD 
    **** MB 8  LEN: 8 EXT: 0 REMOTE: 0 TS: 65200 ID: 2024 Buffer: 2 0 40 D6 94 A0 CD 5D 
    **** MB 8  LEN: 8 EXT: 0 REMOTE: 0 TS: 61917 ID: 2024 Buffer: 2 0 F0 B4 77 99 C1 34 
    **** MB 8  LEN: 8 EXT: 0 REMOTE: 0 TS: 52312 ID: 2024 Buffer: 2 0 C 10 15 0 0 0 
    RPM: 1029.00
    **** MB 8  LEN: 8 EXT: 0 REMOTE: 0 TS: 58635 ID: 2024 Buffer: 2 0 16 3B 46 D7 2D 38 
    **** MB 8  LEN: 8 EXT: 0 REMOTE: 0 TS: 55353 ID: 2024 Buffer: 2 0 F1 C7 28 C B4 61 
    **** MB 8  LEN: 8 EXT: 0 REMOTE: 0 TS: 52070 ID: 2024 Buffer: 2 0 48 28 C6 52 E B8 
    **** MB 8  LEN: 8 EXT: 0 REMOTE: 0 TS: 48786 ID: 2024 Buffer: 2 0 C5 75 75 2A CF CE 
    **** MB 8  LEN: 8 EXT: 0 REMOTE: 0 TS: 45503 ID: 2024 Buffer: 2 0 1E 62 4D 2C BF 98 
    *HEARTBEAT* 14303
    Will play with it some more later.

  23. #48
    Senior Member+
    Join Date
    Jul 2014
    Location
    New York
    Posts
    3,228

    IFCT and ODD II Implementation

    Hi all

    After a frustrating day getting the connector wiring wrong and dealing with the heat I finally was able to get obd data from the Hyundai Sonata 2006. Had to restructure the sketch to accept all MB though. Unfortunately the data doesn't make any sense to me when compared to the standard. Here is a sample:
    Code:
    **** MB 0  LEN: 8 EXT: 0 REMOTE: 0 TS: 35261 ID: 1349 Buffer: DC 2E 0 8C A5 0 A6 0 
    **** MB 0  LEN: 8 EXT: 0 REMOTE: 0 TS: 35376 ID: 672 Buffer: 8 0 66 1C 14 1 15 0 
    **** MB 0  LEN: 8 EXT: 0 REMOTE: 0 TS: 35495 ID: 608 Buffer: 36 36 36 28 FF EA 0 0 
    **** MB 0  LEN: 8 EXT: 0 REMOTE: 0 TS: 35613 ID: 1695 Buffer: 3C 71 0 0 0 0 0 0 
    **** MB 0  LEN: 8 EXT: 0 REMOTE: 0 TS: 53736 ID: 608 Buffer: 36 36 36 28 FF EA 0 0 
    **** MB 0  LEN: 8 EXT: 0 REMOTE: 0 TS: 53854 ID: 1087 Buffer: 0 40 50 FE 46 BB C 0 
    **** MB 0  LEN: 8 EXT: 0 REMOTE: 0 TS: 53973 ID: 1088 Buffer: FF FF 0 AA AA AA AA AA 
    **** MB 0  LEN: 8 EXT: 0 REMOTE: 0 TS: 55055 ID: 339 Buffer: 0 21 0 FF 0 FF 0 0 
    **** MB 0  LEN: 8 EXT: 0 REMOTE: 0 TS: 57185 ID: 790 Buffer: 45 36 8F D 36 28 0 7C 
    **** MB 0  LEN: 8 EXT: 0 REMOTE: 0 TS: 57299 ID: 809 Buffer: B 98 7F 8 11 2E 0 21 
    **** MB 0  LEN: 8 EXT: 0 REMOTE: 0 TS: 57416 ID: 640 Buffer: 10 0 84 98 1B 1D 66 4E
    This is a snippet but the grouping seems to keep repeating.

    Thanks
    Mike

  24. #49
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,003
    Yup, thats normal. The groupings and repetitive broadcasts are normal, this shows your connections are fine. The data you see is the traffic scrolling off the multiple modules on the car, not just the ECU.

    You could now talk to the ECU provided its the correct 11/29bit identifier or even parse the live traffic in the stream (which needs to be decoded(lots of patience)), it definately contains RPM data, speedometer, and many other things, even a bit for the AC compressor status is there too (at least on mine)

  25. #50
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,003
    Hello all, I've updated the library to support FIFO filtering tables B & C, auto masking is done with Tables A & B, I omitted to include auto masking for TableC as since all extended and standard IDs are partial, it would make no sense really.

    As per the datasheet:

    RXIDA
    — Rx Frame Identifier (Format A)
    Specifies an ID to be used as acceptance criteria for the FIFO. In the standard frame
    format, only the 11 most significant bits (29 to 19) are used for frame identification. In
    the extended frame format, all bits are used.
    RXIDB_0, RXIDB_1
    — Rx Frame Identifier (Format B)
    Specifies an ID to be used as acceptance criteria for the FIFO. In the standard frame
    format, the 11 most significant bits (a full standard ID) (29 to 19 and 13 to 3) are used for
    frame identification. In the extended frame format, all 14 bits of the field are compared to
    the 14 most significant bits of the received ID.
    RXIDC_0, RXIDC_1, RXIDC_2, RXIDC_3
    — Rx Frame Identifier (Format C)
    Specifies an ID to be used as acceptance criteria for the FIFO. In both standard and
    extended frame formats, all 8 bits of the field are compared to the 8 most significant bits
    of the received ID.
    In the library, tables A & B support range based ID inputs in the library, TableC accepts 4 ID's extended or standard
    You can still use mailbox filtering for mailboxes above the FIFO table that are available.

Posting Permissions

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