Clocks

Clock instances are functions that can be scheduled to run after a certain number of system ticks. Clock instances are either one-shot or periodic. These instances start immediately upon creation, are configured to start after a delay, and can be stopped at any time. All clock instances are executed when they expire in the context of a Swi. The following example shows the minimum resolution is the TI-RTOS clock tick period set in the TI-RTOS configuration file (.cfg).

Note

The default TI-RTOS kernel tick period is 1 millisecond. For CC2640R2F devices, this is reconfigured in the TI-RTOS configuration file (.cfg):

Clock.tickPeriod = 10;

Each system tick, which is derived from the real-time clock RTC, launches a Clock object that compares the running tick count with the period of each clock to determine if the associated function should run. For higher-resolution timers, TI recommends using a 16-bit hardware timer channel or the sensor controller. See the Clock module in the package ti.sysbios.knl section of the TI-RTOS Kernel User Guide for more information on these functions.

You can use the Kernel’s Clock APIs directly in your application and in addition the Util module also contains a set of abstracted TI-RTOS Clock functions as shown here:

Functional Example

The following example was taken from the simple_peripheral project in BLE-Stack.

@startuml
hide footbox

participant simple_perpherial.c as A
box "Swi context"
    participant "Clock Object" as B
end box

activate A
group Initialize Clock object
    autonumber
    A -> B : Util_clockConstruct()
    autonumber stop
    A <-- B
end

...

group Start Clock object
    A -> B : Util_clockStart()

    B --> A
    note left: Event_pend(event,...)

    deactivate A
end

...

group Clock function triggers after expiration
    autonumber resume
    rnote over B
        The Clock object invokes supplied function pointer
        (e.g. SimplePeripheral_performPeriodicTask())
        This function only posts a signal such as an Event
    end note
    B -> B : SimplePeripheral_clockHandler();
    activate B
    autonumber stop
    B -> : Event_post(event, SP_PERIODIC_EVT);
    B <--
    deactivate B
end

group Process period function and restart Clock object
    -> A : Unblocked due to posted SP_PERIODIC_EVT.
    activate A
    rnote over A
        Given that an event was posted, we can process the
        periodic function from a Task context
        (e.g. SimplePeripheral_performPeriodicTask())
    end note
    autonumber resume
    A -> A : SimplePeripheral_performPeriodicTask()
    activate A

    rnote over A
        Restart the clock after the periodic process
    end note
    deactivate A
    autonumber stop
    A -> B : Util_startClock();
    B --> A

    deactivate A
    note left: Event_pend(event,...)
end

rnote over A, B
    The Clock object will trigger after
    expiration and the cycle will repeat itself.
end note

...

@enduml

Figure 34. Triggering Clock objects

Step 1 in Triggering Clock objects constructs the Clock object via Util_constructClock(). After the example entered a connected state, it will then start the Clock object via a Util_startClock().

Listing 14. Constructing periodicClock Clock object in simple_peripheral
// Clock instances for internal periodic events.
static Clock_Struct periodicClock;

// Create one-shot clocks for internal periodic events.
Util_constructClock(&periodicClock, SimplePeripheral_clockHandler,
    SP_PERIODIC_EVT_PERIOD, 0, false, SP_PERIODIC_EVT);

Step 2 in Triggering Clock objects, after the Clock object’s timer expired, it will execute SimplePeripheral_clockHandler() within a Swi context. As this call cannot be blocked and blocks all Tasks, it is kept short by invoking an Event_post(SP_PERIODIC_EVT) for post processing in simple_peripheral.

Listing 15. Defining SimplePeripheral_clockHandler()
static void SimplePeripheral_clockHandler(UArg arg)
{
    /* arg is passed in from Clock_construct() */
    Event_post(events, arg);
}

Attention

Clock functions must not call blocking kernel APIs or TI-RTOS driver APIs! Executing long routines will impact real-time constraints placed in high priority tasks allocated for wireless protocol stacks!

Step 3 in Triggering Clock objects, the simple_peripheral task is unblocked due the Event_post(SP_PERIODIC_EVT), where it proceeds to invoke the SimplePeripheral_performPeriodicTask() function. Afterwards, to restart the periodic execution of this function, it will restart the periodicClock Clock object.

Listing 16. Servicing the SP_PERIODIC_EVT event
if (events & SP_PERIODIC_EVT)
{
  // Perform periodic application task
  SimplePeripheral_performPeriodicTask();

  Util_startClock(&periodicClock);
}