Advertisement

Application timers

January 14, 2019

Colin Walls-January 14, 2019

The idea of application timers was introduced in an earlier article. They are kernel objects that provide tasks with simple means to time events or, more commonly, perform an activity on a regular basis. All the detail of timing functionality – accuracy, interrupt handling, etc. – in Nucleus SE was covered in the last article.

Using Timers

Application timers may be configured to be one-shot – i.e. they are started and then, after the assigned time period, they simply terminate. Or a timer may be configured to repeat – i.e. when it expires, it automatically restarts; the time interval for the restart period may be different from the initial time. A timer may also be optionally configured to run a specific function – an expiration routine – when (or each time) the timer expires.

Configuring Timers

Number of Timers

As with most aspects of Nucleus SE, the configuration of timers is primarily controlled by #define statements in nuse_config.h. The key setting is NUSE_TIMER_NUMBER, which determines how many timers are configured for the application. The default setting is 0 (i.e. no timers are in use) and you can set it to any value up to 16. An erroneous value will result in a compile time error, which is generated by a test in nuse_config_check.h (this is included into nuse_config.c and hence compiled with this module) resulting in a #error statement being compiled.

Choosing a non-zero value is the “master enable” for timers. This results in some data structures being defined and sized accordingly, of which more later in this article. It also activates the API enabling settings.

Expiration Routine Enable

In Nucleus SE, I looked for opportunities to make functionality optional, where its omission would save memory. A good example of that is support for timer expiration routines. Apart from being optional for each individual timer, the facility may be enabled (or not) for the whole application by means of the NUSE_TIMER_EXPIRATION_ROUTINE_SUPPORT setting in nuse_config.h. Setting this to FALSE suppresses the definition of two ROM data structures, of which more later in this article.

API Enables

Every API function (service call) in Nucleus SE has an enabling #define symbol in nuse_config.h. For timers, these are:

   NUSE_TIMER_CONTROL
   NUSE_TIMER_GET_REMAINING
   NUSE_TIMER_RESET
   NUSE_TIMER_INFORMATION
   NUSE_TIMER_COUNT

By default, all of these are set to FALSE, thus disabling each service call and inhibiting the inclusion of any implementation code. To configure timers for an application, you need to select the API calls that you want to use and set their enabling symbols to TRUE.

Here is an extract from the default nuse_config.h file.

   #define NUSE_TIMER_NUMBER  0  /* Number of application timers in
                                 the system - 0-16 */
                                 /* Service call enablers */
   #define NUSE_TIMER_CONTROL          FALSE
   #define NUSE_TIMER_GET_REMAINING    FALSE
   #define NUSE_TIMER_RESET            FALSE
   #define NUSE_TIMER_INFORMATION      FALSE
   #define NUSE_TIMER_COUNT            FALSE
    

A compile time error will result if a timer API function is enabled and no timers are configured (except for NUSE_Timer_Count() which is always permitted). If your code uses an API call, which has not been enabled, a link time error will result, as no implementation code will have been included in the application.

Timer Service Calls

Nucleus RTOS supports eight service calls that appertain to timers, which provide the following functionality:

  • Control (start/stop) a timer. Implemented by NUSE_Timer_Control() in Nucleus SE.

  • Obtain remaining time from a timer. Implemented by NUSE_Timer_Get_Remaining() in Nucleus SE.

  • Restore a timer to the unused state (reset). Implemented by NUSE_Timer_Reset() in Nucleus SE.

  • Provide information about a specified timer. Implemented by NUSE_Timer_Information() in Nucleus SE.

  • Return a count of how many timers are (currently) configured for the application. Implemented by NUSE_Timer_Count() in Nucleus SE.

  • Add a new timer to the application (create). Not implemented in Nucleus SE.

  • Remove a timer from the application (delete). Not implemented in Nucleus SE.

  • Return pointers to all the timers (currently) in the application. Not implemented in Nucleus SE.

The implementation of each of these service calls is examined in detail.

Timer Services

The fundamental operations, which can be performed on a timer, are controlling it – starting and stopping – and reading its current value. Nucleus RTOS and Nucleus SE each provide two basic API calls for these operations, which will be discussed here.

Controlling a Timer

The Nucleus RTOS API call for controlling a timer simply permits the timer to be enabled or disabled (i.e. started or stopped). Nucleus SE provides the same service.

Nucleus RTOS API Call for Controlling a Timer

Service call prototype:

   STATUS NU_Control_Timer(NU_TIMER *timer, OPTION enable);

Parameters:

timer – pointer to the user-supplied timer control block
enable – required function; may be NU_ENABLE_TIMER or NU_DISABLE_TIMER

Returns:

NU_SUCCESS – the call was completed successfully
NU_INVALID_TIMER – the timer pointer is invalid
NU_INVALID_ENABLE – the specified function is invalid

Nucleus SE API Call for Controlling a Timer

This API call supports the full functionality of the Nucleus RTOS API.

Service call prototype:

   STATUS NUSE_Timer_Control(NUSE_TIMER timer, OPTION enable);

Parameters:

timer – the index (ID) of the timer to be utilized
enable – required function; may be NUSE_ENABLE_TIMER or NUSE_DISABLE_TIMER

Returns:

NUSE_SUCCESS – the call was completed successfully
NUSE_INVALID_TIMER – the timer index is invalid
NUSE_INVALID_ENABLE – the specified function is invalid

Nucleus SE Implementation of Timer Control

The code of the NUSE_Timer_Control() API function – after parameter checking – is reasonably straightforward:

NUSE_CS_Enter();
if (enable == NUSE_ENABLE_TIMER)
{
   NUSE_Timer_Status[timer] = TRUE;
   if (NUSE_Timer_Expirations_Counter[timer] == 0)
   {
      NUSE_Timer_Value[timer] = NUSE_Timer_Initial_Time[timer];
   }
   else
   {
      NUSE_Timer_Value[timer] = NUSE_Timer_Reschedule_Time[timer];
   }
}
else  /* enable == NUSE_DISABLE_TIMER */
{
   NUSE_Timer_Status[timer] = FALSE;
}
NUSE_CS_Exit();


If the specified function is NUSE_DISABLE_TIMER, the timer’s status (NUSE_Timer_Status[] entry) is set to FALSE, which results in it being ignored by the clock ISR.

If NUSE_ENABLE_TIMER is specified, the timer counter (NUSE_Timer_Value[]) is set to NUSE_Timer_Initial_Time[], if the timer has never expired since last reset. Otherwise it is set to NUSE_Timer_Reschedule_Time[]. Then the timer’s status (NUSE_Timer_Status[] entry) is set to TRUE, which results in it being processed by the clock ISR.

Reading a Timer

The Nucleus RTOS API call for getting the remaining time from a timer does just that – returns the number of ticks before it will expire. Nucleus SE provides the same service.

Nucleus RTOS API Call for Getting Remaining Time

Service call prototype:

   STATUS NU_Get_Remaining_Time (NU_TIMER *timer,
                                 UNSIGNED *remaining_time);

Parameters:

timer – pointer to the user-supplied timer control block.
remaining_time – a pointer to storage for the remaining time value, which is a single variable of type UNSIGNED

Returns:

NU_SUCCESS – the call was completed successfully
NU_INVALID_TIMER – the timer pointer is invalid

Nucleus SE API Call for Getting Remaining Time

This API call supports the full functionality of the Nucleus RTOS API.

Service call prototype:

   STATUS NUSE_Timer_Get_Remaining(NUSE_TIMER timer,
                                   U16 *remaining_time);

Parameters:

timer – the index (ID) of the timer to be utilized
remaining_time – a pointer to storage for the remaining time value, which is a single variable of type U16

Returns:

NUSE_SUCCESS – the call was completed successfully
NUSE_INVALID_TIMER – the timer index is invalid
NUSE_INVALID_POINTER – the remaining time pointer is NULL

Nucleus SE Implementation of Timer Read

The bulk of the code of the NUSE_ Timer_Get_Remaining() API function – after parameter checking – is almost trivially simple. The value of NUSE_Timer_Value[] is obtained and returned within a critical section.

Timer Utility Services

Nucleus RTOS has four API calls which provide utility functions associated with timers: reset timer, return information about a timer, return number of timers in the application and return pointers to all timers in the application. The first three of these are implemented in Nucleus SE.

Resetting a Timer

This API call restores the timer to its initial, unused state. The timer may be enabled or disabled after the completion of this call. It is only allowed after a timer has been disabled (using NUSE_Timer_Control()). On the next occasion that the timer is enabled, it will be initialized with its entry from NUSE_Timer_Initial_Time[]. Nucleus RTOS permits new initial and reschedule times to be provided and the expiration routine to be specified when a timer is reset; in Nucleus SE, these values are set at configuration time and cannot be changed, as they may be stored in ROM.

Nucleus RTOS API Call for Resetting a Timer

Service call prototype:

   STATUS NU_Reset_Timer(NU_TIMER *timer,
   VOID (*expiration_routine)(UNSIGNED), UNSIGNED initial_time,
   UNSIGNED reschedule_time, OPTION enable);

Parameters:

timer – pointer to the timer to be reset
expiration_routine – specifies the application routine to execute when the timer expires
initial_time – the initial number of timer ticks for timer expiration
reschedule_time – the number of timer ticks for expiration after the first expiration
enable – required state after reset; may be NU_ENABLE_TIMER or NU_DISABLE_TIMER

Returns:

NU_SUCCESS – the call was completed successfully
NU_INVALID_TIMER – the timer control block pointer is not valid
NU_INVALID_FUNCTION – the expiration function pointer is NULL
NU_INVALID_ENABLE – the specified state is invalid
NU_NOT_DISABLED – the time is currently enabled (disable required before reset)

Nucleus SE API Call for Resetting a Timer

This API call supports a simplified version of the key functionality of the Nucleus RTOS API.

Service call prototype:

   STATUS NUSE_Timer_Reset(NUSE_TIMER timer, OPTION enable);

Parameters:

timer – the index (ID) of the timer to be reset
enable – required state after reset; may be NUSE_ENABLE_TIMER or NUSE_DISABLE_TIMER

Returns:

NUSE_SUCCESS – the call was completed successfully
NUSE_INVALID_TIMER – the timer index is not valid
NUSE_INVALID_ENABLE – the specified state is invalid
NUSE_NOT_DISABLED – the time is currently enabled (disable required before reset)

Nucleus SE Implementation of Timer Reset

The bulk of the code of the NUSE_Timer_Reset() API function – after parameter and current status checking – is quite straightforward:

NUSE_CS_Enter();
NUSE_Init_Timer(timer);
if (enable == NUSE_ENABLE_TIMER)
{
   NUSE_Timer_Status[timer] = TRUE;
}
/* else enable == NUSE_DISABLE_TIMER and status remains FALSE */
NUSE_CS_Exit();


NUSE_Init_Timer() is called which initializes the time value and clears the expiration counter. A check is then made on required state and the timer enabled, if required.

Continue reading on page two, Timer Information >>

 

 

< Previous
Page 1 of 2
Next >

Loading comments...