Skip to content

Instantly share code, notes, and snippets.

@dccourt
Created January 29, 2012 01:26
Show Gist options
  • Save dccourt/1696597 to your computer and use it in GitHub Desktop.
Save dccourt/1696597 to your computer and use it in GitHub Desktop.
Generic timer setup utility
//Setup Timer2.
//Configures the 8-Bit Timer2 to generate an interrupt
//at the specified frequency.
//Returns the timer load value which must be loaded into TCNT2
//inside your ISR routine.
//See the example usage below.
unsigned char SetupTimer2(float timeoutFrequency){
unsigned char result; //The timer load value.
/* We need to work out what divisor of the chip clock can be
used to get an 8-bit counter preload value that represents
the requested frequency.
timer preload_val = scaled_freq / requested_freq
=> scaled_freq = clock_freq / scaler
=> preload_val = clock_freq / scaler / requested_freq
=> 256 > clock_freq / scaler / requested_freq
=> clock_freq / scaler < 256 * requested_freq
=> 1 / scaler < 256 * requested_freq / clock_freq
=> scaler > clock_freq / (256 * requested_freq)
*/
Serial.print("clock/requested:");
Serial.println(TIMER_CLOCK_FREQ / timeoutFrequency);
int min_scaler = TIMER_CLOCK_FREQ / (256 * timeoutFrequency);
Serial.print("Min scaler:");
Serial.println(min_scaler);
// Need to convert min_scaler into a power-of-2 value to use.
// Allowable values are actually 1, 8, 32, 64, 128, 256, 1024 -
// see data sheet, section 18.10.
int scaler = 1;
while ((scaler < min_scaler) && (scaler < 1024))
{
scaler <<= 1;
// skip disallowed values
if ((scaler == 2) || (scaler == 4) || (scaler == 16) || (scaler == 512))
{
scaler <<= 1;
}
}
if (scaler < min_scaler)
{
// Output a warning.
Serial.println("Requested timer frequency too low - unable to find a suitable divider");
}
else
{
Serial.print("Chosen prescaler:");
Serial.println(scaler);
}
long scaled_freq = TIMER_CLOCK_FREQ / scaler;
// Convert the scaler value into register settings
switch (scaler)
{
case 1:
TCCR2B = 0b00000001;
break;
case 8:
TCCR2B = 0b00000010;
break;
case 32:
TCCR2B = 0b00000011;
break;
case 64:
TCCR2B = 0b00000100;
break;
case 128:
TCCR2B = 0b00000101;
break;
case 256:
TCCR2B = 0b00000110;
break;
case 1024:
TCCR2B = 0b00000111;
break;
default:
Serial.print("Unrecognised scaler: ");
Serial.println(scaler);
break;
}
//Calculate the timer load value
result=(int)((256.0-(scaled_freq/timeoutFrequency))+0.5);
//Timer2 Settings: Timer mode 0
TCCR2A = 0;
//Timer2 Overflow Interrupt Enable
TIMSK2 = 1<<TOIE2;
//load the timer for its first cycle
TCNT2=result;
Serial.print("Timer2 reload value:");
Serial.println(result);
return(result);
}
// And using this within an ISR to maintain an accurate interval that
// takes account of the time spent within the ISR:
ISR(TIMER2_OVF_vect) {
// ... do some work here ...
//Capture the current timer value. This is how much error we
//have due to interrupt latency and the work in this function
latency=TCNT2;
//Reload the timer and correct for latency.
TCNT2=latency+timerLoadValue;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment