By Neil

1. Features of NiosII Timers

The timer core with Avalon® interface is a 32-bit interval timer for Avalon-based processor systems, such as a Nios® II processor system. The timer provides the following features:
■ Controls to start, stop, and reset the timer
■ Two count modes: count down once and continuous count-down
■ Count-down period register
■ Maskable interrupt request (IRQ) upon reaching zero
■ Optional watchdog timer feature that resets the system if timer ever reaches zero
■ Optional periodic pulse generator feature that outputs a pulse when timer reaches zero
■ Compatible with 32-bit and 16-bit processors

Corresponding to the timer spcification of tinyos, the NiosII timer features could be abstracted like the followings:

NiosII:

Two 32-bit timer, each allowing:

■ Multiple prescale values, cauze we could set different value to periodl and periodh registers;

■ Two timers are for a system clock or a timestamp, but not both;

■ No compare register, but by setting periodl and periodh, this could have the same effect with compare register;

■ Optional watchdog functionality

2. The NiosII HAL for Timer Devices

The HAL API provides two types of timer device drivers:
■ System clock driver. This type of driver supports alarms, such as you would use in a scheduler.

■ Timestamp driver. This driver supports high-resolution time measurement.

An individual timer peripheral can behave as either a system clock or a timestamp, but not both.

Note:The HAL-specific API functions for accessing timer devices are defined in sys/alt_alarm.h and  sys/alt_timestamp.h.

System Clock Driver

The HAL system clock driver provides a periodic “heartbeat”, causing the system clock to increment on each beat. Software can use the system clock facilities to execute functions at specified times, and to obtain timing information. You select a specific hardware timer peripheral as the system clock device by manipulating BSP settings.

The HAL provides implementations of the following standard UNIX functions: gettimeofday(), settimeofday(), and times(). The times returned by these functions are based on the HAL system clock.

At runtime, you can obtain the current value of the system clock by calling the alt_nticks() function. This function returns the elapsed time in system clock ticks since reset. You can get the system clock rate, in ticks per second, by calling the function alt_ticks_per_second(). The HAL timer driver initializes the tick frequency when it creates the
instance of the system clock.

Alarms

You can register functions to be executed at a specified time using the HAL alarm facility. A software program registers an alarm by calling the function alt_alarm_start():
int alt_alarm_start (alt_alarm* alarm, alt_u32 nticks, alt_u32 (*callback) (void* context), void* context);

The callback function can reset the alarm. The return value of the registered callback function is the number of ticks until the next call to callback. A return value of zero indicates that the alarm should be stopped. You can manually cancel an alarm by calling alt_alarm_stop().

One alarm is created for each call to alt_alarm_start(). Multiple alarms can be running simultaneously.

Timestamp Driver

Sometimes you want to measure time intervals with a degree of accuracy greater than that provided by HAL system clock ticks. The HAL provides high resolution timing functions using a timestamp driver.

If a timestamp driver is present, the following functions are available:
■ alt_timestamp_start()
■ alt_timestamp()

Calling alt_timestamp_start() starts the counter running. Subsequent calls to alt_timestamp() return the current value of the timestamp counter. Calling alt_timestamp_start() again resets the counter to zero. The behavior of the timestamp driver is undefined when the counter reaches (2^32 – 1).

You can obtain the rate at which the timestamp counter increments by calling the function alt_timestamp_freq().

3. Developing Timer for TinyOS using the Low Level IO

Considering the limitation of HAL, maybe later on will have to use low level IO to write driver for various components, obviously, I will refer to corresponding HAL part. For now, still use HAL to implement basic functions.

3.1 Nios2 Timer Subsystem

The Toni exposes its four timers through a common set of interfaces:
• HplTimer<width> – get/set current time, overflow event, control, init
• HplCompare<width> – get/set compare time, fired event, control
• HplCapture<width> – get/set capture time, captured event, control, config
Parameterising these interfaces by width allows reusing the same interfaces for the 16 and 32-bit timers. This simplifies building reusable higher level components which are independent of timer width.

interface HplNios2Timer<timer_size>
{
    /// Timer value register: Direct access
    async command timer_size get();//Get the current time. For the set being, invoke gettimeofday() instead.          
    async command void set( timer_size t );  //Set the current time. Cauz NiosII hasn’t the API to set ticks                                                     //of CPU clock, so invoke settimeofday() instead. or record original ticks and do some tricks?

    /// Interrupt signals
    //async event void overflow(); //<! Signalled on overflow interrupt
   /// Interrupt flag utilites: Bit level set/clr
   //async command void reset(); //<! Clear the overflow interrupt flag
   //async command void start(); //<! Enable the overflow interrupt
   //async command void stop(); //<! Turn off overflow interrupts
   //async command bool test(); //<! Did overflow interrupt occur?
   //async command bool isOn(); //<! Is overflow interrupt on?
   /// Clock initialization interface
   //async command void off(); //<! Turn off the clock    ???
   async command void setScale( uint8_t scale); //<! Turn on the clock
   async command uint8_t getScale(); //<! Get prescaler setting
}
interface HplNios2Compare<size_type>
{
    /// Compare value register: Direct access
    async command size_type get();
    async command void set(size_type t);
    /// Interrupt signals

    async event void fired(); //<! Signalled on compare interrupt
    /// Interrupt flag utilites: Bit level set/clr
    //async command void reset(); //<! Clear the compare interrupt flag
    //async command void start(); //<! Enable the compare interrupt
    //async command void stop(); //<! Turn off comparee interrupts
    //async command bool test(); //<! Did compare interrupt occur?
    //async command bool isOn(); //<! Is compare interrupt on?
}
interface HplAtm128Capture<size_type>
{
    /// Capture value register: Direct access
    async command size_type get();
    async command void set(size_type t);
    /// Interrupt signals
    async event void captured(size_type t); //<! Signalled on capture int
    /// Interrupt flag utilites: Bit level set/clr
    async command void reset(); //<! Clear the capture interrupt flag
    async command void start(); //<! Enable the capture interrupt
    async command void stop(); //<! Turn off capture interrupts
    async command bool test(); //<! Did capture interrupt occur?
    async command bool isOn(); //<! Is capture interrupt on?
    //async command void setEdge(bool up); //<! True = detect rising edge
}

These interfaces are provided by two components, corresponding to each hardware timer: HplNios2Timer0C through HplNios2Timer1C.

3.3 HAL

Timer 0: 32-bit timer is set to run at 100MHz if possible. Could set divider directly by setting period register. So can limit it to 1, 8, 64, 256 and 1024. So, when clocked at 100MHz, a divider of 1 is selected and timer 1 runs at 100MHz. To reflect this fact, the HAL components exposing timer 0 are named CounterZero32C and AlarmOne32C(rather than the CounterMicro32C and AlarmMicro32C).

Advertisements