Files

19 KiB
Raw Permalink Blame History

FreeRTOS C — book-led card sequence

Status: FC01FC02 exist; FC03 is the next implementation; FC04FC15 are planned. This series uses only the FreeRTOS C API. C++ wrappers belong to a later, separate series.

Primary source and ordering rule

The content map follows the official FreeRTOS Kernel Book:

The book supplies the concepts and API order. Each card adds the local Hazard3/RV32I observation contract: stable checkpoints, source and ELF identity, a debugging strategy and a timestamped runtime proof. We do not copy the book examples verbatim; every program is a small deterministic experiment suitable for replay.

FreeRTOS Kernel Book
├── Ch. 3  Heap memory management              → FC01, revisited in FC11
├── Ch. 4  Task management                     → FC02FC04
├── Ch. 5  Queue management                    → FC05
├── Ch. 6  Software timer management           → FC06
├── Ch. 7  Interrupt management                → FC07, FC13FC14
├── Ch. 8  Resource management                 → FC08
├── Ch. 9  Event groups                        → FC09
├── Ch. 10 Task notifications                  → FC10, FC13
├── Ch. 11 Low-power support                   → optional extension after FC15
├── Ch. 12 Developer support                   → FC12
└── Ch. 13 Troubleshooting                     → FC12 and every acceptance gate

FC11 deliberately revisits static allocation after the student has already seen tasks, queues and timers. The book introduces it in Chapter 3; the later placement lets one card compare real dynamic and static forms of several kernel objects without teaching APIs that have not appeared yet.

A1A8 viewpoint policy

A1A8 is a set of questions, not a requirement to draw eight decorative diagrams. A view is enabled only when it adds a distinct proof.

A1 CONTEXT      system boundary and responsibility
A2 STRUCTURE    C structs, handles, kernel objects and ownership
A3 DISPATCH     callback, ISR or other binding boundary
A4 APPLICATION  concrete task/object topology and invariants
A5 FLOW         ordered execution and checkpoints
A6 STATE        task/object state and lifetime
A7 RUNTIME      addresses, TCB, stack, registers, tick and ELF evidence
A8 PATTERNS     named reusable design decision, only when real

Every enabled diagram is interactive. A CODE step opens a stable source or artifact reference without running the target. A RUN step replays from clean RAM to a verified checkpoint. Moving the cursor alone never mutates the simulator.

Curated sequence

FreeRTOS C — 15 cards
├── FC01 · Heap schemes and heap_4 block mechanics
├── FC02 · First task, typed context, TCB and task stack
├── FC03 · Tick, priorities, preemption and time slicing
├── FC04 · Delay, blocking, task states and deletion
├── FC05 · Queues, blocking and byte-copy semantics
├── FC06 · Software timers and the daemon task
├── FC07 · Interrupt-safe API and semaphore handoff
├── FC08 · Critical sections, mutexes and priority inheritance
├── FC09 · Event groups and multi-event synchronization
├── FC10 · Direct-to-task notifications
├── FC11 · Static allocation and bounded kernel storage
├── FC12 · Assertions, hooks, stack checks and runtime diagnostics
├── FC13 · UART interrupt-to-task pipeline
├── FC14 · GPIO, hardware timer and deferred work
└── FC15 · Integrated deterministic FreeRTOS C application

FC01 — Heap schemes and heap_4 block mechanics

Book basis: 3.13.4: heap_1heap_5, heap utilities, allocation failure and static allocation introduction.

  • Raw API: pvPortMalloc, vPortFree, xPortGetFreeHeapSize, xPortGetMinimumEverFreeHeapSize, vPortGetHeapStats.
  • Main task: compare allocator policies, then walk allocation, split, free and coalescing in heap_4.
  • Blocks: A1 allocator boundary; A2 block/list layout; A5 allocation flow; A6 free/allocated block state; A7 heap addresses and statistics.
  • Exercise: predict the free-list shape for a new allocate/free order.
  • Hazard3/GDB proof: block headers, aligned sizes and coalesced neighbors agree with the final heap statistics.
  • Main pitfall: treating the minimum-ever-free value as current free space or assuming all heap implementations support free/coalescing.

FC02 — First task, typed context, TCB and task stack

Book basis: 4.24.6 and the creation/parameter parts of Examples 4.14.2.

  • Raw API: xTaskCreate, vTaskStartScheduler, vTaskDelete, uxTaskGetStackHighWaterMark.
  • Main task: two equal-priority workers compute sum(1..20000) through void *pvParameters; a lower-priority supervisor verifies both results.
  • Enabled views: A1, A2, A3, A5, A6 and A7.
  • Exercise: add a third typed context without introducing global task data.
  • Hazard3/GDB proof: callback-entry a0, context, opaque handle/TCB, task stack and A→B→A execution trace are distinct and consistent.
  • Main pitfall: confusing &handle, the handle value, TCB, context and stack.

Detailed plan: FC02 — A1A8 raw C task.

FC03 — Tick, priorities, preemption and time slicing

Book basis: 4.5, 4.6, 4.9 and 4.12, especially prioritized preemptive scheduling, runtime priority changes and time slicing.

  • Raw API/config: uxTaskPriorityGet, vTaskPrioritySet, xTaskGetTickCount, configUSE_PREEMPTION, configUSE_TIME_SLICING.
  • Main task: two equal-priority peers establish A→B→A; one peer raises a dormant probe from priority 0 to 3, which must preempt before the peer's next committed write; a priority-1 verifier runs only after higher-priority work ends.
  • Blocks: A1 tick/scheduler boundary; A2 task/priority/trace data; A4 experiment topology; A5 two-part scheduling flow; A6 Ready/Running lanes; A7 timer interrupt, current TCB, PC/SP and trace evidence.
  • Exercise: run a bounded expected-noncompletion observation with time slicing disabled, then explain why a CPU-bound peer can starve its equal-priority neighbor.
  • Hazard3/GDB proof: nondecreasing ticks, A→B→A, immediate high-priority takeover and delayed low-priority verifier.
  • Main pitfall: interpreting priority as fairness or treating a tick as a guarantee that every Ready task ran.

Detailed plan: FC03 — scheduler experiment.

FC04 — Delay, blocking, task states and deletion

Book basis: 4.74.10 and Examples 4.44.8.

  • Raw API: vTaskDelay, vTaskDelayUntil, eTaskGetState, vTaskSuspend, vTaskResume, vTaskDelete.
  • Main task: periodic and non-periodic tasks cross Ready, Running, Blocked, Suspended and Deleted states on a controlled tick timeline.
  • Blocks: A2 state-bearing contexts/handles; A5 delay and resume sequence; A6 canonical task-state machine; A7 wake tick, PC/SP, TCB and idle cleanup.
  • Exercise: replace relative delay with vTaskDelayUntil and quantify drift.
  • Hazard3/GDB proof: actual wake ticks and public eTaskState observations match the selected state-machine edges.
  • Main pitfall: busy waiting instead of blocking, or assuming vTaskDelete immediately erases every forensic trace.

FC05 — Queues, blocking and byte-copy semantics

Book basis: Chapter 5, with emphasis on 5.25.5 and Examples 5.15.2.

  • Raw API: xQueueCreate, xQueueSendToBack, xQueueSendToFront, xQueueReceive, uxQueueMessagesWaiting, xQueuePeek.
  • Main task: two producers send typed messages by value to one consumer; a full and an empty queue deliberately block the correct task.
  • Blocks: A1 producer/kernel/consumer boundary; A2 queue item/ring/storage; A4 producer-consumer topology; A5 send/copy/block/wake/receive; A6 queue and task states; A7 source address versus copied queue slot and destination.
  • Exercise: compare a value queue with a queue of pointers and write the ownership contract for the latter.
  • Hazard3/GDB proof: changing the producer buffer after send does not change the queued value; waiting counts and task transitions are correct.
  • Main pitfall: assuming queues hold references, or queuing a pointer without an explicit lifetime owner.

FC06 — Software timers and the daemon task

Book basis: Chapter 6 and Examples 6.16.3.

  • Raw API: xTimerCreate, xTimerStart, xTimerChangePeriod, xTimerReset, pvTimerGetTimerID.
  • Main task: one-shot and auto-reload timers share a callback but use distinct IDs; task code resets one timer and changes the other's period.
  • Blocks: A1 application/timer service/kernel boundary; A2 timer objects, IDs and command queue; A3 callback dispatch; A5 command→daemon→callback; A6 dormant/active/expired states; A7 daemon task, callback PC and tick.
  • Exercise: derive the callback order for a changed period and verify it.
  • Hazard3/GDB proof: callback context is the timer daemon task, not the task that issued xTimerStart.
  • Main pitfall: blocking inside a timer callback or assuming timer commands execute synchronously in the caller.

FC07 — Interrupt-safe API and semaphore handoff

Book basis: Chapter 7, especially 7.27.5 and queue/ISR considerations.

  • Raw API: xSemaphoreCreateBinary, xSemaphoreCreateCounting, xSemaphoreGiveFromISR, xSemaphoreTake, portYIELD_FROM_ISR.
  • Main task: a deterministic simulated interrupt gives a semaphore, sets xHigherPriorityTaskWoken, and transfers execution to a waiting task.
  • Blocks: A1 ISR/task/kernel boundary; A2 semaphore and ISR evidence; A3 FromISR dispatch/yield contract; A5 interrupt→unblock→yield→task flow; A6 waiting/ready/running; A7 trap frame, mcause, PC/SP and awakened TCB.
  • Exercise: replace binary with counting semantics and explain event loss or accumulation.
  • Hazard3/GDB proof: ISR uses only FromISR API, does not block, and a required yield selects the unblocked higher-priority task.
  • Main pitfall: calling task-context API from an ISR or ignoring xHigherPriorityTaskWoken.

FC08 — Critical sections, mutexes and priority inheritance

Book basis: Chapter 8, including critical sections, scheduler suspension, mutexes, priority inversion/inheritance, deadlock and gatekeeper tasks.

  • Raw API: taskENTER_CRITICAL, taskEXIT_CRITICAL, vTaskSuspendAll, xTaskResumeAll, xSemaphoreCreateMutex, xSemaphoreTake/Give.
  • Main task: low/medium/high tasks first expose bounded priority inversion, then prove inherited priority while a mutex protects a shared resource.
  • Blocks: A2 mutex owner/waiters/resource; A4 three-task topology; A5 inversion and inheritance flow; A6 mutex/task states; A7 effective versus base priority and owner TCB; A8 mutex versus gatekeeper decisions.
  • Exercise: construct a lock-order table that removes a demonstrated two-mutex deadlock.
  • Hazard3/GDB proof: low task's effective priority rises while high waits and returns after release; the shared invariant remains intact.
  • Main pitfall: using a binary semaphore where priority inheritance is required, or holding a mutex across an unbounded operation.

FC09 — Event groups and multi-event synchronization

Book basis: Chapter 9.

  • Raw API: xEventGroupCreate, xEventGroupSetBits, xEventGroupWaitBits, xEventGroupSync.
  • Main task: two workers publish independent readiness bits; a coordinator waits for ALL bits, then all participants cross a reusable barrier.
  • Blocks: A2 bit ownership and event object; A4 participant topology; A5 set/wait/unblock/barrier; A6 bit mask and blocked-task state; A7 EventBits_t, wait masks and TCB wake evidence; A8 barrier pattern.
  • Exercise: compare ANY versus ALL and clear-on-exit semantics on the same event trace.
  • Hazard3/GDB proof: the coordinator cannot pass before the complete mask and the barrier releases the intended set of tasks once.
  • Main pitfall: reusing one bit for incompatible meanings or forgetting the effects of automatic bit clearing.

FC10 — Direct-to-task notifications

Book basis: Chapter 10, especially benefits/limits and 10.3.210.3.6.

  • Raw API: xTaskNotifyGive, ulTaskNotifyTake, xTaskNotify, xTaskNotifyWait and their explicit FromISR variants as a comparison.
  • Main task: one receiver exercises counting, value overwrite and bit-set notification modes without an intermediary queue/semaphore object.
  • Blocks: A2 notification value in the target task; A3 sender→target binding; A5 notify/block/wake/consume; A6 notification state/value; A7 target TCB, value transitions and RAM comparison with queue/semaphore alternatives.
  • Exercise: choose the correct notification action for three stated protocols and justify what information can be lost.
  • Hazard3/GDB proof: only the selected target wakes, and the observed value transition matches the selected action.
  • Main pitfall: treating a single notification slot as a general multi-reader message queue.

FC11 — Static allocation and bounded kernel storage

Book basis: 3.4 plus the static creation variants introduced throughout Chapters 46.

  • Raw API: xTaskCreateStatic, xQueueCreateStatic, xTimerCreateStatic, vApplicationGetIdleTaskMemory, vApplicationGetTimerTaskMemory.
  • Main task: rebuild a small task+queue+timer topology with explicit TCB, stack and object buffers; compare it to the dynamic build.
  • Blocks: A1 ownership boundary; A2 complete storage graph; A4 bounded topology; A5 initialization order; A7 .bss addresses, map file and zero heap growth.
  • Exercise: calculate and declare all required storage for one additional task and queue.
  • Hazard3/GDB proof: kernel object addresses lie in declared static storage, and free-heap values do not change during creation.
  • Main pitfall: confusing a statically allocated task with a static C function, or under-sizing stack/object buffers.

FC12 — Assertions, hooks, stack checks and runtime diagnostics

Book basis: Chapters 1213.

  • Raw API/config: configASSERT, malloc-failed and stack-overflow hooks, uxTaskGetStackHighWaterMark, uxTaskGetSystemState, trace hooks.
  • Main task: run controlled positive diagnostics plus isolated expected-fail fixtures for an assertion, allocation failure and stack guard.
  • Blocks: A1 diagnostic boundaries; A2 evidence record and hook contracts; A5 fault→hook→frozen evidence; A6 healthy/failing terminal states; A7 stack watermark, task statistics, fault PC and build identity.
  • Exercise: diagnose a supplied trace without changing the program first.
  • Hazard3/GDB proof: every fixture stops in the intended hook with preserved source/ELF/checkpoint identity and no false PASS.
  • Main pitfall: optimizing hooks away, allocating/printing unsafely inside a hook, or treating watermark as the exact current stack use.

FC13 — UART interrupt-to-task pipeline

Book basis: 7.27.7 and the UART notification example in 10.3.7.

  • Raw API: explicit UART ISR, vTaskNotifyGiveFromISR or xTaskNotifyFromISR, ulTaskNotifyTake, portYIELD_FROM_ISR.
  • Main task: RX ISR transfers bytes into a bounded ring; a task drains and validates complete frames while TX ownership remains explicit.
  • Blocks: A1 peripheral/ISR/task boundary; A2 MMIO/ring/task context; A3 ISR→notification binding; A5 byte→interrupt→ring→task→frame flow; A6 ring and receiver states; A7 MMIO, indices, trap frame and task stack.
  • Exercise: specify overflow policy and prove it with an overlong frame.
  • Hazard3/GDB proof: ISR duration is bounded, no blocking API is used, ring indices remain valid and the consumer wakes at the correct boundary.
  • Main pitfall: doing parsing in the ISR or publishing an index before the corresponding byte is visible.

FC14 — GPIO, hardware timer and deferred work

Book basis: 6.4, 7.3 and 7.6, applied to GPIO/timer peripherals.

  • Raw API: hardware timer ISR, xTimerPendFunctionCallFromISR, optional notification/semaphore comparison, GPIO MMIO.
  • Main task: a timer edge records minimal ISR evidence, defers a bounded callback to the daemon task, and updates GPIO state under a stated timing contract.
  • Blocks: A1 hardware/ISR/daemon/task boundary; A2 event record; A3 deferred callback binding; A5 edge→ISR→daemon queue→callback→GPIO; A6 pending and applied states; A7 mtime/mtimecmp, trap frame, daemon task and MMIO.
  • Exercise: select notification, semaphore or daemon deferral for three different workloads.
  • Hazard3/GDB proof: ISR and deferred callback have different stacks/PCs, exactly one GPIO transition is associated with each accepted event.
  • Main pitfall: confusing a hardware timer interrupt with a FreeRTOS software timer callback or overloading the daemon task.

FC15 — Integrated deterministic FreeRTOS C application

Book basis: synthesis of Chapters 313.

  • Raw API: tasks, queues, notification, event group, mutex, software timer, FromISR handoff and diagnostics, selected only where justified.
  • Main task: acquire deterministic UART/GPIO/timer events, process one algorithmic workload, publish results and supervise health under bounded memory.
  • Blocks: all A1A8 views may be enabled because architecture, topology, dispatch, flow, state, runtime and patterns are all distinct here.
  • Exercise: change one application policy while preserving the published concurrency and memory contracts.
  • Hazard3/GDB proof: timestamped end-to-end trace connects input event, selected task, communication object, result, deadline/ordering invariant and final PASS.
  • Main pitfall: adding every learned primitive instead of choosing the smallest correct synchronization mechanism.

Common card contract

Every new card must contain:

  1. a one-page goal and scope contract;
  2. one principal Task divided into viewpoint Blocks and Phases/Steps;
  3. only applicable A1A8 views, with explicit reasons for unavailable views;
  4. a stable code_ref for every CODE step;
  5. a debug strategy, checkpoint and non-empty assertion set for every RUN step;
  6. a student exercise that changes one variable without changing the whole experiment;
  7. a Hazard3/GDB acceptance proof including source and ELF identity;
  8. HTML and TeX generated from one card_source.json;
  9. no PDF generation and no commit unless explicitly requested.

Implementation order

FC03 scheduler
→ FC04 state/delay
→ FC05 queues
→ FC06 software timers
→ FC07 interrupts/semaphores
→ FC08 resources/mutex
→ FC09 event groups
→ FC10 notifications
→ FC11 static allocation
→ FC12 diagnostics
→ FC13 UART
→ FC14 GPIO/timer
→ FC15 integration

Ukończenie FC15 jest pierwszą z dwóch bramek wejścia do FreeRTOS C++; drugą jest ukończenie właściwych kart językowych C++/OOP.