409 lines
20 KiB
Markdown
409 lines
20 KiB
Markdown
# FreeRTOS C — book-led card sequence
|
||
|
||
Status: FC01–FC15 istnieją; blok 15 kart FreeRTOS C jest kompletny i stanowi
|
||
zamknięty fundament przed serią FreeRTOS C++. Każda karta używa publicznego
|
||
API C, a końcowa FC15 scala mechanizmy w jeden deterministyczny eksperyment.
|
||
|
||
## Primary source and ordering rule
|
||
|
||
The content map follows the official **FreeRTOS Kernel Book**:
|
||
|
||
- <https://github.com/FreeRTOS/FreeRTOS-Kernel-Book>
|
||
- <https://github.com/FreeRTOS/FreeRTOS-Kernel-Book/blob/main/toc.md>
|
||
|
||
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.
|
||
|
||
```text
|
||
FreeRTOS Kernel Book
|
||
├── Ch. 3 Heap memory management → FC01, revisited in FC11
|
||
├── Ch. 4 Task management → FC02–FC04
|
||
├── Ch. 5 Queue management → FC05
|
||
├── Ch. 6 Software timer management → FC06
|
||
├── Ch. 7 Interrupt management → FC07, FC13–FC14
|
||
├── 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.
|
||
|
||
## A1–A8 viewpoint policy
|
||
|
||
A1–A8 is a set of questions, not a requirement to draw eight decorative
|
||
diagrams. A view is enabled only when it adds a distinct proof.
|
||
|
||
```text
|
||
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
|
||
|
||
```text
|
||
FreeRTOS C — 15 cards
|
||
├── FC01 · heap_4: from a linear cursor to reusable blocks
|
||
├── 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_4`: from a linear cursor to reusable blocks
|
||
|
||
**Duration:** one 30-minute lesson.
|
||
|
||
**Direct predecessor:** C07, K&R 5.4 Task04 — `allocbuf[64]`, `allocp`,
|
||
`alloc(5)`, `alloc(7)` and cursor offsets `0 -> 5 -> 12`.
|
||
|
||
**Book basis:** the `heap_4` and heap-statistics parts of Chapter 3. The other
|
||
FreeRTOS heap implementations are a one-minute map of alternatives, not
|
||
parallel lesson content.
|
||
|
||
- Opening problem: the linear project cannot release the first 5-byte area
|
||
while preserving the later 7-byte area, cannot remember reusable holes and
|
||
recovers the arena only with a whole-arena reset.
|
||
- New model: a block header, an address-ordered free list, first-fit selection,
|
||
splitting and coalescing of physically adjacent free blocks.
|
||
- Raw API: `pvPortMalloc`, `vPortFree`, `xPortGetFreeHeapSize`,
|
||
`xPortGetMinimumEverFreeHeapSize`, `vPortGetHeapStats`.
|
||
- Task 1 and Task 2 are short teacher-led models with a student prediction;
|
||
they are not separate build/debug sessions during the lesson.
|
||
- Task 3 is the only central student replay: real upstream `heap_4.c`, two
|
||
stable checkpoints, fragmentation metrics, recovery and OOM.
|
||
- Pico 2 W supplies one prebuilt RP2350 hardware observation. `heap_4` is the
|
||
allocator selected and linked by the project, not a hardware feature of the
|
||
microcontroller.
|
||
- Acceptance: the student names the three additions over the linear allocator
|
||
(header, free list, coalescing), predicts `2 free blocks -> 1 free block`,
|
||
and distinguishes current free bytes, largest free block and minimum-ever
|
||
free bytes.
|
||
- Main pitfall: assuming that a large sum of free bytes guarantees one large
|
||
allocation, or that minimum-ever-free increases after `free`.
|
||
|
||
## FC02 — First task, typed context, TCB and task stack
|
||
|
||
**Book basis:** 4.2–4.6 and the creation/parameter parts of Examples 4.1–4.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 — A1–A8 raw C task](freertos-c-fc02-a1-a8.md).
|
||
|
||
## 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](freertos-c-fc03-a1-a8.md).
|
||
|
||
## FC04 — Delay, blocking, task states and deletion
|
||
|
||
**Book basis:** 4.7–4.10 and Examples 4.4–4.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.2–5.5 and Examples 5.1–5.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.1–6.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.2–7.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.2–10.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 4–6.
|
||
|
||
- 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 12–13.
|
||
|
||
- 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.2–7.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 3–13.
|
||
|
||
- 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 A1–A8 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 A1–A8 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.
|
||
|
||
## Completed implementation order
|
||
|
||
```text
|
||
FC01 heap_4
|
||
→ FC02 first task
|
||
→ 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
|
||
```
|
||
|
||
Obie bramki wejścia do FreeRTOS C++ są spełnione: FC15 zamyka tor systemowy C,
|
||
a właściwe karty językowe C++/OOP dostarczają model własności, RAII, szablony i
|
||
statyczne trampoline. Następnym etapem jest audyt i realizacja serii FreeRTOS
|
||
C++ karta po karcie, bez mieszania wrapperów z implementacją kernela w C.
|