Aller au contenu

Les Software Timer

Un software timer permet d’appeler périodiquement une fonction grâce à un mécanisme de callback. Notez que les fonctions appelées par le software timer s’exécutent dans un contexte de thread et pas dans un contexte d’interruption. C’est un système simple et efficace pour faire des actions répétitives, mais comme c’est le scheduler de FreeRTOS qui appelle les fonctions, la période de la répétition est limitée par ce scheduler.

Souvent, la résolution de du timer interne de FreeRTOS est de 1ms (1 kHz) et les software timers ne peuvent donc pas être utilisés pour des périodes plus petites. Si on a besoin de période de l’ordre de la milliseconde ou moins, on utilise alors les hardware timers offerts par le HAL (STM32Cube dans notre cas).

Un software timer est créé avec la fonction xTimerCreate() :

TimerHandle_t xTimerCreate(const char* const pcTimerName,
                           const TickType_t xTimerPeriod,
                           const UBaseType_t uxAutoReload,
                           void* const pvTimerID,
                           TimerCallbackFunction_t pxCallbackFunction);

Exemple :

#define NUM_TIMERS 5

// An array to hold handles to the created timers.
TimerHandle_t xTimers[NUM_TIMERS];

// Define a callback function that will be used by multiple timer
// instances.  The callback function does nothing but count the number
// of times the associated timer expires, and stop the timer once the
// timer has expired 10 times.  The count is saved as the ID of the
// timer.
void vTimerCallback(TimerHandle_t xTimer) {
    const uint32_t ulMaxExpiryCountBeforeStopping = 10;
    uint32_t ulCount;

    // Optionally do something if the pxTimer parameter is NULL.
    configASSERT(xTimer);

    // The number of times this timer has expired is saved as the
    // timer's ID.  Obtain the count.
    ulCount = (uint32_t)pvTimerGetTimerID(xTimer);

    // Increment the count, then test to see if the timer has expired
    // ulMaxExpiryCountBeforeStopping yet.
    ulCount++;

    // If the timer has expired 10 times then stop it from running.
    if (ulCount >= ulMaxExpiryCountBeforeStopping) {
        // Do not use a block time if calling a timer API function
        // from a timer callback function, as doing so could cause a
        // deadlock!
        xTimerStop(xTimer, 0);
    } else {
        // Store the incremented count back into the timer's ID field
        // so it can be read back again the next time this software timer
        // expires.
        vTimerSetTimerID(xTimer, (void*)ulCount);
    }
}

void main(void) {
    long x;

    // Create then start some timers.  Starting the timers before
    // the RTOS scheduler has been started means the timers will start
    // running immediately that the RTOS scheduler starts.
    for (x = 0; x < NUM_TIMERS; x++) {
        xTimers[x] = xTimerCreate(
            "Timer",          // Just a text name, not used by the RTOS kernel.
            (100 * x) + 100,  // The timer period in ticks, must be
                              // greater than 0.
            pdTRUE,           // The timers will auto-reload themselves
                              // when they expire.
            (void*)0,         // The ID is used to store a count of the
                              // number of times the timer has expired,
                              // which is initialised to 0.
            vTimerCallback);  // Each timer calls the same callback when
                              // it expires.

        if (xTimers[x] == NULL) {
            // The timer was not created.
        } else {
            // Start the timer.  No block time is specified, and
            // even if one was it would be ignored because the RTOS
            // scheduler has not yet been started.
            if (xTimerStart(xTimers[x], 0) != pdPASS) {
                // The timer could not be set into the Active
                // state.
            }
        }
    }

    // ...
    // Create tasks here.
    // ...

    // Starting the RTOS scheduler will start the timers running
    // as they have already been set into the active state.
    vTaskStartScheduler();

    // Should not reach here.
    for (;;)
        ;
}