While trying to generate pulses, few millisecs to few seconds apart using timer1 CTC interrupts, I noticed that
the timing accuracies are way off initially, inaccuracies are also affected by pre-scaler used. As a scope is not
available, I tried using millis() :-[ to measure a bunch of (practically empty) timer ISR calls.
Following test program repeatedly causes 10 ISR for a specific delay setup timer1 at 1024 prescaler
CTC mode and reports the total time taken on serial monitor. The pulse delay is set using "stepGap" variable,
Compile/Uploaded to ArduMega and open serial monitor to see results ( do this for each / any of the delay
values used below). Close serial monitor change value of "stepGap" and repeat again.
The "stepGap" values used were 30 (1.9ms) , 60(3.8 ms), 120, 7812 (0.5 sec), 1564 ( 1 sec), was expecting the total
time period to be off by 1-5 ms, however the first iteration of 10 pulses is way way off. What am I missing?
As the delay value is increased the total time taken over shoots by several 100's of ms. Why does this happen?
volatile int stepsRequired = 10; //number of pulses required in one iteration
volatile unsigned int stepGap = 7812;//15624,30,60,120 ORC1A count at 1024 prescaler. Multiply with 64us to get timer period
volatile unsigned long lastRecTime = 0;
volatile byte once = 1;
void setup()
{
Serial.begin(115200);
sei();
}
void loop()
{
//do once
if(once == 1)
{
if((millis() - lastRecTime) > 1000) //some gap between reading
{
startPulsing();
once = 2;
}
}
if(once == 3)
{
//create messages
lastRecTime = millis()-lastRecTime;//give almost identical results even if the calculation happens inside ISR
Serial.print((lastRecTime), DEC);
Serial.print(" ms for ");
stepsRequired = 10;
Serial.print(stepsRequired,DEC);
Serial.print(" pulses, Each pulse set for ");
float pulse_time = ((stepGap+1)*0.064);
Serial.print(pulse_time , 2);
Serial.print(" ms (Total) ");
Serial.println(pulse_time*10 , 2);
lastRecTime = millis();
//once = 4;//stop after one run
once = 1; // so that we can start all over again
}
}
void startPulsing()
{
//start the timers
//TCNT1 = 0;
TCCR1A = 0;
TCCR1B = 0;
OCR1B = 0;
OCR1A = stepGap;
TIFR1 = 0;//reset any previous unserviced interrupts
lastRecTime = millis(); //store the starting count
TCCR1B |= (1<<WGM12);//enable CTC Mode
TIMSK1 |= (1<<OCIE1A) ;
TCCR1B |= (1<<CS12) | (1<<CS10); //1024 prescaler , counting starts here
}
ISR(TIMER1_COMPA_vect)
{
//sei(); // incase the millis is stuck due to this ISR//no effect
//check if more steps are required
if(stepsRequired < 1)
{
//if not stop timer
//TIMSK1 = 0 ;
TCCR1B = 0; // if prescaler bits are set to 0 then counting stops
//TCCR1A = 0;
//OCR1A = 0;
//OCR1B = 0;
//TCNT1 = 0;
once = 3;
//lastRecTime = millis()-lastRecTime;//dosent make much of a diferrence in result if done here or out side
}
else
{
//reduce counter
stepsRequired--;
}
}
for stepGap = 30 (1.9ms period)
4212 ms for 10 pulses, Each pulse set for 1.98 ms (Total) 19.84
22 ms for 10 pulses, Each pulse set for 1.98 ms (Total) 19.84
22 ms for 10 pulses, Each pulse set for 1.98 ms (Total) 19.84
22 ms for 10 pulses, Each pulse set for 1.98 ms (Total) 19.84
22 ms for 10 pulses, Each pulse set for 1.98 ms (Total) 19.84
for stepGap = 15624 (1 s period)
9997 ms for 10 pulses, Each pulse set for 1000.00 ms (Total) 10000.00
11000 ms for 10 pulses, Each pulse set for 1000.00 ms (Total) 10000.00
11000 ms for 10 pulses, Each pulse set for 1000.00 ms (Total) 10000.00
11000 ms for 10 pulses, Each pulse set for 1000.00 ms (Total) 10000.00