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.9 2004/07/22 02:01:14 bernie
19 * Use TIMER_PRESCALER consistently.
21 * Revision 1.8 2004/07/20 23:50:20 bernie
22 * Also define TIMER_PRESCALER.
24 * Revision 1.7 2004/07/20 23:49:40 bernie
25 * Compute value of OCR_DIVISOR from CLOCK_FREQ.
27 * Revision 1.6 2004/07/20 23:48:16 bernie
28 * Finally remove redundant protos.
30 * Revision 1.5 2004/07/18 22:16:35 bernie
31 * Add missing header; Prevent warning for project_ks-specific code.
33 * Revision 1.4 2004/06/27 15:22:15 aleph
36 * Revision 1.3 2004/06/07 15:57:40 aleph
37 * Update to latest AVR timer code
39 * Revision 1.2 2004/06/03 11:27:09 bernie
40 * Add dual-license information.
42 * Revision 1.1 2004/05/23 18:23:30 bernie
43 * Import drv/timer module.
47 #ifndef DRV_TIMER_AVR_H
48 #define DRV_TIMER_AVR_H
51 #include <avr/signal.h>
53 #if defined(ARCH_BOARD_KC) && (ARCH & ARCH_BOARD_KC)
58 /* Not needed, IRQ timer flag cleared automatically */
59 #define timer_hw_irq() do {} while (0)
61 #define TIMER_PRESCALER 64
64 * System timer: additional division after the prescaler
65 * 12288000 / 64 / 192 (0..191) = 1 ms
67 #define OCR_DIVISOR (CLOCK_FREQ / TIMER_PRESCALER / TICKS_PER_SEC - 1) /* 191 */
69 /*! HW dependent timer initialization */
70 #if defined(CONFIG_TIMER_ON_TIMER0)
72 //! Type of time expressed in ticks of the hardware high-precision timer
73 typedef uint8_t hptime_t;
75 static void timer_hw_init(void)
78 DISABLE_IRQSAVE(flags);
80 /* Reset Timer flags */
81 TIFR = BV(OCF0) | BV(TOV0);
83 /* Setup Timer/Counter interrupt */
84 ASSR = 0x00; /* Internal system clock */
85 TCCR0 = BV(WGM01) /* Clear on Compare match */
86 #if TIMER_PRESCALER == 64
89 #error Unsupported value of TIMER_PRESCALER
92 TCNT0 = 0x00; /* Initialization of Timer/Counter */
93 OCR0 = OCR_DIVISOR; /* Timer/Counter Output Compare Register */
95 /* Enable timer interrupts: Timer/Counter2 Output Compare (OCIE2) */
99 ENABLE_IRQRESTORE(flags);
102 //! Frequency of the hardware high precision timer
103 #define TIMER_HW_HPTICKS_PER_SEC (CLOCK_FREQ / TIMER_PRESCALER)
105 INLINE hptime_t timer_hw_hpread(void)
110 #elif defined(CONFIG_TIMER_ON_TIMER1_OVERFLOW)
112 //! Type of time expressed in ticks of the hardware high precision timer
113 typedef uint16_t hptime_t;
115 static void timer_hw_init(void)
118 DISABLE_IRQSAVE(flags);
120 /* Reset Timer overflow flag */
123 /* Fast PWM mode, 9 bit, 24 kHz, no prescaling. When changing freq or
124 resolution (top of TCNT), change TIMER_HW_HPTICKS_PER_SEC too */
126 TCCR1A &= ~BV(WGM10);
127 TCCR1B |= BV(WGM12) | BV(CS10);
128 TCCR1B &= ~(BV(WGM13) | BV(CS11) | BV(CS12));
130 TCNT1 = 0x00; /* initialization of Timer/Counter */
132 /* Enable timer interrupt: Timer/Counter1 Overflow */
135 ENABLE_IRQRESTORE(flags);
138 //! Frequency of the hardware high precision timer
139 #define TIMER_HW_HPTICKS_PER_SEC (24000ul * 512)
141 INLINE hptime_t timer_hw_hpread(void)
146 #elif defined(CONFIG_TIMER_ON_TIMER2)
148 //! Type of time expressed in ticks of the hardware high precision timer
149 typedef uint8_t hptime_t;
151 static void timer_hw_init(void)
154 DISABLE_IRQSAVE(flags);
156 /* Reset Timer flags */
157 TIFR = BV(OCF2) | BV(TOV2);
159 /* Setup Timer/Counter interrupt */
160 #warning Aleph, please use TIMER_PRESCALER here
161 TCCR2 = BV(WGM21) | BV(CS21) | BV(CS20);
162 /* Clear on Compare match & prescaler = 64, internal sys clock.
163 When changing prescaler change TIMER_HW_HPTICKS_PER_SEC too */
164 TCNT2 = 0x00; /* initialization of Timer/Counter */
165 OCR2 = OCR_DIVISOR; /* Timer/Counter Output Compare Register */
167 /* Enable timer interrupts: Timer/Counter2 Output Compare (OCIE2) */
171 ENABLE_IRQRESTORE(flags);
174 //! Frequency of the hardware high precision timer
175 #define TIMER_HW_HPTICKS_PER_SEC (CLOCK_FREQ / TIMER_PRESCALER)
177 INLINE hptime_t timer_hw_hpread(void)
183 #error Choose witch timer to use with CONFIG_TIMER_ON_TIMERx
184 #endif /* CONFIG_TIMER_ON_TIMERx */
187 #if defined(CONFIG_TIMER_ON_TIMER1_OVERFLOW)
189 #define DEFINE_TIMER_ISR \
190 static void timer_handler(void)
195 * Timer 1 overflow irq handler. It's called at the frequency of the timer 1
196 * PWM (should be 24 kHz). It's too much for timer purposes, so the interrupt
197 * handler is really a counter that call the true handler in timer.c
200 SIGNAL(SIG_OVERFLOW1)
203 * How many overflow we have to count before calling the true timer handler.
204 * If timer overflow is at 24 kHz, with a value of 24 we have 1 ms between
207 #define TIMER1_OVF_COUNT 24
209 static uint8_t count = TIMER1_OVF_COUNT;
215 count = TIMER1_OVF_COUNT;
218 #if (ARCH & ARCH_BOARD_KC)
220 * Super-optimization-hack: switch CPU ADC mux here, ASAP after the start
221 * of conversion (auto-triggered with timer 1 overflow).
222 * The switch can be done 2 ADC cycles after start of conversion.
223 * The handler prologue takes a little more than 32 CPU cycles: with
224 * the prescaler at 1/16 the timing should be correct even at the start
227 * The switch is synchronized with the ADC handler using _adc_trigger_lock.
229 extern uint8_t _adc_idx_next;
230 extern bool _adc_trigger_lock;
232 if (!_adc_trigger_lock)
235 ADC_SETCHN(_adc_idx_next);
237 _adc_trigger_lock = true;
242 #elif defined (CONFIG_TIMER_ON_TIMER0)
244 #define DEFINE_TIMER_ISR \
245 SIGNAL(SIG_OUTPUT_COMPARE0)
247 #elif defined(CONFIG_TIMER_ON_TIMER2)
249 #define DEFINE_TIMER_ISR \
250 SIGNAL(SIG_OUTPUT_COMPARE2)
253 #error Choose witch timer to use with CONFIG_TIMER_ON_TIMERx
254 #endif /* CONFIG_TIMER_ON_TIMERx */
256 #endif /* DRV_TIMER_AVR_H */