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.5 2004/07/18 22:16:35 bernie
19 * Add missing header; Prevent warning for project_ks-specific code.
21 * Revision 1.4 2004/06/27 15:22:15 aleph
24 * Revision 1.3 2004/06/07 15:57:40 aleph
25 * Update to latest AVR timer code
27 * Revision 1.2 2004/06/03 11:27:09 bernie
28 * Add dual-license information.
30 * Revision 1.1 2004/05/23 18:23:30 bernie
31 * Import drv/timer module.
35 #ifndef DRV_TIMER_AVR_H
36 #define DRV_TIMER_AVR_H
39 #include <avr/signal.h>
41 #if defined(ARCH_BOARD_KC) && (ARCH & ARCH_BOARD_KC)
46 #define timer_hw_irq() /* Not needed, IRQ timer flag cleared automatically */
49 * System timer: additional division after the prescaler
50 * 12288000 / 64 / 192 (0..191) = 1 ms
52 #define OCR_DIVISOR 191
54 /*! HW dependent timer initialization */
55 #if defined(CONFIG_TIMER_ON_TIMER0)
57 //! Type of time expressed in ticks of the hardware high-precision timer
58 typedef uint8_t hptime_t;
60 static void timer_hw_init(void)
63 DISABLE_IRQSAVE(flags);
65 /* Reset Timer flags */
66 TIFR = BV(OCF0) | BV(TOV0);
68 /* Setup Timer/Counter interrupt */
69 ASSR = 0x00; /* internal system clock */
70 TCCR0 = BV(WGM01) | BV(CS02); /* Clear on Compare match & prescaler = 64. When changing
71 prescaler change TIMER_HW_HPTICKS_PER_SEC too */
72 TCNT0 = 0x00; /* initialization of Timer/Counter */
73 OCR0 = OCR_DIVISOR; /* Timer/Counter Output Compare Register */
75 /* Enable timer interrupts: Timer/Counter2 Output Compare (OCIE2) */
79 ENABLE_IRQRESTORE(flags);
82 //! Frequency of the hardware high precision timer
83 #define TIMER_HW_HPTICKS_PER_SEC (CLOCK_FREQ / 64)
85 INLINE hptime_t timer_hw_hpread(void);
86 INLINE hptime_t timer_hw_hpread(void)
91 #elif defined(CONFIG_TIMER_ON_TIMER1_OVERFLOW)
93 //! Type of time expressed in ticks of the hardware high precision timer
94 typedef uint16_t hptime_t;
96 static void timer_hw_init(void)
99 DISABLE_IRQSAVE(flags);
101 /* Reset Timer overflow flag */
104 /* Fast PWM mode, 9 bit, 24 kHz, no prescaling. When changing freq or
105 resolution (top of TCNT), change TIMER_HW_HPTICKS_PER_SEC too */
107 TCCR1A &= ~BV(WGM10);
108 TCCR1B |= BV(WGM12) | BV(CS10);
109 TCCR1B &= ~(BV(WGM13) | BV(CS11) | BV(CS12));
111 TCNT1 = 0x00; /* initialization of Timer/Counter */
113 /* Enable timer interrupt: Timer/Counter1 Overflow */
116 ENABLE_IRQRESTORE(flags);
119 //! Frequency of the hardware high precision timer
120 #define TIMER_HW_HPTICKS_PER_SEC (24000ul * 512)
122 INLINE hptime_t timer_hw_hpread(void);
123 INLINE hptime_t timer_hw_hpread(void)
128 #elif defined(CONFIG_TIMER_ON_TIMER2)
130 //! Type of time expressed in ticks of the hardware high precision timer
131 typedef uint8_t hptime_t;
133 static void timer_hw_init(void)
136 DISABLE_IRQSAVE(flags);
138 /* Reset Timer flags */
139 TIFR = BV(OCF2) | BV(TOV2);
141 /* Setup Timer/Counter interrupt */
142 TCCR2 = BV(WGM21) | BV(CS21) | BV(CS20);
143 /* Clear on Compare match & prescaler = 64, internal sys clock.
144 When changing prescaler change TIMER_HW_HPTICKS_PER_SEC too */
145 TCNT2 = 0x00; /* initialization of Timer/Counter */
146 OCR2 = OCR_DIVISOR; /* Timer/Counter Output Compare Register */
148 /* Enable timer interrupts: Timer/Counter2 Output Compare (OCIE2) */
152 ENABLE_IRQRESTORE(flags);
155 //! Frequency of the hardware high precision timer
156 #define TIMER_HW_HPTICKS_PER_SEC (CLOCK_FREQ / 64)
158 INLINE hptime_t timer_hw_hpread(void);
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 */