From: idgay Date: Mon, 26 Mar 2007 22:38:39 +0000 (+0000) Subject: comments, overflow and increase mindt X-Git-Tag: tinyos/2.0.1~117 X-Git-Url: https://oss.titaniummirror.com/gitweb/?a=commitdiff_plain;h=b535b5d1f8de5853a9d1c1401771e81105f24502;p=tinyos-2.x.git comments, overflow and increase mindt still under test --- diff --git a/tos/chips/atm128/timer/Atm128AlarmAsyncP.nc b/tos/chips/atm128/timer/Atm128AlarmAsyncP.nc index 29f90147..dec6b0a0 100644 --- a/tos/chips/atm128/timer/Atm128AlarmAsyncP.nc +++ b/tos/chips/atm128/timer/Atm128AlarmAsyncP.nc @@ -1,3 +1,23 @@ +// $Id$ +/* + * Copyright (c) 2005-2006 Intel Corporation + * All rights reserved. + * + * This file is distributed under the terms in the attached INTEL-LICENSE + * file. If you do not find these files, copies can be found by writing to + * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, + * 94704. Attention: Intel License Inquiry. + */ +/** + * Build a 32-bit alarm and counter from the atmega128's 8-bit timer 0 + * in asynchronous mode. Attempting to use the generic Atm128AlarmC + * component and the generic timer components runs into problems + * apparently related to letting timer 0 overflow. + * + * So, instead, this version (inspired by the 1.x code and a remark from + * Martin Turon) directly builds a 32-bit alarm and counter on top of timer 0 + * and never lets timer 0 overflow. + */ generic module Atm128AlarmAsyncP(typedef precision, int divider) { provides { interface Init; @@ -12,39 +32,85 @@ generic module Atm128AlarmAsyncP(typedef precision, int divider) { } implementation { - uint8_t set; - uint32_t t0, dt; - uint32_t base; + uint8_t set; /* Is the alarm set? */ + uint32_t t0, dt; /* Time of the next alarm */ + uint32_t base; /* base+TCNT0 is the current time if no + interrupt is pending. See Counter.get() + for the full details. */ enum { - MINDT = 2, - MAXT = 230 + MINDT = 3, /* Minimum interval between interrupts */ + MAXT = 230 /* Maximum value to let timer 0 reach + (from Joe Polastre and Robert Szewczyk's + painful experiences with the 1.x timer ;-)) */ }; + void setInterrupt(); + + /* Configure timer 0 */ + command error_t Init.init() { + atomic + { + Atm128TimerControl_t x; + + call Compare.start(); + x.flat = 0; + x.bits.cs = divider; + x.bits.wgm1 = 1; /* We use the clear-on-compare mode */ + call TimerCtrl.setControl(x); + call Compare.set(MAXT); + setInterrupt(); + } + return SUCCESS; + } + + /* Set compare register for timer 0 to n. But increment n by 1 if TCNT0 + reaches this value before we can set the compare register. + Direct register access used because the HPL doesn't allow us to do this. + */ void setOcr0(uint8_t n) { while (ASSR & 1 << OCR0UB) ; if (n == TCNT0) n++; + /* Support for overflow. Force interrupt at wrap around value. + This does not cause a backwards-in-time value as we do this + every time we set OCR0. */ + if (base + n + 1 < base) + n = -base - 1; OCR0 = n; } + void fire() { + __nesc_enable_interrupt(); + signal Alarm.fired(); + } + + /* Update the compare register to trigger an interrupt at the + appropriate time based on the current alarm settings + */ void setInterrupt() { bool fired = FALSE; atomic { + /* interrupt_in is the time to the next interrupt. Note that + compare register values are off by 1 (i.e., if you set OCR0 to + 3, the interrupt will happen whjen TCNT0 is 4) */ uint8_t interrupt_in = 1 + call Compare.get() - call Timer.get(); uint8_t newOcr0; if (interrupt_in < MINDT || (call TimerCtrl.getInterruptFlag()).bits.ocf0) return; // wait for next interrupt + + /* When no alarm is set, we just ask for an interrupt every MAXT */ if (!set) newOcr0 = MAXT; else { uint32_t now = call Counter.get(); + /* Check if alarm expired */ if ((uint32_t)(now - t0) >= dt) { set = FALSE; @@ -53,6 +119,8 @@ implementation } else { + /* No. Set compare register to time of next alarm if it's + within the next MAXT units */ uint32_t alarm_in = (t0 + dt) - base; if (alarm_in > MAXT) @@ -67,50 +135,58 @@ implementation setOcr0(newOcr0); } if (fired) - signal Alarm.fired(); + fire(); + } + + void overflow() { + __nesc_enable_interrupt(); + signal Counter.overflow(); } async event void Compare.fired() { - base += call Compare.get() + 1; + /* Compare register fired. Update time knowledge */ + base += call Compare.get() + 1; // interrupt is 1ms late setInterrupt(); + if (!base) + overflow(); } - command error_t Init.init() { - atomic - { - Atm128TimerControl_t x; - - call Compare.start(); - x.flat = 0; - x.bits.cs = divider; - x.bits.wgm1 = 1; - call TimerCtrl.setControl(x); - call Compare.set(MAXT); - setInterrupt(); - } - return SUCCESS; - } - async command uint32_t Counter.get() { uint32_t now; atomic { + /* Current time is base+TCNT0 if no interrupt is pending. But if + an interrupt is pending, then it's base + compare value + 1 + TCNT0 */ uint8_t now8 = call Timer.get(); if ((call TimerCtrl.getInterruptFlag()).bits.ocf0) - now = base + call Counter.get() + call Timer.get(); + /* We need to reread TCNT0 as it might've overflowed after we + read TCNT0 the first time */ + now = base + call Counter.get() + 1 + call Timer.get(); else + /* We need to use the value of TCNT0 from before we check the + interrupt flag, as it might wrap around after the check */ now = base + now8; } return now; } async command bool Counter.isOverflowPending() { - return FALSE; + atomic + return (call TimerCtrl.getInterruptFlag()).bits.ocf0 && + !(base + call Counter.get() + 1); } - async command void Counter.clearOverflow() { } + async command void Counter.clearOverflow() { + atomic + if (call Counter.isOverflowPending()) + { + base = 0; + call Compare.reset(); + setInterrupt(); + } + } async command void Alarm.start(uint32_t ndt) { call Alarm.startAt(call Counter.get(), ndt);