I am trying to sample analog data at exactly 1k Hz and send it to the serial port. I have this timer set up, but for some reason I am getting a sample rate of 994-998Hz.
When I just serial print the execution time I get 1004uS. Can anyone help explain why its not exact? I Used an NI Elvis to see how accurate the clock is, and it seems fine.
Im using a Leonardo at 16MHz. Thanks for any help!
/*
* Arduino 101: timer and interrupts
* 2: Timer1 overflow interrupt example
* more infos: http://www.letmakerobots.com/node/28278
* created by RobotFreak
*/
#define ledPin 13
unsigned long t1, t2;
void setup()
{
Serial.begin(115200);
pinMode(ledPin, OUTPUT);
t1 = 0; t2 = 0;
// initialize timer1
noInterrupts(); // disable all interrupts
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 63535; // preload timer 65536-16MHz/256/2Hz
TCCR1B |= (1 << CS11); // 256 prescaler
TIMSK1 |= (1 << TOIE1); // enable timer overflow interrupt
interrupts(); // enable all interrupts
}
// interrupt service routine that wraps a user defined function
// supplied by attachInterrupt
ISR(TIMER1_OVF_vect)
{
TCNT1 = 63535; // preload timer
//digitalWrite(ledPin, digitalRead(ledPin) ^ 1);
t2 = micros();
Serial.println(t2 - t1);
t1 = t2;
}
void loop()
{
// your program here...
}
So... how did you get 63535? I get 16e6/256 = 62500, so for a 1s timer expiration, you'd want TCNT to interrupt on a 62500 count. Or preload with 3036 if you're counting up and interrupting on overflow. Though I'd think a zero to 62500 with automatic reset would be preferable (CTC mode.)
I did not change the commenting on the code (ooops). It was set to a prescaler of 8. That is why the timer preload was not making sense.
1000/(16000000/8) = 2000000
1000/2000000 = .0005uS (time per tick)
1mS/.0005 = 2000
2000-65535 = 63535
I changed the code to set the timer in CTC Mode, but still get 1004uS every once in a while (it seems to be a lot better!).
I am verifying this by setting up another arduino with the blink sketch and measuring a one second period. The blink sketch arduino was verified to be accurate using an o-scope, but when I import the data into excell I get data anywhere from 1010 to 991. Any other ideas?
I changed the code to set the timer in CTC Mode, but still get 1004uS every once in a while
Every once in a while, your timer will expire while the AVR is off in un-interruptable code (notably the timer0 interrupt or a serial interrupt), leading to some delay before the ISR is serviced.
Note that doing serial output in an ISR is "strongly not recommended" - if you ever hit a condition where the serial output buffer is full, your code will hang waiting for the uart TX interrupt to empty the buffer and make room. But since you're in an ISR, the TX interrupt will never be serviced. (There may be other problems as well.) You might get away with it as long as the average data rate is much lower than the serial bitrate, and nothing else does serial output...