Skip to content

Instantly share code, notes, and snippets.

@larsch
Created September 20, 2018 18:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save larsch/5bf14afd153a42fdcb609bf0a0164a6b to your computer and use it in GitHub Desktop.
Save larsch/5bf14afd153a42fdcb609bf0a0164a6b to your computer and use it in GitHub Desktop.
#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