Wrote an electronic fuel injection simulation where events are queued up to control the on-off states of injectors and coils. The timer interrupt intervals vary and because of changes in rpm, the next event time is not calculated until it is at the head of the queue. The main loop is busy collecting sensor inputs and calculating a new schedule.
My goal has been 1 us precision at 22k rpm's since this is the maximum rpm's I could find for an engine. With 8 cylinders, that would be 32 events within a 2.73 ms period. At 1000 rpm it is 60 ms to give an idea of the range. The error rates do appear acceptable up to the typical requirement of 7000 rpm, but the error increases significantly above that. Event times vary with inputs and can sometimes stack up on their own.
I subtract a slop time from the interval to account for cpu overhead, the isr execution time, and recent isr contention. The slop is adjusted based on late frequency. Timers.cpp contains implementations for the Due and the Mega here:
Defining TIMER_TEST will cause the timers to wakeup, compute a fixed interval and sleep for the time in handleTimer. The minimum slop I get for the Due is 6 us, the Mega runs between 30-40 if I recall correctly. It is pretty easy to setup the timer test mode. Set serial to 115200 and type 'i' to see what the timer interrupts are up to.
Here are some stats from the program in test mode:
timer:{id= 4 idx= 0 slop= 7 sleep= 897 asleep= 895 -awake= 2 +awake= 4 -late= -3 +late= 7 retest= 207 late= 0.38 hist:{0=2110 5=2110 6=2111 7=2054 8=8}}
timer:{id= 5 idx= 1 slop= 14 sleep= 897 asleep= 887 -awake= 2 +awake= 4 -late= -10 +late= -1 retest= 177 hist:{0=2118 5=2118 6=2118 7=2074}}
This is timers 4 & 5, the sleep interval was 900 us, and they are pretty much always early. I believe what is going on is that #4 gets a higher priority, and is not late very often, in fact it was late only 7 times out of 2110 events, probably because #5 got ahead. #4 gets in front of #5 enough that it has adjusted the slop factor to compensate and was never late in the last 2118 events. Early is a marginal improvement over late, and in order to never be late, the timers are more than 1 us early 2054 and 2074 times respectively. The awake time is 2-4 us, and some of that is definitely overhead from the stats I am tracking.
When enabled, the two efi related isr's take 10 and 20 us on the Due, but events don't overlap as much at lower rpm's so the slop times often start at 6. The longer execution times with interrupt queuing is my principal source of worse case jitter so I have tried to reduce the isr times and call overhead as much as possible.
The oem computer is running at 16 mhz, and seems like I should be able to match it with a Mega and the Due should be a no-brainer. Unfortunately I do not know what level of accuracy it had so I may already be ahead.
Can I get a less jitter out of the timers other than removing my metrics?
Are there performance advantages at all to using a prescaler when possible?
The DueTimer library always tries to pick the largest prescaler .. with a downside. The slop required to keep DueTimer on time went to 120 us, likely because of all the floating point recalculations each time you start a timer .. that could be substantially optimized.