[Tinyos-2-commits] CVS: tinyos-2.x/tos/chips/atm128/timer/sim
HplAtm128Timer0AsyncP.nc, NONE, 1.1 HplAtm128CompareC.nc, 1.4,
1.5 HplAtm128Timer0AsyncC.nc, 1.4, 1.5
Phil Levis
scipio at users.sourceforge.net
Mon Apr 9 18:21:26 PDT 2007
Update of /cvsroot/tinyos/tinyos-2.x/tos/chips/atm128/timer/sim
In directory sc8-pr-cvs10.sourceforge.net:/tmp/cvs-serv25162
Modified Files:
HplAtm128CompareC.nc HplAtm128Timer0AsyncC.nc
Added Files:
HplAtm128Timer0AsyncP.nc
Log Message:
Fixed timer system to follow new implementation from DGay.
--- NEW FILE: 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 at cs.stanford.edu>
* @author Martin Turon <mturon at xbow.com>
* @author David Gay <dgay at intel-research.net>
*/
// $Id: HplAtm128Timer0AsyncP.nc,v 1.1 2007/04/10 01:21:22 scipio 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;
}
}
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();
}
default async event void Timer0.overflow() { }
AVR_ATOMIC_HANDLER(SIG_OVERFLOW0) {
inOverflow = TRUE;
signal Timer0.overflow();
inOverflow = FALSE;
}
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.
*
* This code is pretty tricky. */
async command void Timer0.set(uint8_t newVal) {
uint8_t curVal = call Timer0.get();
dbg("HplAtm128Timer0AsyncP", "HplAtm128Timer0AsyncP: Setting timer: %hhu\n", newVal);
if (newVal == curVal) {
return;
}
else {
sim_time_t adjustment = curVal - newVal;
adjustment = adjustment << shiftFromScale();
adjustment = clock_to_sim(adjustment);
if (newVal < curVal) {
lastZero += adjustment;
}
else { // newVal > curVal
lastZero -= adjustment;
}
schedule_new_overflow();
notify_changed();
}
}
//=== Read the current timer scale. ===================================
async command uint8_t Timer0.getScale() {
return TCCR0 & 0x7;
}
//=== Turn off the timers. ============================================
async command void Timer0.off() {
call Timer0.setScale(AVR_CLOCK_OFF);
savedCounter = call Timer0.get();
cancel_overflow();
notify_changed();
}
//=== Write a new timer scale. ========================================
async command void Timer0.setScale(uint8_t s) {
Atm128TimerControl_t ctrl;
uint8_t currentScale = call Timer0.getScale();
uint8_t currentCounter;
dbg("HplAtm128Timer0AsyncP", "Timer0 scale set to %i\n", (int)s);
if (currentScale == 0) {
currentCounter = savedCounter;
}
else {
currentCounter = call Timer0.get();
}
ctrl = call Timer0Ctrl.getControl();
ctrl.flat &= ~(0x7);
ctrl.flat |= (s & 0x7);
call Timer0Ctrl.setControl(ctrl);
if (currentScale != s) {
adjust_zero(currentCounter);
schedule_new_overflow();
}
notify_changed();
}
//=== Read the control registers. =====================================
async command Atm128TimerControl_t Timer0Ctrl.getControl() {
return *(Atm128TimerControl_t*)&TCCR0;
}
//=== Write the control registers. ====================================
async command void Timer0Ctrl.setControl( Atm128TimerControl_t x ) {
dbg("HplAtm128Timer0AsyncP", "Setting control to be 0x%hhx\n", x.flat);
TCCR0 = x.flat;
}
//=== Read the interrupt mask. =====================================
async command Atm128_TIMSK_t Timer0Ctrl.getInterruptMask() {
return *(Atm128_TIMSK_t*)&TIMSK;
}
//=== Write the interrupt mask. ====================================
DEFINE_UNION_CAST(TimerMask8_2int, Atm128_TIMSK_t, uint8_t);
DEFINE_UNION_CAST(TimerMask16_2int, Atm128_ETIMSK_t, uint8_t);
async command void Timer0Ctrl.setInterruptMask( Atm128_TIMSK_t x ) {
TIMSK = TimerMask8_2int(x);
}
//=== Read the interrupt flags. =====================================
async command Atm128_TIFR_t Timer0Ctrl.getInterruptFlag() {
Atm128_TIFR_t at;
at.flat = TIFR;
return at;
}
//=== Write the interrupt flags. ====================================
DEFINE_UNION_CAST(TimerFlags8_2int, Atm128_TIFR_t, uint8_t);
DEFINE_UNION_CAST(TimerFlags16_2int, Atm128_ETIFR_t, uint8_t);
async command void Timer0Ctrl.setInterruptFlag( Atm128_TIFR_t x ) {
TIFR = TimerFlags8_2int(x);
}
//=== Timer 8-bit implementation. ====================================
async command void Timer0.reset() {
// Clear TOV0. On real hardware, this is a write.
TIFR &= ~(1 << TOV0);
}
async command void Timer0.start() {
SET_BIT(ATM128_TIMSK, TOIE0);
dbg("HplAtm128Timer0AsyncP", "Enabling TOIE0 at %llu\n", sim_time());
schedule_new_overflow();
}
async command void Timer0.stop() {
dbg("HplAtm128Timer0AsyncP", "Timer stopped @ %llu\n", sim_time());
CLR_BIT(ATM128_TIMSK, TOIE0);
cancel_overflow();
}
bool overflowed() {
return READ_BIT(ATM128_TIFR, TOV0);
}
inline void stabiliseOverflow() {
/* From the atmel manual:
During asynchronous operation, the synchronization of the interrupt
flags for the asynchronous timer takes three processor cycles plus one
timer cycle. The timer is therefore advanced by at least one before
the processor can read the timer value causing the setting of the
interrupt flag. The output compare pin is changed on the timer clock
and is not synchronized to the processor clock.
So: if the timer is = 0, wait till it's = 1, except if
- we're currently in the overflow interrupt handler
- or, the overflow flag is already set
*/
//if (!inOverflow)
// while (!TCNT0 && !overflowed())
//;
}
async command bool Timer0.test() {
stabiliseOverflow();
return overflowed();
}
async command bool Timer0.isOn() {
return (call Timer0Ctrl.getInterruptMask()).bits.toie0;
}
async command void Compare.reset() { TIFR = 1 << OCF0; }
async command void Compare.start() { SET_BIT(ATM128_TIMSK,OCIE0); }
async command void Compare.stop() { CLR_BIT(ATM128_TIMSK,OCIE0); }
async command bool Compare.test() {
return (call Timer0Ctrl.getInterruptFlag()).bits.ocf0;
}
async command bool Compare.isOn() {
return (call Timer0Ctrl.getInterruptMask()).bits.ocie0;
}
//=== Read the compare registers. =====================================
async command uint8_t Compare.get() {
dbg("HplAtm128Timer0AsyncP", "HplAtm128Timer0AsyncP: Getting compare: %hhu\n", OCR0);
return OCR0;
}
//=== Write the compare registers. ====================================
async command void Compare.set(uint8_t t) {
dbg("HplAtm128Timer0AsyncP", "HplAtm128Timer0AsyncP: Setting compare: %hhu\n", t);
atomic {
/* Re the comment above: it's a bad idea to wake up at time 0, as
we'll just spin when setting the next deadline. Try and reduce
the likelihood by delaying the interrupt...
*/
if (t == 0 || t >= 0xfe)
t = 1;
if (t != OCR0) {
OCR0 = t;
schedule_new_compare();
}
}
}
sim_event_t* overflow;
void timer0_overflow_handle(sim_event_t* evt) {
if (evt->cancelled) {
return;
}
else {
if (READ_BIT(ATM128_TIMSK, TOIE0)) {
CLR_BIT(ATM128_TIFR, TOV0);
dbg("HplAtm128Timer0AsyncP", "Overflow interrupt at %s\n", sim_time_string());
SIG_OVERFLOW0();
}
else {
dbg("HplAtm128Timer0AsyncP", "Setting overflow bit at %s\n", sim_time_string());
SET_BIT(ATM128_TIFR, TOV0);
}
configure_overflow(evt);
sim_queue_insert(evt);
}
}
sim_event_t* allocate_overflow() {
sim_event_t* newEvent = sim_queue_allocate_event();
newEvent->handle = timer0_overflow_handle;
newEvent->cleanup = sim_queue_cleanup_none;
return newEvent;
}
void configure_overflow(sim_event_t* evt) {
sim_time_t overflowTime = 0;
uint8_t timerVal = call Timer0.get();
uint8_t overflowVal = 0;
// Calculate how many counter increments until timer
// hits compare, considering wraparound, and special
// case of complete wraparound.
overflowTime = ((overflowVal - timerVal) & 0xff);
if (overflowTime == 0) {
overflowTime = 256;
}
// Now convert the compare time from counter increments
// to simulation ticks, considering the fact that the
// increment actually has a phase offset.
overflowTime = overflowTime << shiftFromScale();
overflowTime = clock_to_sim(overflowTime);
overflowTime += sim_time();
overflowTime -= (sim_time() - last_zero()) % (1 << shiftFromScale());
dbg("HplAtm128Timer0AsyncP", "Scheduling new overflow for %i at time %llu\n", sim_node(), overflowTime);
evt->time = overflowTime;
}
void schedule_new_overflow() {
sim_event_t* newEvent = allocate_overflow();
configure_overflow(newEvent);
if (overflow != NULL) {
cancel_overflow();
}
overflow = newEvent;
sim_queue_insert(newEvent);
}
void cancel_overflow() {
if (overflow != NULL) {
overflow->cancelled = 1;
dbg("HplAtm128Timer0AsyncP", "Cancelling overflow %p.\n", overflow);
overflow->cleanup = sim_queue_cleanup_total;
}
}
async command Atm128Assr_t TimerAsync.getAssr() {
return *(Atm128Assr_t *)&ASSR;
}
async command void TimerAsync.setAssr(Atm128Assr_t x) {
ASSR = x.flat;
}
async command void TimerAsync.setTimer0Asynchronous() {
ASSR |= 1 << AS0;
}
async command int TimerAsync.controlBusy() {
return (ASSR & (1 << TCR0UB)) != 0;
}
async command int TimerAsync.compareBusy() {
return (ASSR & (1 << OCR0UB)) != 0;
}
async command int TimerAsync.countBusy() {
return (ASSR & (1 << TCN0UB)) != 0;
}
void cancel_compare() {
dbg("HplAtm128CompareC", "Cancelling compare at 0x%p\n", compare);
if (compare != NULL) {
compare->cancelled = 1;
compare->cleanup = sim_queue_cleanup_total;
}
}
}
Index: HplAtm128CompareC.nc
===================================================================
RCS file: /cvsroot/tinyos/tinyos-2.x/tos/chips/atm128/timer/sim/HplAtm128CompareC.nc,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -d -r1.4 -r1.5
*** HplAtm128CompareC.nc 12 Dec 2006 18:23:04 -0000 1.4
--- HplAtm128CompareC.nc 10 Apr 2007 01:21:22 -0000 1.5
***************
*** 193,203 ****
}
else {
! char time[128];
! sim_print_now(time, 128);
dbg("HplAtm128CompareC", "Handling compare at 0x%p @ %s\n", evt, sim_time_string());
if (READ_BIT(interruptRegister, interruptBit)) {
CLR_BIT(flagRegister, flagBit);
! dbg("HplAtm128CompareC", "Compare interrupt @ %s\n", time);
SIG_OUTPUT_COMPARE0();
}
--- 193,203 ----
}
else {
! char timeStr[128];
! sim_print_now(timeStr, 128);
dbg("HplAtm128CompareC", "Handling compare at 0x%p @ %s\n", evt, sim_time_string());
if (READ_BIT(interruptRegister, interruptBit)) {
CLR_BIT(flagRegister, flagBit);
! dbg("HplAtm128CompareC", "Compare interrupt @ %s\n", timeStr);
SIG_OUTPUT_COMPARE0();
}
Index: HplAtm128Timer0AsyncC.nc
===================================================================
RCS file: /cvsroot/tinyos/tinyos-2.x/tos/chips/atm128/timer/sim/HplAtm128Timer0AsyncC.nc,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -d -r1.4 -r1.5
*** HplAtm128Timer0AsyncC.nc 12 Dec 2006 18:23:04 -0000 1.4
--- HplAtm128Timer0AsyncC.nc 10 Apr 2007 01:21:22 -0000 1.5
***************
*** 43,69 ****
{
provides {
- interface Init @atleastonce();
// 8-bit Timers
interface HplAtm128Timer<uint8_t> as Timer;
interface HplAtm128TimerCtrl8 as TimerCtrl;
interface HplAtm128Compare<uint8_t> as Compare;
}
}
implementation {
! components HplAtm128Counter0C, new HplAtm128CompareC(uint8_t,
! ATM128_OCR0,
! ATM128_TIMSK,
! OCIE0,
! ATM128_TIFR,
! OCF0);
!
! Init = HplAtm128Counter0C;
! Timer = HplAtm128Counter0C;
! TimerCtrl = HplAtm128Counter0C;
! Compare = HplAtm128CompareC;
!
! HplAtm128CompareC.Timer -> HplAtm128Counter0C;
! HplAtm128CompareC.TimerCtrl -> HplAtm128Counter0C;
! HplAtm128CompareC.Notify -> HplAtm128Counter0C;
!
}
--- 43,58 ----
{
provides {
// 8-bit Timers
interface HplAtm128Timer<uint8_t> as Timer;
interface HplAtm128TimerCtrl8 as TimerCtrl;
interface HplAtm128Compare<uint8_t> as Compare;
+ interface HplAtm128TimerAsync as TimerAsync;
}
}
implementation {
! components HplAtm128Timer0AsyncP;
! Timer = HplAtm128Timer0AsyncP;
! TimerCtrl = HplAtm128Timer0AsyncP;
! Compare = HplAtm128Timer0AsyncP;
! TimerAsync = HplAtm128Timer0AsyncP;
}
More information about the Tinyos-2-commits
mailing list