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