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.3 2004/06/07 15:57:40 aleph
19 * Update to latest AVR timer code
21 * Revision 1.2 2004/06/03 11:27:09 bernie
22 * Add dual-license information.
24 * Revision 1.1 2004/05/23 18:23:30 bernie
25 * Import drv/timer module.
29 #ifndef DRV_TIMER_AVR_H
30 #define DRV_TIMER_AVR_H
34 #if (ARCH & ARCH_BOARD_KC)
39 #define timer_hw_irq() /* Not needed, IRQ timer flag cleared automatically */
42 * System timer: additional division after the prescaler
43 * 12288000 / 64 / 192 (0..191) = 1 ms
45 #define OCR_DIVISOR 191
47 /*! HW dependent timer initialization */
48 #if defined(CONFIG_TIMER_ON_TIMER0)
50 //! Type of time expressed in ticks of the hardware high-precision timer
51 typedef uint8_t hptime_t;
53 static void timer_hw_init(void)
56 DISABLE_IRQSAVE(flags);
58 /* Reset Timer flags */
59 TIFR = BV(OCF0) | BV(TOV0);
61 /* Setup Timer/Counter interrupt */
62 ASSR = 0x00; /* internal system clock */
63 TCCR0 = BV(WGM01) | BV(CS02); /* Clear on Compare match & prescaler = 64. When changing
64 prescaler change TIMER_HW_HPTICKS_PER_SEC too */
65 TCNT0 = 0x00; /* initialization of Timer/Counter */
66 OCR0 = OCR_DIVISOR; /* Timer/Counter Output Compare Register */
68 /* Enable timer interrupts: Timer/Counter2 Output Compare (OCIE2) */
72 ENABLE_IRQRESTORE(flags);
75 //! Frequency of the hardware high precision timer
76 #define TIMER_HW_HPTICKS_PER_SEC (CLOCK_FREQ / 64)
78 INLINE hptime_t timer_hw_hpread(void);
79 INLINE hptime_t timer_hw_hpread(void)
84 #elif defined(CONFIG_TIMER_ON_TIMER1_OVERFLOW)
86 //! Type of time expressed in ticks of the hardware high precision timer
87 typedef uint16_t hptime_t;
89 static void timer_hw_init(void)
92 DISABLE_IRQSAVE(flags);
94 /* Reset Timer overflow flag */
97 /* Fast PWM mode, 9 bit, 24 kHz, no prescaling. When changing freq or
98 resolution (top of TCNT), change TIMER_HW_HPTICKS_PER_SEC too */
100 TCCR1A &= ~BV(WGM10);
101 TCCR1B |= BV(WGM12) | BV(CS10);
102 TCCR1B &= ~(BV(WGM13) | BV(CS11) | BV(CS12));
104 TCNT1 = 0x00; /* initialization of Timer/Counter */
106 /* Enable timer interrupt: Timer/Counter1 Overflow */
109 ENABLE_IRQRESTORE(flags);
112 //! Frequency of the hardware high precision timer
113 #define TIMER_HW_HPTICKS_PER_SEC (24000ul * 512)
115 INLINE hptime_t timer_hw_hpread(void);
116 INLINE hptime_t timer_hw_hpread(void)
121 #elif defined(CONFIG_TIMER_ON_TIMER2)
123 //! Type of time expressed in ticks of the hardware high precision timer
124 typedef uint8_t hptime_t;
126 static void timer_hw_init(void)
129 DISABLE_IRQSAVE(flags);
131 /* Reset Timer flags */
132 TIFR = BV(OCF2) | BV(TOV2);
134 /* Setup Timer/Counter interrupt */
135 TCCR2 = BV(WGM21) | BV(CS21) | BV(CS20);
136 /* Clear on Compare match & prescaler = 64, internal sys clock.
137 When changing prescaler change TIMER_HW_HPTICKS_PER_SEC too */
138 TCNT2 = 0x00; /* initialization of Timer/Counter */
139 OCR2 = OCR_DIVISOR; /* Timer/Counter Output Compare Register */
141 /* Enable timer interrupts: Timer/Counter2 Output Compare (OCIE2) */
145 ENABLE_IRQRESTORE(flags);
148 //! Frequency of the hardware high precision timer
149 #define TIMER_HW_HPTICKS_PER_SEC (CLOCK_FREQ / 64)
151 INLINE hptime_t timer_hw_hpread(void);
152 INLINE hptime_t timer_hw_hpread(void)
158 #error Choose witch timer to use with CONFIG_TIMER_ON_TIMERx
159 #endif /* CONFIG_TIMER_ON_TIMERx */
162 #if defined(CONFIG_TIMER_ON_TIMER1_OVERFLOW)
164 #define DEFINE_TIMER_ISR \
165 static void timer_handler(void)
170 * Timer 1 overflow irq handler. It's called at the frequency of the timer 1
171 * PWM (should be 24 kHz). It's too much for timer purposes, so the interrupt
172 * handler is really a counter that call the true handler in timer.c
175 SIGNAL(SIG_OVERFLOW1)
178 * How many overflow we have to count before calling the true timer handler.
179 * If timer overflow is at 24 kHz, with a value of 24 we have 1 ms between
182 #define TIMER1_OVF_COUNT 24
184 static uint8_t count = TIMER1_OVF_COUNT;
190 count = TIMER1_OVF_COUNT;
193 #if (ARCH & ARCH_BOARD_KC)
195 * Super-optimization-hack: switch CPU ADC mux here, ASAP after the start
196 * of conversion (auto-triggered with timer 1 overflow).
197 * The switch can be done 2 ADC cycles after start of conversion.
198 * The handler prologue takes a little more than 32 CPU cycles: with
199 * the prescaler at 1/16 the timing should be correct even at the start
202 * The switch is synchronized with the ADC handler using _adc_trigger_lock.
204 extern uint8_t _adc_idx_next;
205 extern bool _adc_trigger_lock;
207 if (!_adc_trigger_lock)
210 ADC_SETCHN(_adc_idx_next);
212 _adc_trigger_lock = true;
217 #elif defined (CONFIG_TIMER_ON_TIMER0)
219 #define DEFINE_TIMER_ISR \
220 SIGNAL(SIG_OUTPUT_COMPARE0)
222 #elif defined(CONFIG_TIMER_ON_TIMER2)
224 #define DEFINE_TIMER_ISR \
225 SIGNAL(SIG_OUTPUT_COMPARE2)
228 #error Choose witch timer to use with CONFIG_TIMER_ON_TIMERx
229 #endif /* CONFIG_TIMER_ON_TIMERx */
231 #endif /* DRV_TIMER_AVR_H */