4 * This file is part of BeRTOS.
6 * Bertos is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 * As a special exception, you may use this file as part of a free software
21 * library without restriction. Specifically, if other files instantiate
22 * templates or use macros or inline functions from this file, or you compile
23 * this file and link it with other files to produce an executable, this
24 * file does not by itself cause the resulting executable to be covered by
25 * the GNU General Public License. This exception does not however
26 * invalidate any other reasons why the executable file might be covered by
27 * the GNU General Public License.
29 * Copyright 2005 Develer S.r.l. (http://www.develer.com/)
35 * \author Bernardo Innocenti <bernie@develer.com>
36 * \author Francesco Sacchi <batt@develer.com>
38 * \brief Low-level timer module for AVR (implementation).
43 *#* Revision 1.6 2007/06/07 14:35:12 batt
44 *#* Merge from project_ks.
46 *#* Revision 1.5 2007/03/21 11:03:56 batt
47 *#* Add missing support for ATMega1281.
49 *#* Revision 1.4 2006/07/19 12:56:26 bernie
50 *#* Convert to new Doxygen style.
52 *#* Revision 1.3 2006/06/12 21:37:02 marco
53 *#* implemented some commands (ver and sleep)
55 *#* Revision 1.2 2006/05/18 00:37:58 bernie
56 *#* Don't include unneeded header hw.h.
58 *#* Revision 1.1 2005/07/19 07:28:36 bernie
59 *#* Refactor to decouple timer ticks from milliseconds.
61 *#* Revision 1.1 2005/05/24 09:17:58 batt
62 *#* Move drivers to top-level.
65 #include <drv/timer_avr.h>
66 #include <cfg/macros.h> // BV()
70 #include <avr/interrupt.h>
73 #if CPU_AVR_ATMEGA1281 || CPU_AVR_ATMEGA168
74 #define REG_TIFR0 TIFR0
75 #define REG_TIFR2 TIFR2
77 #define REG_TIMSK0 TIMSK0
78 #define REG_TIMSK2 TIMSK2
80 #define REG_TCCR2A TCCR2A
81 #define REG_TCCR2B TCCR2B
83 #define REG_OCR2A OCR2A
85 #define BIT_OCF0A OCF0A
86 #define BIT_OCF2A OCF2A
88 #define BIT_OCIE0A OCIE0A
89 #define BIT_OCIE2A OCIE2A
91 #define REG_TIFR0 TIFR
92 #define REG_TIFR2 TIFR
94 #define REG_TIMSK0 TIMSK
95 #define REG_TIMSK2 TIMSK
97 #define REG_TCCR2A TCCR2
98 #define REG_TCCR2B TCCR2
100 #define REG_OCR2A OCR2
102 #define BIT_OCF0A OCF0
103 #define BIT_OCF2A OCF2
105 #define BIT_OCIE0A OCIE0
106 #define BIT_OCIE2A OCIE2
110 /** HW dependent timer initialization */
111 #if (CONFIG_TIMER == TIMER_ON_OUTPUT_COMPARE0)
113 static void timer_hw_init(void)
116 IRQ_SAVE_DISABLE(flags);
118 /* Reset Timer flags */
119 REG_TIFR0 = BV(BIT_OCF0A) | BV(TOV0);
121 /* Setup Timer/Counter interrupt */
122 ASSR = 0x00; /* Internal system clock */
123 TCCR0 = BV(WGM01) /* Clear on Compare match */
124 #if TIMER_PRESCALER == 64
127 #error Unsupported value of TIMER_PRESCALER
130 TCNT0 = 0x00; /* Initialization of Timer/Counter */
131 OCR0 = OCR_DIVISOR; /* Timer/Counter Output Compare Register */
133 /* Enable timer interrupts: Timer/Counter2 Output Compare (OCIE2) */
134 REG_TIMSK0 &= ~BV(TOIE0);
135 REG_TIMSK0 |= BV(OCIE0);
140 INLINE hptime_t timer_hw_hpread(void)
145 #elif (CONFIG_TIMER == TIMER_ON_OVERFLOW1)
147 static void timer_hw_init(void)
150 IRQ_SAVE_DISABLE(flags);
152 /* Reset Timer overflow flag */
155 /* Fast PWM mode, 9 bit, 24 kHz, no prescaling. */
156 #if (TIMER_PRESCALER == 1) && (TIMER_HW_BITS == 9)
158 TCCR1A &= ~BV(WGM10);
159 TCCR1B |= BV(WGM12) | BV(CS10);
160 TCCR1B &= ~(BV(WGM13) | BV(CS11) | BV(CS12));
161 /* Fast PWM mode, 8 bit, 24 kHz, no prescaling. */
162 #elif (TIMER_PRESCALER == 1) && (TIMER_HW_BITS == 8)
164 TCCR1A &= ~BV(WGM11);
165 TCCR1B |= BV(WGM12) | BV(CS10);
166 TCCR1B &= ~(BV(WGM13) | BV(CS11) | BV(CS12));
168 #error Unsupported value of TIMER_PRESCALER or TIMER_HW_BITS
171 TCNT1 = 0x00; /* initialization of Timer/Counter */
173 /* Enable timer interrupt: Timer/Counter1 Overflow */
179 INLINE hptime_t timer_hw_hpread(void)
184 #elif (CONFIG_TIMER == TIMER_ON_OUTPUT_COMPARE2)
185 static void timer_hw_init(void)
188 IRQ_SAVE_DISABLE(flags);
190 /* Reset Timer flags */
191 REG_TIFR2 = BV(BIT_OCF2A) | BV(TOV2);
193 /* Setup Timer/Counter interrupt */
194 REG_TCCR2A = 0; // TCCR2 reg could be separate or a unique register with both A & B values, this is needed to
195 REG_TCCR2B = 0; // ensure correct initialization.
197 REG_TCCR2A = BV(WGM21);
198 #if TIMER_PRESCALER == 64
199 #if CPU_AVR_ATMEGA1281 || CPU_AVR_ATMEGA168
200 // ATMega1281 & ATMega168 have undocumented differences in timer2 prescaler!
201 REG_TCCR2B |= BV(CS22);
203 REG_TCCR2B |= BV(CS21) | BV(CS20);
206 #error Unsupported value of TIMER_PRESCALER
209 /* Clear on Compare match & prescaler = 64, internal sys clock.
210 When changing prescaler change TIMER_HW_HPTICKS_PER_SEC too */
211 TCNT2 = 0x00; /* initialization of Timer/Counter */
212 REG_OCR2A = OCR_DIVISOR; /* Timer/Counter Output Compare Register */
214 /* Enable timer interrupts: Timer/Counter2 Output Compare (OCIE2) */
215 REG_TIMSK2 &= ~BV(TOIE2);
216 REG_TIMSK2 |= BV(BIT_OCIE2A);
221 INLINE hptime_t timer_hw_hpread(void)
225 #elif (CONFIG_TIMER == TIMER_ON_OVERFLOW3)
227 static void timer_hw_init(void)
230 IRQ_SAVE_DISABLE(flags);
232 /* Reset Timer overflow flag */
235 /* Fast PWM mode, 9 bit, 24 kHz, no prescaling. */
236 #if (TIMER_PRESCALER == 1) && (TIMER_HW_BITS == 9)
238 TCCR3A &= ~BV(WGM30);
239 TCCR3B |= BV(WGM32) | BV(CS30);
240 TCCR3B &= ~(BV(WGM33) | BV(CS31) | BV(CS32));
241 /* Fast PWM mode, 8 bit, 24 kHz, no prescaling. */
242 #elif (TIMER_PRESCALER == 1) && (TIMER_HW_BITS == 8)
244 TCCR3A &= ~BV(WGM31);
245 TCCR3B |= BV(WGM32) | BV(CS30);
246 TCCR3B &= ~(BV(WGM33) | BV(CS31) | BV(CS32));
248 #error Unsupported value of TIMER_PRESCALER or TIMER_HW_BITS
251 TCNT3 = 0x00; /* initialization of Timer/Counter */
253 /* Enable timer interrupt: Timer/Counter3 Overflow */
254 /* ATTENTION! TOIE3 is only on ETIMSK, not TIMSK */
260 INLINE hptime_t timer_hw_hpread(void)
266 #error Unimplemented value for CONFIG_TIMER
267 #endif /* CONFIG_TIMER */