📄 tep102.txt
字号:
============================
Timers
============================
:TEP: 102
:Group: Core Working Group
:Type: Documentary
:Status: Final
:TinyOS-Version: 2.x
:Author: Cory Sharp, Martin Turon, David Gay
.. Note::
This memo documents a part of TinyOS for the TinyOS Community, and
requests discussion and suggestions for improvements. Distribution
of this memo is unlimited. This memo is in full compliance with
TEP 1.
Abstract
====================================================================
This TEP proposes a Timer design that supports common timing
requirements both in precision and width across common hardware
configurations. This TEP focuses on aligning the Timer abstraction
with the three-layer Hardware Abstraction Architecture (HAA).
1. Introduction
====================================================================
Most microcontrollers offer a rich timer system, with features like:
* several counters, possibly of different widths, with multiple clocking options
* one or more compare registers for each counter, which can trigger
interrupts, changes to output pins and changes to the counter value
* capture of the time of input pin changes
The interested reader can refer to Appendix A for a brief overview of
the timer hardware on some current TinyOS platforms.
TinyOS does not attempt to capture all this diversity in a
platform-independent fashion. Instead, following the principles of the
HAA[_tep2], each microcontroller should expose all this functionality
via components and interfaces at the HPL and, where appropriate, HAL levels.
However, two aspects of timers are sufficiently common and important
that they should be made available in a well-defined way: measuring time,
and triggering (possibly repeating) events at specific times. The rest
of this TEP specifies:
* a set of platform-independent interfaces for counting time and triggering
events (`2. Interfaces`_)
* guidelines on how each microcontroller's HAL SHOULD expose its timer hardware
in terms of the above interfaces (`3. HAL guidelines`_)
* what components a microcontroller's timer HIL MUST implement
(`4. HIL requirements`_)
* a set of utility components whose use simplifies building the components
specified by the HAL guidelines and HIL requirements (`5. Utility components`_)
This TEP ends with appendices documenting, as an example, the mica2
timer subsystem implementation.
2. Interfaces
====================================================================
Before presenting the interfaces (2.2), we start with a general
discussion of the issues of precision, width and accuracy in
timer interfaces (2.1).
2.1 Precision, Width and Accuracy
--------------------------------------------------------------------
Three fundamental properties of timers are *precision*, *width* and
*accuracy*.
Examples of precision are millisecond, a cycle of a 32kHz clock, and
microseconds. All precisions presented in this TEP are in "binary"
units with respect to one second. That is, one second contains 1024
binary milliseconds, 32768 32kHz ticks, or 1048576 microseconds.
This TEP emphasizes millisecond and 32kHz tick precisions while
reasonably accommodating other precisions. The use of "binary" units
is motivated by the common availability of hardware clocks driven
by a 32768Hz crystal.
Examples of widths are 8-bit, 16-bit, 32-bit, and 64-bit. The width
for timer interfaces and components SHOULD be 32-bits. This TEP
emphasizes 32-bit widths while reasonably accommodating other widths -
a particular platform may have good reasons not to expose a 32-bit
interface.
Accuracy reflects how closely a component conforms to the precision it
claims to provide. Accuracy is affected by issues such as clock drift (much
higher for internal vs crystal oscillators) and hardware limitations. As an
example of hardware limitations, a mica2 clocked at 7.37MHz cannot offer an
exact binary microsecond timer -- the closest it can come is 7.37MHz/8. Rather
than introduce a plethora of precisions, we believe it is often best to
pick the existing precision closest to what can be provided, along with
appropriate documentation. However, the accuracy MUST remain reasonable:
for instance, it would be inappropriate to claim that a millisecond timer
is a 32kHz timer.
This TEP parameterizes all interfaces by precision and some
interfaces by width. This intentionally makes similar timer
interfaces with different precision or width mutually incompatible.
It also allows user code to clearly express and understand the
precision and width for a given timer interface. Accuracy is not
reflected in the interface type.
Precision is expressed as a dummy type -- TMilli, T32khz, and
TMicro -- written in the standard Timer.h header like this::
typedef struct { int notUsed; } TMilli; // 1024 ticks per second
typedef struct { int notUsed; } T32khz; // 32768 ticks per second
typedef struct { int notUsed; } TMicro; // 1048576 ticks per second
Note that the precision names are expressed as either frequency or
period, whichever is convenient.
2.2 Timer interfaces
--------------------------------------------------------------------
This TEP proposes these timer interfaces::
interface Counter< precision_tag, size_type >
interface Alarm< precision_tag, size_type >
interface BusyWait< precision_tag, size_type >
interface LocalTime< precision_tag >
interface Timer< precision_tag >
The LocalTime and Timer interfaces are used primarily by user
applications and use a fixed width of 32-bits. The Alarm, BusyWait,
and Counter interfaces are used by the TinyOS timer system and
advanced user components.
Counter
--------------------------------------------------------------------
The Counter interface returns the current time and provides commands
and an event for managing overflow conditions. These overflow
commands and events are necessary for properly deriving larger width
Counters from smaller widths. ::
interface Counter<precision_tag,size_type>
{
async command size_type get();
async command bool isOverflowPending();
async command void clearOverflow();
async event void overflow();
}
get()
return the current time.
isOverflowPending()
return TRUE if the overflow flag is set for this counter, i.e., if and
only if an overflow event will occur after the outermost atomic
block exits. Return FALSE otherwise. This command only returns the
state of the overflow flag and causes no side effect.
clearOverflow()
cancel the pending overflow event clearing the overflow flag.
overflow()
signals that an overflow in the current time. That is, the current
time has wrapped around from its maximum value to zero.
Alarm
--------------------------------------------------------------------
Alarm components are extensions of Counters that signal an event
when their compare register detects the alarm time has been hit.
All commands and events of the Alarm interface are asynchronous (or
in "interrupt context"). The Alarm interface provides a set of
"basic" commands for common usage and provides a set of "extended"
commands for advanced use. ::
interface Alarm<precision_tag,size_type>
{
// basic interface
async command void start( size_type dt );
async command void stop();
async event void fired();
// extended interface
async command bool isRunning();
async command void startAt( size_type t0, size_type dt );
async command size_type getNow();
async command size_type getAlarm();
}
start(dt)
cancel any previously running alarm and set to fire in dt time units
from the time of invocation. The alarm will only fire once then
stop.
stop()
cancel any previously running alarm.
fired()
signals that the alarm has expired.
isRunning()
return TRUE if the alarm has been started and has not been cancelled
or has not yet fired. FALSE is returned otherwise.
startAt(t0,dt)
cancel any previously running alarm and set to fire at time t1 =
t0+dt. This form allows a delay to be anchored to some time t0 taken
before the invocation of startAt. The timer subsystem uses this form
internally, to be able to use of the full width of an alarm while also
detecting when a short alarm elapses prematurely.
The time ``t0`` is always assumed to be in the past. A value of ``t0``
numerically greater than the current time (returned by ``getNow()``)
represents a time from before the last wraparound.
getNow()
return the current time in the precision and width of the alarm.
getAlarm()
return the time the currently running alarm will fire or the time
that the previously running alarm was set to fire. getAlarm can
be used with startAt to set an alarm from the previous alarm time,
as in startAt(getAlarm(),dt). This pattern is used within the
fired() event to construct periodic alarms.
BusyWait
--------------------------------------------------------------------
The BusyWait interface allows for very short synchronous delays.
BusyWait should be used sparingly and when an Alarm would not be
reasonably efficient or accurate. The BusyWait interface replaces
the TOSH_uwait macro from TinyOS 1.x.
BusyWait blocks for no less than the specified amount of time. No
explicit upper bound is imposed on the enacted delay, though it is
expected that the underlying implementation spins in a busy loop until
the specified amount of time has elapsed.
::
interface BusyWait<precision_tag,size_type>
{
async command void wait( size_type dt );
}
wait(dt)
block until at least dt time units have elapsed
LocalTime
--------------------------------------------------------------------
The LocalTime interface exposes a 32-bit counter without overflow
utilities. This is primarily for application code that does not
care about overflow conditions. ::
interface LocalTime<precision_tag>
{
async command uint32_t get();
}
get()
return the current time.
Timer
--------------------------------------------------------------------
All commands and events of the Timer interface are synchronous (or
in "task context"). The Timer interface provides a set of "basic"
commands for common usage and provides a set of "extended" commands
for advanced use. The Timer interface allows for periodic events.
::
interface Timer<precision_tag>
{
// basic interface
command void startPeriodic( uint32_t dt );
command void startOneShot( uint32_t dt );
command void stop();
event void fired();
// extended interface
command bool isRunning();
command bool isOneShot();
command void startPeriodicAt( uint32_t t0, uint32_t dt );
command void startOneShotAt( uint32_t t0, uint32_t dt );
command uint32_t getNow();
command uint32_t gett0();
command uint32_t getdt();
}
startPeriodic(dt)
cancel any previously running timer and set to fire in dt time units
from the time of invocation. The timer will fire periodically every
dt time units until stopped.
startOneShot(dt)
cancel any previously running timer and set to fire in dt time units
from the time of invocation. The timer will only fire once then
stop.
stop()
cancel any previously running timer.
fired()
signals that the timer has expired (one-shot) or repeated (periodic).
isRunning()
return TRUE if the timer has been started and has not been cancelled
and has not fired for the case of one-shot timers. Once a periodic
timer is started, isRunning will return TRUE until it is cancelled.
isOneShot()
return TRUE if the timer is a one-shot timer. Return FALSE
otherwise if the timer is a periodic timer.
startPeriodicAt(t0,dt)
cancel any previously running timer and set to fire at time t1 =
t0+dt. The timer will fire periodically every dt time units until
stopped.
As with alarms, the time ``t0`` is always assumed to be in the past. A
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -