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.12 2004/08/10 06:59:45 bernie
19 * CONFIG_TIMER_STROBE: Define no-op default macros.
21 * Revision 1.11 2004/08/03 15:53:17 aleph
24 * Revision 1.10 2004/08/02 20:20:29 aleph
25 * Merge from project_ks
27 * Revision 1.9 2004/07/22 02:01:14 bernie
28 * Use TIMER_PRESCALER consistently.
30 * Revision 1.8 2004/07/20 23:50:20 bernie
31 * Also define TIMER_PRESCALER.
33 * Revision 1.7 2004/07/20 23:49:40 bernie
34 * Compute value of OCR_DIVISOR from CLOCK_FREQ.
36 * Revision 1.6 2004/07/20 23:48:16 bernie
37 * Finally remove redundant protos.
39 * Revision 1.5 2004/07/18 22:16:35 bernie
40 * Add missing header; Prevent warning for project_ks-specific code.
42 * Revision 1.4 2004/06/27 15:22:15 aleph
45 * Revision 1.3 2004/06/07 15:57:40 aleph
46 * Update to latest AVR timer code
48 * Revision 1.2 2004/06/03 11:27:09 bernie
49 * Add dual-license information.
51 * Revision 1.1 2004/05/23 18:23:30 bernie
52 * Import drv/timer module.
56 #ifndef DRV_TIMER_AVR_H
57 #define DRV_TIMER_AVR_H
60 #include <avr/signal.h>
62 #if defined(ARCH_BOARD_KC) && (ARCH & ARCH_BOARD_KC)
68 * \def CONFIG_TIMER_STROBE
70 * This is a debug facility that can be used to
71 * monitor timer interrupt activity on an external pin.
73 * To use strobes, redefine the macros TIMER_STROBE_ON,
74 * TIMER_STROBE_OFF and TIMER_STROBE_INIT and set
75 * CONFIG_TIMER_STROBE to 1.
77 #ifndef CONFIG_TIMER_STROBE
78 #define TIMER_STROBE_ON do {/*nop*/} while(0)
79 #define TIMER_STROBE_OFF do {/*nop*/} while(0)
80 #define TIMER_STROBE_INIT do {/*nop*/} while(0)
84 /* Not needed, IRQ timer flag cleared automatically */
85 #define timer_hw_irq() do {} while (0)
87 #define TIMER_PRESCALER 64
90 * System timer: additional division after the prescaler
91 * 12288000 / 64 / 192 (0..191) = 1 ms
93 #define OCR_DIVISOR (CLOCK_FREQ / TIMER_PRESCALER / TICKS_PER_SEC - 1) /* 191 */
95 /*! HW dependent timer initialization */
96 #if defined(CONFIG_TIMER_ON_TIMER0)
98 //! Type of time expressed in ticks of the hardware high-precision timer
99 typedef uint8_t hptime_t;
101 static void timer_hw_init(void)
104 DISABLE_IRQSAVE(flags);
106 /* Reset Timer flags */
107 TIFR = BV(OCF0) | BV(TOV0);
109 /* Setup Timer/Counter interrupt */
110 ASSR = 0x00; /* Internal system clock */
111 TCCR0 = BV(WGM01) /* Clear on Compare match */
112 #if TIMER_PRESCALER == 64
115 #error Unsupported value of TIMER_PRESCALER
118 TCNT0 = 0x00; /* Initialization of Timer/Counter */
119 OCR0 = OCR_DIVISOR; /* Timer/Counter Output Compare Register */
121 /* Enable timer interrupts: Timer/Counter2 Output Compare (OCIE2) */
125 ENABLE_IRQRESTORE(flags);
128 //! Frequency of the hardware high precision timer
129 #define TIMER_HW_HPTICKS_PER_SEC (CLOCK_FREQ / TIMER_PRESCALER)
131 INLINE hptime_t timer_hw_hpread(void)
136 #elif defined(CONFIG_TIMER_ON_TIMER1_OVERFLOW)
138 //! Type of time expressed in ticks of the hardware high precision timer
139 typedef uint16_t hptime_t;
141 static void timer_hw_init(void)
144 DISABLE_IRQSAVE(flags);
146 /* Reset Timer overflow flag */
149 /* Fast PWM mode, 9 bit, 24 kHz, no prescaling. When changing freq or
150 resolution (top of TCNT), change TIMER_HW_HPTICKS_PER_SEC too */
152 TCCR1A &= ~BV(WGM10);
153 TCCR1B |= BV(WGM12) | BV(CS10);
154 TCCR1B &= ~(BV(WGM13) | BV(CS11) | BV(CS12));
156 TCNT1 = 0x00; /* initialization of Timer/Counter */
158 /* Enable timer interrupt: Timer/Counter1 Overflow */
161 ENABLE_IRQRESTORE(flags);
164 //! Frequency of the hardware high precision timer
165 #define TIMER_HW_HPTICKS_PER_SEC (24000ul * 512)
167 INLINE hptime_t timer_hw_hpread(void)
172 #elif defined(CONFIG_TIMER_ON_TIMER2)
174 //! Type of time expressed in ticks of the hardware high precision timer
175 typedef uint8_t hptime_t;
177 static void timer_hw_init(void)
180 DISABLE_IRQSAVE(flags);
182 /* Reset Timer flags */
183 TIFR = BV(OCF2) | BV(TOV2);
185 /* Setup Timer/Counter interrupt */
187 #if TIMER_PRESCALER == 64
188 | BV(CS21) | BV(CS20)
190 #error Unsupported value of TIMER_PRESCALER
193 /* Clear on Compare match & prescaler = 64, internal sys clock.
194 When changing prescaler change TIMER_HW_HPTICKS_PER_SEC too */
195 TCNT2 = 0x00; /* initialization of Timer/Counter */
196 OCR2 = OCR_DIVISOR; /* Timer/Counter Output Compare Register */
198 /* Enable timer interrupts: Timer/Counter2 Output Compare (OCIE2) */
202 ENABLE_IRQRESTORE(flags);
205 //! Frequency of the hardware high precision timer
206 #define TIMER_HW_HPTICKS_PER_SEC (CLOCK_FREQ / TIMER_PRESCALER)
208 INLINE hptime_t timer_hw_hpread(void)
214 #error Choose witch timer to use with CONFIG_TIMER_ON_TIMERx
215 #endif /* CONFIG_TIMER_ON_TIMERx */
218 #if defined(CONFIG_TIMER_ON_TIMER1_OVERFLOW)
220 #define DEFINE_TIMER_ISR \
221 static void timer_handler(void)
226 * Timer 1 overflow irq handler. It's called at the frequency of the timer 1
227 * PWM (should be 24 kHz). It's too much for timer purposes, so the interrupt
228 * handler is really a counter that call the true handler in timer.c
231 SIGNAL(SIG_OVERFLOW1)
234 * How many overflow we have to count before calling the true timer handler.
235 * If timer overflow is at 24 kHz, with a value of 24 we have 1 ms between
238 #define TIMER1_OVF_COUNT 24
240 static uint8_t count = TIMER1_OVF_COUNT;
246 count = TIMER1_OVF_COUNT;
249 #if (ARCH & ARCH_BOARD_KC)
251 * Super-optimization-hack: switch CPU ADC mux here, ASAP after the start
252 * of conversion (auto-triggered with timer 1 overflow).
253 * The switch can be done 2 ADC cycles after start of conversion.
254 * The handler prologue takes a little more than 32 CPU cycles: with
255 * the prescaler at 1/16 the timing should be correct even at the start
258 * The switch is synchronized with the ADC handler using _adc_trigger_lock.
260 extern uint8_t _adc_idx_next;
261 extern bool _adc_trigger_lock;
263 if (!_adc_trigger_lock)
266 ADC_SETCHN(_adc_idx_next);
268 _adc_trigger_lock = true;
273 #elif defined (CONFIG_TIMER_ON_TIMER0)
275 #define DEFINE_TIMER_ISR \
276 SIGNAL(SIG_OUTPUT_COMPARE0)
278 #elif defined(CONFIG_TIMER_ON_TIMER2)
280 #define DEFINE_TIMER_ISR \
281 SIGNAL(SIG_OUTPUT_COMPARE2)
284 #error Choose witch timer to use with CONFIG_TIMER_ON_TIMERx
285 #endif /* CONFIG_TIMER_ON_TIMERx */
287 #endif /* DRV_TIMER_AVR_H */