Contiki 3.x
rtimer-arch.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2007, Swedish Institute of Computer Science.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  *
31  */
32 
33 /**
34  * \file
35  * AVR-specific rtimer code
36  * Defaults to Timer3 for those ATMEGAs that have it.
37  * If Timer3 not present Timer1 will be used.
38  * \author
39  * Fredrik Osterlind <fros@sics.se>
40  * Joakim Eriksson <joakime@sics.se>
41  */
42 
43 /* OBS: 8 seconds maximum time! */
44 
45 #include <avr/io.h>
46 #include <avr/interrupt.h>
47 #include <stdio.h>
48 
49 #include "sys/energest.h"
50 #include "sys/rtimer.h"
51 #include "rtimer-arch.h"
52 
53 #if defined(__AVR_ATmega1284P__)
54 #define ETIMSK TIMSK3
55 #define ETIFR TIFR3
56 #define TICIE3 ICIE3
57 
58 //Has no 'C', so we just set it to B. The code doesn't really use C so this
59 //is safe to do but lets it compile. Probably should enable the warning if
60 //it is ever used on other platforms.
61 //#warning no OCIE3C in timer3 architecture, hopefully it won't be needed!
62 
63 #define OCIE3C OCIE3B
64 #define OCF3C OCF3B
65 #endif
66 
67 #if defined(__AVR_ATmega1281__) || defined(__AVR_AT90USB1287__) || defined(__AVR_ATmega128RFA1__)
68 #define ETIMSK TIMSK3
69 #define ETIFR TIFR3
70 #define TICIE3 ICIE3
71 #endif
72 
73 #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega644__)
74 #define TIMSK TIMSK1
75 #define TICIE1 ICIE1
76 #define TIFR TIFR1
77 #endif
78 
79 /* Track flow through rtimer interrupts*/
80 #if DEBUGFLOWSIZE&&0
81 extern uint8_t debugflowsize,debugflow[DEBUGFLOWSIZE];
82 #define DEBUGFLOW(c) if (debugflowsize<(DEBUGFLOWSIZE-1)) debugflow[debugflowsize++]=c
83 #else
84 #define DEBUGFLOW(c)
85 #endif
86 
87 /*---------------------------------------------------------------------------*/
88 #if defined(TCNT3) && RTIMER_ARCH_PRESCALER
89 ISR (TIMER3_COMPA_vect) {
90  DEBUGFLOW('/');
91  ENERGEST_ON(ENERGEST_TYPE_IRQ);
92 
93  /* Disable rtimer interrupts */
94  ETIMSK &= ~((1 << OCIE3A) | (1 << OCIE3B) | (1 << TOIE3) |
95  (1 << TICIE3) | (1 << OCIE3C));
96 
97 #if RTIMER_CONF_NESTED_INTERRUPTS
98  /* Enable nested interrupts. Allows radio interrupt during rtimer interrupt. */
99  /* All interrupts are enabled including recursive rtimer, so use with caution */
100  sei();
101 #endif
102 
103  /* Call rtimer callback */
104  rtimer_run_next();
105 
106  ENERGEST_OFF(ENERGEST_TYPE_IRQ);
107  DEBUGFLOW('\\');
108 }
109 
110 #elif RTIMER_ARCH_PRESCALER
111 #warning "No Timer3 in rtimer-arch.c - using Timer1 instead"
112 ISR (TIMER1_COMPA_vect) {
113  DEBUGFLOW('/');
114  TIMSK &= ~((1<<TICIE1)|(1<<OCIE1A)|(1<<OCIE1B)|(1<<TOIE1));
115 
116  rtimer_run_next();
117  DEBUGFLOW('\\');
118 }
119 
120 #endif
121 /*---------------------------------------------------------------------------*/
122 void
123 rtimer_arch_init(void)
124 {
125 #if RTIMER_ARCH_PRESCALER
126  /* Disable interrupts (store old state) */
127  uint8_t sreg;
128  sreg = SREG;
129  cli ();
130 
131 #ifdef TCNT3
132  /* Disable all timer functions */
133  ETIMSK &= ~((1 << OCIE3A) | (1 << OCIE3B) | (1 << TOIE3) |
134  (1 << TICIE3) | (1 << OCIE3C));
135  /* Write 1s to clear existing timer function flags */
136  ETIFR |= (1 << ICF3) | (1 << OCF3A) | (1 << OCF3B) | (1 << TOV3) |
137  (1 << OCF3C);
138 
139  /* Default timer behaviour */
140  TCCR3A = 0;
141  TCCR3B = 0;
142  TCCR3C = 0;
143 
144  /* Reset counter */
145  TCNT3 = 0;
146 
147 #if RTIMER_ARCH_PRESCALER==1024
148  TCCR3B |= 5;
149 #elif RTIMER_ARCH_PRESCALER==256
150  TCCR3B |= 4;
151 #elif RTIMER_ARCH_PRESCALER==64
152  TCCR3B |= 3;
153 #elif RTIMER_ARCH_PRESCALER==8
154  TCCR3B |= 2;
155 #elif RTIMER_ARCH_PRESCALER==1
156  TCCR3B |= 1;
157 #else
158 #error Timer3 PRESCALER factor not supported.
159 #endif
160 
161 #elif RTIMER_ARCH_PRESCALER
162  /* Leave timer1 alone if PRESCALER set to zero */
163  /* Obviously you can not then use rtimers */
164 
165  TIMSK &= ~((1<<TICIE1)|(1<<OCIE1A)|(1<<OCIE1B)|(1<<TOIE1));
166  TIFR |= (1 << ICF1) | (1 << OCF1A) | (1 << OCF1B) | (1 << TOV1);
167 
168  /* Default timer behaviour */
169  TCCR1A = 0;
170  TCCR1B = 0;
171 
172  /* Reset counter */
173  TCNT1 = 0;
174 
175  /* Start clock */
176 #if RTIMER_ARCH_PRESCALER==1024
177  TCCR1B |= 5;
178 #elif RTIMER_ARCH_PRESCALER==256
179  TCCR1B |= 4;
180 #elif RTIMER_ARCH_PRESCALER==64
181  TCCR1B |= 3;
182 #elif RTIMER_ARCH_PRESCALER==8
183  TCCR1B |= 2;
184 #elif RTIMER_ARCH_PRESCALER==1
185  TCCR1B |= 1;
186 #else
187 #error Timer1 PRESCALER factor not supported.
188 #endif
189 
190 #endif /* TCNT3 */
191 
192  /* Restore interrupt state */
193  SREG = sreg;
194 #endif /* RTIMER_ARCH_PRESCALER */
195 }
196 /*---------------------------------------------------------------------------*/
197 void
198 rtimer_arch_schedule(rtimer_clock_t t)
199 {
200 #if RTIMER_ARCH_PRESCALER
201  /* Disable interrupts (store old state) */
202  uint8_t sreg;
203  sreg = SREG;
204  cli ();
205  DEBUGFLOW(':');
206 #ifdef TCNT3
207  /* Set compare register */
208  OCR3A = t;
209  /* Write 1s to clear all timer function flags */
210  ETIFR |= (1 << ICF3) | (1 << OCF3A) | (1 << OCF3B) | (1 << TOV3) |
211  (1 << OCF3C);
212  /* Enable interrupt on OCR3A match */
213  ETIMSK |= (1 << OCIE3A);
214 
215 #elif RTIMER_ARCH_PRESCALER
216  /* Set compare register */
217  OCR1A = t;
218  TIFR |= (1 << ICF1) | (1 << OCF1A) | (1 << OCF1B) | (1 << TOV1);
219  TIMSK |= (1 << OCIE1A);
220 
221 #endif
222 
223  /* Restore interrupt state */
224  SREG = sreg;
225 #endif /* RTIMER_ARCH_PRESCALER */
226 }
227 
228 #if RDC_CONF_MCU_SLEEP
229 /*---------------------------------------------------------------------------*/
230 void
231 rtimer_arch_sleep(rtimer_clock_t howlong)
232 {
233 /* Deep Sleep for howlong rtimer ticks. This will stop all timers except
234  * for TIMER2 which can be clocked using an external crystal.
235  * Unfortunately this is an 8 bit timer; a lower prescaler gives higher
236  * precision but smaller maximum sleep time.
237  * Here a maximum 128msec (contikimac 8Hz channel check sleep) is assumed.
238  * The rtimer and system clocks are adjusted to reflect the sleep time.
239  */
240 #include <avr/sleep.h>
241 #include <dev/watchdog.h>
242 uint32_t longhowlong;
243 #if AVR_CONF_USE32KCRYSTAL
244 /* Save TIMER2 configuration if clock.c is using it */
245  uint8_t savedTCNT2=TCNT2, savedTCCR2A=TCCR2A, savedTCCR2B = TCCR2B, savedOCR2A = OCR2A;
246 #endif
247  cli();
248  watchdog_stop();
249  set_sleep_mode(SLEEP_MODE_PWR_SAVE);
250 
251 /* Set TIMER2 clock asynchronus from external source, CTC mode */
252  ASSR |= (1 << AS2);
253  TCCR2A =(1<<WGM21);
254 /* Set prescaler and TIMER2 output compare register */
255 #if 0 //Prescale by 1024 - 32 ticks/sec, 8 seconds max sleep
256  TCCR2B =((1<<CS22)|(1<<CS21)|(1<<CS20));
257  longhowlong=howlong*32UL;
258 #elif 0 // Prescale by 256 - 128 ticks/sec, 2 seconds max sleep
259  TCCR2B =((1<<CS22)|(1<<CS21)|(0<<CS20));
260  longhowlong=howlong*128UL;
261 #elif 0 // Prescale by 128 - 256 ticks/sec, 1 seconds max sleep
262  TCCR2B =((1<<CS22)|(0<<CS21)|(1<<CS20));
263  longhowlong=howlong*256UL;
264 #elif 0 // Prescale by 64 - 512 ticks/sec, 500 msec max sleep
265  TCCR2B =((1<<CS22)|(0<<CS21)|(0<<CS20));
266  longhowlong=howlong*512UL;
267 #elif 1 // Prescale by 32 - 1024 ticks/sec, 250 msec max sleep
268  TCCR2B =((0<<CS22)|(1<<CS21)|(1<<CS20));
269  longhowlong=howlong*1024UL;
270 #elif 0 // Prescale by 8 - 4096 ticks/sec, 62.5 msec max sleep
271  TCCR2B =((0<<CS22)|(1<<CS21)|(0<<CS20));
272  longhowlong=howlong*4096UL;
273 #else // No Prescale - 32768 ticks/sec, 7.8 msec max sleep
274  TCCR2B =((0<<CS22)|(0<<CS21)|(1<<CS20));
275  longhowlong=howlong*32768UL;
276 #endif
277  OCR2A = longhowlong/RTIMER_ARCH_SECOND;
278 
279 /* Reset timer count, wait for the write (which assures TCCR2x and OCR2A are finished) */
280  TCNT2 = 0;
281  while(ASSR & (1 << TCN2UB));
282 
283 /* Enable TIMER2 output compare interrupt, sleep mode and sleep */
284  TIMSK2 |= (1 << OCIE2A);
285  SMCR |= (1 << SE);
286  sei();
287  ENERGEST_OFF(ENERGEST_TYPE_CPU);
288  if (OCR2A) sleep_mode();
289  //...zzZZZzz...Ding!//
290 
291 /* Disable sleep mode after wakeup, so random code cant trigger sleep */
292  SMCR &= ~(1 << SE);
293 
294 /* Adjust rtimer ticks if rtimer is enabled. TIMER3 is preferred, else TIMER1 */
295 #if RTIMER_ARCH_PRESCALER
296 #ifdef TCNT3
297  TCNT3 += howlong;
298 #else
299  TCNT1 += howlong;
300 #endif
301 #endif
302  ENERGEST_ON(ENERGEST_TYPE_CPU);
303 
304 #if AVR_CONF_USE32KCRYSTAL
305 /* Restore clock.c configuration */
306  cli();
307  TCCR2A = savedTCCR2A;
308  TCCR2B = savedTCCR2B;
309  OCR2A = savedOCR2A;
310  TCNT2 = savedTCNT2;
311  sei();
312 #else
313 /* Disable TIMER2 interrupt */
314  TIMSK2 &= ~(1 << OCIE2A);
315 #endif
316  watchdog_start();
317 
318 /* Adjust clock.c for the time spent sleeping */
319  longhowlong=CLOCK_CONF_SECOND;
320  longhowlong*=howlong;
321  clock_adjust_ticks(longhowlong/RTIMER_ARCH_SECOND);
322 
323 }
324 #if !AVR_CONF_USE32KCRYSTAL
325 /*---------------------------------------------------------------------------*/
326 /* TIMER2 Interrupt service */
327 
328 ISR(TIMER2_COMPA_vect)
329 {
330 // TIMSK2 &= ~(1 << OCIE2A); //Just one interrupt needed for waking
331 }
332 #endif /* !AVR_CONF_USE32KCRYSTAL */
333 #endif /* RDC_CONF_MCU_SLEEP */
334 
void watchdog_start(void)
Starts the WDT in watchdog mode if enabled by user configuration, maximum interval.
Definition: watchdog.c:49
void rtimer_arch_init(void)
We don&#39;t need to explicitly initialise anything but this routine is required by the API...
Definition: rtimer-arch.c:78
Header file for the energy estimation mechanism
void clock_adjust_ticks(clock_time_t howmany)
Adjust the system current clock time.
Definition: clock.c:289
void watchdog_stop(void)
In watchdog mode, the WDT can not be stopped.
Definition: watchdog.c:58
Header file for the real-time timer module.
void rtimer_arch_schedule(rtimer_clock_t t)
Schedules an rtimer task to be triggered at time t.
Definition: rtimer-arch.c:115
void rtimer_run_next(void)
Execute the next real-time task and schedule the next task, if any.
Definition: rtimer.c:92