How can a FreeRTOS program notice a button press: by polling or with an interrupt? What are the trade-offs?
Polling: a task reads the pin every few milliseconds and sleeps in between. Interrupt: the pin's edge triggers an ISR that wakes a waiting task. Polling is simpler and filters bounce. An interrupt reacts at once and uses no CPU while idle.
* Both end in a task setting the LED; they differ in what wakes that task up. *
| Polling task | Interrupt + task | |
|---|---|---|
| How it notices | Reads the pin in a loop, vTaskDelay between reads |
The GPIO peripheral raises an interrupt on the edge |
| Latency | Up to one polling period (10 ms is fine for a person) | Microseconds |
| CPU while idle | Wakes on every period, even when nothing happens | None, the task is blocked until notified |
| Bounce | Mostly filtered by the slow sampling | Every bounce fires the ISR, so debounce is still needed |
| Complexity | A few lines | ISR rules apply (see below) |
Polling is not busy-waiting. A task that calls vTaskDelay is blocked between reads, so lower-priority tasks run in the meantime. For one human-operated button a 10 ms polling task is a perfectly good design.
Interrupts pay off for fast or rare events and for battery-powered devices that should sleep. The rule then is deferred interrupt handling: the ISR does almost nothing. It sends a notification with an ...FromISR API and returns, and a normal task does the actual work. ISRs must be short, cannot block, and may only call the interrupt-safe FreeRTOS functions.
Go deeper:
FreeRTOS — Deferred interrupt handling — why the ISR hands its work to a task, and how.
Wikipedia — Polling (computer science) — polling vs interrupt-driven I/O in general.
Wikipedia — Interrupt — edge- and level-triggered interrupts and how a CPU services them.