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