Hardware Events
One mechanism: GPIO interrupts. A pin event lowers to gpio_pin_interrupt_configure_dt plus a callback registered the Zephyr way, with the edge or level mode expressed as Zephyr’s own GPIO.INT_* tokens.
For sequential “wait for a signal” logic, interrupts are the wrong tool — poll inside an async function with Time.sleep and let the task yield between checks. Both patterns are below.
Attaching an Interrupt
import { GPIO } from '@typecad/hal';
import { LED, BUTTON } from '@typecad/board';
const led = new GPIO(LED, GPIO.OUTPUT);
const button = new GPIO(BUTTON, GPIO.INPUT | GPIO.PULL_UP);
button.onInterrupt(GPIO.INT_EDGE_FALLING, () => {
led.toggle();
});The mode is one of these tokens — Zephyr’s names, covering edges and levels:
| Token | Fires when |
|---|---|
GPIO.INT_EDGE_RISING | the pin goes low → high |
GPIO.INT_EDGE_FALLING | the pin goes high → low |
GPIO.INT_EDGE_BOTH | either transition |
GPIO.INT_LEVEL_LOW | the pin is held low |
GPIO.INT_LEVEL_HIGH | the pin is held high |
A misspelled token is an editor-visible member error; an invalid mode is a build error naming the valid spellings.
Detaching
button.offInterrupt(); // disable and remove the callbackISR Safety
The handler runs in interrupt context. The transpiler checks handler bodies: setting variables and driving pins is fine, but calls that would block — delays, bus transactions, UART writes — are flagged at build time with the offending call named.
The pattern that always works: set a flag in the handler, act on it in the main flow.
let pressed = false;
button.onInterrupt(GPIO.INT_EDGE_FALLING, () => { pressed = true; });
while (true) {
if (pressed) {
pressed = false;
UART0.writeLine('pressed'); // safe here
}
Time.sleep(10);
}Interrupts or Polling?
| Interrupt | Poll in an async task | |
|---|---|---|
| Latency | microseconds | the poll period (typically milliseconds) |
| Context | ISR constraints apply | none — ordinary code |
| Best at | events that must not be missed | sequential logic, debouncing |
| Many inputs | one callback per pin | one task can watch many conditions |
Debouncing is the classic deciding case: an interrupt fires on every bounce, while a polling task reads a settled level. while (button.get()) { await Time.sleep(20); } debounces by construction.
API Reference
| Member | Description |
|---|---|
onInterrupt(intFlags, handler) | Attach with a GPIO.INT_* token. |
offInterrupt() | Detach. |
On This Page