# K15 — Explicit FromISR, UART and GPIO wrappers

## Position

- Series: FreeRTOS C++
- Lesson: L14, card K15
- Duration: 30 minutes
- Real machine-external interrupt on Hazard3
- Queue capacity 1 with drop-newest overflow

## Outcome

The student distinguishes task and ISR driver views, publishes UART/GPIO events
only through explicit FromISR APIs, accumulates one wake decision, yields once,
and proves backpressure plus immediate high-priority task execution.

## Lesson plan

| Time | Mode | Evidence |
| --- | --- | --- |
| 0–5 | ISR contract | task/ISR views and one IsrContext |
| 5–10 | real IRQ | mcause=0x8000000b and separate ISR stack |
| 10–15 | UART queue | 0x41 queued, 0x42 drop-newest |
| 15–20 | GPIO notify | edge 1→0, notification count 1 |
| 20–25 | wake/yield | accumulated wake=true, exactly one yield |
| 25–30 | context switch | receiver at tick 1 before stimulus resumes |

## Acceptance

- the interrupt is a real machine-external IRQ through the FreeRTOS trap path;
- Uart and GpioPin expose distinct task and ISR views;
- only xQueueSendFromISR and vTaskNotifyGiveFromISR are used in the handler;
- one IsrContext accumulates both wake requests;
- RX queue capacity 1 accepts 0x41 and drop-newest rejects/counts 0x42;
- UART ready and GPIO edge MMIO-model state clear from 1 to 0;
- higherPriorityTaskWoken is true and yield_if_needed is called once;
- receiver gets byte 0x41 and notification count 1 at tick 1;
- receiver sees stimulus_after=0; stimulus later sees receiver_done=1;
- static storage has heap delta zero and target exits with PASS.

## Main traps

1. Calling an ordinary blocking API from an ISR.
2. Automatically guessing execution context instead of explicit views.
3. Yielding after each primitive rather than once at handler exit.
4. Ignoring queue overflow or silently overwriting data.
5. Performing parsing, debounce or long GPIO policy in the handler.
