📄 hplatm128timer0asyncp.nc
字号:
/* * "Copyright (c) 2005 Stanford University. All rights reserved. * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose, without fee, and without written * agreement is hereby granted, provided that the above copyright * notice, the following two paragraphs and the author appear in all * copies of this software. * * IN NO EVENT SHALL STANFORD UNIVERSITY BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN * IF STANFORD UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * * STANFORD UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND STANFORD UNIVERSITY * HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, * ENHANCEMENTS, OR MODIFICATIONS." *//** * The TOSSIM implementation of the Atm128 Timer0 counter. It handles * overflow, scaling, and phase considerations. * * @date November 22 2005 * * @author Philip Levis <pal@cs.stanford.edu> * @author Martin Turon <mturon@xbow.com> * @author David Gay <dgay@intel-research.net> */// $Id: HplAtm128Timer0AsyncP.nc,v 1.1 2008/06/12 14:02:20 klueska Exp $/// $Id: HplAtm128Timer2C.nc,#include <Atm128Timer.h>#include <hardware.h>module HplAtm128Timer0AsyncP { provides { interface HplAtm128Timer<uint8_t> as Timer0; interface HplAtm128TimerCtrl8 as Timer0Ctrl; interface HplAtm128Compare<uint8_t> as Compare; interface HplAtm128TimerAsync as TimerAsync; } uses interface ThreadScheduler;}implementation { bool inOverflow = 0; uint8_t savedCounter = 0; void adjust_zero(uint8_t currentCounter); void cancel_overflow(); sim_event_t* allocate_overflow(); void configure_overflow(sim_event_t* e); void schedule_new_overflow(); sim_time_t clock_to_sim(sim_time_t t); sim_time_t sim_to_clock(sim_time_t t); uint16_t shiftFromScale(); /* lastZero keeps track of the phase of the clock. It denotes the sim * time at which the underlying clock started, which is needed to * calculate when compares will occur. */ sim_time_t lastZero = 0; /** This variable is needed to keep track of when the underlying * timer starts, in order to reset lastZero. When oldScale is * AVR_CLOCK_OFF and the scale is set to something else, the * clock starts ticking. */ uint8_t oldScale = AVR_CLOCK_OFF; void adjust_zero(uint8_t currentCounter); void cancel_compare(); sim_event_t* allocate_compare(); void configure_compare(sim_event_t* e); void schedule_new_compare(); sim_time_t clock_to_sim(sim_time_t t); sim_time_t sim_to_clock(sim_time_t t); uint16_t shiftFromScale(); default async event void Compare.fired() { } AVR_ATOMIC_HANDLER(SIG_OUTPUT_COMPARE0) { //stabiliseTimer0(); signal Compare.fired(); call ThreadScheduler.interruptPostAmble(); } default async event void Timer0.overflow() { } AVR_ATOMIC_HANDLER(SIG_OVERFLOW0) { inOverflow = TRUE; signal Timer0.overflow(); inOverflow = FALSE; call ThreadScheduler.interruptPostAmble(); } sim_time_t last_zero() { if (lastZero == 0) { lastZero = sim_mote_start_time(sim_node()); } return lastZero; } void notify_changed() { uint8_t newScale = call Timer0.getScale(); if (newScale != AVR_CLOCK_OFF && oldScale == AVR_CLOCK_OFF) { lastZero = sim_time(); } oldScale = newScale; schedule_new_compare(); } sim_time_t notify_clockTicksPerSec() { return ATM128_TIMER0_TICKSPPS; } /** * If the clock was stopped and has restarted, then * we need to move the time when the clock was last * zero to a time that reflects the current settings. * For example, if the clock was stopped when the counter * was 52 and then later restarted, then <tt>lastZero</tt> * needs to be moved forward in time so that the 52 * reflects the current time. */ void adjust_zero(uint8_t currentCounter) { sim_time_t now = sim_time(); sim_time_t adjust = currentCounter; adjust = adjust << shiftFromScale(); adjust = clock_to_sim(adjust); lastZero = now - adjust; } sim_time_t clock_to_sim(sim_time_t t) { t *= sim_ticks_per_sec(); t /= notify_clockTicksPerSec(); return t; } sim_time_t sim_to_clock(sim_time_t t) { t *= notify_clockTicksPerSec(); t /= sim_ticks_per_sec(); return t; } uint16_t shiftFromScale() { uint8_t scale = call Timer0.getScale(); switch (scale) { case 0: return 0; case 1: return 0; case 2: return 3; case 3: return 5; case 4: return 6; case 5: return 7; case 6: return 8; case 7: return 10; default: return 255; } } sim_event_t* compare; void timer0_compare_handle(sim_event_t* evt) { dbg("HplAtm128Timer0AsyncP", "Beginning compare 0x%p at %s\n", evt, sim_time_string()); if (evt->cancelled) { return; } else { char timeStr[128]; sim_print_now(timeStr, 128); dbg("HplAtm128Timer0AsyncP", "Handling compare at 0x%p @ %s\n", evt, sim_time_string()); if (READ_BIT(ATM128_TCCR0, WGM01) && !READ_BIT(ATM128_TCCR0, WGM00)) { dbg("HplAtm128Timer0AsyncP", "%s: CTC is set, clear timer.\n", __FUNCTION__); call Timer0.set(0); } else { dbg("HplAtm128Timer0AsyncP", "%s: TCCR is 0x%hhx, %i, %i\n", __FUNCTION__, TCCR0, (int)READ_BIT(ATM128_TCCR0, WGM01), (int)READ_BIT(ATM128_TCCR0, WGM00)); } if (READ_BIT(ATM128_TIMSK, OCIE0)) { dbg("HplAtm128Timer0AsyncP", "TIFR is %hhx\n", TIFR); CLR_BIT(ATM128_TIFR, OCF0); dbg("HplAtm128Timer0AsyncP", "TIFR is %hhx\n", TIFR); dbg("HplAtm128Timer0AsyncP", "Compare interrupt @ %s\n", timeStr); SIG_OUTPUT_COMPARE0(); } else { SET_BIT(ATM128_TIFR, OCF0); } // If we haven't been cancelled if (!evt->cancelled) { configure_compare(evt); sim_queue_insert(evt); } } } sim_event_t* allocate_compare() { sim_event_t* newEvent = sim_queue_allocate_event(); dbg("HplAtm128Timer0AsyncP", "Allocated compare at 0x%p\n", newEvent); newEvent->handle = timer0_compare_handle; newEvent->cleanup = sim_queue_cleanup_none; return newEvent; } void configure_compare(sim_event_t* evt) { sim_time_t compareTime = 0; sim_time_t phaseOffset = 0; uint8_t timerVal = call Timer0.get(); uint8_t compareVal = call Compare.get(); // Calculate how many counter increments until timer // hits compare, considering wraparound, and special // case of complete wraparound. compareTime = ((compareVal - timerVal) & 0xff); if (compareTime == 0) { compareTime = 256; } // Now convert the compare time from counter increments // to simulation ticks, considering the fact that the // increment actually has a phase offset. // The +1 is from the timer behavior: if you set OCR0 to be X, // it will actually fire when TCNT is X+1 compareTime = (compareTime + 1) << shiftFromScale(); compareTime = clock_to_sim(compareTime); compareTime += sim_time(); // How long into a timer tick was the clock actually reset? // This covers the case when the compare is set midway between // a tick, so it will go off a little early phaseOffset = sim_time(); phaseOffset -= last_zero(); phaseOffset %= clock_to_sim(1 << shiftFromScale()); compareTime -= phaseOffset; dbg("HplAtm128Timer0AsyncP", "Configuring new compare of %i for %i at time %llu (@ %llu)\n", (int)compareVal, sim_node(), compareTime, sim_time()); evt->time = compareTime; } void schedule_new_compare() { if (compare != NULL) { cancel_compare(); } if (call Timer0.getScale() != AVR_CLOCK_OFF) { sim_event_t* newEvent = allocate_compare(); configure_compare(newEvent); compare = newEvent; sim_queue_insert(newEvent); } } //=== Read the current timer value. =================================== async command uint8_t Timer0.get() { uint8_t rval; sim_time_t elapsed = sim_time() - last_zero(); elapsed = sim_to_clock(elapsed); elapsed = elapsed >> shiftFromScale(); rval = (uint8_t)(elapsed & 0xff); dbg("HplAtm128Timer0AsyncP", "HplAtm128Timer0AsyncP: Getting timer: %hhu\n", rval); return rval; } //=== Set/clear the current timer value. ============================== /** * Set/clear the current timer value. *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -