OBD2 example code - solved

#1

We’re working on a little demo project on a `16 Ford Fiesta. @CollinK was kind enough to make this example sketch to spit out a handful of OBD2 PIDs to the terminal. The code works great on a '08 Buick, but not the Fiesta.

Anyone else want to try out on their car or have some suggestions for what to try next?

Here is the code:

#include <due_can.h>

uint8_t codes[4] = {5, 0xB, 0xC, 0xD};
int idx = 0;
uint32_t tick = 0;

void sendPIDRequest(uint32_t id, uint8_t PID)
{
   CAN_FRAME frame;
   frame.id = id;
   frame.length = 8;
   for (int i = 0; i < 8; i++) frame.data.bytes[i] = 0xAA;
   frame.data.bytes[0] = 2; //2 more bytes to follow
   frame.data.bytes[1] = 1;
   frame.data.bytes[2] = PID;
   Can0.sendFrame(frame);
}

void processPID(CAN_FRAME &frame)
{
   int temperature;
   float psi;
   int RPM;
   int MPH;
   
   if (frame.data.bytes[1] != 0x41) return; //not anything we're interested in then
   switch (frame.data.bytes[2])
   {
   case 5:
      temperature = frame.data.bytes[3] - 40;
      SerialUSB.print("Coolant temperature (C): ");
      SerialUSB.println(temperature);
      break;
   case 0xB:
      psi = frame.data.bytes[3] * 0.145038; //kPA to PSI
      SerialUSB.print("Manifold abs pressure (psi): ");
      SerialUSB.println(psi);      
      break;
   case 0xC:
      RPM = ((frame.data.bytes[3] * 256) + frame.data.bytes[4])/4;
      SerialUSB.print("Engine RPM: ");
      SerialUSB.println(RPM);            
      break;
   case 0xD:
      MPH = frame.data.bytes[3] * 0.621371;
      SerialUSB.print("Vehicle Speed (MPH): ");
      SerialUSB.println(MPH);
      break;
   }
}

void setup() {
  Can0.begin(CAN_BPS_500K);
  int filter;
  //extended
  for (filter = 0; filter < 3; filter++) {
  Can0.setRXFilter(filter, 0, 0, false);
  Can1.setRXFilter(filter, 0, 0, false);
  }  
}

void loop() {
   CAN_FRAME incoming;

   if (Can0.available() > 0) {
      Can0.read(incoming);
      if (incoming.id > 0x7DF && incoming.id < 0x7F0)
      {
         processPID(incoming);
      }    
   }

   //every second rotate to a new code and send it. Hopefully something replies
   if (millis() > (tick + 1000) )
   {
       tick = millis();
       sendPIDRequest(0x7DF, codes[idx]);
       idx = (idx + 1) % 4;
       SerialUSB.println(".");
   }
}

Couple things we’re going to try next:

  1. Send “tester present” messages periodically like this:
CAN_FRAME frame;
frame.id = 0x7DF;
frame.length = 8;
frame.data.bytes[0] = 2;
frame.data.bytes[1] = 0x3E;
frame.data.bytes[2] = 0;
Can0.sendFrame(frame);
  1. Target the first ECU address directly in case it doesn’t respond to the broadcast address. In that case turn 0x7DF to 0x7E0 and try 0x7E1 through 0x7E8 too.
#2

you need to continuously sent tester present message when you are doing OBD2 requests on GM vehicles. if not you have to reinitialize the request sequence all over again to get another answer.

#3

Quick update - we’ve got it figured out now. Had to change from 29-bit to 11-bit frame by adding this line:

frame.extended = 0;

To this code as shown here:

void sendPIDRequest(uint32_t id, uint8_t PID)
{
  CAN_FRAME frame;
  frame.id = id;
  frame.extended = 0;
  frame.length = 8;
  for (int i = 0; i < 8; i++) frame.data.bytes[i] = 0xAA;
  frame.data.bytes[0] = 2; //2 more bytes to follow
  frame.data.bytes[1] = 1;
  frame.data.bytes[2] = PID;
  Can0.sendFrame(frame);
}