Add missing support for ATMega1281.
[bertos.git] / drv / timer_avr.c
1 /**
2  * \file
3  * <!--
4  * Copyright 2005 Develer S.r.l. (http://www.develer.com/)
5  * This file is part of DevLib - See README.devlib for information.
6  * -->
7  *
8  * \version $Id$
9  *
10  * \author Bernardo Innocenti <bernie@develer.com>
11  * \author Francesco Sacchi <batt@develer.com>
12  *
13  * \brief Low-level timer module for AVR (implementation).
14  */
15
16 /*#*
17  *#* $Log$
18  *#* Revision 1.5  2007/03/21 11:03:56  batt
19  *#* Add missing support for ATMega1281.
20  *#*
21  *#* Revision 1.4  2006/07/19 12:56:26  bernie
22  *#* Convert to new Doxygen style.
23  *#*
24  *#* Revision 1.3  2006/06/12 21:37:02  marco
25  *#* implemented some commands (ver and sleep)
26  *#*
27  *#* Revision 1.2  2006/05/18 00:37:58  bernie
28  *#* Don't include unneeded header hw.h.
29  *#*
30  *#* Revision 1.1  2005/07/19 07:28:36  bernie
31  *#* Refactor to decouple timer ticks from milliseconds.
32  *#*
33  *#* Revision 1.1  2005/05/24 09:17:58  batt
34  *#* Move drivers to top-level.
35  *#*
36  *#*/
37 #include <drv/timer_avr.h>
38 #include <cfg/macros.h> // BV()
39
40 #include <avr/interrupt.h>
41 #include <avr/io.h>
42
43 #if CPU_AVR_ATMEGA1281
44         #define REG_TIFR0 TIFR0
45         #define REG_TIFR2 TIFR2
46
47         #define REG_TIMSK0 TIMSK0
48         #define REG_TIMSK2 TIMSK2
49
50         #define REG_TCCR2A TCCR2A
51         #define REG_TCCR2B TCCR2B
52
53         #define REG_OCR2A  OCR2A
54
55         #define BIT_OCF0A  OCF0A
56         #define BIT_OCF2A  OCF2A
57
58         #define BIT_OCIE0A OCIE0A
59         #define BIT_OCIE2A OCIE2A
60 #else
61         #define REG_TIFR0 TIFR
62         #define REG_TIFR2 TIFR
63
64         #define REG_TIMSK0 TIMSK
65         #define REG_TIMSK2 TIMSK
66
67         #define REG_TCCR2A TCCR2
68         #define REG_TCCR2B TCCR2
69
70         #define REG_OCR2A  OCR2
71
72         #define BIT_OCF0A  OCF0
73         #define BIT_OCF2A  OCF2
74
75         #define BIT_OCIE0A OCIE0
76         #define BIT_OCIE2A OCIE2
77 #endif
78
79
80 /** HW dependent timer initialization  */
81 #if (CONFIG_TIMER == TIMER_ON_OUTPUT_COMPARE0)
82
83         static void timer_hw_init(void)
84         {
85                 cpuflags_t flags;
86                 IRQ_SAVE_DISABLE(flags);
87
88                 /* Reset Timer flags */
89                 REG_TIFR0 = BV(BIT_OCF0A) | BV(TOV0);
90
91                 /* Setup Timer/Counter interrupt */
92                 ASSR = 0x00;                  /* Internal system clock */
93                 TCCR0 = BV(WGM01)             /* Clear on Compare match */
94                         #if TIMER_PRESCALER == 64
95                                 | BV(CS02)
96                         #else
97                                 #error Unsupported value of TIMER_PRESCALER
98                         #endif
99                 ;
100                 TCNT0 = 0x00;                 /* Initialization of Timer/Counter */
101                 OCR0 = OCR_DIVISOR;           /* Timer/Counter Output Compare Register */
102
103                 /* Enable timer interrupts: Timer/Counter2 Output Compare (OCIE2) */
104                 REG_TIMSK0 &= ~BV(TOIE0);
105                 REG_TIMSK0 |= BV(OCIE0);
106
107                 IRQ_RESTORE(flags);
108         }
109
110         INLINE hptime_t timer_hw_hpread(void)
111         {
112                 return TCNT0;
113         }
114
115 #elif (CONFIG_TIMER == TIMER_ON_OVERFLOW1)
116
117         static void timer_hw_init(void)
118         {
119                 cpuflags_t flags;
120                 IRQ_SAVE_DISABLE(flags);
121
122                 /* Reset Timer overflow flag */
123                 TIFR |= BV(TOV1);
124
125                 /* Fast PWM mode, 9 bit, 24 kHz, no prescaling. */
126                 #if (TIMER_PRESCALER == 1) && (TIMER_HW_BITS == 9)
127                         TCCR1A |= BV(WGM11);
128                         TCCR1A &= ~BV(WGM10);
129                         TCCR1B |= BV(WGM12) | BV(CS10);
130                         TCCR1B &= ~(BV(WGM13) | BV(CS11) | BV(CS12));
131                 /* Fast PWM mode, 8 bit, 24 kHz, no prescaling. */
132                 #elif (TIMER_PRESCALER == 1) && (TIMER_HW_BITS == 8)
133                         TCCR1A |= BV(WGM10);
134                         TCCR1A &= ~BV(WGM11);
135                         TCCR1B |= BV(WGM12) | BV(CS10);
136                         TCCR1B &= ~(BV(WGM13) | BV(CS11) | BV(CS12));
137                 #else
138                         #error Unsupported value of TIMER_PRESCALER or TIMER_HW_BITS
139                 #endif
140
141                 TCNT1 = 0x00;         /* initialization of Timer/Counter */
142
143                 /* Enable timer interrupt: Timer/Counter1 Overflow */
144                 TIMSK |= BV(TOIE1);
145
146                 IRQ_RESTORE(flags);
147         }
148
149         INLINE hptime_t timer_hw_hpread(void)
150         {
151                 return TCNT1;
152         }
153
154 #elif (CONFIG_TIMER == TIMER_ON_OUTPUT_COMPARE2)
155
156         static void timer_hw_init(void)
157         {
158                 cpuflags_t flags;
159                 IRQ_SAVE_DISABLE(flags);
160
161                 /* Reset Timer flags */
162                 REG_TIFR2 = BV(BIT_OCF2A) | BV(TOV2);
163
164                 /* Setup Timer/Counter interrupt */
165                 REG_TCCR2A = 0; // TCCR2 reg could be separate or a unique register with both A & B values, this is needed to
166                 REG_TCCR2B = 0; // ensure correct initialization.
167
168                 REG_TCCR2A = BV(WGM21);
169                 #if TIMER_PRESCALER == 64
170                 #if CPU_AVR_ATMEGA1281
171                         // ATMega1281 has undocumented differences in timer2 prescaler!
172                         REG_TCCR2B |= BV(CS22);
173                 #else
174                         REG_TCCR2B |= BV(CS21) | BV(CS20);
175                 #endif
176                 #else
177                         #error Unsupported value of TIMER_PRESCALER
178                 #endif
179
180                 /* Clear on Compare match & prescaler = 64, internal sys clock.
181                    When changing prescaler change TIMER_HW_HPTICKS_PER_SEC too */
182                 TCNT2 = 0x00;         /* initialization of Timer/Counter */
183                 REG_OCR2A = OCR_DIVISOR;   /* Timer/Counter Output Compare Register */
184
185                 /* Enable timer interrupts: Timer/Counter2 Output Compare (OCIE2) */
186                 REG_TIMSK2 &= ~BV(TOIE2);
187                 REG_TIMSK2 |= BV(BIT_OCIE2A);
188
189                 IRQ_RESTORE(flags);
190         }
191
192         INLINE hptime_t timer_hw_hpread(void)
193         {
194                 return TCNT2;
195         }
196 #elif (CONFIG_TIMER == TIMER_ON_OVERFLOW3)
197
198         static void timer_hw_init(void)
199         {
200                 cpuflags_t flags;
201                 IRQ_SAVE_DISABLE(flags);
202
203                 /* Reset Timer overflow flag */
204                 TIFR |= BV(TOV3);
205
206                 /* Fast PWM mode, 9 bit, 24 kHz, no prescaling. */
207                 #if (TIMER_PRESCALER == 1) && (TIMER_HW_BITS == 9)
208                         TCCR3A |= BV(WGM31);
209                         TCCR3A &= ~BV(WGM30);
210                         TCCR3B |= BV(WGM32) | BV(CS30);
211                         TCCR3B &= ~(BV(WGM33) | BV(CS31) | BV(CS32));
212                 /* Fast PWM mode, 8 bit, 24 kHz, no prescaling. */
213                 #elif (TIMER_PRESCALER == 1) && (TIMER_HW_BITS == 8)
214                         TCCR3A |= BV(WGM30);
215                         TCCR3A &= ~BV(WGM31);
216                         TCCR3B |= BV(WGM32) | BV(CS30);
217                         TCCR3B &= ~(BV(WGM33) | BV(CS31) | BV(CS32));
218                 #else
219                         #error Unsupported value of TIMER_PRESCALER or TIMER_HW_BITS
220                 #endif
221
222                 TCNT3 = 0x00;         /* initialization of Timer/Counter */
223
224                 /* Enable timer interrupt: Timer/Counter3 Overflow */
225                 /* ATTENTION! TOIE3 is only on ETIMSK, not TIMSK */
226                 ETIMSK |= BV(TOIE3);
227
228                 IRQ_RESTORE(flags);
229         }
230
231         INLINE hptime_t timer_hw_hpread(void)
232         {
233                 return TCNT3;
234         }
235
236 #else
237         #error Unimplemented value for CONFIG_TIMER
238 #endif /* CONFIG_TIMER */
239