5.5.10Embedded Systems & Real-Time Software

FreeRTOS — task creation, priorities, xTaskCreate

1,946 words9 min readdifficulty · medium

WHAT is a task?

A task is always in exactly one state:

State Meaning
Running Currently using the CPU (only one at a time on single core)
Ready Able to run, waiting for the CPU
Blocked Waiting for an event (delay, queue, semaphore) — uses no CPU
Suspended Removed from scheduling until resumed
Figure — FreeRTOS — task creation, priorities, xTaskCreate

HOW you create a task: xTaskCreate

StackBytes=usStackDepth×sizeof(StackType_t)\text{StackBytes} = \text{usStackDepth} \times \text{sizeof(StackType\_t)}


Priorities — the heart of scheduling


Worked Example 1 — two blinking LEDs

void vBlink(void *pvParameters) {
    int pin = (int)pvParameters;          // Why? pass which LED via param
    for (;;) {                            // Why? a task NEVER returns
        gpio_toggle(pin);
        vTaskDelay(pdMS_TO_TICKS(500));   // Why? Blocked → frees CPU for others
    }
}
 
void main(void) {
    xTaskCreate(vBlink, "L1", 128, (void*)13, 1, NULL);  // Why prio 1: above idle
    xTaskCreate(vBlink, "L2", 128, (void*)14, 1, NULL);  // Why same prio: fair share
    vTaskStartScheduler();   // Why? hands control to FreeRTOS; never returns
    for(;;);                 // Why? only reached if heap was too small
}

Why pdMS_TO_TICKS? FreeRTOS counts time in ticks, not ms. This macro converts using configTICK_RATE_HZ, keeping code readable and portable.

Worked Example 2 — priority preemption

void vHigh(void *p){ for(;;){ readSensor(); vTaskDelay(pdMS_TO_TICKS(10)); } }
void vLow (void *p){ for(;;){ heavyMath(); } }   // never blocks!
 
xTaskCreate(vLow,  "low",  256, NULL, 1, NULL);
xTaskCreate(vHigh, "high", 256, NULL, 3, NULL);   // Why prio 3 > 1: must preempt

Why does this work? Every 10 ms vHigh becomes Ready. Because 3 > 1 the scheduler preempts vLow instantly, runs the sensor read, then vHigh blocks again and vLow resumes its math. The sensor gets deterministic timing even though vLow hogs the CPU.

Worked Example 3 — checking the return value

TaskHandle_t h;
if (xTaskCreate(vBlink, "L", 4096, NULL, 1, &h) != pdPASS) {
    // Why check? huge stack (4096 words = 16 KB) may exhaust the heap
    error_blink();   // fail loudly instead of silently not running
}
vTaskDelete(h);      // Why store handle? to delete/suspend this task later


Recall Feynman: explain to a 12-year-old

Imagine one cook (the CPU) in a kitchen with many recipes (tasks). The cook can only do one thing at a time, but a smart manager (the scheduler) makes him switch so fast it looks like all dishes are cooking at once. Each recipe has an urgency number — bigger number = drop everything and do this first. xTaskCreate is you handing the manager a new recipe card, telling him how much counter space (stack) it needs and how urgent it is. A good recipe says "now wait 5 minutes" (vTaskDelay) so the cook can go help others instead of standing idle.


Flashcards

In FreeRTOS, does a higher priority number mean more or less urgent?
More urgent — the numerically largest READY priority always runs.
What unit is usStackDepth in xTaskCreate?
Words, not bytes (multiply by sizeof(StackType_t), e.g. ×4 on Cortex-M).
What are the 6 parameters of xTaskCreate in order?
Function, Name, StackDepth(words), Parameters(void*), Priority, &TaskHandle.
What does xTaskCreate return on success vs failure?
pdPASS on success; errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY if heap can't fit stack+TCB.
Why must a high-priority task block (e.g. vTaskDelay)?
Otherwise it never yields the CPU and all lower-priority tasks starve.
What happens to two READY tasks of equal priority?
Round-robin time-slicing (if configUSE_TIME_SLICING=1) — they share the CPU fairly.
What are the four task states?
Running, Ready, Blocked, Suspended.
What is the TCB?
Task Control Block — kernel struct holding a task's priority, state, stack pointer; allocated per task alongside its stack.
What runs at tskIDLE_PRIORITY (0)?
The idle task — lowest priority, runs when nothing else is ready.
Why must a task function never return?
Returning corrupts the scheduler; wrap in for(;;) or call vTaskDelete(NULL) to exit safely.
What does pdMS_TO_TICKS do and why is it needed?
Converts milliseconds to kernel ticks using configTICK_RATE_HZ; FreeRTOS counts time in ticks, not ms.
What is preemption in the default FreeRTOS scheduler?
A higher-priority task becoming READY immediately interrupts a running lower-priority task.

Connections

  • FreeRTOS — vTaskDelay vs vTaskDelayUntil
  • FreeRTOS — Queues and inter-task communication
  • FreeRTOS — Semaphores and Mutexes
  • Priority Inversion and Priority Inheritance
  • Context Switching and the TCB
  • ISR-safe APIs (FromISR) and deferred interrupt handling
  • Heap memory management (heap_1..heap_5) in FreeRTOS
  • Round-robin vs Preemptive Scheduling

Concept Map

solved by

provides

contains

is

picks highest

created by

has

has

higher number = more urgent

lowest is 0

holds state in

allocates

allocates

is in one

Blocked uses

Many jobs one CPU core

FreeRTOS

Task = infinite loop

Scheduler

Preemptive priority-based

READY task runs

xTaskCreate

Own stack in words

Priority number

Idle task

TCB Task Control Block

State Running Ready Blocked Suspended

No CPU

Hinglish (regional understanding)

Intuition Hinglish mein samjho

Dekho, microcontroller mein sirf ek CPU hota hai par kaam bahut saare — LED blink karo, sensor padho, UART pe data bhejo. Agar sab ek hi bade while(1) loop mein karoge to timing bigad jaati hai. FreeRTOS isko solve karta hai tasks se: har task apna alag chhota while(1) loop hai jo sochta hai ki poora CPU uske paas hai. Ek chhota sa scheduler itni tezi se task switch karta hai ki lagta hai sab parallel chal rahe hain. xTaskCreate se aap scheduler ko naya task de dete ho.

xTaskCreate ke 6 arguments yaad rakho: function (task ka body), name (sirf debug ke liye), stack depth (words mein, bytes mein nahi — Cortex-M pe ×4 karo bytes ke liye), parameter, priority, aur handle. Sabse bada trap: FreeRTOS mein bada number = zyada urgent. Yani priority 3 wala task priority 1 wale ko beech mein rok dega (preemption). "Big is Boss" yaad rakho.

Ek aur zaroori baat: high-priority task ko hamesha block karna chahiye — vTaskDelay ya queue/semaphore wait se. Agar high task bina ruke kaam karta rahega to neeche wale saare tasks bhookhe (starve) reh jayenge, LED kabhi nahi blink karega. Isliye real-time task apna zyaadatar time Blocked state mein rehta hai, sirf kaam aane par jaagta hai. Aur task function kabhi return mat karna — for(;;) mein wrap karo, warna scheduler crash ho jata hai.

Bas itna samajh lo: tasks = alag-alag recipes, scheduler = manager jo urgency dekh ke cook (CPU) ko switch karwata hai, aur xTaskCreate = nayi recipe card dena with stack size aur urgency. Yeh embedded real-time software ka foundation hai.

Go deeper — visual, from zero

Test yourself — Embedded Systems & Real-Time Software

Connections