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