Example: GPIO width trigger
The Protocol Exerciser can arm a GPIO width trigger on supported pins and deliver a global event when the measured pulse matches the configured rules. Use AqProtocolExerciser.set_gpio_trigger to arm the hardware and register a handler for the event name gpio_trigger. The payload is carried on PxEventMsg.global_event.gpio_trigger as PxGpioTriggerEvent (see aqpxlib.gpio or aqpxlib.event).
Constraints¶
- Pins: Width trigger and pulse generation are only supported on GPIO indices 8 and 9 (the same restriction as
send_gpio_pulse). - Durations:
min_duration_nsandmax_duration_nsmust each be greater than 5 ns and less than 1 s. - Events: Subscribe by registering a handler for the logical name
gpio_triggeron the exerciser session. This is a global event, not a per-device event.
Configure the trigger¶
Call set_gpio_trigger with:
| Argument | Meaning |
|---|---|
gpio_idx |
Pin index (8 or 9). |
min_duration_ns / max_duration_ns |
Pulse width window in nanoseconds. |
low_pulse |
Consider low-going pulses when True. |
high_pulse |
Consider high-going pulses when True. |
mode |
PxGpioWidthTriggerMode.TRIGGER_PULSE_WIDTH_IN_RANGE (default) or TRIGGER_PULSE_WIDTH_OUT_OF_RANGE. |
The mode selects whether a fire occurs when the width is inside or outside the [min, max] interval.
Handle gpio_trigger¶
Handlers receive a PxEventMsg. The payload is under global_event.gpio_trigger (PxGpioTriggerEvent):
| Field | Type | Meaning |
|---|---|---|
pin_idx |
int |
Pin index that caused the trigger. |
pulse_duration |
int |
Measured width (nanoseconds). |
pulse_polarity |
bool |
Polarity of the detected pulse. |
Example¶
The script below arms a width-in-range trigger on pin 8, registers a handler, then emits a short pulse with send_gpio_pulse so the handler runs. Replace the pulse call with your own stimulus if you drive the pin from external equipment.
import logging
import threading
from aqpxlib import AqProtocolExerciser, PxGpioWidthTriggerMode, PxIoState
from aqpxlib.event import PxEventMsg
logger = logging.getLogger(__name__)
def run_gpio_trigger_example() -> None:
with AqProtocolExerciser.connect(port=60600) as px:
done = threading.Event()
def on_gpio_trigger(event_msg: PxEventMsg) -> None:
g = event_msg.global_event.gpio_trigger
logger.info(
"GPIO trigger: pin=%d duration_ns=%d polarity=%s",
g.pin_idx,
g.pulse_duration,
g.pulse_polarity,
)
done.set()
px.add_event_handler("gpio_trigger", on_gpio_trigger)
pin = 8
px.set_gpio_trigger(
gpio_idx=pin,
min_duration_ns=500,
max_duration_ns=50_000,
low_pulse=True,
high_pulse=True,
mode=PxGpioWidthTriggerMode.TRIGGER_PULSE_WIDTH_IN_RANGE,
)
px.send_gpio_pulse(
gpio_idx=pin,
active_state=PxIoState.HIGH,
idle_state=PxIoState.LOW,
active_time_ns=5000,
)
assert done.wait(timeout=3), "GPIO trigger event not received"
if __name__ == "__main__":
logging.basicConfig(format="[%(levelname)s] %(message)s")
logger.setLevel(logging.INFO)
run_gpio_trigger_example()
Run:
See also¶
- GPIO read, drive, and pulse —
get_gpio_state,set_gpio_state,send_gpio_pulse - GPIO (API) — mkdocstrings reference for types and exerciser methods
- Event registration and handler setup — device events vs global events
- Basic abstractions — bus and device APIs (GPIO helpers live on
AqProtocolExerciserin code)