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.4 2004/06/27 15:22:15 aleph
21 * Revision 1.3 2004/06/07 15:57:40 aleph
22 * Update to latest AVR timer code
24 * Revision 1.2 2004/06/03 11:27:09 bernie
25 * Add dual-license information.
27 * Revision 1.1 2004/05/23 18:23:30 bernie
28 * Import drv/timer module.
32 #ifndef DRV_TIMER_AVR_H
33 #define DRV_TIMER_AVR_H
37 #if (ARCH & ARCH_BOARD_KC)
42 #define timer_hw_irq() /* Not needed, IRQ timer flag cleared automatically */
45 * System timer: additional division after the prescaler
46 * 12288000 / 64 / 192 (0..191) = 1 ms
48 #define OCR_DIVISOR 191
50 /*! HW dependent timer initialization */
51 #if defined(CONFIG_TIMER_ON_TIMER0)
53 //! Type of time expressed in ticks of the hardware high-precision timer
54 typedef uint8_t hptime_t;
56 static void timer_hw_init(void)
59 DISABLE_IRQSAVE(flags);
61 /* Reset Timer flags */
62 TIFR = BV(OCF0) | BV(TOV0);
64 /* Setup Timer/Counter interrupt */
65 ASSR = 0x00; /* internal system clock */
66 TCCR0 = BV(WGM01) | BV(CS02); /* Clear on Compare match & prescaler = 64. When changing
67 prescaler change TIMER_HW_HPTICKS_PER_SEC too */
68 TCNT0 = 0x00; /* initialization of Timer/Counter */
69 OCR0 = OCR_DIVISOR; /* Timer/Counter Output Compare Register */
71 /* Enable timer interrupts: Timer/Counter2 Output Compare (OCIE2) */
75 ENABLE_IRQRESTORE(flags);
78 //! Frequency of the hardware high precision timer
79 #define TIMER_HW_HPTICKS_PER_SEC (CLOCK_FREQ / 64)
81 INLINE hptime_t timer_hw_hpread(void);
82 INLINE hptime_t timer_hw_hpread(void)
87 #elif defined(CONFIG_TIMER_ON_TIMER1_OVERFLOW)
89 //! Type of time expressed in ticks of the hardware high precision timer
90 typedef uint16_t hptime_t;
92 static void timer_hw_init(void)
95 DISABLE_IRQSAVE(flags);
97 /* Reset Timer overflow flag */
100 /* Fast PWM mode, 9 bit, 24 kHz, no prescaling. When changing freq or
101 resolution (top of TCNT), change TIMER_HW_HPTICKS_PER_SEC too */
103 TCCR1A &= ~BV(WGM10);
104 TCCR1B |= BV(WGM12) | BV(CS10);
105 TCCR1B &= ~(BV(WGM13) | BV(CS11) | BV(CS12));
107 TCNT1 = 0x00; /* initialization of Timer/Counter */
109 /* Enable timer interrupt: Timer/Counter1 Overflow */
112 ENABLE_IRQRESTORE(flags);
115 //! Frequency of the hardware high precision timer
116 #define TIMER_HW_HPTICKS_PER_SEC (24000ul * 512)
118 INLINE hptime_t timer_hw_hpread(void);
119 INLINE hptime_t timer_hw_hpread(void)
124 #elif defined(CONFIG_TIMER_ON_TIMER2)
126 //! Type of time expressed in ticks of the hardware high precision timer
127 typedef uint8_t hptime_t;
129 static void timer_hw_init(void)
132 DISABLE_IRQSAVE(flags);
134 /* Reset Timer flags */
135 TIFR = BV(OCF2) | BV(TOV2);
137 /* Setup Timer/Counter interrupt */
138 TCCR2 = BV(WGM21) | BV(CS21) | BV(CS20);
139 /* Clear on Compare match & prescaler = 64, internal sys clock.
140 When changing prescaler change TIMER_HW_HPTICKS_PER_SEC too */
141 TCNT2 = 0x00; /* initialization of Timer/Counter */
142 OCR2 = OCR_DIVISOR; /* Timer/Counter Output Compare Register */
144 /* Enable timer interrupts: Timer/Counter2 Output Compare (OCIE2) */
148 ENABLE_IRQRESTORE(flags);
151 //! Frequency of the hardware high precision timer
152 #define TIMER_HW_HPTICKS_PER_SEC (CLOCK_FREQ / 64)
154 INLINE hptime_t timer_hw_hpread(void);
155 INLINE hptime_t timer_hw_hpread(void)
161 #error Choose witch timer to use with CONFIG_TIMER_ON_TIMERx
162 #endif /* CONFIG_TIMER_ON_TIMERx */
165 #if defined(CONFIG_TIMER_ON_TIMER1_OVERFLOW)
167 #define DEFINE_TIMER_ISR \
168 static void timer_handler(void)
173 * Timer 1 overflow irq handler. It's called at the frequency of the timer 1
174 * PWM (should be 24 kHz). It's too much for timer purposes, so the interrupt
175 * handler is really a counter that call the true handler in timer.c
178 SIGNAL(SIG_OVERFLOW1)
181 * How many overflow we have to count before calling the true timer handler.
182 * If timer overflow is at 24 kHz, with a value of 24 we have 1 ms between
185 #define TIMER1_OVF_COUNT 24
187 static uint8_t count = TIMER1_OVF_COUNT;
193 count = TIMER1_OVF_COUNT;
196 #if (ARCH & ARCH_BOARD_KC)
198 * Super-optimization-hack: switch CPU ADC mux here, ASAP after the start
199 * of conversion (auto-triggered with timer 1 overflow).
200 * The switch can be done 2 ADC cycles after start of conversion.
201 * The handler prologue takes a little more than 32 CPU cycles: with
202 * the prescaler at 1/16 the timing should be correct even at the start
205 * The switch is synchronized with the ADC handler using _adc_trigger_lock.
207 extern uint8_t _adc_idx_next;
208 extern bool _adc_trigger_lock;
210 if (!_adc_trigger_lock)
213 ADC_SETCHN(_adc_idx_next);
215 _adc_trigger_lock = true;
220 #elif defined (CONFIG_TIMER_ON_TIMER0)
222 #define DEFINE_TIMER_ISR \
223 SIGNAL(SIG_OUTPUT_COMPARE0)
225 #elif defined(CONFIG_TIMER_ON_TIMER2)
227 #define DEFINE_TIMER_ISR \
228 SIGNAL(SIG_OUTPUT_COMPARE2)
231 #error Choose witch timer to use with CONFIG_TIMER_ON_TIMERx
232 #endif /* CONFIG_TIMER_ON_TIMERx */
234 #endif /* DRV_TIMER_AVR_H */