Hardware Events

Attach a handler to a pin with an edge or level token, and it fires when the pin changes — the way hardware interrupts always have, without the setup ceremony.

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.

method group

onInterrupt / offInterrupt

Attach and detach a GPIO interrupt with an edge or level token — a misspelled token is an editor error; an invalid mode is a build error naming the valid spellings.

Example first

interrupts.ts
import { GPIO, LED, BUTTON } from '@typecad/hal';

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();
});

Mode tokens

TokenFires when
GPIO.INT_EDGE_RISINGthe pin goes low → high
GPIO.INT_EDGE_FALLINGthe pin goes high → low
GPIO.INT_EDGE_BOTHeither transition
GPIO.INT_LEVEL_LOWthe pin is held low
GPIO.INT_LEVEL_HIGHthe pin is held high

offInterrupt offInterrupt(): void

detach.ts
button.offInterrupt();   // disable and remove the callback

ISR safety

The handler runs in interrupt context. Setting variables and driving pins in the handler 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.

flag-pattern.ts
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?

InterruptPoll in an async task
Latencymicrosecondsthe poll period (typically milliseconds)
ContextISR constraints applynone — ordinary code
Best atevents that must not be missedsequential logic, debouncing
Many inputsone callback per pinone 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.

© 2026 typeCAD — code-defined electronics github