Skip to content

Lab: Multi-Task Firmware with FreeRTOS

Course 1 · Module 4 Type: Hands-on lab (create tasks, then add queue / mutex) Suggested time: 2.5–3.5 hours

Read first: Lesson · Cheatsheet · ← Table of Contents · ← M03 · M05 →

Note: the snippets in this lab use the API of the TESAIoT Bitstream firmware, which is not yet open source. See detail and equivalent examples in the public SDK in the note at the top of the lesson Multi-task Firmware with FreeRTOS

Document Use when
Lesson snippets xTaskCreate, queue, mutex, event group
M03 Driver APIs LED / button / UART / I²C
TESAIoT Developer Hub System / Real-Time examples
FreeRTOS xTaskCreate Checking the parameters

Once complete, you will:

  • Have created at least two tasks running at different periods
  • Use vTaskDelay(pdMS_TO_TICKS(...)) instead of busy-waiting
  • Send an event through at least one queue path
  • Use a mutex (or cm55_i2c_manager_i2c_lock) when sharing a resource
  • (Recommended) use an event group or a binary semaphore as a ready flag

  • Have passed Lab M03 (at least GPIO + UART)
  • An example project that can call cm55_initialize / cm55_start_scheduler
  • Know the point at which the project allows xTaskCreate (after init / in a callback)

Don’t call vTaskStartScheduler() yourself again if the project already uses cm55_start_scheduler()


  1. Create a task LAB_BLINK_SLOW that blinks an LED at a 500 ms period
  2. Create a task LAB_BLINK_FAST that blinks another LED (or switches colour) at a 200 ms period
  3. Use slightly different priorities (such as idle+1 and idle+2) and observe the behaviour
led_controller_toggle(LED_RED);
vTaskDelay(pdMS_TO_TICKS(500));

Pass when: you see two distinct rhythms on the board, with no long while busy-delay inside a single task


Lab B — Button → Queue → UART task (required)

Section titled “Lab B — Button → Queue → UART task (required)”
  1. Create a short-message queue (xQueueCreate)
  2. Create a task that pulls from the queue and calls printf / LOG_INFO
  3. In cm55_button_on_pressed (or wherever the button event fires), xQueueSend a message, such as btn\r\n

Pass when: pressing the button shows a message on serial, while the blink task from Lab A keeps running


Choose at least one:

  • Create with xSemaphoreCreateMutex
  • Have two tasks share printing, or share a status variable, under Take/Give
  • Read a sensor in one task
  • Wrap it with cm55_i2c_manager_i2c_lock / unlock (or the lock API your project has)

Pass when: you can explain why locking is needed, and demonstrate there is no random bus contention breaking things


  1. Create with xEventGroupCreate
  2. Have a setup task set the “READY” bit once init is done
  3. Have another task call xEventGroupWaitBits before starting its work

Or use a binary semaphore as a “now ready” signal instead.

Pass when: the waiting task does not start its work before the ready signal


Answer briefly (5–8 lines):

  1. What would you risk by putting printf inside an ISR?
  2. What would happen to the system if the heaviest task’s priority stayed at maximum all the time?
  3. How does a queue’s depth × sizeof(item) affect RAM?

Symptom Approach
xTaskCreate returns something other than pdPASS The heap is exhausted · the stack is too large · called before the system is ready
The task doesn’t run cm55_start_scheduler not called yet · a priority/name clash · the task’s loop ended and wasn’t recreated
A HardFault when pressing the button A blocking API is inside an ISR · check for FromISR
UART output is garbled / hangs Missing a mutex / recursive lock around printf
Random I²C NACKs Missing a bus lock when several tasks use it

  • Lab A passed
  • Lab B passed
  • Lab C passed
  • (Recommended) Lab D
  • Lab E fully answered
  • The API table in rtos-patterns.md filled in

Lesson · Cheatsheet · Table of Contents · M05 →

Cite this lesson

If you teach from this lesson or reuse it in slides or documents, credit it with the text below. If you changed it, add (adapted) after the title.

"Lab: Multi-Task Firmware with FreeRTOS" from TESA Open Knowledge by the Thai Embedded Systems Association (TESA), https://github.com/tesaiot/tesa-qualification-program, licensed under CC BY-NC 4.0

Thai attribution: "แล็บ: เฟิร์มแวร์หลาย task ด้วย FreeRTOS" จาก TESA Open Knowledge โดยสมาคมสมองกลฝังตัวไทย (Thai Embedded Systems Association: TESA) https://github.com/tesaiot/tesa-qualification-program สัญญาอนุญาต CC BY-NC 4.0

Lesson link: https://tesaiot.github.io/tesa-qualification-program/en/courses/firmware-sdk-edge-ai/m04-rtos/l02-lab/

This lesson adapts the source below; keep its credit too.
https://github.com/drsanti/TESAIoT-Courses/blob/287c21814ba8c75f693136616dcd270349a15966/C1/M04/lab.md · Original content by Asst. Prof. Dr. Santi Nuratch (ผศ.ดร.สันติ นุราช), KMUTT. Course 1 (C1/) of drsanti/TESAIoT-Courses. TESA funded the work and holds the rights; published here under CC BY-NC 4.0. The upstream repository carries no licence file. Text kept faithful; structure, front matter, quizzes and notes added by TESA Open Knowledge.

Full guide: how to cite TESA

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

Content is licensed CC BY-NC 4.0. Reuse it non-commercially and credit the Thai Embedded Systems Association (TESA) every time. · How to cite TESA