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.6 2004/07/20 23:48:16 bernie
19 * Finally remove redundant protos.
21 * Revision 1.5 2004/07/18 22:16:35 bernie
22 * Add missing header; Prevent warning for project_ks-specific code.
24 * Revision 1.4 2004/06/27 15:22:15 aleph
27 * Revision 1.3 2004/06/07 15:57:40 aleph
28 * Update to latest AVR timer code
30 * Revision 1.2 2004/06/03 11:27:09 bernie
31 * Add dual-license information.
33 * Revision 1.1 2004/05/23 18:23:30 bernie
34 * Import drv/timer module.
38 #ifndef DRV_TIMER_AVR_H
39 #define DRV_TIMER_AVR_H
42 #include <avr/signal.h>
44 #if defined(ARCH_BOARD_KC) && (ARCH & ARCH_BOARD_KC)
49 #define timer_hw_irq() /* Not needed, IRQ timer flag cleared automatically */
52 * System timer: additional division after the prescaler
53 * 12288000 / 64 / 192 (0..191) = 1 ms
55 #define OCR_DIVISOR 191
57 /*! HW dependent timer initialization */
58 #if defined(CONFIG_TIMER_ON_TIMER0)
60 //! Type of time expressed in ticks of the hardware high-precision timer
61 typedef uint8_t hptime_t;
63 static void timer_hw_init(void)
66 DISABLE_IRQSAVE(flags);
68 /* Reset Timer flags */
69 TIFR = BV(OCF0) | BV(TOV0);
71 /* Setup Timer/Counter interrupt */
72 ASSR = 0x00; /* internal system clock */
73 TCCR0 = BV(WGM01) | BV(CS02); /* Clear on Compare match & prescaler = 64. When changing
74 prescaler change TIMER_HW_HPTICKS_PER_SEC too */
75 TCNT0 = 0x00; /* initialization of Timer/Counter */
76 OCR0 = OCR_DIVISOR; /* Timer/Counter Output Compare Register */
78 /* Enable timer interrupts: Timer/Counter2 Output Compare (OCIE2) */
82 ENABLE_IRQRESTORE(flags);
85 //! Frequency of the hardware high precision timer
86 #define TIMER_HW_HPTICKS_PER_SEC (CLOCK_FREQ / 64)
88 INLINE hptime_t timer_hw_hpread(void)
93 #elif defined(CONFIG_TIMER_ON_TIMER1_OVERFLOW)
95 //! Type of time expressed in ticks of the hardware high precision timer
96 typedef uint16_t hptime_t;
98 static void timer_hw_init(void)
101 DISABLE_IRQSAVE(flags);
103 /* Reset Timer overflow flag */
106 /* Fast PWM mode, 9 bit, 24 kHz, no prescaling. When changing freq or
107 resolution (top of TCNT), change TIMER_HW_HPTICKS_PER_SEC too */
109 TCCR1A &= ~BV(WGM10);
110 TCCR1B |= BV(WGM12) | BV(CS10);
111 TCCR1B &= ~(BV(WGM13) | BV(CS11) | BV(CS12));
113 TCNT1 = 0x00; /* initialization of Timer/Counter */
115 /* Enable timer interrupt: Timer/Counter1 Overflow */
118 ENABLE_IRQRESTORE(flags);
121 //! Frequency of the hardware high precision timer
122 #define TIMER_HW_HPTICKS_PER_SEC (24000ul * 512)
124 INLINE hptime_t timer_hw_hpread(void)
129 #elif defined(CONFIG_TIMER_ON_TIMER2)
131 //! Type of time expressed in ticks of the hardware high precision timer
132 typedef uint8_t hptime_t;
134 static void timer_hw_init(void)
137 DISABLE_IRQSAVE(flags);
139 /* Reset Timer flags */
140 TIFR = BV(OCF2) | BV(TOV2);
142 /* Setup Timer/Counter interrupt */
143 TCCR2 = BV(WGM21) | BV(CS21) | BV(CS20);
144 /* Clear on Compare match & prescaler = 64, internal sys clock.
145 When changing prescaler change TIMER_HW_HPTICKS_PER_SEC too */
146 TCNT2 = 0x00; /* initialization of Timer/Counter */
147 OCR2 = OCR_DIVISOR; /* Timer/Counter Output Compare Register */
149 /* Enable timer interrupts: Timer/Counter2 Output Compare (OCIE2) */
153 ENABLE_IRQRESTORE(flags);
156 //! Frequency of the hardware high precision timer
157 #define TIMER_HW_HPTICKS_PER_SEC (CLOCK_FREQ / 64)
159 INLINE hptime_t timer_hw_hpread(void)
165 #error Choose witch timer to use with CONFIG_TIMER_ON_TIMERx
166 #endif /* CONFIG_TIMER_ON_TIMERx */
169 #if defined(CONFIG_TIMER_ON_TIMER1_OVERFLOW)
171 #define DEFINE_TIMER_ISR \
172 static void timer_handler(void)
177 * Timer 1 overflow irq handler. It's called at the frequency of the timer 1
178 * PWM (should be 24 kHz). It's too much for timer purposes, so the interrupt
179 * handler is really a counter that call the true handler in timer.c
182 SIGNAL(SIG_OVERFLOW1)
185 * How many overflow we have to count before calling the true timer handler.
186 * If timer overflow is at 24 kHz, with a value of 24 we have 1 ms between
189 #define TIMER1_OVF_COUNT 24
191 static uint8_t count = TIMER1_OVF_COUNT;
197 count = TIMER1_OVF_COUNT;
200 #if (ARCH & ARCH_BOARD_KC)
202 * Super-optimization-hack: switch CPU ADC mux here, ASAP after the start
203 * of conversion (auto-triggered with timer 1 overflow).
204 * The switch can be done 2 ADC cycles after start of conversion.
205 * The handler prologue takes a little more than 32 CPU cycles: with
206 * the prescaler at 1/16 the timing should be correct even at the start
209 * The switch is synchronized with the ADC handler using _adc_trigger_lock.
211 extern uint8_t _adc_idx_next;
212 extern bool _adc_trigger_lock;
214 if (!_adc_trigger_lock)
217 ADC_SETCHN(_adc_idx_next);
219 _adc_trigger_lock = true;
224 #elif defined (CONFIG_TIMER_ON_TIMER0)
226 #define DEFINE_TIMER_ISR \
227 SIGNAL(SIG_OUTPUT_COMPARE0)
229 #elif defined(CONFIG_TIMER_ON_TIMER2)
231 #define DEFINE_TIMER_ISR \
232 SIGNAL(SIG_OUTPUT_COMPARE2)
235 #error Choose witch timer to use with CONFIG_TIMER_ON_TIMERx
236 #endif /* CONFIG_TIMER_ON_TIMERx */
238 #endif /* DRV_TIMER_AVR_H */