ini
[aversive.git] / modules / base / time_ext / time_ext.c
1 /*  
2  *  Copyright Droids Corporation (2008)
3  * 
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  */
19
20 /*
21  * Author : Julien LE GUEN - jlg@jleguen.info
22  */
23
24 #include <aversive.h>
25 #include <aversive/error.h>
26 #include <aversive/wait.h>
27
28 #include <time_ext.h>
29 #include <time_ext_config.h>
30
31 /* Global time variable */
32 static volatile time_ext_t g_time;
33
34
35 /* Global counters */
36 static volatile uint32_t g_timer1_cnt;
37 static volatile uint16_t g_timer1_val;
38 static volatile uint32_t g_inst_number;
39 static volatile uint32_t g_frequency;
40 static volatile uint16_t g_nano_per_inst;
41
42 #if 0
43 /* Function pointer (points to the current interrupt) */
44 static volatile void (*g_timer1_ovf_interrupt)(void);
45 static volatile void (*g_timer2_ovf_interrupt)(void);
46
47
48 /*
49  *      Interrupt vector: Timer1 OVerFlow
50  */
51 void SIG_OVERFLOW1(void) __attribute__ ((signal));
52 void SIG_OVERFLOW1(void)
53 {
54         g_timer1_cnt++;
55 }
56 #endif
57
58
59 /*
60  *      Interrupt vector: Timer2 OVerFlow
61  */
62 void SIG_OVERFLOW2(void) __attribute__ ((signal));
63 void SIG_OVERFLOW2(void)
64 {
65 #if 0
66         TCNT1 = 0;
67         g_timer1_cnt = 0;
68 #endif
69         /* 256 times NANO_PER_QUARTZ_TICK / prescaler since last overflow */
70         g_time.nano += (NANO_PER_QUARTZ_TICK << 8) / time_ext_get_prescaler();
71
72         if(g_time.nano >= NANO_PER_S)
73         {
74                 g_time.nano -= NANO_PER_S;
75                 g_time.sec++;
76         }
77 }
78
79
80 #if 0
81 /*
82  *      Timer1 overflow interrupt
83  *      Basic one, used in production
84  */
85 void timer1_ovf_basic(void)
86 {
87         g_timer1_cnt++;
88 }
89
90 /*
91  *      Timer1 overflow interrupt
92  *      Calibration
93  */
94 void timer1_ovf_calib(void)
95 {
96         /* Remember how many times we were here */
97         g_timer1_cnt++;
98 }
99
100 /*
101  *      Timer2 overflow interrupt
102  *      Basic one, used in production
103  */
104 void timer2_ovf_basic(void)
105 {
106         TCNT1 = 0;
107         g_timer1_cnt = 0;
108         /* 256 times NANO_PER_QUARTZ_TICK / prescaler since last overflow */
109         g_time.nano += (NANO_PER_QUARTZ_TICK << 8) / time_ext_get_prescaler();
110
111         if(g_time.nano >= NANO_PER_S)
112         {
113                 g_time.nano -= NANO_PER_S;
114                 g_time.sec++;
115         }
116 }
117
118 /*
119  *      Timer2 overflow interrupt
120  *      Used for crystal calibration
121  */ 
122 void timer2_ovf_calib(void)
123 {
124         /* XXX nothing for now */
125
126         /*      
127          *      When calibrating the main crystal, this
128          *      interrupt is triggered exactly one second
129          *      after the start of the calibration.
130          *      This then reads the number of instructions
131          *      executed during this second, and deduces the
132          *      main crystal frequency.
133          *      It then configures the module back to its normal
134          *      function (that is, couting time).
135          */
136         
137         /* STOP timers */
138         TCCR1B = 0x00;
139         TIFR1 = 0xFF;
140         TCCR2B = 0x00;
141         TIFR2 = 0xFF;
142
143         /* Fetch the value of TCNT1 */
144         g_timer1_val = TCNT1; //(((uint16_t)TCNT1H) << 8) + TCNT1L;
145
146         /* Total number of instructions */
147         g_inst_number = (((uint32_t)g_timer1_cnt) << 16) + g_timer1_val;
148
149         /* Print that */
150         NOTICE(E_TIME_EXT, "%ld instructions in 8 second !", g_inst_number);
151         NOTICE(E_TIME_EXT, "timer_val = %d, timer_cnt = %ld", g_timer1_val, g_timer1_cnt);
152         g_frequency = g_inst_number >> 3;
153         NOTICE(E_TIME_EXT, "Main crystal frequency = %ld Hz", g_frequency);
154         g_nano_per_inst = (1000000000UL / g_frequency);
155         NOTICE(E_TIME_EXT, "Instruction every %d nanosecond", g_nano_per_inst);
156
157         /* Come back to normal state */
158         g_timer1_ovf_interrupt = timer1_ovf_basic;
159         g_timer2_ovf_interrupt = timer2_ovf_basic;
160
161         g_timer1_cnt = 0;
162         TCNT2 = 0;
163
164         TCCR1B = 0x01;
165         TCCR2B = 0x01;
166 }
167 #endif
168
169
170
171
172 /*
173  *      Initialize TIMER2
174  */
175 void time_ext_init(void)
176 {
177         /* 
178          * Asynchronous operation of Timer2
179          * Some considerations must be taken.
180          * See DataSheet for additional information.
181          */
182         
183         NOTICE(E_TIME_EXT, "Initialization");   
184
185 #if 0
186         /* Set interrupt */
187         g_timer1_ovf_interrupt = timer1_ovf_basic;
188         g_timer2_ovf_interrupt = timer2_ovf_basic;
189
190         /* Deactivate TIMER1 */
191         TIMSK1 = 0x00;
192         TCCR1A = 0x00;
193         TCCR1B = 0x00;
194         TCNT1 = 0x00;
195         g_timer1_val = 0;
196         g_timer1_cnt = 0;
197 #endif
198
199         /* Asynchronous mode:
200          *      EXCLK = 0 (we have an oscillator)
201          *      AS2 = 1
202          *      other bits are read only
203          */
204         ASSR = _BV(AS2);
205         /* We want a 'normal' operation mode */
206         TCCR2A = 0x00;
207         /* Clock Select: no prescaling */
208         TCCR2B = 0x01;
209         /* Reset the counter */
210         TCNT2 = 0x00;
211         /* We want an interrupt when TCNT2 overflows */
212         TIMSK2 = _BV(TOIE2);
213
214
215         g_time.sec = 0;
216         g_time.nano = 0;
217 }
218
219
220 /*
221  *      Change the prescaler
222  */
223 inline void time_ext_set_prescaler(uint8_t p)
224 {
225         /* Prevent fools to pass an incorrect value */
226         TCCR2B = p & 0x07;
227 }
228
229 /*
230  *      Get the prescaler value
231  */
232 inline uint8_t time_ext_get_prescaler(void)
233 {
234         return TCCR2B & 0x07;
235 }
236
237 #if 0
238 /*
239  *      Calibration of main crystal
240  */
241 void time_ext_calib(void)
242 {
243         /*
244          *      Configure TIMER1 and all the stuff
245          *      No prescaler, normal mode, interrupt on OVF
246          */
247         TCCR1A = 0x00;
248         TCCR1B = 0x00;
249         TIMSK1 = _BV(TOIE1);
250         TIFR1 = 0xFF;   /* clear flags */
251
252         /* Configure TIMER2 */
253         time_ext_set_prescaler(TIMER2_PRESCALER_OFF);
254
255         /* Change the interrupt handlers */
256         g_timer1_ovf_interrupt = timer1_ovf_calib;
257         g_timer2_ovf_interrupt = timer2_ovf_calib;
258
259         g_frequency = 0;
260         g_nano_per_inst = 0;
261         g_inst_number = 0;
262
263         g_timer1_cnt = 0;
264         g_timer1_val = 0;
265         TCNT1 = 0;
266         TCNT2 = 0;
267         
268         /* Launch the prescalers -> timers ON */
269         TCCR2B = TIMER2_PRESCALER_1024;
270         TCCR1B = 0x01;
271 }
272 #endif
273
274
275 /*
276  *      Get time.
277  *      Since we only update g_time when TCNT2 overflows,
278  *      we add the value of TCNT2 to the nano field.
279  */
280 inline uint32_t time_ext_get_s(void)
281 {
282         return g_time.sec;
283 }
284
285 inline uint32_t time_ext_get_ns(void)
286 {
287         uint32_t tmp, tmp1;
288         /* Fetch timer1 value */
289         //tmp1 = TCNT1;
290         
291         tmp = ((uint32_t)TCNT2) * NANO_PER_QUARTZ_TICK / time_ext_get_prescaler();
292         //tmp += tmp1 * g_nano_per_inst;
293
294         return g_time.nano + tmp;
295 }
296
297 time_ext_t time_ext_get(void)
298 {
299         time_ext_t t;
300         t.nano = time_ext_get_ns();
301         t.sec = time_ext_get_s();
302         if(t.nano >= NANO_PER_S) {
303                 t.sec++;
304                 t.nano -= NANO_PER_S;
305         }
306         return t;
307 }
308
309
310 /*
311  *      Set the time
312  *      Resets TCNT2 as well
313  */
314 inline void time_ext_set(uint32_t sec, uint32_t nano)
315 {
316         TCNT2 = 0;
317         g_time.nano = nano;
318         g_time.sec = sec;
319         NOTICE(E_TIME_EXT, "Time set to %ld %ld", sec, nano);
320 }
321
322
323
324
325
326
327