RTA Knowledge Base

General

Counters register how many “things” have happened in the OS in terms of ticks. A tick is an abstract unit. It is up to you to decide what you want a tick to mean and, therefore,
what are the “things” the counter is counting. Possible definitions of a tick can be:

  • Time
  • Rotation
  • Error's
  • Other Events


You might define a tick to be:

  • Time, for example a millisecond, microsecond, minute etc and the counter then
    tells you how much time has elapsed.
  • Rotation, for example in degrees or minutes, in which case the counter would tell
    you by how much something has rotated.
  • Button Presses, in which case the counter would tell you how many times the button
    has been pressed.
  • Errors, in which case the counter is counting how often an error has occurred.


Counters in RTA-OS

When configuring counters in RTA-OS there are mandatory parameters that require configuration:

ParameterDescription
NameHandle Name for the counter.
TypeHardware or Software. (This is developed on in the next sections)
Max ValueMaximum count value. All counters wrap to zero after this.
Min CycleShortest number of ticks when setting a cycle value of an alarm or schedule table offset.
Ticks per baseNumber of underlying ticks that drive a single counter tick. Not used by RTA-OS (optional).
Seconds per tickDuration of a counter tick. Required if tick/time conversion features required.

Counter Drivers

RTA-OS aims to be easy to integrate with lots of platforms therefore it does not enforce a method of controlling all counters. It instead provides a simple interface

for the integrator to drive the counter from. This is dependent on the driver type chosen for the counter. 

Software Counters

These are counters purely handled and driven within software and are incremented via an API. AUTOSAR specifies an IncrementCounter(Counter) API but RTA-OS also offers

a configuration specific IncrementCounter_Counter() API that is custom to the specific counter. This makes the call faster and more suitable for use in interrupt handlers.

Note that error checks are not performed.

Example

One of the most common examples of a software counter are to either provide some notion of time to either the schedule table, or modules that require relative time through use of 

other APIs such as GetElapsedCounterValue(). In these cases the counter is linked to time, this is done by incrementing the counter at a fixed interval from a CAT2 ISR. In the ETAS

Starter Kit this can be seen with the Wdg_Counter that is incremented every 1ms by a periodic 1ms GPT interrupt:

ISR(Millisecond)
{
#ifdef FAST_API
	Os_IncrementCounter_Wdg_Counter();
#else
	IncrementCounter(Wdg_Counter);
#endif
}


Hardware Counters

When using a hardware counter the count value is held in an external hardware peripheral. Your application must then provide a more complex driver which tells RTA-OS when a requested
number of ticks have elapsed. RTA-OS uses special call-backs to set a requested number of ticks, cancel a request, get the current count value and get the status of the counter.

Providing a hardware counter driver is tricky as there is lots to consider and requires very project and target specific knowledge to get the desired behaviour for a specific use case.



RTA-OS requires the four following callbacks to be implemented for a hardware counter:

Os_Cbk_Now_Counter()

The callback must return the current value of the hardware counter. It can be called on any core in a multi-core system.

Example

FUNC(TickType, OS_CALLOUT_CODE) Os_Cbk_Now_Rte_TickCounter(void)
{
    return HwCounter->current(); /* current tick of counter */
}


Os_Cbk_Set_Counter()

This callback must configure the hardware to generate an appropriate interrupt when its value meets a match value (comparator). A Match value is passed to the callback and is an absolute value

at which the next counter action needs to be processed. The interrupt that is generated as a result should call the AdvanceCounter API (or fast configuration specific version Os_AdvanceCounter_Counter()).

Care must be taken to handle with the following situations:

  • Where intervals are short, it is possible for the hardware count to have already moved past the Match value at the point this get called. If so, it is important to ensure that the interrupt pending bit gets set in software.
  • Where an Alarm or ScheduleTable can be started with an interval shorter than one already set, the code must be able to reduce the match value and detect if this means that the hardware count has already passed this point.
  • The callback does not normally initialize the underlying hardware. That is usually done in initialization code before the OS is started.

Example

FUNC(void, OS_CALLOUT_CODE) Os_Cbk_Set_Rte_TickCounter(TickType Match)
{
    /* Disable Comparator */
    HwCounter->disable(); 
    /* Is Match before current? */
    if((((sint32)(HwCounter->current() - Match + BUFFER_TICKS)) >= 0) &&
           (FALSE == HwCounter->is_pending()))
    {
        HwCounter->set_pending(); /* raise */
    }
    else
    {
        /* second check - and no interrupt is pending */
        if(((sint32)(HwCounter->current() - Match + BUFFER_TICKS)) >= 0)
        {
            HwCounter->set_pending(); /* raise */
        }
        else
        {
            /* Set new match of comparator */
            HwCounter->set_match(Match);
        }
    }
    /* Enable Matching */
    HwCounter->enable();
}


Resulting Interrupt example:

ISR(Millisecond)
{
#ifdef FAST_API
    Os_AdvanceCounter_Rte_TickCounter();
#else
    AdvanceCounter(Rte_TickCounter);
#endif
}


Os_Cbk_Cancel_Counter()

This callback is called by the OS from within Os_AdvanceCounter when there are no Alarms or ScheduleTables running. It should be used to stop the hardware counter from asserting matches.

This is normally done by disabling the interrupt source. You may also need to clear any related interrupt pending bits. The hardware counter itself should continue counting.

Example

FUNC(void, OS_CALLOUT_CODE) Os_Cbk_Cancel_Rte_TickCounter(void)
{
    HwCounter->disable();       /* disable further raising of interrupts */
    HwCounter->clear_pending(); /* clear pending interrupt */
}


Os_Cbk_State_Counter()

This is called by the OS when it needs to decide whether to start a counter. It can also be called by user-code (typically the counter interrupt) to determine the state of the
counter. It must update the State structure to indicate if the counter is running, whether a match interrupt is pending, and (if needed) how long the interval is to the next match.

Example

FUNC(void, OS_CALLOUT_CODE) Os_Cbk_State_Rte_TickCounter(Os_CounterStatusRefType State)
{
    State->Running =  HwCounter->running();                       /* free running timer started? */
    State->Pending =  HwCounter->is_pending();                    /* interrupt pending? */
    State->Delay   = (HwCounter->match() - HwCounter->current()); /* time until next interrupt */
}


Hardware vs Software

When you use a software counter, the driver tells RTA-OS each time a tick has elapsed. RTA-OS counts ticks internally and, when the match value is reached, the action is
taken. RTA-OS then calculates the next match value and the process repeats. This means there may be a lot of ticks that are interrupting the OS which require no action.

By contrast, when you use an hardware counter, RTA-OS tells the driver, through a callback function, when the next action is needed. Your peripheral counts the requested
number of ticks and generates an interrupt when the correct number have elapsed. The interrupt handler then makes the Os_AdvanceCounter_CounterID() API call to tell
RTA-OS to process the next action due on CounterID. RTA-OS does this and the process repeats.

When using an interrupt in both models, an interrupt occurs each tick for a software counter, whereas only once an action is required when using a hardware counter.

In conclusion, the interrupt interference can be significantly reduced when using a hardware counter.