ATmega328P Data Sheet - https://content.arduino.cc/assets/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf
Using Timer1
static uint8_t saveTCCR1A, saveTCCR1B;
static inline void capture_init(void)
{
// save existing timer settings
saveTCCR1A = TCCR1A;
saveTCCR1B = TCCR1B;
// initialize timer1
TCCR1B = 0;
TCCR1A = 0;
//Initialize counter value to 0
TCNT1 = 0;
//Set Timer/Counter1 Interrupt Flag Register
//ICF1: Timer/Counter1, Input Capture Flag
//TOV1: Timer/Counter1, Overflow Flag
TIFR1 = (1<<ICF1) | (1<<TOV1);
//Set Interrupt Mask Register
// ICIE1: Timer/Counter1, Input Capture Interrupt Enable
// TOIE1: Timer/Counter1 Overflow Interrupt Enable
TIMSK1 = (1<<ICIE1) | (1<<TOIE1);}
}
static inline void capture_start(void)
{
//Set Timer/Counter1 Control Register B
// ICNC1: Input Capture Noise Canceler
// ICES1: Input Capture Edge Select
// CS10: Clock Select - clkIo/1 (no prescaling)
TCCR1B = (1<<ICNC1) | (1<<ICES1) | (1<<CS10);
}
static inline uint16_t capture_read(void)
{
//input capture register
return ICR1;
}
static inline uint8_t capture_overflow(void)
{
//Set Timer/Counter1 Interrupt Flag Register
// TOV1: Timer/Counter1, Overflow Flag
return TIFR1 & (1<<TOV1);
}
static inline void capture_overflow_reset(void)
{
//Set Timer/Counter1 Interrupt Flag Register
// TOV1: Timer/Counter1, Overflow Flag
TIFR1 = (1<<TOV1);
}
static inline void capture_shutdown(void)
{
TCCR1B = 0;
TIMSK1 = 0;
//Restore old timers
TCCR1A = saveTCCR1A;
TCCR1B = saveTCCR1B;
}
#define TIMER_OVERFLOW_VECTOR TIMER1_OVF_vect
#define TIMER_CAPTURE_VECTOR TIMER1_CAPT_vect
#define FREQMEASURE_BUFFER_LEN 12
static volatile uint32_t buffer_value[FREQMEASURE_BUFFER_LEN];
static volatile uint8_t buffer_head;
static volatile uint8_t buffer_tail;
static uint16_t capture_msw;
static uint32_t capture_previous;
ISR(TIMER_OVERFLOW_VECTOR)
{
capture_msw++;
}
ISR(TIMER_CAPTURE_VECTOR)
{
uint16_t capture_lsw;
uint32_t capture, period;
uint8_t i;
// get the timer capture
capture_lsw = capture_read();
// Handle the case where but capture and overflow interrupts were pending
// (eg, interrupts were disabled for a while), or where the overflow occurred
// while this ISR was starting up. However, if we read a 16 bit number that
// is very close to overflow, then ignore any overflow since it probably
// just happened.
if (capture_overflow() && capture_lsw < 0xFF00) {
capture_overflow_reset();
capture_msw++;
}
// compute the waveform period
capture = ((uint32_t)capture_msw << 16) | capture_lsw;
period = capture - capture_previous;
capture_previous = capture;
// store it into the buffer
i = buffer_head + 1;
if (i >= FREQMEASURE_BUFFER_LEN) i = 0;
if (i != buffer_tail) {
buffer_value[i] = period;
buffer_head = i;
}
}