I think I've narrowed down almost all my issues to the RPM polling failing every other pass on certain screens. After some investigation it appears the ECU is becoming "lethargic" if it is not polled every so often, and this is causing rpm polling in verifyECUAlive() to timeout, resulting in ECUconnection toggling back and forth (the next polling of RPM succeeds). This is happening for me on screen 3 which are all calculated PIDs, and screen 1 in certain instances. This may be an idiosyncracy of the VW ECU, but it causes numerous problems, most intrusive of which is saving trip data every other tick of loop(). I also think it's why reinit from inside the main loop fails when it otherwise succeeds in setup().
I was wondering if anyone has ever seen this or would have any documentation that might reference communication timeouts. That, or really any good reading on 9141-2 would be appreciated - the last URL I saw in this thread gives me a 404.
One other item I ran into that I wonder if worth investigating. In iso_read_data() there's a delay happening to ensure the program waits a sufficient amount of time before polling the ECU again after a read.
Code:
// we send only one command, so result start at buf[4] Actually, result starts at buf[5], buf[4] is pid requested...
memcpy(data, buf+5, len);
delay(ISORequestDelay); //guarantee 55 ms pause between requests
return dataSize - 6; // return payload length
Wouldn't it be a little more efficient to use a timeout mechanism here so the program can be doing other things while the delay expires? Something like:
Code:
// we send only one command, so result start at buf[4] Actually, result starts at buf[5], buf[4] is pid requested...
memcpy(data, buf+5, len);
static long lastRcv=millis();
return dataSize - 6; // return payload length
and then in get_pid() something like...
Code:
cmd[0]=0x01; // ISO cmd 1, get PID
cmd[1]=pid;
long nowms=millis();
while ((nowms - ISORequestDelay) < lastRcv)
{
delay(1);
nowms=millis();
}
// send command, length 2
iso_write_data(cmd, 2);
Lastly, is my understanding of PID caching correct to state that it's really only useful for PIDs that the program will be polling for the fuel calculations and displaying simultaneously (i.e. MAF or VSS)? If so, assuming that no-one would want to display the same PID more than once on a screen, why not just store the ones that are going to be polled each tick in accu_trip() and verifyECUAlive(), i.e. RPM, VSS, MAF, etc. Then add a boolean parameter to get_pid() to signify whether to force ECU polling or just return the cached value. This is what I've tried and it seems to work well.
Code:
boolean get_pid(byte pid, boolean noncrit, char *retbuf, long *ret)
{
<code removed for brevity>
long tmpVal;
boolean cache_hit=false;
<code removed for brevity>
if(delta_time>1000)
{
nbpid_per_second=nbpid;
nbpid=0;
getpid_time=time_now;
}
if (noncrit)
{
// if true return previously read values for display
switch(pid)
{
case ENGINE_RPM:
// disclaimer: i've modified the program to store the full RPM value in a long
sprintf_P(retbuf, PSTR("%ld RPM"), rpm);
cache_hit=true;
break;
case MAF_AIR_FLOW:
long_to_dec_str(maf, decs, 2);
sprintf_P(retbuf, PSTR("%s g/s"), decs);
cache_hit=true;
break;
case VEHICLE_SPEED:
tmpVal=vss;
if(!params.use_metric)
tmpVal=(tmpVal*1000U)/1609U;
sprintf_P(retbuf, pctldpcts, tmpVal, params.use_metric?"\003\004":"\006\004");
cache_hit=true;
break;
}
if (cache_hit=true;)
return true;
}
Then, anywhere we want to force ECU polling for fresh data such as in accu_trip() change the call to: get_pid(PID_NAME,
false, ....) and make all calls from the display() routine use get_pid(PID_NAME,
true, ....)
I don't know if either of these will significantly effect program size, but I do think they'll free up some processor time that was otherwise spent stepping through the pid cache once cell at a time or counting sheep in delay().
I'm very rusty with avr_gcc, and an Arduino newb so I might be making some really erroneous assumptions. Please don't hesitate to correct me - I'm here to learn.