PSoC5LP RTOS
Lab 11 — FreeRTOS Software Timers

FreeRTOS on PSoC 5LP · Lab Series. Platform: CY8CKIT-059 (PSoC 5LP, Cortex-M3) · PSoC Creator 4.4 · FreeRTOS Kernel V11. I/O: LED (heartbeat) + Relay (auto-off) + Buzzer (warning) + Button. Pairs with Chapter 12 — Timers & Event Groups.


1. Introduction & Objectives

Some jobs happen after a delay or on a period but do not deserve a whole task — an LED heartbeat, a relay that switches off by itself, a "no activity" warning. A software timer runs a short callback after a delay (one-shot) or every period (auto-reload), all handled by one shared service task. This lab builds three timers and learns the one rule that makes them safe: never block in a callback.

After this lab you can:

  • Create one-shot and auto-reload timers with xTimerCreate.
  • Start, reset, stop, and re-period timers (xTimerStart, xTimerReset, xTimerStop, xTimerChangePeriod).
  • Build a heartbeat (auto-reload), a relay auto-off, and an inactivity warning (one-shot + reset).
  • Explain why a callback runs in the timer service task and must never block.

2. Prerequisites

Hardware: CY8CKIT-059 PSoC 5LP Prototyping Kit; RobotSoC Kit 1× LED + 220 Ω, 5 V relay, passive/active buzzer, 1× push button.

Software: PSoC Creator 4.4 with the FreeRTOS V11 BaseProject.

Chapters (sync progress): Required — Chapter 12 (Timers & Event Groups: the software-timer half); Peripheral prerequisite — basic GPIO is covered in Lab 02; the buzzer in Lab 06 (Buzzers); relay assumed known.

3. Reading Materials / References

  • Chapter 12 slides — Timers & Event Groups (one-shot vs auto-reload, the callback must not block).
  • FreeRTOS API: xTimerCreate, xTimerStart, xTimerReset, xTimerStop, xTimerChangePeriod.

4. Background & Theory of Operation

A software timer runs a callback, not a task. xTimerCreate(name, period, autoReload, id, callback) makes one. When it expires, the kernel calls your callback function. You do not spend a task's stack on it — many timers share one service task.

One-shot vs auto-reload.

  • Auto-reload (autoReload = pdTRUE): the timer restarts itself after each expiry, so the callback fires every period — ideal for a heartbeat or a periodic poll.
  • One-shot (autoReload = pdFALSE): the timer fires once and stops — ideal for a timeout, like switching a relay off after a delay.

Start, reset, stop. xTimerStart begins the countdown; xTimerStop cancels it; xTimerChangePeriod changes the period at run time. The key one is xTimerReset: it restarts the countdown from now. For a one-shot, resetting on each activity means the timer fires only after a full period of inactivity — exactly how an inactivity warning or a "keep-alive" relay works.

The service task. Every timer's callback runs in the timer service (daemon) task, created automatically when the scheduler starts, at priority configMAX_PRIORITIES - 1 (high, so timers are punctual). Because the timers share this one task, a callback that blocks — vTaskDelay, taking a semaphore, a long CyDelay — stalls every timer. So a callback must do only quick work: toggle a pin, set a flag, give a semaphore, start another timer. Hand any real work to a normal task.

From an ISR. Timers can be started/reset from an ISR with the …FromISR forms, which signal the service task. In this lab the button is polled in a task, so the plain xTimerReset is fine.

5. RTOS Task Architecture

SOFTWARE TIMERS — CALLBACKS WITHOUT A DEDICATED TASK Timer Service (daemon) Task runs every timer's callback · priority = MAX-1 Heartbeat (auto-reload) period 500 ms, repeats callback: LED toggle Relay auto-off (one-shot) Start on event; Reset extends callback: Relay off Inactivity warn (one-shot) Reset on each button press callback: Buzzer beep xTimerCreate(name, period, reload, id, cb) · xTimerStart / xTimerReset / xTimerStop / xTimerChangePeriod Auto-reload restarts itself and fires every period; one-shot fires once, and xTimerReset restarts its countdown. Never block in a callback: it runs in the shared timer service task, so a delay there stalls EVERY timer. ​

One timer service task runs all three callbacks. The Heartbeat (auto-reload) toggles the LED every period. The Relay auto-off (one-shot) turns the relay off after a delay, extended by xTimerReset on activity. The Inactivity warn (one-shot) is reset on each button press; if no press arrives within the period, its callback beeps. None of them is a dedicated task — and none of them may block.

6. Auto-reload vs. One-shot — Over Time

Auto-reload: the callback fires every period (heartbeat):

Auto-reload timer - periodic callback (LED heartbeat) the timer restarts itself, so the callback fires every period - no dedicated task 0 100 200 300 400 500 600 700 800 900 time (ms) TIMER LED fire fire fire fire Conceptual / idealized. xTimerCreate(..., auto-reload=pdTRUE). The callback runs in the timer service task - never block in it. ​

The timer restarts itself, so the LED toggles on a steady period with no task.

One-shot + reset: fires once, a full period after the last activity:

One-shot timer + xTimerReset - fires P after the LAST activity each reset (button / activity) restarts the countdown; the callback fires only after P of inactivity 0 100 200 300 400 500 600 700 800 900 time (ms) TIMER RELAY start reset reset FIRE RELAY ON (kept alive by resets) OFF (callback) Conceptual / idealized. One-shot (auto-reload=pdFALSE). xTimerReset restarts the countdown; it fires P ms after the last reset. ​

Each reset restarts the countdown; the relay stays on while activity continues and switches off after the period of inactivity.

The difference is the autoReload flag. Auto-reload is for "every N ms"; one-shot (often with xTimerReset) is for "N ms after the last thing happened".

7. Schematic Circuit & Pin Configuration

  • LED → GPIO + 220 Ω → GND (heartbeat).
  • Relay control → a GPIO (through its driver).
  • Buzzer → GPIO (via a transistor for a passive buzzer).
  • BTN → push button to GND, internal pull-up (active-low).
  • Assign the pins in <project>.cydwr → Pins.

8. PSoC Creator Configuration

  • Digital Output Pins for LED, relay, buzzer; a Digital Input Pin for the button.
  • FreeRTOSConfig.h (already set): configUSE_TIMERS = 1, configTIMER_TASK_PRIORITY = configMAX_PRIORITIES - 1, configTIMER_QUEUE_LENGTH adequate, heap_4.

9. Provided Template

You are given Lab11_Template_main.c:

  • Given: all includes (note #include "FreeRTOS_PSoC.h"), the three timer handles, and a complete main() that creates the heartbeat (auto-reload), relay-off (one-shot), and warn (one-shot) timers, starts the heartbeat, and creates a button task. Callback placeholders keep the project building and running.
  • You write: the three callbacks (each short, non-blocking) and the button handling that xTimerResets the one-shots.
  • Do not change the boot sequence in main().
static void HeartbeatCb(TimerHandle_t t) { (void)t; LED_Write(!LED_Read()); }  /* quick! */

static void vButtonTask(void *arg) {
    for (;;) {
        if (Button_Read() == 0u) {
            Relay_Write(1);
            xTimerReset(hRelayOff, 0);   /* keep the relay alive */
            xTimerReset(hWarn, 0);       /* activity -> restart warn */
            vTaskDelay(pdMS_TO_TICKS(200));
        }
        vTaskDelay(pdMS_TO_TICKS(10));
    }
}

10. Lab Experiments

Exp01 — Basic: auto-reload heartbeat. Write HeartbeatCb to toggle the LED; the auto-reload timer runs it every HEARTBEAT_MS. Expected: a steady heartbeat LED with no dedicated task — proof a timer can replace a simple periodic task.

Exp02 — Advanced: one-shot relay auto-off (with reset). A button press turns the relay on and xTimerResets the one-shot relay-off timer. The relay switches off RELAY_OFF_MS after the last press; each press extends it. Expected: the relay stays on while you keep pressing and switches off a full period after you stop — the reset behaviour on a scope/LED.

Exp03 — Challenge: inactivity warning, and why callbacks must not block. Reset the warn one-shot on each press; if no press arrives within WARN_MS, the callback beeps. Then deliberately put a vTaskDelay in one callback and observe that all timers (heartbeat included) stall — proving a callback must not block. Remove it. Expected: a working inactivity warning, and a demonstration that blocking in a callback freezes every timer.

11. Testing & Verification

#Pass condition
Exp01 LED heartbeats on a steady period via an auto-reload timer, no task.
Exp02 Relay switches off a full period after the last press; each press extends it.
Exp03 Inactivity warning beeps after the period; a blocking callback visibly stalls all timers.

Submit: your three callbacks and button handling, a capture of the auto-off/reset behaviour, and your note on the blocking-callback demonstration.

12. Q&A & Troubleshooting

  • Heartbeat irregular / everything hitches → a callback blocks (vTaskDelay / long CyDelay); keep callbacks tiny.
  • Relay never switches off → the one-shot was created auto-reload, or you keep resetting it; check the flag and the reset source.
  • Timer "didn't start" → xTimerStart/xTimerReset can fail if the timer command queue is full; check the return value and configTIMER_QUEUE_LENGTH.
  • Callback never runs → configUSE_TIMERS = 0, or the service task priority is too low to run; it should be MAX-1.
  • Reset has no effect → you reset the wrong handle, or the period is shorter than your press interval.

13. Analysis Questions & Lab Report

  1. What is the difference between a one-shot and an auto-reload timer? Give a use for each.
  2. Where does a timer callback run, and why must it never block?
  3. How does xTimerReset turn a one-shot timer into an inactivity timeout?
  4. When would you use a software timer instead of a periodic task, and when not?

Your report should include your callbacks, your captures, and answers to the four questions.

© 2026 Air Supply Information Center (Air Supply BBS)