Linux IIO Triggered Buffers: Timing, Scan Layout, and Loss Diagnosis
Operate Linux IIO triggered buffers by verifying channel scans, trigger timing, binary layout, throughput limits, and data-loss evidence.
The Industrial I/O subsystem gives userspace a common interface to sensors and converters that produce sampled data. A triggered buffer lets a device collect a sequence of scans and deliver them in batches, rather than requiring a userspace read for every conversion. This improves throughput and gives timestamps or trigger-driven acquisition a defined path, but it does not make samples simultaneous, lossless, or self-describing. Correct operation depends on the device driver’s advertised channels, selected scan elements, trigger source, buffer length, data layout, and the sensor’s conversion capabilities.
The useful diagnostic unit is a scan: the set of enabled channel values associated with one trigger or acquisition cycle. Before trusting a file of binary samples, establish which channels were enabled, how each value is represented, which trigger generated scans, and whether the producer kept up with the requested rate.
Discover the IIO device and its ABI
IIO devices are exposed under /sys/bus/iio/devices/, commonly as iio:deviceN. The numeric suffix is an enumeration detail, not a permanent identity. Match the device to its driver, bus address, label, and kernel log before automation relies on it. The IIO core also exposes buffered character devices, usually /dev/iio:deviceN, when the relevant driver and configuration support them.
Start with read-only discovery:
ls -l /sys/bus/iio/devices/
cat /sys/bus/iio/devices/iio:deviceN/name
find /sys/bus/iio/devices/iio:deviceN -type f \
\( -name '*_index' -o -name '*_type' -o -name '*_en' \) -print
Replace N with the device number you identified. Do not assume every device provides all paths or files. Channel attributes under in_* can describe scale, offset, sampling frequency, or raw conversion values; the exact names and semantics are driver-specific and documented by the device. A raw integer is not necessarily a physical unit. Apply the documented scale and offset only with the correct channel and sign convention.
The scan-element attributes describe the fields that can be included in buffered scans. For each supported channel, inspect its *_index, *_type, and *_en attributes in the directory for the buffer being used. Before Linux 5.11, these attributes were exposed under scan_elements; since Linux 5.11, they are available under a buffer-specific bufferY directory so different buffers can have different scan layouts. The index identifies ordering in the scan, while type describes properties such as signedness, endianness, real bits, storage bits, shift, and repetition. The kernel ABI documentation defines how to interpret these fields. Never decode a binary stream by assuming that channels appear in the order of a datasheet or that every value occupies a separate 16-bit word.
A scan is a binary layout, not a text row
Enabling scan elements determines the fields present in the buffer. The IIO core lays out scan data according to channel metadata, including alignment and padding where needed. A 12-bit converter value can occupy a wider storage word; a signed channel needs sign extension; and multiple scan elements can cause padding so that fields satisfy alignment rules. Optional timestamp channels have their own metadata and may not be enabled by default.
A robust consumer reads the scan-element attributes at startup, constructs a layout from them, and fails closed if a channel is missing or its representation changes. It should not hard-code a C struct based on one kernel/device combination unless it also validates the ABI before consuming data. For each channel, record the source, index, enabled state, type string, scale, and units. Keep timestamps distinct from sensor samples: a timestamp can identify the trigger’s timing reference but cannot prove the sensor performed a simultaneous conversion at that instant.
Userspace tools such as iio_info can help enumerate devices when libiio is installed, but their output is a view of the kernel-exposed interface, not a replacement for the ABI definition. Capture the kernel release and device identity alongside test data so a later decoder can explain how a sample was formed.
Select and verify a trigger
An IIO trigger can originate from the sensor itself, such as a data-ready interrupt, or from a separate trigger provider such as a timer. The trigger/current_trigger attribute, when present, selects the trigger associated with a device’s triggered buffer. Trigger names and available options depend on the hardware and loaded drivers; a label that looks periodic does not establish its actual frequency or jitter.
Inspect available trigger devices and the selected trigger before starting acquisition. Confirm whether the trigger is generated by the sensor, a timer, or another provider. A hardware data-ready trigger can align acquisition with conversion completion; a timer trigger may request reads faster than the device can convert. Some drivers reject unsupported rates, clamp settings, or expose a rate attribute that reflects only the trigger source. Verify effective behavior from the documented device ABI, counters, and captured timestamps.
Triggered-buffer setup in a driver separates a top half and a threaded handler. The top half should do minimal work, often capture a timestamp and wake the thread; the thread performs the device-specific sample retrieval and pushes a scan to the IIO buffer. This division matters when investigating latency: timestamp capture, bus transactions, conversion completion, and userspace read time can all occur at different points. A slow I2C/SPI transaction or lengthy threaded handler can make trigger servicing lag even when the configured rate looks correct.
Configure acquisition conservatively
On a test device, configure only supported channels and a buffer length appropriate for the expected consumer. Check the driver’s available sampling frequencies or sampling-frequency list before requesting a value. Set the trigger only after confirming it is available and compatible. Enable the buffer last, and disable it before changing scan layout or trigger state. The exact sysfs attribute set differs across devices, so scripts should discover and validate required attributes rather than blindly writing a generic recipe.
A read-only inspection sequence can establish the ABI:
for f in /sys/bus/iio/devices/iio:deviceN/buffer*/in_*_{index,type}; do
test -r "$f" && printf '%s: ' "$f" && cat "$f"
done
cat /sys/bus/iio/devices/iio:deviceN/trigger/current_trigger
Since Linux 5.11, scan-element attributes are inside each bufferY directory; older kernels used the device-level scan_elements directory. The pattern above is for current kernels and channel attributes whose names begin with in_; inspect the selected buffer and adapt the pattern for output or differently named channels. The selected trigger file might be absent until a buffered mode is available. An empty value can mean no trigger is selected. Do not enable channels by globbing every *_en file; that can include channels with unexpected units, increased bus traffic, or incompatible scan combinations.
The buffer’s length is a number of scans, not a byte count or time duration by itself. Approximate buffering time as scan count divided by effective scan rate, while accounting for implementation details and scheduling. A larger buffer can absorb userspace scheduling pauses but adds latency and memory use; it does not fix a sustained rate mismatch. The consumer should drain data promptly, handle short reads and interruption, and record overflow or overrun indicators exposed by the driver or library.
Diagnose missing, stale, or corrupted-looking samples
If no data arrives, verify the device is registered, the buffer device exists, scan elements are enabled, a valid trigger is selected, and the buffer is enabled. Check kernel messages for probe failures, IRQ problems, bus errors, or trigger setup rejection. Read configuration back after every write; successful shell redirection only proves that the kernel accepted a write, not that the requested physical sampling behavior is occurring.
If scans arrive with an unexpected cadence, distinguish trigger rate from sensor conversion rate and consumer read cadence. Userspace may read a batch every 100 ms while the kernel recorded many faster scans. Conversely, a fast reader does not make a slow trigger faster. Compare the timestamp channel, if supported, with an external reference or hardware data-ready signal. Do not estimate jitter from userspace read timestamps alone because scheduler delay and buffering intervene.
If values look byte-swapped or drift between fields, re-check *_type, scan indices, alignment, enabled channels, and whether the userspace decoder changed after a kernel or firmware update. A decoder that assumes packed fields may shift every subsequent sample after an alignment boundary. Validate with known input levels and safe operating ranges; do not inject out-of-range voltage or current into a physical sensor to test parsing.
If samples are lost, investigate IRQ affinity, bus saturation, trigger-handler runtime, buffer size, and consumer stalls. A bigger buffer can reduce burst loss if the average consumer rate exceeds production and the interruption is bounded. It cannot compensate indefinitely when the consumer’s long-term throughput is lower than the producer’s. Define what happens on overflow: mark a discontinuity, reset acquisition, or discard the batch. Silently concatenating samples across a known gap can invalidate downstream analysis.
Acceptance test and change record
Test a representative device with a known input and record the kernel release, driver, device identity, selected channels, *_type values, trigger provider, effective rate, buffer length, and timestamp semantics. Measure sustained scans per second and the duration of acquisition. Confirm the data decoder’s handling of sign, endianness, shift, storage width, repeat count, and padding. Test stop and restart, unplug/rebind if supported, and error behavior on the target hardware.
For production telemetry, retain metadata with every capture and treat ABI changes as schema changes. Alert on a missing device, unexpected channel layout, stalled timestamps, dropped scans, and implausible physical ranges. Keep the raw representation available for reprocessing when an interpretation bug is found. An IIO buffer is a transport boundary between kernel acquisition and userspace analysis; preserving its description is part of data integrity.
Related:
- Linux V4L2 Streaming: Buffer Queues, mmap, and Recovery
- Linux GPIO Character Device v2: Line Requests and Event Lifetimes
Sources: