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.8 2004/07/20 23:50:20 bernie
19 * Also define TIMER_PRESCALER.
21 * Revision 1.7 2004/07/20 23:49:40 bernie
22 * Compute value of OCR_DIVISOR from CLOCK_FREQ.
24 * Revision 1.6 2004/07/20 23:48:16 bernie
25 * Finally remove redundant protos.
27 * Revision 1.5 2004/07/18 22:16:35 bernie
28 * Add missing header; Prevent warning for project_ks-specific code.
30 * Revision 1.4 2004/06/27 15:22:15 aleph
33 * Revision 1.3 2004/06/07 15:57:40 aleph
34 * Update to latest AVR timer code
36 * Revision 1.2 2004/06/03 11:27:09 bernie
37 * Add dual-license information.
39 * Revision 1.1 2004/05/23 18:23:30 bernie
40 * Import drv/timer module.
44 #ifndef DRV_TIMER_AVR_H
45 #define DRV_TIMER_AVR_H
48 #include <avr/signal.h>
50 #if defined(ARCH_BOARD_KC) && (ARCH & ARCH_BOARD_KC)
55 #define timer_hw_irq() /* Not needed, IRQ timer flag cleared automatically */
57 #define TIMER_PRESCALER 64
60 * System timer: additional division after the prescaler
61 * 12288000 / 64 / 192 (0..191) = 1 ms
63 #define OCR_DIVISOR (CLOCK_FREQ / TIMER_PRESCALER / TICKS_PER_SEC - 1) /* 191 */
65 /*! HW dependent timer initialization */
66 #if defined(CONFIG_TIMER_ON_TIMER0)
68 //! Type of time expressed in ticks of the hardware high-precision timer
69 typedef uint8_t hptime_t;
71 static void timer_hw_init(void)
74 DISABLE_IRQSAVE(flags);
76 /* Reset Timer flags */
77 TIFR = BV(OCF0) | BV(TOV0);
79 /* Setup Timer/Counter interrupt */
80 ASSR = 0x00; /* internal system clock */
81 TCCR0 = BV(WGM01) | BV(CS02); /* Clear on Compare match & prescaler = 64. When changing
82 prescaler change TIMER_HW_HPTICKS_PER_SEC too */
83 TCNT0 = 0x00; /* initialization of Timer/Counter */
84 OCR0 = OCR_DIVISOR; /* Timer/Counter Output Compare Register */
86 /* Enable timer interrupts: Timer/Counter2 Output Compare (OCIE2) */
90 ENABLE_IRQRESTORE(flags);
93 //! Frequency of the hardware high precision timer
94 #define TIMER_HW_HPTICKS_PER_SEC (CLOCK_FREQ / 64)
96 INLINE hptime_t timer_hw_hpread(void)
101 #elif defined(CONFIG_TIMER_ON_TIMER1_OVERFLOW)
103 //! Type of time expressed in ticks of the hardware high precision timer
104 typedef uint16_t hptime_t;
106 static void timer_hw_init(void)
109 DISABLE_IRQSAVE(flags);
111 /* Reset Timer overflow flag */
114 /* Fast PWM mode, 9 bit, 24 kHz, no prescaling. When changing freq or
115 resolution (top of TCNT), change TIMER_HW_HPTICKS_PER_SEC too */
117 TCCR1A &= ~BV(WGM10);
118 TCCR1B |= BV(WGM12) | BV(CS10);
119 TCCR1B &= ~(BV(WGM13) | BV(CS11) | BV(CS12));
121 TCNT1 = 0x00; /* initialization of Timer/Counter */
123 /* Enable timer interrupt: Timer/Counter1 Overflow */
126 ENABLE_IRQRESTORE(flags);
129 //! Frequency of the hardware high precision timer
130 #define TIMER_HW_HPTICKS_PER_SEC (24000ul * 512)
132 INLINE hptime_t timer_hw_hpread(void)
137 #elif defined(CONFIG_TIMER_ON_TIMER2)
139 //! Type of time expressed in ticks of the hardware high precision timer
140 typedef uint8_t hptime_t;
142 static void timer_hw_init(void)
145 DISABLE_IRQSAVE(flags);
147 /* Reset Timer flags */
148 TIFR = BV(OCF2) | BV(TOV2);
150 /* Setup Timer/Counter interrupt */
151 TCCR2 = BV(WGM21) | BV(CS21) | BV(CS20);
152 /* Clear on Compare match & prescaler = 64, internal sys clock.
153 When changing prescaler change TIMER_HW_HPTICKS_PER_SEC too */
154 TCNT2 = 0x00; /* initialization of Timer/Counter */
155 OCR2 = OCR_DIVISOR; /* Timer/Counter Output Compare Register */
157 /* Enable timer interrupts: Timer/Counter2 Output Compare (OCIE2) */
161 ENABLE_IRQRESTORE(flags);
164 //! Frequency of the hardware high precision timer
165 #define TIMER_HW_HPTICKS_PER_SEC (CLOCK_FREQ / 64)
167 INLINE hptime_t timer_hw_hpread(void)
173 #error Choose witch timer to use with CONFIG_TIMER_ON_TIMERx
174 #endif /* CONFIG_TIMER_ON_TIMERx */
177 #if defined(CONFIG_TIMER_ON_TIMER1_OVERFLOW)
179 #define DEFINE_TIMER_ISR \
180 static void timer_handler(void)
185 * Timer 1 overflow irq handler. It's called at the frequency of the timer 1
186 * PWM (should be 24 kHz). It's too much for timer purposes, so the interrupt
187 * handler is really a counter that call the true handler in timer.c
190 SIGNAL(SIG_OVERFLOW1)
193 * How many overflow we have to count before calling the true timer handler.
194 * If timer overflow is at 24 kHz, with a value of 24 we have 1 ms between
197 #define TIMER1_OVF_COUNT 24
199 static uint8_t count = TIMER1_OVF_COUNT;
205 count = TIMER1_OVF_COUNT;
208 #if (ARCH & ARCH_BOARD_KC)
210 * Super-optimization-hack: switch CPU ADC mux here, ASAP after the start
211 * of conversion (auto-triggered with timer 1 overflow).
212 * The switch can be done 2 ADC cycles after start of conversion.
213 * The handler prologue takes a little more than 32 CPU cycles: with
214 * the prescaler at 1/16 the timing should be correct even at the start
217 * The switch is synchronized with the ADC handler using _adc_trigger_lock.
219 extern uint8_t _adc_idx_next;
220 extern bool _adc_trigger_lock;
222 if (!_adc_trigger_lock)
225 ADC_SETCHN(_adc_idx_next);
227 _adc_trigger_lock = true;
232 #elif defined (CONFIG_TIMER_ON_TIMER0)
234 #define DEFINE_TIMER_ISR \
235 SIGNAL(SIG_OUTPUT_COMPARE0)
237 #elif defined(CONFIG_TIMER_ON_TIMER2)
239 #define DEFINE_TIMER_ISR \
240 SIGNAL(SIG_OUTPUT_COMPARE2)
243 #error Choose witch timer to use with CONFIG_TIMER_ON_TIMERx
244 #endif /* CONFIG_TIMER_ON_TIMERx */
246 #endif /* DRV_TIMER_AVR_H */