# 5.3 Deep Dive: FreeRTOS Software Timers

### <span class="ng-star-inserted">Creating, Starting, and Stopping Timers</span>

<span class="ng-star-inserted">Interacting with FreeRTOS software timers is done through a standard set of API functions. The core steps are to create a timer, start it, and, if needed, stop, reset, or delete it.</span>

#### <span class="ng-star-inserted">Creating a Timer</span>

<span class="ng-star-inserted">A software timer is created using the </span>`<span class="inline-code ng-star-inserted">xTimerCreate()</span>`<span class="ng-star-inserted"> function. This function does not start the timer; it only allocates the necessary resources and returns a handle that you will use to reference the timer in other API calls.</span>

<span class="ng-star-inserted">The function signature is:</span>

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

**<span class="ng-star-inserted">Parameters:</span>**

1. `<span class="inline-code ng-star-inserted">pcTimerName</span>`<span class="ng-star-inserted">: A descriptive name for the timer, used mainly for debugging.</span>
2. `<span class="inline-code ng-star-inserted">xTimerPeriodInTicks</span>`<span class="ng-star-inserted">: The timer's period in system ticks. You can use the </span>`<span class="inline-code ng-star-inserted">pdMS_TO_TICKS()</span>`<span class="ng-star-inserted"> macro to easily convert milliseconds to ticks.</span>
3. `<span class="inline-code ng-star-inserted">uxAutoReload</span>`<span class="ng-star-inserted">: Set to </span>`<span class="inline-code ng-star-inserted">pdTRUE</span>`<span class="ng-star-inserted"> for an auto-reload timer or </span>`<span class="inline-code ng-star-inserted">pdFALSE</span>`<span class="ng-star-inserted"> for a one-shot timer.</span>
4. `<span class="inline-code ng-star-inserted">pvTimerID</span>`<span class="ng-star-inserted">: A unique identifier for the timer. This is an application-defined value that can be used within the callback function to determine which timer has expired.</span>
5. `<span class="inline-code ng-star-inserted">pxCallbackFunction</span>`<span class="ng-star-inserted">: A pointer to the function that will be executed when the timer expires.</span>

<span class="ng-star-inserted">It is crucial to </span>**<span class="ng-star-inserted">always check the return value</span>**<span class="ng-star-inserted"> of </span>`<span class="inline-code ng-star-inserted">xTimerCreate()</span>`<span class="ng-star-inserted">. If it returns </span>`<span class="inline-code ng-star-inserted">NULL</span>`<span class="ng-star-inserted">, the timer could not be created, most likely due to insufficient FreeRTOS heap memory.</span>

#### <span class="ng-star-inserted">Controlling a Timer</span>

<span class="ng-star-inserted">Once you have a valid timer handle, you can control it with the following functions:</span>

- **<span class="ng-star-inserted">To start or restart a timer:</span>**  
    `<span class="inline-code ng-star-inserted">xTimerStart(TimerHandle_t xTimer, TickType_t xBlockTime)</span>`  
    <span class="ng-star-inserted">This places the timer into the active state. If the timer was already running, it will be reset to its initial period.</span>
- **<span class="ng-star-inserted">To stop a timer:</span>**  
    `<span class="inline-code ng-star-inserted">xTimerStop(TimerHandle_t xTimer, TickType_t xBlockTime)</span>`  
    <span class="ng-star-inserted">This stops the timer from running.</span>
- **<span class="ng-star-inserted">To reset a timer:</span>**  
    `<span class="inline-code ng-star-inserted">xTimerReset(TimerHandle_t xTimer, TickType_t xBlockTime)</span>`  
    <span class="ng-star-inserted">This is equivalent to calling </span><span class="inline-code ng-star-inserted">xTimerStart()</span><span class="ng-star-inserted"> on a running timer. It resets the timer's period back to its starting value.</span>
- **<span class="ng-star-inserted">To delete a timer:</span>**  
    `<span class="inline-code ng-star-inserted">xTimerDelete(TimerHandle_t xTimer, TickType_t xBlockTime)</span>`  
    <span class="ng-star-inserted">This frees the memory allocated when the timer was created. Once deleted, the handle is no longer valid.</span>

<span class="ng-star-inserted">The </span><span class="inline-code ng-star-inserted">xBlockTime</span><span class="ng-star-inserted"> parameter in these functions specifies how long the calling task should wait if the command cannot be sent to the timer daemon task immediately (because its command queue is full). Using </span>`<span class="inline-code ng-star-inserted">portMAX_DELAY</span>`<span class="ng-star-inserted"> will cause the task to wait indefinitely, which is a safe option in most cases.</span>

### <span class="ng-star-inserted">3.2 One-Shot vs. Auto-Reload Timers</span>

<span class="ng-star-inserted">FreeRTOS offers two types of software timers, defined at creation time by the </span><span class="inline-code ng-star-inserted">uxAutoReload</span><span class="ng-star-inserted"> parameter.</span>

#### <span class="ng-star-inserted">One-Shot Timer (</span><span class="inline-code ng-star-inserted">`uxAutoReload` = `pdFALSE`</span><span class="ng-star-inserted">)</span>

<span class="ng-star-inserted">A one-shot timer will execute its callback function </span>**<span class="ng-star-inserted">only once</span>**<span class="ng-star-inserted"> after its period expires. It is useful for performing a single, delayed action.</span>

- **<span class="ng-star-inserted">Example Use Case:</span>**<span class="ng-star-inserted"> You want to turn off a motor 10 seconds after it has been started.</span>

**<span class="ng-star-inserted">Example Creation:</span>**

```c
TimerHandle_t xOneShotTimer;

void vOneShotCallback(TimerHandle_t xTimer); // Forward declaration

void setup() {
  xOneShotTimer = xTimerCreate(
      "OneShot",                // Timer name
      pdMS_TO_TICKS(2000),      // 2000ms period
      pdFALSE,                  // Set as a one-shot timer
      (void *) 0,               // Timer ID = 0
      vOneShotCallback          // Callback function
  );

  if (xOneShotTimer != NULL) {
    xTimerStart(xOneShotTimer, 0);
  }
}
```

#### <span class="ng-star-inserted">Auto-Reload Timer (</span><span class="inline-code ng-star-inserted">`uxAutoReload `= `pdTRUE`</span><span class="ng-star-inserted">)</span>

<span class="ng-star-inserted">An auto-reload timer will execute its callback function </span>**<span class="ng-star-inserted">repeatedly</span>**<span class="ng-star-inserted"> at a fixed interval. After the callback is executed, the timer automatically resets and starts counting down again.</span>

- **<span class="ng-star-inserted">Example Use Case:</span>**<span class="ng-star-inserted"> You need to read a sensor and print its value every 1000 milliseconds.</span>

**<span class="ng-star-inserted">Example Creation:</span>**

```c
TimerHandle_t xAutoReloadTimer;

void vAutoReloadCallback(TimerHandle_t xTimer); // Forward declaration

void setup() {
  xAutoReloadTimer = xTimerCreate(
      "AutoReload",             // Timer name
      pdMS_TO_TICKS(1000),      // 1000ms period
      pdTRUE,                   // Set as an auto-reload timer
      (void *) 1,               // Timer ID = 1
      vAutoReloadCallback       // Callback function
  );

  if (xAutoReloadTimer != NULL) {
    xTimerStart(xAutoReloadTimer, 0);
  }
}
```

### <span class="ng-star-inserted">3.3 Writing Effective Timer Callback Functions</span>

<span class="ng-star-inserted">The callback function is the heart of the software timer. It's the code that runs when the timer expires. To ensure system stability, it must be written carefully.</span>

<span class="ng-star-inserted">The function must have the following signature:</span>

```c
void YourCallbackName(TimerHandle_t xTimer);
```

<span class="ng-star-inserted">The single parameter, </span>`<span class="inline-code ng-star-inserted">xTimer</span>`<span class="ng-star-inserted">, is the handle of the timer that just expired. This is very useful when a single callback function is used for multiple timers. You can retrieve the Timer ID you assigned during creation to identify which timer it was.</span>

**<span class="ng-star-inserted">Example Callback Implementation:</span>**

```c
void vTimerCallback(TimerHandle_t xTimer) {
  // Get the ID of the timer that expired
  uint32_t ulTimerID = (uint32_t) pvTimerGetTimerID(xTimer);

  // Check which timer it was and perform an action
  if (ulTimerID == 0) {
    // This was the one-shot timer
    Serial.println("One-shot timer expired.");
  } else if (ulTimerID == 1) {
    // This was the auto-reload timer
    Serial.println("Auto-reload timer expired.");
  }
}
```

#### <span class="ng-star-inserted">Rules for Writing Callback Functions</span>

<span class="ng-star-inserted">Timer callbacks execute in the context of the FreeRTOS timer daemon task, not an ISR. However, they share similar restrictions because multiple callbacks may need to execute in sequence.</span>

1. **<span class="ng-star-inserted">Keep them short and fast.</span>**<span class="ng-star-inserted"> A long-running callback will delay the execution of other pending timer callbacks.</span>
2. **<span class="ng-star-inserted">Never block.</span>**<span class="ng-star-inserted"> Do not call any function that could block, such as </span>`<span class="inline-code ng-star-inserted">vTaskDelay()</span>`<span class="ng-star-inserted"> or waiting on a semaphore or queue with a long timeout. Doing so will halt the timer daemon task, preventing any other software timers in the system from running.</span>