CAN Bus : Reading PID - Buffer Issues?

ARDU MEGA2560
SEEED CAN Shield
ADRU IDE 1.8
Library: https://travis-ci.com/Seeed-Studio/CAN_BUS_Shield.svg?branch=master

Hello all,

I'm stuck on what seems to be an easy issue, however not so easy for me. My Hadrware
and program are working fine when requesting a single PID (0x0C, engine RPM).

The problem begins when I try to access multiple PIDs; the data becomes erratic.

Single PID Code and Output are perfect:

#include <SPI.h>
#include "mcp_can.h"

int pidCounter;
unsigned char len = 0;
unsigned char buf[8];


MCP_CAN CAN(9);     // Set CS pin

#define PID_ENGIN_PRM       0x0C
#define PID_VEHICLE_SPEED   0x0D
#define PID_COOLANT_TEMP    0x05
#define CAN_ID_PID          0x7DF


void set_mask_filt(){
    
    //    set mask, set both the mask to 0x3ff
    CAN.init_Mask(0, 0, 0x7FC);
    CAN.init_Mask(1, 0, 0x7FC);

    // set filter, we can receive id from 0x04 ~ 0x09
    CAN.init_Filt(0, 0, 0x7E8);
    CAN.init_Filt(1, 0, 0x7E8);
    CAN.init_Filt(2, 0, 0x7E8);
    CAN.init_Filt(3, 0, 0x7E8);
    CAN.init_Filt(4, 0, 0x7E8);
    CAN.init_Filt(5, 0, 0x7E8);
}


void setup() {
   Serial.begin(115200);
   CAN.begin(CAN_500KBPS); 
   set_mask_filt();
}


void loop() {
    
    unsigned char tmp[8] = {0x02, 0x01, 0x0C, 0, 0, 0, 0, 0};   //engine RPM
    CAN.sendMsgBuf(0x7DF, 0, 8, tmp); 
    CAN.readMsgBuf(&len, buf);                                          // read data,  len: data length, buf: data buf

        Serial.print(pidCounter);  Serial.print(',');
        Serial.print(buf[0], DEC);   Serial.print(','); 
        Serial.print(buf[1], DEC);   Serial.print(',');
        Serial.print(buf[2], DEC);   Serial.print(',');
        Serial.print(buf[3], DEC);   Serial.print(',');
        Serial.print(buf[4], DEC);   Serial.print(',');
        Serial.print(buf[5], DEC);   Serial.print(',');
        Serial.print(buf[6], DEC);   Serial.print(',');
        Serial.println(buf[7], DEC);       
       
}

Serial Monitor Output:
0 4 12 14
0 4 12 14
0 4 12 14
0 4 12 14
0 4 12 14

This is the code for multi-PID requests

#include <SPI.h>
#include "mcp_can.h"

int pidCounter;
unsigned char len = 0;
unsigned char buf[8];

unsigned char PID_INPUT;
unsigned char getPid = 0;
    

MCP_CAN CAN(9);                                    // Set CS pin

#define PID_ENGIN_PRM       0x0C
#define PID_VEHICLE_SPEED   0x0D
#define PID_COOLANT_TEMP    0x05
#define CAN_ID_PID          0x7DF


void set_mask_filt() {
    /*
        set mask, set both the mask to 0x3ff
    */
    CAN.init_Mask(0, 0, 0x7FC);
    CAN.init_Mask(1, 0, 0x7FC);

    /*
        set filter, we can receive id from 0x04 ~ 0x09
    */
    CAN.init_Filt(0, 0, 0x7E8);
    CAN.init_Filt(1, 0, 0x7E8);

    CAN.init_Filt(2, 0, 0x7E8);
    CAN.init_Filt(3, 0, 0x7E8);
    CAN.init_Filt(4, 0, 0x7E8);
    CAN.init_Filt(5, 0, 0x7E8);
}


void setup(){
   Serial.begin(115200);
   CAN.begin(CAN_500KBPS); 
   set_mask_filt();
}


void loop() {
    
    
   if(pidCounter == 1){  unsigned char tmp[8] = {0x02, 0x01, 0x0C, 0, 0, 0, 0, 0};  CAN.sendMsgBuf(0x7DF, 0, 8, tmp); }
    else if(pidCounter == 2){ unsigned char tmp[8] = {0x02, 0x01, 0x00, 0, 0, 0, 0, 0};   clearBuf(); }
     else if(pidCounter == 3){ unsigned char tmp[8] = {0x02, 0x01, 0x0D, 0, 0, 0, 0, 0};   CAN.sendMsgBuf(0x7DF, 0, 8, tmp); }
      else if(pidCounter == 4){ unsigned char tmp[8] = {0x02, 0x01, 0x00, 0, 0, 0, 0, 0};  clearBuf(); }
       else if(pidCounter == 5){ unsigned char tmp[8] = {0x02, 0x01, 0x05, 0, 0, 0, 0, 0};   CAN.sendMsgBuf(0x7DF, 0, 8, tmp); }
        else if(pidCounter == 6){ unsigned char tmp[8] = {0x02, 0x01, 0x00, 0, 0, 0, 0, 0};   clearBuf(); }
         else clearBuf();             
    
   
    CAN.readMsgBuf(&len, buf);                                          // read data,  len: data length, buf: data buf

        Serial.print(pidCounter);  Serial.print(',');
        Serial.print(buf[0], DEC);   Serial.print(','); 
        Serial.print(buf[1], DEC);   Serial.print(',');
        Serial.print(buf[2], DEC);   Serial.print(',');
        Serial.print(buf[3], DEC);   Serial.print(',');
        Serial.print(buf[4], DEC);   Serial.print(',');
        Serial.print(buf[5], DEC);   Serial.print(',');
        Serial.print(buf[6], DEC);   Serial.print(',');
        Serial.println(buf[7], DEC);       
       
  pidCounter++;
  if(pidCounter > 6) pidCounter = 0;
 
  clearBuf();
        
}

void clearBuf(){

 buf[0] = '0';
 buf[1] = '0';
 buf[2] = '0';
 buf[3] = '0';
 buf[4] = '0';
 buf[5] = '0';
 buf[6] = '0';
 buf[7] = '0'; 
}

Now the array elements begin to shift as you see in this output scan:

1,48,48,48,48,48,48,48,48
1,3,65,5,123,170,170,170,170
1,3,65,5,123,170,170,170,170
1,3,65,5,123,170,170,170,170
1,48,48,48,48,48,48,48,48
1,3,65,5,123,170,170,170,170

every time pidCounter == 1, the 0x0C PID is sent, then buf is read and printed.
The next pidCounter cycle attempts to send 0x00, the clearBuf() sets the array to zeros.

You will notice I tried to add my own function to clear the buffer [clearBuf()].
Then an attempt was made to add rows to call a PID of 0x00 to wipe the contents
I even tried increasing the counter "spacing" to give the Engine ECU time to respond.

Nothing I've tried is working, and I'm out of ideas and programming knowledge.

Even if I simplify to the following, I get a similar random output:

  if(pidCounter == 1){  unsigned char tmp[8] = {0x02, 0x01, 0x0C, 0, 0, 0, 0, 0};  CAN.sendMsgBuf(0x7DF, 0, 8, tmp); }
     else if(pidCounter == 3){ unsigned char tmp[8] = {0x02, 0x01, 0x0D, 0, 0, 0, 0, 0};   CAN.sendMsgBuf(0x7DF, 0, 8, tmp); }
       else if(pidCounter == 5){ unsigned char tmp[8] = {0x02, 0x01, 0x05, 0, 0, 0, 0, 0};   CAN.sendMsgBuf(0x7DF, 0, 8, tmp); }
         else clearBuf();             
    
   
    CAN.readMsgBuf(&len, buf);                                          // read data,  len: data length, buf: data buf

I know I can use an array and counter to change the PID, instead of assigning the char array for each PID send, but that doesn't solve the problem.

Any tips in the proper direction would be appreciated.
Thanks!

Cars are very independent and will respond in due time when they feel like it and at what order they feel like it. Also note other messages are also on the bus with higher and lower priorities. Doing one at a time is the safest and most reliable method. Some of the information you are requesting may be in another message.

Thanks for the message Gilshutz.

This code specifically queries the Engine ECU for a specific PID, and the response returns fairly quickly.

The problem is not the response time , but rather the transition from one PID to another

For example going from Engine RPM to Engine Temperature causes some of the buffer data to be shifted because RPM is 2 bytes and Temperature is 1 byte.

My main concern is clearing/resetting the buffer before the next PID is requested. I thought my clearBuf() function would do the job, but the data still shows random values.

Do you have any experience with clearing char type buffers/arrays?

Yes I clear buffers but slightly differently, I use a 0x00 not a '0'. The '0' is an ASCII zero with the value of 0x30. I have a feeling the unwanted characters are from this. I Normally do not clear the receive buffer, I just read the values I need, save them before processing them and ignore all the others in the buffer.

Good call on the buffer clearing. I switched to 0x00 from '0' and no issues for stray data.
I call the clearBuf() function before polling the ECU; data is crystal clear.

Also found an error in the byte order for one of the calculations which was messing me up.

Thanks for the tips !

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.