Available Languages?:

OSA : Timers

Intro

Timers in OSA are used to simplify writing time-dependent processes. By using timers you can allocate a quantum of time to a task, or create delays or timeouts in functions that are not tasks. Time in OSA is incremented by the service OS_Timer. When this service is called, all active timers are incremented by 1. If any timer overflows, then the corresponding timeout bit is set.

Types of timers

OSA allows the use of four types of timer:

Why so many? Which of them is better? See how to choose a timer's type.

Each type of timer has its advantages. The selection of the timer's type depends on the number of timers used and the purpose of the timers. The features of each type of timer are described below.

Task timers

Description

Each task descriptor may contain a counter for use by delays (OS_Delay) and by waits for events with timeout (OS_xxx_Wait_TO). This counter is called a task timer. It can be used to count time in the background (a task can perform some actions and check time).

Advantages
  1. After a task has called OS_Delay the scheduler does not check the task for readiness and does not compare the task's priority with others until the timer has expired. This feature increases the speed of scheduler.
  2. The services OS_xxx_Wait_TO work with task timers only.
Disadvantages
  1. One task - one timer. Each task can only control its own timer.
  2. Work with timers can be performed only inside the task or inside functions called by the task.
Usage

Defines in OSAcfg.h:

OS_ENABLE_TTIMERS You should define this constant to use task timers
OS_TTIMER_SIZE Timer width in bytes: 1, 2 or 4 (2 by default).
OS_TTIMERS_OPTIMIZE_SIZE Optimize OS_Timer for code size (the default is for speed)
OS_BANK_TASKS Define RAM-bank to allocate task descriptors: 0,1,2 or 3 (0 by default)

Static timers

Description

Static timers are implemented by an array of counters of size OS_STIMERS. The counter width is set by the constant OS_STIMER_SIZE in OSAcfg.h. To use a static timer through an OS service, the timer's ID must be passed as a parameter. The most significant bit of each counter means "counting" when set and "stopped" ("timeout") when cleared. Thus the counter is one bit less than the size of variable needed to store it (e.g. when OS_STIMER_SIZE = 2, the counter width is 15 bits). Static timers can be used to reduce RAM and ROM usage.

In OSA versions 91219 and below static timers were assigned at compile time and could not be re-assigned. Each timer was accessed through a fixed ID. This was awkward since there were problems with using existing modules in new projects (the programmer had to re-define all timer IDs in OSAcfg.h and match them with the OS_STIMERS constant). Starting with OSA version 100210 you can assign the ID at run-time (see below).

Advantages
  1. compact
  2. fast
Disadvantages
  1. you have to know the maximum number of timers that can be used simultaneously (to set the OS_STIMERS constant)
  2. OS_STIMERS can't exceed 64
Usage

Defines in OSAcfg.h:

OS_STIMERS This constant defines the number of elements in the array of static timers
OS_STIMER_SIZE Timer width in bytes: 1, 2 or 4 (2 by default)
OS_STIMERS_OPTIMIZE_SIZE Optimize OS_Timer for code size (the default is for speed)
OS_STIMERS_ENABLE_ALLOCATION Allow assignment of static timer IDs at run-time. Enables services OS_Stimer_Alloc, OS_Stimer_Free, OS_Stimer_Found
OS_BANK_STIMERS Define RAM-bank to allocate static timers: 0,1,2 or 3 (0 by default)

There are two ways of using static timers:

  1. Assign timer IDs at run time. In this case two small functions will be added to the program. In addition, one byte of RAM will be allocated for each eight static timers to indicate their state (busy/free);
  2. Assign timer IDs at compile time and use constants. In this case the timer's purpose has to be defined once and for all, and each timer must have a fixed ID.

The first way is preferable since it allows the re-use of modules in new projects with minimal configuration modifications.

Queue of timers

Description

This type of timer was introduced in OSA version 100210. All running timers are put into a queue sorted by remaining count time. This method allows processing a large number of timers very quickly. Each call to OS_Timer only decreases the first timer in the queue. This can be very useful, since OS_Timer is usually called from an interrupt routine.

1. For PIC16, these timers can be allocated in bank0 and bank1 only.
2. Queue of timers is not supported by 12-bit controllers.

Advantages
  1. you can use as many timers as you want
  2. fast processing of a large number of timers in OS_Timer
Disadvantages
  1. each timer needs an additional two bytes (or two words in C30) for flags and pointer to next timer in queue;
  2. needs a huge function to control queue (add/remove timers);
  3. adding a timer to the queue may take a long time, depending on the value of the timer to be added: a greater value → longer time to add
Usage

Defines in OSAcfg.h:

OS_ENABLE_QTIMERS You must define this constant to use a queue of timers
OS_QTIMER_SIZE Timer width in bytes: 1, 2 or 4 (2 by default)

Timers are declared in your program as normal variables:

OST_QTIMER qt_1, qt_2;

The timer must be created before using it (by the service OS_Qtimer_Create). After creation, the timer can be run, got, checked, etc. On every call to OS_Timer the first timer in the queue is decreased by 1. When it becomes zero it is marked as "timed-out" and deleted from the queue.

E.g. we want to run two timers with counter values 30 and 10:

    OS_Qtimer_Run(qt_1, 30);
    OS_Qtimer_Run(qt_2, 10);

The first timer qt_1 will be added to an empty queue. It is placed at the beginning of queue with counter value = 30. When qt_2 is added it will be placed at the beginning of the queue (since its counter value is less than qt_1) and qt_1 will now be in second position. The value of the counter of qt_1 will be changed to 20. On every call of OS_Timer qt_2's counter will be decreased by 1. When it becomes zero it will be deleted from the queue ("timeout" bit will be set), and timer qt_1 will become first in the queue with a counter value of 20 (10 ticks have elapsed, 20 remain, for a total = 30).

Now if we want to add a third timer with value 100:

    OS_Qtimer_Run(qt_3, 100);

it will be placed at the end of the queue with a counter value = 100-20 = 80.

Dynamic timers

Description

(This is an old type of timer. It is not recommended for use in new projects.)

Dynamic timers are organized as a one-directional unsorted list. On every call to OS_Timer() all timers in the list are decremented by 1. This is done through indirect accessing, so the run time of OS_Timer() can be rather long when there are a lot of timers in the list.

The important feature of dynamic timers is that they continue counting even after timeout occurs. This feature allows you to make several time markers with greater accuracy than with other types of timer (without losses due to running the scheduler).

For PIC16, these timers can be allocated in bank0 and bank1 only.

Advantages
  1. continue counting after overflow occurs
  2. you can use as many timers as RAM allows
Disadvantages
  1. OS_Timer takes a long time
  2. each timer needs an additional two bytes (or two words in C30) for flags and pointer to the next timer in the list
Usage

Defines in OSAcfg.h:

OS_ENABLE_DTIMERS You must define this constant to use dynamic timers
OS_DTIMER_SIZE Timer width in bytes: 1, 2 or 4 (2 by default)

Timers are declared in your program as normal variables:

OST_DTIMER dt_1, dt_2;

First, timers should be created by the OS_Dtimer_Create service. This will add a timer to the list (the timer will be cleared and stopped). After using the timer, it should be deleted from the list (by OS_Dtimer_Delete) to reduce OS_Timer's processing time.

Maximum delays

Here are the maximum possible time intervals that timers can count for the most commonly-used sizes of system ticks:

OS_Timer's period 1-byte 2-bytes 4-bytes
Range of allowed init values 0-255 0-65535 0-4294967295
1 ms 255 ms 64 sec 48 days
10 ms 2.4 sec 10 min 490 days
18.2 ms 9.2 sec 18 min 900 days
256 us 130 ms 16 sec 12 days
1024 us 520 ms 65 sec 50 days
8192 us 4 sec 8 min 400 days

As noted above, a static timer's width is one bit less then its type. Thus all time intervals in the table must be divided by 2 for static timers.

OS services for timers

How to choose a timer's type

Why are there so many types of timer?

The large number of timer types is a result of OSA evolution. Initially, timers were in task descriptors only. But there are cases when one task needs more than one timer, or when several tasks want to check one timer. Thus user timers were added. First they looked like four arrays (of chars, ints, longs and 24-bit ints). But they were too awkward. So only one array remained (size of elements user-specified by OS_STIMER_SIZE constant). But an array was still awkward, and after a while I added dynamic timers. They could be declared in any place in the program. But dynamic timers were too slow. And then I added a queue of timers.

"What timer should I use?"

In most cases task timers are enough. They have only one limitation: one task can use only one timer. But most problems can be solved with it.

But there are some problems that need more than one timer per task and the programmer has to use some other type of timer. There is no necessity to use several types of timers in one project (except paired with task timers). My opinion is that the best type of timer in most cases is the static timer. It is fast and compact. But if you use a large number of timers it may be reasonable to use a queue of timers.

Example formulas for PICC18

The choice of timer type should depend on their functions and number. Look at the formulas below. They are for PICC18 and timer size = 2 bytes (for other compilers result will be rather close)

TTIMERS STIMERS DTIMERS QTIMERS
(speed)* (size)* (speed)* (size)*
ROM, words t*6+30 57 t*4 (+60)* * 14 (+60)* * 74 482
RAM, bytes t*2 t*2 (+t/8)* * t*4+2
OS_Timer, cycles  t*4+To*1  t*15+Ta*6+To*2+4  t*3+Ta*1  t*8+Ta*3+3  t*9+Ta*13+5  17+To*22 

* - task timers and static timers can be optimized by speed or by size by setting OS_TTIMERS_OPTIMIZE_SIZE and OS_STIMERS_OPTIMIZE_SIZE constants in OSAcfg.h

* * - 60 bytes of ROM and 1 byte rep each 8 timers of RAM are added when static timer assignment is used (OS_STIMERS_ENABLE_ALLOCATION is defined)

Here:

  • t - total number of timers of chosen type used in program
  • Ta - number of currently active (counting) timers
  • To - number of currently overflowing timers

The timer type should be chosen depending on optimization criteria (ROM, RAM or speed) and available resources. The two tables below correspond to the number of timers equal to 5 and 50.

Number of timers = 5
TTIMERS STIMERS DTIMERS QTIMERS
(Speed) (size) (speed) (size)
ROM, words 60 57 80 74 74 482
RAM, bytes 10 11 22
OS_Timer,
cycles min/cycles max*
  20 (25)    109 (119)    20 (20)    58 (58)    50 (115)    17 (127)  

* - cycles min - OS_Timer execution time when there is no overflowing timers.
cycle max - rare situation when all timers overflow at the same time.

As you can see from this table, all parameters are almost identical when the number of timers is small (except ROM size for QTIMERS). Thus, if you use a small number of timers then you can use any type of timers you like.

Number of timers = 50
TTIMERS STIMERS DTIMERS QTIMERS
(Speed) (size) (speed) (size)
ROM, words 330 57 260 74 74 482
RAM, bytes 100 107 202
OS_Timer,
cycles min/cycles max*
  200 (250)    1054 (1154)    200 (200)    553 (553)    1105    17 (1122)  

* - cycles min - OS_Timer execution time when there is no overflowing timers.
cycle max - rare situation when all timers overflow at the same time.

Now we can see that the right choice will reduce RAM or ROM usage or will increase processing speed. For example we see that the most compact type is task timers with code size optimization. Or we see that the fastest is a queue of timers with one exception: when the first timer in the queue overflows, it should be removed from the queue. That takes some time, so if you need to use short delays, then a queue of timers will not be an effective choice.

 
en/osa/ref/services/timers.txt · Last modified: 07.10.2010 13:58 (external edit)
 
Creative Commons License Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki