Include top-level headers from cfg/ subdir.
[bertos.git] / drv / timer_avr.h
1 /*!
2  * \file
3  * <!--
4  * Copyright 2003, 2004, 2005 Develer S.r.l. (http://www.develer.com/)
5  * Copyright 2000 Bernardo Innocenti <bernie@develer.com>
6  * This file is part of DevLib - See README.devlib 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.24  2005/04/11 19:10:28  bernie
19  *#* Include top-level headers from cfg/ subdir.
20  *#*
21  *#* Revision 1.23  2005/03/01 23:24:51  bernie
22  *#* Tweaks for avr-libc 1.2.x.
23  *#*
24  *#* Revision 1.21  2004/12/13 12:07:06  bernie
25  *#* DISABLE_IRQSAVE/ENABLE_IRQRESTORE: Convert to IRQ_SAVE_DISABLE/IRQ_RESTORE.
26  *#*
27  *#* Revision 1.20  2004/11/16 20:59:46  bernie
28  *#* Include <avr/io.h> explicitly.
29  *#*
30  *#* Revision 1.19  2004/10/19 08:56:41  bernie
31  *#* TIMER_STROBE_ON, TIMER_STROBE_OFF, TIMER_STROBE_INIT: Move from timer_avr.h to timer.h, where they really belong.
32  *#*
33  *#* Revision 1.18  2004/09/20 03:31:03  bernie
34  *#* Fix racy racy code.
35  *#*
36  *#* Revision 1.17  2004/09/14 21:07:09  bernie
37  *#* Include hw.h explicitly.
38  *#*
39  *#* Revision 1.16  2004/09/06 21:49:26  bernie
40  *#* CONFIG_TIMER_STROBE: be tolerant with missing optional macro.
41  *#*
42  *#* Revision 1.15  2004/08/25 14:12:08  rasky
43  *#* Aggiornato il comment block dei log RCS
44  *#*
45  *#* Revision 1.14  2004/08/24 16:27:01  bernie
46  *#* Add missing headers.
47  *#*
48  *#* Revision 1.13  2004/08/24 14:30:11  bernie
49  *#* Use new-style config macros for drv/timer.c
50  *#*
51  *#* Revision 1.12  2004/08/10 06:59:45  bernie
52  *#* CONFIG_TIMER_STROBE: Define no-op default macros.
53  *#*
54  *#* Revision 1.11  2004/08/03 15:53:17  aleph
55  *#* Fix spacing
56  *#*
57  *#* Revision 1.10  2004/08/02 20:20:29  aleph
58  *#* Merge from project_ks
59  *#*
60  *#* Revision 1.9  2004/07/22 02:01:14  bernie
61  *#* Use TIMER_PRESCALER consistently.
62  *#*/
63 #ifndef DRV_TIMER_AVR_H
64 #define DRV_TIMER_AVR_H
65
66 #include <cfg/arch_config.h> // ARCH_BOARD_KC
67 #include <cfg/macros.h> // BV()
68 #include <hw.h>
69
70 #include <avr/signal.h>
71 #include <avr/io.h>
72
73 #if defined(ARCH_BOARD_KC) && (ARCH & ARCH_BOARD_KC)
74         #include <drv/adc.h>
75 #endif
76
77
78 /*!
79  * Values for CONFIG_TIMER.
80  *
81  * Select which hardware timer interrupt to use for system clock and softtimers.
82  * \note The timer 1 overflow mode set the timer as a 24 kHz PWM.
83  */
84 #define TIMER_ON_OUTPUT_COMPARE0  1
85 #define TIMER_ON_OVERFLOW1        2
86 #define TIMER_ON_OUTPUT_COMPARE2  3
87
88
89 /* Not needed, IRQ timer flag cleared automatically */
90 #define timer_hw_irq() do {} while (0)
91
92 #define TIMER_PRESCALER 64
93
94 /*!
95  * System timer: additional division after the prescaler
96  * 12288000 / 64 / 192 (0..191) = 1 ms
97  */
98 #define OCR_DIVISOR  (CLOCK_FREQ / TIMER_PRESCALER / TICKS_PER_SEC - 1) /* 191 */
99
100 /*! HW dependent timer initialization  */
101 #if (CONFIG_TIMER == TIMER_ON_OUTPUT_COMPARE0)
102
103         //! Type of time expressed in ticks of the hardware high-precision timer
104         typedef uint8_t hptime_t;
105
106         static void timer_hw_init(void)
107         {
108                 cpuflags_t flags;
109                 IRQ_SAVE_DISABLE(flags);
110
111                 /* Reset Timer flags */
112                 TIFR = BV(OCF0) | BV(TOV0);
113
114                 /* Setup Timer/Counter interrupt */
115                 ASSR = 0x00;                  /* Internal system clock */
116                 TCCR0 = BV(WGM01)             /* Clear on Compare match */
117                         #if TIMER_PRESCALER == 64
118                                 | BV(CS02)
119                         #else
120                                 #error Unsupported value of TIMER_PRESCALER
121                         #endif
122                 ;
123                 TCNT0 = 0x00;                 /* Initialization of Timer/Counter */
124                 OCR0 = OCR_DIVISOR;           /* Timer/Counter Output Compare Register */
125
126                 /* Enable timer interrupts: Timer/Counter2 Output Compare (OCIE2) */
127                 TIMSK &= ~BV(TOIE0);
128                 TIMSK |= BV(OCIE0);
129
130                 IRQ_RESTORE(flags);
131         }
132
133         //! Frequency of the hardware high precision timer
134         #define TIMER_HW_HPTICKS_PER_SEC  (CLOCK_FREQ / TIMER_PRESCALER)
135
136         INLINE hptime_t timer_hw_hpread(void)
137         {
138                 return TCNT0;
139         }
140
141 #elif (CONFIG_TIMER == TIMER_ON_OVERFLOW1)
142
143         //! Type of time expressed in ticks of the hardware high precision timer
144         typedef uint16_t hptime_t;
145
146         static void timer_hw_init(void)
147         {
148                 cpuflags_t flags;
149                 IRQ_SAVE_DISABLE(flags);
150
151                 /* Reset Timer overflow flag */
152                 TIFR |= BV(TOV1);
153
154                 /* Fast PWM mode, 9 bit, 24 kHz, no prescaling. When changing freq or
155                    resolution (top of TCNT), change TIMER_HW_HPTICKS_PER_SEC too */
156                 TCCR1A |= BV(WGM11);
157                 TCCR1A &= ~BV(WGM10);
158                 TCCR1B |= BV(WGM12) | BV(CS10);
159                 TCCR1B &= ~(BV(WGM13) | BV(CS11) | BV(CS12));
160
161                 TCNT1 = 0x00;         /* initialization of Timer/Counter */
162
163                 /* Enable timer interrupt: Timer/Counter1 Overflow */
164                 TIMSK |= BV(TOIE1);
165
166                 IRQ_RESTORE(flags);
167         }
168
169         //! Frequency of the hardware high precision timer
170         #define TIMER_HW_HPTICKS_PER_SEC  (24000ul * 512)
171
172         INLINE hptime_t timer_hw_hpread(void)
173         {
174                 return TCNT1;
175         }
176
177 #elif (CONFIG_TIMER == TIMER_ON_OUTPUT_COMPARE2)
178
179         //! Type of time expressed in ticks of the hardware high precision timer
180         typedef uint8_t hptime_t;
181
182         static void timer_hw_init(void)
183         {
184                 cpuflags_t flags;
185                 IRQ_SAVE_DISABLE(flags);
186
187                 /* Reset Timer flags */
188                 TIFR = BV(OCF2) | BV(TOV2);
189
190                 /* Setup Timer/Counter interrupt */
191                 TCCR2 = BV(WGM21)
192                         #if TIMER_PRESCALER == 64
193                                 | BV(CS21) | BV(CS20)
194                         #else
195                                 #error Unsupported value of TIMER_PRESCALER
196                         #endif
197                 ;
198                 /* Clear on Compare match & prescaler = 64, internal sys clock.
199                    When changing prescaler change TIMER_HW_HPTICKS_PER_SEC too */
200                 TCNT2 = 0x00;         /* initialization of Timer/Counter */
201                 OCR2 = OCR_DIVISOR;   /* Timer/Counter Output Compare Register */
202
203                 /* Enable timer interrupts: Timer/Counter2 Output Compare (OCIE2) */
204                 TIMSK &= ~BV(TOIE2);
205                 TIMSK |= BV(OCIE2);
206
207                 IRQ_RESTORE(flags);
208         }
209
210         //! Frequency of the hardware high precision timer
211         #define TIMER_HW_HPTICKS_PER_SEC  (CLOCK_FREQ / TIMER_PRESCALER)
212
213         INLINE hptime_t timer_hw_hpread(void)
214         {
215                 return TCNT2;
216         }
217
218 #else
219         #error Unimplemented value for CONFIG_TIMER
220 #endif /* CONFIG_TIMER */
221
222
223 #if (CONFIG_TIMER == TIMER_ON_OVERFLOW1)
224
225         #define DEFINE_TIMER_ISR        \
226                 static void timer_handler(void)
227
228         DEFINE_TIMER_ISR;
229
230         /*
231          * Timer 1 overflow irq handler. It's called at the frequency of the timer 1
232          * PWM (should be 24 kHz). It's too much for timer purposes, so the interrupt
233          * handler is really a counter that call the true handler in timer.c
234          * every 1 ms.
235          */
236         SIGNAL(SIG_OVERFLOW1)
237         {
238         #if (ARCH & ARCH_BOARD_KC)
239                 /*
240                  * Super-optimization-hack: switch CPU ADC mux here, ASAP after the start
241                  * of conversion (auto-triggered with timer 1 overflow).
242                  * The switch can be done 2 ADC cycles after start of conversion.
243                  * The handler prologue takes a little more than 32 CPU cycles: with
244                  * the prescaler at 1/16 the timing should be correct even at the start
245                  * of the handler.
246                  *
247                  * The switch is synchronized with the ADC handler using _adc_trigger_lock.
248                  *
249                  *      Mel (A Real Programmer)
250                  */
251                 extern uint8_t _adc_idx_next;
252                 extern bool _adc_trigger_lock;
253
254                 if (!_adc_trigger_lock)
255                 {
256                         // Backwards compatibility fix for avr-libc 1.0.4
257                         #ifndef ADATE
258                         #define ADATE ADFR
259                         #endif
260
261                         /*
262                          * Disable free-running mode to avoid starting a
263                          * new conversion before the ADC handler has read
264                          * the ongoing one.  This condition could occur
265                          * under very high interrupt load and would have the
266                          * unwanted effect of reading from the wrong ADC
267                          * channel.
268                          *
269                          * NOTE: writing 0 to ADSC and ADIF has no effect.
270                          */
271                         ADCSRA = ADCSRA & ~(BV(ADATE) | BV(ADIF) | BV(ADSC));
272
273                         ADC_SETCHN(_adc_idx_next);
274                         _adc_trigger_lock = true;
275                 }
276         #endif // ARCH_BOARD_KC
277
278                 /*!
279                  * How many timer overflows we must count before calling the real
280                  * timer handler.
281                  * When the timer is programmed to overflow at 24 kHz, a value of
282                  * 24 will result in 1ms between each call.
283                  */
284                 #define TIMER1_OVF_COUNT 24
285                 //#warning TIMER1_OVF_COUNT for timer at 12 kHz
286                 //#define TIMER1_OVF_COUNT 12
287
288                 static uint8_t count = TIMER1_OVF_COUNT;
289
290                 count--;
291                 if (!count)
292                 {
293                         timer_handler();
294                         count = TIMER1_OVF_COUNT;
295                 }
296         }
297
298 #elif (CONFIG_TIMER == TIMER_ON_OUTPUT_COMPARE0)
299
300         #define DEFINE_TIMER_ISR        \
301                 SIGNAL(SIG_OUTPUT_COMPARE0)
302
303 #elif (CONFIG_TIMER == TIMER_ON_OUTPUT_COMPARE2)
304
305         #define DEFINE_TIMER_ISR        \
306                 SIGNAL(SIG_OUTPUT_COMPARE2)
307
308 #else
309         #error Unimplemented value for CONFIG_TIMER
310 #endif /* CONFIG_TIMER */
311
312 #endif /* DRV_TIMER_AVR_H */