Created
September 20, 2018 18:29
-
-
Save larsch/5bf14afd153a42fdcb609bf0a0164a6b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <avr/io.h> | |
#include <avr/interrupt.h> | |
#include <util/delay.h> | |
#include <stdio.h> | |
/* #define F_CPU 16000000UL */ | |
#define BAUD 115200L | |
#include <util/setbaud.h> | |
/* Period between tick increments */ | |
#define TIMER0_PERIOD 128 | |
/* Timer 0 value that triggers overflow interrupt */ | |
#define TIMER0_OCR0A (TIMER0_PERIOD - 1) | |
/* How many interrupts to count */ | |
#define COUNT 50 | |
#define SIMULATE_INPUT 0 | |
#define TRIGGER_ON_INT0 0 | |
#define TRIGGER_ON_ICP1 1 | |
void uart_init() { | |
UBRR0H = UBRRH_VALUE; | |
UBRR0L = UBRRL_VALUE; | |
#if USE_2X | |
UCSR0A |= _BV(U2X0); | |
#else | |
UCSR0A &= ~(_BV(U2X0)); | |
#endif | |
UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); /* 8-bit data */ | |
UCSR0B = _BV(RXEN0) | _BV(TXEN0); /* Enable RX and TX */ | |
} | |
int uart_putchar(char tick, FILE* stream) { | |
if (tick == '\n') uart_putchar('\r', stream); | |
loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */ | |
UDR0 = tick; | |
return 0; | |
} | |
/* Global counter, incremented on Timer0 overflow */ | |
volatile uint32_t counter = 0; | |
/* ISR(TIMER0_OVF_vect, ISR_BLOCK) { */ | |
/* counter++; */ | |
/* } */ | |
volatile uint16_t timer1counter; | |
/* ISR(TIMER1_OVF_vect, ISR_NAKED) { */ | |
/* asm("push r16"); */ | |
/* asm("in r16, 0x3f"); */ | |
/* cli(); */ | |
/* timer1counter++; */ | |
/* sei(); */ | |
/* asm("out 0x3f, r16"); */ | |
/* asm("pop r16"); */ | |
/* reti(); */ | |
/* } */ | |
ISR(TIMER1_OVF_vect, ISR_BLOCK) { | |
timer1counter++; | |
} | |
/* Copy of counter every COUNT interrupts */ | |
volatile uint16_t ticksh; | |
volatile uint16_t ticksl; | |
/* Signal to main that ticks has been loaded (set to 1 by interrupt, | |
* cleared by main) */ | |
volatile char signal = 0; | |
static void latch_timer1() { | |
static uint8_t count = 0; | |
if (++count == COUNT) { | |
uint16_t tcnt1 = TCNT1; | |
uint16_t tc1 = timer1counter; | |
if (TIFR1 & _BV(TOV1)) { | |
ticksh = tc1 + 1; | |
ticksl = 0; | |
} else { | |
ticksh = tc1; | |
ticksl = tcnt1; | |
} | |
count = 0; | |
signal = 1; | |
} | |
} | |
#if TRIGGER_ON_INT0 | |
ISR(INT0_vect) { | |
latch_timer1(); | |
} | |
#endif | |
#if SIMULATE_INPUT | |
ISR(TIMER2_OVF_vect, ISR_BLOCK) { | |
latch_timer1(); | |
} | |
#endif | |
ISR(TIMER1_CAPT_vect, ISR_NAKED) { | |
asm("push r24"); | |
asm("push r25"); | |
ticksl = ICR1; | |
ticksh = timer1counter; | |
signal = 1; | |
asm("pop r25"); | |
asm("pop r24"); | |
reti(); | |
/* reti(); */ | |
/* uint16_t ticksl_tmp = ICR1; */ | |
/* static uint8_t count = 0; */ | |
/* if (++count == COUNT) { */ | |
/* count = 0; */ | |
/* signal = 1; */ | |
/* } */ | |
} | |
void timer_init() { | |
/* TCCR0A = _BV(WGM00) | _BV(WGM01); /\* fast pwm mode *\/ */ | |
/* TCCR0B = _BV(WGM02) | _BV(CS00); /\* fast pwm, no prescaling *\/ */ | |
/* OCR0A = TIMER0_OCR0A; */ | |
/* TIMSK0 = _BV(TOIE0); /\* overflow interrupt enable *\/ */ | |
#if TRIGGER_ON_INT0 | |
EICRA = _BV(ISC01); /* falling edge interrupt */ | |
EIMSK = _BV(INT0); /* INT0 enable */ | |
#endif | |
TCCR1A = 0; /* fast pwm */ | |
TCCR1B = _BV(CS10); /* , input capture enable (falling edge), fast pwm, no prescaling */ | |
TIMSK1 = _BV(ICIE1) | _BV(TOIE1); /* overflow interrupt enable */ | |
#if SIMULATE_INPUT | |
TCCR2A = 0; /* normal pwm mode */ | |
TCCR2B = _BV(CS20) | _BV(CS21) | _BV(CS22); /* fast pwm mode, clk/1024 */ | |
TIMSK2 = _BV(TOIE2); /* overflow interrupt enable */ | |
#endif | |
} | |
FILE uart_output = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE); | |
int main() | |
{ | |
uart_init(); | |
stdout = &uart_output; | |
printf("Frequency monitor\n"); | |
timer_init(); | |
/* Enable global interrupt */ | |
sei(); | |
/* Wait for first reading, so we can find deltas */ | |
while (!signal); | |
cli(); | |
uint32_t last = (uint32_t)ticksh << 16 | ticksl; | |
sei(); | |
signal = 0; | |
/* Wait for reading, print result */ | |
static int32_t sum = 0; | |
for (;;) { | |
for (int count = 0; count < COUNT; ++count) { | |
while (!signal); | |
signal = 0; | |
} | |
cli(); | |
uint32_t tick = (uint32_t)ticksh << 16 | ticksl; | |
sei(); | |
uint32_t delta = tick - last; | |
const uint64_t numerator = ((uint64_t)F_CPU * COUNT * 10004905ll); // 100049055 | |
int32_t offset = delta - (F_CPU / 50 * COUNT); | |
sum += offset; | |
uint32_t freq = numerator / delta; | |
printf("%lu clock ticks / %d cycles, %lu.%07lu Hz, offset %ld, cumulative %ld low %lu\n", delta, COUNT, freq / 10000000, freq % 10000000, offset, sum, tick & 0xffff); | |
last = tick; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment