| 1 | /* $Id: timers.c,v 1.1 2010/06/27 22:18:26 simimeie Exp $ |
| 2 | * Functions for timing. |
| 3 | * This mainly allows you to get a timestamp value |
| 4 | */ |
| 5 | |
| 6 | #include <avr/io.h> |
| 7 | #include <avr/interrupt.h> |
| 8 | #include "timers.h" |
| 9 | |
| 10 | /* Internal ticks */ |
| 11 | static volatile uint16_t ticks = 0; |
| 12 | |
| 13 | /* FIXME TCNT1H TCNT1L */ |
| 14 | |
| 15 | /* Executes every 65536 cpu cycles when the timer overflows */ |
| 16 | ISR(TIMER1_OVF_vect) |
| 17 | { |
| 18 | ticks++; |
| 19 | } |
| 20 | |
| 21 | uint16_t getticks(void) |
| 22 | { |
| 23 | uint16_t res; |
| 24 | cli(); |
| 25 | res = ticks; |
| 26 | sei(); |
| 27 | return res; |
| 28 | } |
| 29 | |
| 30 | uint16_t getticks_noirq(void) |
| 31 | { |
| 32 | return ticks; |
| 33 | } |
| 34 | |
| 35 | struct timestamp gettimestamp(void) |
| 36 | { |
| 37 | uint16_t cou1, cou2, tick1; |
| 38 | struct timestamp res; |
| 39 | /* Low byte must be read first for 16bit registers */ |
| 40 | cou1 = TCNT1L; |
| 41 | cou1 |= (uint16_t)(TCNT1H) << 8; |
| 42 | tick1 = getticks(); /* enables interrupts! */ |
| 43 | cou2 = TCNT1L; |
| 44 | cou2 |= (uint16_t)(TCNT1H) << 8; |
| 45 | if (cou1 > cou2) { /* An overflow occured in between */ |
| 46 | /* get new ticks value - we could already have it, but we do not know |
| 47 | * for sure. If we get another one now, we do - because there is no |
| 48 | * way we're going to need another 65k cpu cycles. */ |
| 49 | res.ticks = getticks(); |
| 50 | } else { /* no overflow. */ |
| 51 | res.ticks = tick1; |
| 52 | } |
| 53 | res.partticks = cou2; |
| 54 | return res; |
| 55 | } |
| 56 | |
| 57 | struct timestamp gettimestamp_noirq(void) |
| 58 | { |
| 59 | uint16_t cou1, cou2; uint8_t ovf; |
| 60 | struct timestamp res; |
| 61 | /* Low byte must be read first for 16bit registers */ |
| 62 | cou1 = TCNT1L; |
| 63 | cou1 |= (uint16_t)(TCNT1H) << 8; |
| 64 | /* Check if there is an overflow pending */ |
| 65 | ovf = TIFR1 & _BV(TOV1); |
| 66 | if (ovf) { |
| 67 | /* Overflow pending, reread the counter to be sure */ |
| 68 | cou2 = TCNT1L; |
| 69 | cou2 |= (uint16_t)(TCNT1H) << 8; |
| 70 | res.ticks = ticks + 1; |
| 71 | res.partticks = cou2; |
| 72 | } else { |
| 73 | res.ticks = ticks; |
| 74 | res.partticks = cou1; |
| 75 | } |
| 76 | return res; |
| 77 | } |
| 78 | |
| 79 | void timers_init(void) |
| 80 | { |
| 81 | /* Enable counter1, no prescaling (1 increment per clock cycle!) */ |
| 82 | TCCR1B |= _BV(CS10); |
| 83 | /* Enable interrupt when timer overflows (at 65536) */ |
| 84 | TIMSK1 |= _BV(TOIE1); |
| 85 | } |