Worked examples — FreeRTOS — task creation, priorities, xTaskCreate
5.5.10 · D3· Coding › Embedded Systems & Real-Time Software › FreeRTOS — task creation, priorities, xTaskCreate
Scenario matrix
Is topic se jo bhi situation aati hai woh in cells mein se kisi ek mein aati hai. Har worked example neeche tagged hai un cell(s) ke saath jo woh cover karta hai, toh ant mein koi cell dark nahi bachti. Table mein do words pehle pin down karne padenge:
| # | Case class | Woh question jo yeh force karta hai |
|---|---|---|
| C1 | Higher priority preempts lower | Kya urgent task sach mein beech kaam ke cut in karta hai? |
| C2 | Equal priority, dono busy | Kaun run karta hai — aur kitne der ke liye? |
| C3 | High-priority task kabhi block nahi karta | Kya starve hota hai, aur kitna visible hai? |
| C4 | Stack bahut chhota (degenerate) | Kya creation fail hoti hai, ya run karke crash hota hai? |
| C5 | Heap exhausted (limiting) | xTaskCreate kya return karta hai, aur kya karna chahiye? |
| C6 | Zero-argument / NULL handle |
Kya NULL pass karna params aur handle ke liye legal hai? |
| C7 | Priority ceiling ke upar | Kya hoga agar uxPriority ≥ configMAX_PRIORITIES ho? |
| C8 | Task function return kar jaaye | Forbidden move — actually kya toot ta hai? |
| C9 | Real-world word problem | Teen real tasks ko sahi se end to end size karna. |
| C10 | Exam-style twist | Ek subtle ordering/timing gotcha. |
Hum assume karte hain configTICK_RATE_HZ = 1000 (toh 1 tick = 1 ms) jab tak problem kuch aur na kahe.
Example 1 — Higher priority preempts lower (covers C1)

Step 1 — vHigh ki wake period ticks mein nikalo.
Yeh step kyun? Scheduler ticks mein sochta hai, toh insaani "10 ms" ko pdMS_TO_TICKS se translate karo (upar define hua).
Step 2 — 100 ms window mein wakes count karo.
Yeh step kyun? Har wake ek preemption event hai; inhe count karne se pata chalta hai vLow kitni baar interrupt hota hai.
Yeh figure ke das red spikes se match karta hai.
Step 3 — CPU add karo jo vHigh steal karta hai.
Yeh step kyun? Dekhne ke liye kya vLow sirf delayed hai ya actually broken hai.
Step 4 — vLow ka finish time compute karo.
Yeh step kyun? vLow ko 100 ms CPU chahiye, lekin jo vHigh chhodta hai wahi milta hai.
Example 2 — Equal priority, dono busy (covers C2)

Step 1 — Equal-priority rule yaad karo.
Yeh step kyun? Priority difference nahi hai toh scheduler koi "winner" nahi chun sakta, isliye configUSE_TIME_SLICING = 1 ke saath woh round-robin time-slicing pe fall back karta hai: ek tick each, phir rotate.
Step 2 — Figure se tick schedule padho. Yeh step kyun? Concreteness hand-waving se better hai — figure ke chhe alternating slots exactly yeh hain:
| Tick | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|
| Runs | A | B | A | B | A | B |
Step 3 — Har task ka share sum karo. Yeh step kyun? Numeric question ka jawab dene ke liye.
Example 3 — High-priority task kabhi block nahi karta (covers C3)

Step 1 — "Highest READY runs" rule apply karo.
Yeh step kyun? vGreedy priority 5 hai, hamesha Ready (kabhi block nahi karta), toh woh hamesha numerically largest Ready priority hai.
Step 2 — Baaki sabka share deduce karo.
Yeh step kyun? Ek core; jo vGreedy yield nahi karta, koi aur nahi le sakta.
Step 3 — Collateral damage list karo. Yeh step kyun? Starvation sirf "LED off" nahi hai — idle task bhi priority 0 pe kabhi run nahi karta.
- Idle task nahi ⇒ low-power sleep entry nahi.
- Idle task nahi ⇒ watchdog (jo aksar idle hook se feed hota hai) timeout ho jaata hai aur chip reset ho jaati hai.
Example 4 — Stack bahut chhota (degenerate input) (covers C4)
Step 1 — Requested stack ko bytes mein convert karo. Yeh step kyun? Declaration bytes mein hai; API words mein hai. Same units ho tabhi kuch matlab hai.
Step 2 — Demand se compare karo. Yeh step kyun? Local buffer alone ko 600 bytes chahiye, plus saved registers aur call frames ke liye room.
Step 3 — Predict karo ki yeh kab fail hoga.
Yeh step kyun? Yahi trap hai. xTaskCreate succeed karta hai — heap easily 512 bytes fit kar leta hai. Crash baad mein aata hai, jab task run hota hai aur apne stack top se aage push karta hai, silently neighbouring TCB ya heap corrupt karta hai.
Example 5 — Heap exhausted (limiting case) (covers C5)
Step 1 — Ek task ki cost bytes mein nikalo. Yeh step kyun? Heap bytes mein kharch hota hai; word-based stack ko convert karo.
Step 2 — Heap mein kitne fit hote hain. Yeh step kyun? Integer division: tum fractional task allocate nahi kar sakte.
Step 3 — 5th call kya return karta hai. Yeh step kyun? 4 tasks ke baad, bytes gone hain; bytes bache hain — 5th ke 2148-byte ke liye enough nahi.
Example 6 — Zero args aur NULL handle (covers C6)
Step 1 — pvParameters = NULL interpret karo.
Yeh step kyun? Yeh argument sirf ek void* hai jo tumhare task ko diya jaata hai. NULL ek perfectly valid pointer value hai; tumhara task simply isse dereference nahi karega.
void vBlink(void*p){ /* p ko ignore karo */ for(;;){ ... } }Step 2 — pxCreatedTask = NULL interpret karo.
Yeh step kyun? Yeh output handle hai. NULL pass karna matlab "mujhe handle nahi chahiye." FreeRTOS NULL check karta hai aur writing skip karta hai — design se safe hai.
Step 3 — NULL handle kab problem dega?
Yeh step kyun? Handle tab chahiye jab baad mein vTaskDelete, vTaskSuspend, ya is task ko notify karna ho. Agar task forever jeeti hai aur koi bahar se control nahi karta, toh NULL correct aur idiomatic hai.
Example 7 — Priority ceiling ke upar (covers C7)
Step 1 — Legal range symbols mein likho.
Yeh step kyun? "9 illegal hai" decide karne se pehle, exactly likhna hoga ki kaun se numbers legal hain. configMAX_PRIORITIES kitne priority levels hain yeh count karta hai, 0 se shuru karke — toh 5 levels ke saath valid numbers hain 0, 1, 2, 3, 4. Top number configMAX_PRIORITIES − 1 hai, configMAX_PRIORITIES nahi (5 last valid slot se ek aage hai):
Kyunki , requested priority out of range hai.
Step 2 — FreeRTOS 9 ke saath kya karta hai.
Yeh step kyun? FreeRTOS internally over-range priority ko highest legal value, configMAX_PRIORITIES - 1, tak clamp kar deta hai.
Step 3 — Clamping kyun dangerous hai phir bhi. Yeh step kyun? Silent clamping ka matlab hai tumhara "super-urgent priority 9" task quietly priority 4 ban jaata hai — possibly doosre task se tie karta hai jise tum samajhte the ki woh outrank karta hai. Koi error raise nahi hota.
Example 8 — Task function return kar jaati hai (covers C8)
Step 1 — Stack trace karo jab function return karta hai.
Yeh step kyun? Task kernel ne vBad mein jump karke launch kiya tha. Uske upar koi valid return address nahi hai — kernel ne ise normal function ki tarah "call" nahi kiya tha.
Step 2 — Outcome predict karo.
Yeh step kyun? Return karne se stack se ek garbage address pop hota hai aur CPU wahan jump karta hai → hard fault, ya FreeRTOS trap handler prvTaskExitError() mein jump (agar configured ho).
Step 3 — Do correct patterns. Yeh step kyun? Har task body in mein se ek honi chahiye:
- ek infinite loop:
for(;;){ ... }, ya - return karne se pehle self-delete:
vTaskDelete(NULL);last line mein.
Example 9 — Real-world word problem: data-logger size karna (covers C9)
Step 1 — Urgency ke hisaab se priorities assign karo. Yeh step kyun? "Koi reading miss nahi honi chahiye" sabse hard deadline hai ⇒ highest number. UI cosmetic hai ⇒ idle ke upar sabse low.
Step 2 — Har stack mein jo fixed overhead add karte hain use justify karo. Yeh step kyun? Stack mein sirf tumhara buffer nahi hona chahiye. Cortex-M pe, har task ki stack mein yeh bhi hota hai: exception frame jo CPU context switch pe auto-push karta hai (16 registers × 4 B = 64 B), software-saved registers jo FreeRTOS push karta hai (8 registers × 4 B = 32 B), plus ek ya do nested function call ka headroom (~100 B). Us sum ko safety ke liye round up karo: Isliye hum neeche har task mein flat 200 B add karte hain — yeh derived hai, magic nahi.
Step 3 — Har stack words mein size karo (buffer + 200 B overhead, phir ÷4, round up). Yeh step kyun? API words chahta hai; hum pehle bytes compute karte hain, convert karte hain, phir comfortable power-of-two-ish value tak round up karte hain.
| Task | buffer (B) | +overhead (B) | total (B) | ÷4 → words | rounded up |
|---|---|---|---|---|---|
| sensor | 200 | 200 | 400 | 100 | 128 |
| logger | 1000 | 200 | 1200 | 300 | 384 |
| ui | 300 | 200 | 500 | 125 | 192 |
Toh: xTaskCreate(vSensor,"sensor",128,NULL,3,NULL), xTaskCreate(vLogger,"logger",384,NULL,2,NULL), xTaskCreate(vUi,"ui",192,NULL,1,NULL).
Step 4 — Total heap cost (stack bytes + 100 B TCB each). Yeh step kyun? Flash karne se pehle confirm karo ki 8192 bytes mein fit hota hai.
Step 5 — Safety margin compute karo. Yeh step kyun? Jaanna hai ki queues, semaphores, aur future tasks ke liye kitna heap bacha hai.
Step 6 — Sensor deadline check karo. Yeh step kyun? Poori baat hi sensor ki reading miss na hone ki hai. Priority 3 top hai, toh sensor har cheez ko preempt karta hai jis instant uska 20 ms timer fire karta hai; scheduling jitter ≈ 0.
Example 10 — Exam twist: creation order vs run order (covers C10)
Step 1 — Creation aur scheduling alag karo.
Yeh step kyun? xTaskCreate sirf ek task ko Ready mein register karta hai; ise run nahi karta. Kuch bhi tab tak nahi chalta jab tak vTaskStartScheduler() na ho. Toh dono xTaskCreate lines kisi bhi task body ke execute hone se pehle complete ho jaati hain.
Step 2 — Start-up pe scheduling rule apply karo. Yeh step kyun? Scheduling shuru hone pe rule unchanged hai: highest-priority Ready task pehle run karta hai.
Step 3 — Trap note karo.
Yeh step kyun? Yahan creation order H phir L hai, jo run order se match karta hai — lekin yeh coincidence hai. Agar tumne L wali line pehle likhi hoti, H phir bhi pehle run karta, kyunki 4 > 1. Creation order irrelevant hai; sirf priority decide karta hai.
Recall Har cell ke liye one-line self-test
C1 preempt outcome ::: vHigh 10×/100 ms run karta hai; vLow 102 ms pe finish karta hai. C2 equal-priority split ::: 50/50 round-robin, 6 mein 3 ticks each. C3 greedy top task ::: vBlink ko 0% milta hai; idle+watchdog bhi starve karte hain. C4 tiny stack ::: creation pdPASS return karta hai, phir runtime overflow (512 B < 600 B). C5 heap limit ::: 4 tasks succeed karte hain, 5th errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY return karta hai. C6 NULL params+handle ::: fully legal aur idiomatic hai. C7 over-range priority ::: configMAX_PRIORITIES-1 tak clamp hota hai (9→4) silently. C8 task returns ::: crash/trap — for(;;) mein wrap karo ya vTaskDelete(NULL) karo. C9 logger sizing ::: 3116 bytes heap used, 5076 free, priorities 3/2/1. C10 order vs priority ::: highest priority pehle run karta hai, creation order irrelevant hai.
See also: FreeRTOS — vTaskDelay vs vTaskDelayUntil · Round-robin vs Preemptive Scheduling · Heap memory management (heap_1..heap_5) in FreeRTOS · Context Switching and the TCB · ISR-safe APIs (FromISR) and deferred interrupt handling · Priority Inversion and Priority Inheritance