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.
11 * \author Bernardo Innocenti <bernie@develer.com>
13 * \brief Low-level timer module for AVR
18 * Revision 1.11 2004/08/03 15:53:17 aleph
21 * Revision 1.10 2004/08/02 20:20:29 aleph
22 * Merge from project_ks
24 * Revision 1.9 2004/07/22 02:01:14 bernie
25 * Use TIMER_PRESCALER consistently.
27 * Revision 1.8 2004/07/20 23:50:20 bernie
28 * Also define TIMER_PRESCALER.
30 * Revision 1.7 2004/07/20 23:49:40 bernie
31 * Compute value of OCR_DIVISOR from CLOCK_FREQ.
33 * Revision 1.6 2004/07/20 23:48:16 bernie
34 * Finally remove redundant protos.
36 * Revision 1.5 2004/07/18 22:16:35 bernie
37 * Add missing header; Prevent warning for project_ks-specific code.
39 * Revision 1.4 2004/06/27 15:22:15 aleph
42 * Revision 1.3 2004/06/07 15:57:40 aleph
43 * Update to latest AVR timer code
45 * Revision 1.2 2004/06/03 11:27:09 bernie
46 * Add dual-license information.
48 * Revision 1.1 2004/05/23 18:23:30 bernie
49 * Import drv/timer module.
53 #ifndef DRV_TIMER_AVR_H
54 #define DRV_TIMER_AVR_H
57 #include <avr/signal.h>
59 #if defined(ARCH_BOARD_KC) && (ARCH & ARCH_BOARD_KC)
64 /* Not needed, IRQ timer flag cleared automatically */
65 #define timer_hw_irq() do {} while (0)
67 #define TIMER_PRESCALER 64
70 * System timer: additional division after the prescaler
71 * 12288000 / 64 / 192 (0..191) = 1 ms
73 #define OCR_DIVISOR (CLOCK_FREQ / TIMER_PRESCALER / TICKS_PER_SEC - 1) /* 191 */
75 /*! HW dependent timer initialization */
76 #if defined(CONFIG_TIMER_ON_TIMER0)
78 //! Type of time expressed in ticks of the hardware high-precision timer
79 typedef uint8_t hptime_t;
81 static void timer_hw_init(void)
84 DISABLE_IRQSAVE(flags);
86 /* Reset Timer flags */
87 TIFR = BV(OCF0) | BV(TOV0);
89 /* Setup Timer/Counter interrupt */
90 ASSR = 0x00; /* Internal system clock */
91 TCCR0 = BV(WGM01) /* Clear on Compare match */
92 #if TIMER_PRESCALER == 64
95 #error Unsupported value of TIMER_PRESCALER
98 TCNT0 = 0x00; /* Initialization of Timer/Counter */
99 OCR0 = OCR_DIVISOR; /* Timer/Counter Output Compare Register */
101 /* Enable timer interrupts: Timer/Counter2 Output Compare (OCIE2) */
105 ENABLE_IRQRESTORE(flags);
108 //! Frequency of the hardware high precision timer
109 #define TIMER_HW_HPTICKS_PER_SEC (CLOCK_FREQ / TIMER_PRESCALER)
111 INLINE hptime_t timer_hw_hpread(void)
116 #elif defined(CONFIG_TIMER_ON_TIMER1_OVERFLOW)
118 //! Type of time expressed in ticks of the hardware high precision timer
119 typedef uint16_t hptime_t;
121 static void timer_hw_init(void)
124 DISABLE_IRQSAVE(flags);
126 /* Reset Timer overflow flag */
129 /* Fast PWM mode, 9 bit, 24 kHz, no prescaling. When changing freq or
130 resolution (top of TCNT), change TIMER_HW_HPTICKS_PER_SEC too */
132 TCCR1A &= ~BV(WGM10);
133 TCCR1B |= BV(WGM12) | BV(CS10);
134 TCCR1B &= ~(BV(WGM13) | BV(CS11) | BV(CS12));
136 TCNT1 = 0x00; /* initialization of Timer/Counter */
138 /* Enable timer interrupt: Timer/Counter1 Overflow */
141 ENABLE_IRQRESTORE(flags);
144 //! Frequency of the hardware high precision timer
145 #define TIMER_HW_HPTICKS_PER_SEC (24000ul * 512)
147 INLINE hptime_t timer_hw_hpread(void)
152 #elif defined(CONFIG_TIMER_ON_TIMER2)
154 //! Type of time expressed in ticks of the hardware high precision timer
155 typedef uint8_t hptime_t;
157 static void timer_hw_init(void)
160 DISABLE_IRQSAVE(flags);
162 /* Reset Timer flags */
163 TIFR = BV(OCF2) | BV(TOV2);
165 /* Setup Timer/Counter interrupt */
167 #if TIMER_PRESCALER == 64
168 | BV(CS21) | BV(CS20)
170 #error Unsupported value of TIMER_PRESCALER
173 /* Clear on Compare match & prescaler = 64, internal sys clock.
174 When changing prescaler change TIMER_HW_HPTICKS_PER_SEC too */
175 TCNT2 = 0x00; /* initialization of Timer/Counter */
176 OCR2 = OCR_DIVISOR; /* Timer/Counter Output Compare Register */
178 /* Enable timer interrupts: Timer/Counter2 Output Compare (OCIE2) */
182 ENABLE_IRQRESTORE(flags);
185 //! Frequency of the hardware high precision timer
186 #define TIMER_HW_HPTICKS_PER_SEC (CLOCK_FREQ / TIMER_PRESCALER)
188 INLINE hptime_t timer_hw_hpread(void)
194 #error Choose witch timer to use with CONFIG_TIMER_ON_TIMERx
195 #endif /* CONFIG_TIMER_ON_TIMERx */
198 #if defined(CONFIG_TIMER_ON_TIMER1_OVERFLOW)
200 #define DEFINE_TIMER_ISR \
201 static void timer_handler(void)
206 * Timer 1 overflow irq handler. It's called at the frequency of the timer 1
207 * PWM (should be 24 kHz). It's too much for timer purposes, so the interrupt
208 * handler is really a counter that call the true handler in timer.c
211 SIGNAL(SIG_OVERFLOW1)
214 * How many overflow we have to count before calling the true timer handler.
215 * If timer overflow is at 24 kHz, with a value of 24 we have 1 ms between
218 #define TIMER1_OVF_COUNT 24
220 static uint8_t count = TIMER1_OVF_COUNT;
226 count = TIMER1_OVF_COUNT;
229 #if (ARCH & ARCH_BOARD_KC)
231 * Super-optimization-hack: switch CPU ADC mux here, ASAP after the start
232 * of conversion (auto-triggered with timer 1 overflow).
233 * The switch can be done 2 ADC cycles after start of conversion.
234 * The handler prologue takes a little more than 32 CPU cycles: with
235 * the prescaler at 1/16 the timing should be correct even at the start
238 * The switch is synchronized with the ADC handler using _adc_trigger_lock.
240 extern uint8_t _adc_idx_next;
241 extern bool _adc_trigger_lock;
243 if (!_adc_trigger_lock)
246 ADC_SETCHN(_adc_idx_next);
248 _adc_trigger_lock = true;
253 #elif defined (CONFIG_TIMER_ON_TIMER0)
255 #define DEFINE_TIMER_ISR \
256 SIGNAL(SIG_OUTPUT_COMPARE0)
258 #elif defined(CONFIG_TIMER_ON_TIMER2)
260 #define DEFINE_TIMER_ISR \
261 SIGNAL(SIG_OUTPUT_COMPARE2)
264 #error Choose witch timer to use with CONFIG_TIMER_ON_TIMERx
265 #endif /* CONFIG_TIMER_ON_TIMERx */
267 #endif /* DRV_TIMER_AVR_H */