Fix spacing
[bertos.git] / drv / timer_avr.h
1 /*!
2  * \file
3  * <!--
4  * Copyright 2003,2004 Develer S.r.l. (http://www.develer.com/)
5  * Copyright 2000 Bernardo Innocenti <bernie@develer.com>
6  * This file is part of DevLib - See devlib/README for information.
7  * -->
8  *
9  * \version $Id$
10  *
11  * \author Bernardo Innocenti <bernie@develer.com>
12  *
13  * \brief Low-level timer module for AVR
14  */
15
16 /*
17  * $Log$
18  * Revision 1.4  2004/06/27 15:22:15  aleph
19  * Fix spacing
20  *
21  * Revision 1.3  2004/06/07 15:57:40  aleph
22  * Update to latest AVR timer code
23  *
24  * Revision 1.2  2004/06/03 11:27:09  bernie
25  * Add dual-license information.
26  *
27  * Revision 1.1  2004/05/23 18:23:30  bernie
28  * Import drv/timer module.
29  *
30  */
31
32 #ifndef DRV_TIMER_AVR_H
33 #define DRV_TIMER_AVR_H
34
35 #include <avr/wdt.h>
36
37 #if (ARCH & ARCH_BOARD_KC)
38         #include <drv/adc.h>
39 #endif
40
41
42 #define timer_hw_irq()  /* Not needed, IRQ timer flag cleared automatically */
43
44 /*!
45  * System timer: additional division after the prescaler
46  * 12288000 / 64 / 192 (0..191) = 1 ms
47  */
48 #define OCR_DIVISOR 191
49
50 /*! HW dependent timer initialization  */
51 #if defined(CONFIG_TIMER_ON_TIMER0)
52
53         //! Type of time expressed in ticks of the hardware high-precision timer
54         typedef uint8_t hptime_t;
55
56         static void timer_hw_init(void)
57         {
58                 cpuflags_t flags;
59                 DISABLE_IRQSAVE(flags);
60
61                 /* Reset Timer flags */
62                 TIFR = BV(OCF0) | BV(TOV0);
63
64                 /* Setup Timer/Counter interrupt */
65                 ASSR = 0x00;                  /* internal system clock */
66                 TCCR0 = BV(WGM01) | BV(CS02); /* Clear on Compare match & prescaler = 64. When changing
67                                                  prescaler change TIMER_HW_HPTICKS_PER_SEC too */
68                 TCNT0 = 0x00;                 /* initialization of Timer/Counter */
69                 OCR0 = OCR_DIVISOR;           /* Timer/Counter Output Compare Register */
70
71                 /* Enable timer interrupts: Timer/Counter2 Output Compare (OCIE2) */
72                 TIMSK &= ~BV(TOIE0);
73                 TIMSK |= BV(OCIE0);
74
75                 ENABLE_IRQRESTORE(flags);
76         }
77
78         //! Frequency of the hardware high precision timer
79         #define TIMER_HW_HPTICKS_PER_SEC  (CLOCK_FREQ / 64)
80
81         INLINE hptime_t timer_hw_hpread(void);
82         INLINE hptime_t timer_hw_hpread(void)
83         {
84                 return TCNT0;
85         }
86
87 #elif defined(CONFIG_TIMER_ON_TIMER1_OVERFLOW)
88
89         //! Type of time expressed in ticks of the hardware high precision timer
90         typedef uint16_t hptime_t;
91
92         static void timer_hw_init(void)
93         {
94                 cpuflags_t flags;
95                 DISABLE_IRQSAVE(flags);
96
97                 /* Reset Timer overflow flag */
98                 TIFR |= BV(TOV1);
99
100                 /* Fast PWM mode, 9 bit, 24 kHz, no prescaling. When changing freq or
101                    resolution (top of TCNT), change TIMER_HW_HPTICKS_PER_SEC too */
102                 TCCR1A |= BV(WGM11);
103                 TCCR1A &= ~BV(WGM10);
104                 TCCR1B |= BV(WGM12) | BV(CS10);
105                 TCCR1B &= ~(BV(WGM13) | BV(CS11) | BV(CS12));
106
107                 TCNT1 = 0x00;         /* initialization of Timer/Counter */
108
109                 /* Enable timer interrupt: Timer/Counter1 Overflow */
110                 TIMSK |= BV(TOIE1);
111
112                 ENABLE_IRQRESTORE(flags);
113         }
114
115         //! Frequency of the hardware high precision timer
116         #define TIMER_HW_HPTICKS_PER_SEC  (24000ul * 512)
117
118         INLINE hptime_t timer_hw_hpread(void);
119         INLINE hptime_t timer_hw_hpread(void)
120         {
121                 return TCNT1;
122         }
123
124 #elif defined(CONFIG_TIMER_ON_TIMER2)
125
126         //! Type of time expressed in ticks of the hardware high precision timer
127         typedef uint8_t hptime_t;
128
129         static void timer_hw_init(void)
130         {
131                 cpuflags_t flags;
132                 DISABLE_IRQSAVE(flags);
133
134                 /* Reset Timer flags */
135                 TIFR = BV(OCF2) | BV(TOV2);
136
137                 /* Setup Timer/Counter interrupt */
138                 TCCR2 = BV(WGM21) | BV(CS21) | BV(CS20);
139                 /* Clear on Compare match & prescaler = 64, internal sys clock.
140                    When changing prescaler change TIMER_HW_HPTICKS_PER_SEC too */
141                 TCNT2 = 0x00;         /* initialization of Timer/Counter */
142                 OCR2 = OCR_DIVISOR;   /* Timer/Counter Output Compare Register */
143
144                 /* Enable timer interrupts: Timer/Counter2 Output Compare (OCIE2) */
145                 TIMSK &= ~BV(TOIE2);
146                 TIMSK |= BV(OCIE2);
147
148                 ENABLE_IRQRESTORE(flags);
149         }
150
151         //! Frequency of the hardware high precision timer
152         #define TIMER_HW_HPTICKS_PER_SEC  (CLOCK_FREQ / 64)
153
154         INLINE hptime_t timer_hw_hpread(void);
155         INLINE hptime_t timer_hw_hpread(void)
156         {
157                 return TCNT2;
158         }
159
160 #else
161         #error Choose witch timer to use with CONFIG_TIMER_ON_TIMERx
162 #endif /* CONFIG_TIMER_ON_TIMERx */
163
164
165 #if defined(CONFIG_TIMER_ON_TIMER1_OVERFLOW)
166
167         #define DEFINE_TIMER_ISR        \
168                 static void timer_handler(void)
169
170         DEFINE_TIMER_ISR;
171
172         /*
173          * Timer 1 overflow irq handler. It's called at the frequency of the timer 1
174          * PWM (should be 24 kHz). It's too much for timer purposes, so the interrupt
175          * handler is really a counter that call the true handler in timer.c
176          * every 1 ms.
177          */
178         SIGNAL(SIG_OVERFLOW1)
179         {
180                 /*!
181                  * How many overflow we have to count before calling the true timer handler.
182                  * If timer overflow is at 24 kHz, with a value of 24 we have 1 ms between
183                  * each call.
184                  */
185                 #define TIMER1_OVF_COUNT 24
186
187                 static uint8_t count = TIMER1_OVF_COUNT;
188
189                 count--;
190                 if (!count)
191                 {
192                         timer_handler();
193                         count = TIMER1_OVF_COUNT;
194                 }
195
196         #if (ARCH & ARCH_BOARD_KC)
197                 /*
198                  * Super-optimization-hack: switch CPU ADC mux here, ASAP after the start
199                  * of conversion (auto-triggered with timer 1 overflow).
200                  * The switch can be done 2 ADC cycles after start of conversion.
201                  * The handler prologue takes a little more than 32 CPU cycles: with
202                  * the prescaler at 1/16 the timing should be correct even at the start
203                  * of the handler.
204                  *
205                  * The switch is synchronized with the ADC handler using _adc_trigger_lock.
206                  */
207                 extern uint8_t _adc_idx_next;
208                 extern bool _adc_trigger_lock;
209
210                 if (!_adc_trigger_lock)
211                 {
212                         TIMER_STROBE_ON;
213                         ADC_SETCHN(_adc_idx_next);
214                         TIMER_STROBE_OFF;
215                         _adc_trigger_lock = true;
216                 }
217         #endif
218         }
219
220 #elif defined (CONFIG_TIMER_ON_TIMER0)
221
222         #define DEFINE_TIMER_ISR        \
223                 SIGNAL(SIG_OUTPUT_COMPARE0)
224
225 #elif defined(CONFIG_TIMER_ON_TIMER2)
226
227         #define DEFINE_TIMER_ISR        \
228                 SIGNAL(SIG_OUTPUT_COMPARE2)
229
230 #else
231         #error Choose witch timer to use with CONFIG_TIMER_ON_TIMERx
232 #endif /* CONFIG_TIMER_ON_TIMERx */
233
234 #endif /* DRV_TIMER_AVR_H */