Skip to content

IIO Buffered Capture

Time estimate: ~60 minutes Prerequisites: BMI160 SPI Driver (for context), SPI DMA Optimization (for DMA background)

Learning Objectives

By the end of this tutorial you will be able to:

  • Load the mainline BMI160 IIO driver and read sensor data through the IIO sysfs interface
  • Configure IIO buffered mode: scan elements, triggers, and buffer parameters
  • Write a C program that reads high-rate sensor data from /dev/iio:deviceN
  • Compare CPU load and throughput between polled sysfs, custom chardev, and IIO buffered capture
  • Verify DMA activation for SPI bulk transfers
IIO: The Kernel's Standard Sensor Framework

The Industrial I/O (IIO) subsystem is the kernel's standard framework for sensors — accelerometers, gyroscopes, ADCs, pressure sensors, and more. Instead of writing a custom character device with hand-crafted sysfs attributes (as we did in the BMI160 SPI Driver tutorial), IIO provides a standard interface: sysfs channels for polled reads, a ring buffer for high-rate capture, trigger support, automatic timestamps, and a userspace toolchain (iio_readdev, libiio).

The mainline kernel already includes a BMI160 IIO driver (drivers/iio/imu/bmi160/). In this tutorial you will use it — writing zero kernel code — and compare the results to your custom driver.

See also: IIO Subsystem reference | DMA Fundamentals reference

Course Source Repository

This tutorial references source files from the course repository. If you haven't cloned it yet on your Pi:

cd ~
git clone https://github.com/OE-KVK-H2IoT/embedded-linux.git

Source files for this tutorial are in ~/embedded-linux/apps/iio-buffered-capture/ and ~/embedded-linux/overlays/bmi160-iio.dts.


Introduction

In the BMI160 SPI Driver tutorial, you wrote ~530 lines of kernel code to expose the BMI160 as a custom character device. That gave you full control — but also full responsibility for sysfs attributes, data formatting, and any buffering.

The kernel's mainline BMI160 IIO driver gives you the same raw sensor data through a standardized interface — with buffered capture, triggers, timestamps, and DMA support included. In this tutorial you will:

  1. Switch from your custom driver to the mainline IIO driver
  2. Read sensor data via IIO sysfs (polled mode)
  3. Enable buffered capture at 200 Hz
  4. Write a C program to read buffered data from /dev/iio:device0
  5. Compare CPU load across all three approaches

1. Switch to the Mainline IIO Driver

The BMI160 IIO Module Is Not in the Stock Raspberry Pi Kernel

The stock Raspberry Pi OS kernel does not include the BMI160 IIO driver (CONFIG_BMI160 is not set). You need to build it yourself. Choose one of these approaches:

Option A: Build from kernel source (recommended for learning)

# Install kernel headers (package name varies by Pi OS version)
sudo apt install linux-headers-$(uname -r)
# If not found, try: sudo apt install linux-headers-rpi-v8

# Create a build directory
mkdir -p ~/bmi160-iio && cd ~/bmi160-iio

# Download the BMI160 IIO driver source from the RPi kernel repo
KVER=$(uname -r)
# Extract the RPi kernel branch tag (e.g., "rpi-6.12.y" from "6.12.47+rpt-rpi-v8")
KMAJMIN=$(echo $KVER | grep -oP '^\d+\.\d+')
KBRANCH="rpi-${KMAJMIN}.y"
BASE="https://raw.githubusercontent.com/raspberrypi/linux/${KBRANCH}/drivers/iio/imu/bmi160"
for f in bmi160_core.c bmi160_spi.c bmi160_i2c.c bmi160.h; do
    wget -q "$BASE/$f" && echo "Downloaded $f" || echo "Failed: $f"
done

# Create Makefile
cat > Makefile << 'EOF'
obj-m += bmi160_core.o bmi160_spi.o bmi160_i2c.o
KDIR ?= /lib/modules/$(shell uname -r)/build
all:
   make -C $(KDIR) M=$(PWD) modules
clean:
   make -C $(KDIR) M=$(PWD) clean
EOF

make

# ── Fix: SPI timing after soft reset ──
# The upstream driver waits only 1 ms after soft reset, but the BMI160
# needs up to 80 ms to complete startup (datasheet §2.11.1). With 1 ms
# the first SPI read returns 0xFF and the accelerometer stays in suspend.
# Increase the delay and add a pause after the SPI-mode dummy read:
sed -i 's/#define BMI160_SOFTRESET_USLEEP.*/#define BMI160_SOFTRESET_USLEEP         100000/' bmi160_core.c
sed -i '/ret = regmap_read(data->regmap, BMI160_REG_DUMMY, \&val);/{n;s/if (ret)/usleep_range(1000, 2000);\n\t\tif (ret)/}' bmi160_core.c
make clean && make

# Test: load directly from the build directory
# IIO framework modules first, then core, then bus binding:
sudo modprobe industrialio
sudo modprobe industrialio-triggered-buffer
sudo insmod bmi160_core.ko
sudo modprobe regmap-spi
sudo insmod bmi160_spi.ko

# Once verified, install permanently:
sudo mkdir -p /lib/modules/$KVER/extra
sudo cp bmi160_core.ko bmi160_spi.ko /lib/modules/$KVER/extra/
sudo depmod -a
# Now modprobe handles load order automatically:
# sudo modprobe bmi160_spi

# Load on every boot — add all modules to /etc/modules:
sudo tee -a /etc/modules << 'MODS'
industrialio
industrialio-triggered-buffer
regmap-spi
bmi160_core
bmi160_spi
MODS

Option B: Use a Buildroot custom image

If you completed the Buildroot SDL2 Image tutorial, enable CONFIG_BMI160=m, CONFIG_BMI160_SPI=m, and CONFIG_IIO=y in your kernel config. The modules will be included in the image automatically.

Option C: Use rpi-update to switch to a kernel that includes it

Some rpi-testing kernels include CONFIG_BMI160=m. Check with: find /lib/modules/$(uname -r) -name '*bmi160*'

If you have the custom bmi160_spi module from the BMI160 SPI Driver tutorial loaded, unload it first:

# Unload the custom driver
sudo rmmod bmi160_spi

# Load the mainline IIO driver (IIO framework first, then core, then bus binding)
sudo modprobe industrialio          # IIO framework (iio_device_register etc.)
sudo modprobe industrialio-triggered-buffer  # triggered buffer support
sudo modprobe regmap-spi            # SPI regmap (__devm_regmap_init_spi)
sudo insmod ~/bmi160-iio/bmi160_core.ko
sudo insmod ~/bmi160-iio/bmi160_spi.ko

# Or, if you installed the modules with depmod (see Option A above):
# sudo modprobe bmi160_spi
Load Order Matters

Each module depends on symbols from the previous one. With insmod, load in this exact order:

  1. industrialio — IIO framework (iio_device_register, iio_push_to_buffers, etc.)
  2. industrialio-triggered-buffer — triggered buffer support
  3. regmap-spi — SPI regmap (__devm_regmap_init_spi)
  4. bmi160_core.ko — BMI160 channel definitions, register access
  5. bmi160_spi.ko — SPI bus binding

If any step gives Unknown symbol in module, check dmesg | tail — it shows which symbol is missing and which module provides it. Using modprobe (after depmod -a) handles the dependency chain automatically.

Device Tree: compatible String Matters

Your custom driver used compatible = "bmi160" (no vendor prefix). The mainline driver expects compatible = "bosch,bmi160" (with vendor prefix, as required by upstream naming conventions).

Use the IIO-specific overlay:

# Copy fomr the source folder
cp src/embedded-linux/overlays/bmi160-iio.dts ~/bmi160-iio/
# Compile the IIO overlay
dtc -@ -I dts -O dtb -o bmi160-iio.dtbo bmi160-iio.dts
sudo cp bmi160-iio.dtbo /boot/firmware/overlays/

Then in /boot/firmware/config.txt, replace dtoverlay=bmi160-spi with dtoverlay=bmi160-iio and reboot.

The overlay source is in src/embedded-linux/overlays/bmi160-iio.dts.

Verify the IIO device appeared:

cat /sys/bus/iio/devices/iio:device0/name
# → bmi160

ls /sys/bus/iio/devices/iio:device0/in_*
Checkpoint
  1. cat /sys/bus/iio/devices/iio:device0/name shows bmi160
  2. ls /sys/bus/iio/devices/iio:device0/in_accel_* shows in_accel_x_raw, in_accel_y_raw, in_accel_z_raw, in_accel_scale
  3. ls /sys/bus/iio/devices/iio:device0/in_anglvel_* shows gyroscope channels
Stuck?
  • "No iio:device found" — check dmesg | grep bmi160 for probe errors. Verify the Device Tree overlay uses compatible = "bosch,bmi160".
  • "Chip id not found: ff" and accelerometer reads 0 — the soft reset delay is too short. The BMI160 defaults to I2C mode after reset; a dummy SPI read switches it to SPI mode, but both the reset and the mode switch need enough delay. Apply the timing fix from the build step above (increase BMI160_SOFTRESET_USLEEP to 100 ms, add 1 ms delay after the dummy read), rebuild, and reinstall.
  • "Device or resource busy" — another driver has claimed the SPI device. Run lsmod | grep bmi160 and rmmod any custom module first.
  • "modprobe: FATAL: Module not found" — the stock Raspberry Pi OS kernel does not include the BMI160 IIO module. See the warning box above for how to build it.

2. Polled Reads via Sysfs

Read individual channels — each cat triggers one SPI transaction:

IIO=/sys/bus/iio/devices/iio:device0

# Read raw accelerometer values
cat $IIO/in_accel_x_raw
cat $IIO/in_accel_y_raw
cat $IIO/in_accel_z_raw

# Read scale factor
cat $IIO/in_accel_scale
# → 0.000598  (for ±2g range)

# Convert to physical units: physical = raw × scale
# If in_accel_z_raw = 16384: 16384 × 0.000598 = 9.8 m/s² (1g)

Compare with your custom driver output:

# Custom driver (if still available):
cat /sys/class/bmi160/bmi160/accel_x
# vs IIO:
cat /sys/bus/iio/devices/iio:device0/in_accel_x_raw

The values should be identical (same sensor, same register read). The interface is different — IIO uses standardized naming.

Measure Polled Read Speed

# Time 100 sequential sysfs reads
time for i in $(seq 100); do cat $IIO/in_accel_x_raw > /dev/null; done

Each read opens the sysfs file, triggers a kernel call, executes an SPI transaction, and returns. At higher rates, this per-read overhead becomes significant.

Checkpoint
  1. Raw values are consistent between IIO and custom driver (for the same sensor orientation)
  2. The timing test shows measurable per-read overhead (typically 0.5–2 ms per read)

3. Enable Buffered Mode

Why buffered mode? Polled vs buffered at the hardware level

In polled mode (Section 2), every cat in_accel_x_raw triggers this sequence:

Userspace            Kernel (IIO driver)          SPI bus            BMI160
   │                        │                        │                 │
   ├─ open() ──────────────►│                        │                 │
   ├─ read() ──────────────►│                        │                 │
   │                        ├─ spi_sync() ──────────►│                 │
   │                        │                        ├─ CLK + MOSI ───►│
   │                        │                        │◄── MISO ────────┤
   │                        │◄── 2 bytes ────────────┤                 │
   │◄── "16384\n" ──────────┤                        │                 │
   ├─ close() ─────────────►│                        │                 │

Each read is a full round-trip: userspace → kernel → SPI transaction → kernel → userspace. At 100 Hz that's fine. At 1000 Hz, the overhead of 1000 open()/read()/close() syscalls per second dominates — you spend more time in system calls than reading the sensor.

Buffered mode inverts the control flow. Instead of userspace asking for data, a trigger tells the kernel when to sample. The driver reads the sensor and pushes data into a ring buffer (kfifo). Userspace reads batches when ready:

Trigger (IRQ/hrtimer)    Kernel (IIO driver)         SPI bus         BMI160
   │                           │                        │               │
   ├─ IRQ fires ──────────────►│                        │               │
   │                           ├─ spi_sync() ──────────►│               │
   │                           │                        ├─ CLK+MOSI ───►│
   │                           │                        │◄── MISO ──────┤
   │                           ├─ push to kfifo ────────┤               │
   │                           │  (+ timestamp)         │               │
   ├─ IRQ fires ──────────────►│                        │               │
   │                           ├─ spi_sync() ... push   │               │
   │                           :  (repeats at trigger rate)             │
   │                           │                        │               │
                  Userspace    │                        │               │
                     │         │                        │               │
                     ├─ read(/dev/iio:device0) ────────►│               │
                     │◄── batch of N samples ───────────┤               │

Key difference: zero syscalls per sample. Userspace makes one read() and gets hundreds of samples with nanosecond timestamps. The kernel does all the work in interrupt context.

Why a trigger? Why the interrupt pin?

The kernel needs to know when to read the sensor. Three options:

Trigger How it works Pros Cons
Data-ready IRQ BMI160 pulls INT1 pin low when new data is ready. Kernel GPIO interrupt fires → driver reads sensor immediately. Lowest latency, no missed samples, hardware-paced Requires wiring INT1 pin to a GPIO
hrtimer Kernel high-resolution timer fires at a configured rate (e.g., 200 Hz). No extra wiring needed Software-paced — can miss samples if kernel is busy, slight jitter
sysfs Manual echo 1 > trigger_now. Good for testing Not practical for continuous capture

Without any trigger, echo 1 > buffer/enable fails with Invalid argument — the kernel refuses to start buffered capture because it has no way to know when to sample.

The data-ready interrupt in detail

The BMI160 has a configurable INT1 output pin. When the internal ADC finishes a conversion (at the configured sampling_frequency), the chip asserts INT1. This creates a GPIO interrupt on the Raspberry Pi:

  1. BMI160 finishes conversion → pulls INT1 low
  2. Pi's GPIO controller detects the edge → raises an IRQ to the CPU
  3. Kernel runs the IIO trigger handler → calls bmi160_trigger_handler()
  4. Handler reads all enabled channels via SPI → pushes data + timestamp to kfifo
  5. BMI160 deasserts INT1 → ready for the next sample

This is declared in the device tree overlay:

interrupt-parent = <&gpio>;
interrupts = <25 1>;  // GPIO 25, rising edge

Without this declaration, the BMI160 IIO driver does not register a trigger — ls /sys/bus/iio/devices/trigger*/ is empty.

If the INT1 pin is not wired

You can still use buffered mode with the hrtimer software trigger:

sudo modprobe iio-trig-hrtimer
mkdir -p /sys/kernel/config/iio/triggers/hrtimer/my_trigger
echo 200 > /sys/bus/iio/devices/trigger0/sampling_frequency
echo my_trigger > /sys/bus/iio/devices/iio:device0/trigger/current_trigger

This uses a kernel timer instead of the hardware interrupt — slightly more jitter, but no wiring needed.

For polled use cases (like the Doom IMU controller), buffered mode is not needed — direct sysfs reads at 100 Hz are sufficient.

Reference

For the full IIO architecture — channels, triggers, buffers, DMA, and when to use IIO vs a custom driver — see IIO Subsystem reference, particularly §3 Sysfs Interface and §4 Buffered Mode and Triggers.

Select Channels

IIO=/sys/bus/iio/devices/iio:device0

# Enable accelerometer channels
echo 1 > $IIO/scan_elements/in_accel_x_en
echo 1 > $IIO/scan_elements/in_accel_y_en
echo 1 > $IIO/scan_elements/in_accel_z_en

# Enable gyroscope channels
echo 1 > $IIO/scan_elements/in_anglvel_x_en
echo 1 > $IIO/scan_elements/in_anglvel_y_en
echo 1 > $IIO/scan_elements/in_anglvel_z_en

# Enable timestamp
echo 1 > $IIO/scan_elements/in_timestamp_en

Check Scan Element Format

cat $IIO/scan_elements/in_accel_x_type
# → le:s16/16>>0
# Meaning: little-endian, signed 16-bit, stored in 16 bits, no shift

cat $IIO/scan_elements/in_timestamp_type
# → le:s64/64>>0
# Meaning: little-endian, signed 64-bit (nanoseconds)

Set Trigger and Buffer

# List available triggers
cat /sys/bus/iio/devices/trigger*/name

# Set trigger (data-ready IRQ if available, or hrtimer)
# Option A: BMI160 data-ready trigger
echo bmi160-dev0 > $IIO/trigger/current_trigger

# Option B: hrtimer trigger (if no hardware IRQ)
# sudo modprobe iio-trig-hrtimer
# echo 200 > /sys/bus/iio/devices/trigger0/sampling_frequency

# Set sample rate (if using data-ready trigger)
echo 200 > $IIO/sampling_frequency

# Set buffer length (number of sample sets)
echo 256 > $IIO/buffer/length

# Enable buffer
echo 1 > $IIO/buffer/enable

Quick Test

# Read buffered data (binary)
cat /dev/iio:device0 | hexdump -C | head -20

# Or use iio_generic_buffer (from kernel tools)
iio_generic_buffer -n bmi160 -t bmi160-dev0 -c 10

Stop the buffer when done:

echo 0 > $IIO/buffer/enable
Checkpoint
  1. hexdump shows continuous binary data with changing values
  2. Data stops when you disable the buffer
  3. dmesg shows no errors during capture
Stuck?
  • "No trigger available" — load the hrtimer trigger module: sudo modprobe iio-trig-hrtimer
  • "Permission denied" on /dev/iio:device0 — run with sudo or add a udev rule
  • "Device or resource busy" when enabling buffer — disable the buffer first (echo 0 > buffer/enable), then reconfigure scan elements

4. C Program: High-Rate Capture

Write a C program that reads buffered IIO data, parses the binary format, and prints timestamped samples.

The source code is in src/embedded-linux/apps/iio-buffered-capture/iio_capture.c:

/* iio_capture.c — Read BMI160 IIO buffered data
 *
 * Usage: sudo ./iio_capture [device_num] [num_samples]
 *
 * Reads scan element format from sysfs, opens /dev/iio:deviceN,
 * and prints timestamped accelerometer + gyroscope data.
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>

#define IIO_SYSFS "/sys/bus/iio/devices/iio:device%d"
#define IIO_DEV   "/dev/iio:device%d"

/* One sample set: 6 × int16 channels + padding + int64 timestamp */
struct iio_sample {
    int16_t accel_x;
    int16_t accel_y;
    int16_t accel_z;
    int16_t anglvel_x;
    int16_t anglvel_y;
    int16_t anglvel_z;
    int16_t _pad;      /* alignment padding to 8-byte boundary */
    int64_t timestamp;
} __attribute__((packed));

static float read_float_attr(int dev_num, const char *attr)
{
    char path[256];
    snprintf(path, sizeof(path), IIO_SYSFS "/%s", dev_num, attr);
    FILE *f = fopen(path, "r");
    if (!f) { perror(path); exit(1); }
    float val;
    if (fscanf(f, "%f", &val) != 1) { fprintf(stderr, "Bad value: %s\n", path); exit(1); }
    fclose(f);
    return val;
}

int main(int argc, char *argv[])
{
    int dev_num = argc > 1 ? atoi(argv[1]) : 0;
    int num_samples = argc > 2 ? atoi(argv[2]) : 100;

    /* Read scale factors */
    float accel_scale = read_float_attr(dev_num, "in_accel_scale");
    float gyro_scale = read_float_attr(dev_num, "in_anglvel_scale");

    printf("Accel scale: %f, Gyro scale: %f\n", accel_scale, gyro_scale);
    printf("Sample size: %zu bytes\n", sizeof(struct iio_sample));

    /* Open the IIO character device */
    char dev_path[64];
    snprintf(dev_path, sizeof(dev_path), IIO_DEV, dev_num);
    int fd = open(dev_path, O_RDONLY);
    if (fd < 0) { perror(dev_path); return 1; }

    printf("Reading %d samples from %s...\n\n", num_samples, dev_path);
    printf("%12s  %8s %8s %8s  %8s %8s %8s\n",
           "timestamp_ns", "ax", "ay", "az", "gx", "gy", "gz");

    struct iio_sample sample;
    int count = 0;

    while (count < num_samples) {
        ssize_t n = read(fd, &sample, sizeof(sample));
        if (n < 0) {
            if (errno == EAGAIN) continue;
            perror("read");
            break;
        }
        if (n != sizeof(sample)) {
            fprintf(stderr, "Short read: %zd bytes\n", n);
            continue;
        }

        printf("%12ld  %8.3f %8.3f %8.3f  %8.3f %8.3f %8.3f\n",
               (long)sample.timestamp,
               sample.accel_x * accel_scale,
               sample.accel_y * accel_scale,
               sample.accel_z * accel_scale,
               sample.anglvel_x * gyro_scale,
               sample.anglvel_y * gyro_scale,
               sample.anglvel_z * gyro_scale);
        count++;
    }

    close(fd);
    printf("\nCaptured %d samples.\n", count);
    return 0;
}

Build and Run

cd ~/embedded-linux/apps/iio-buffered-capture
gcc -Wall -O2 -o iio_capture iio_capture.c
sudo ./iio_capture 0 100
Buffer Must Be Enabled First

The C program reads from /dev/iio:device0, which only produces data when buffered mode is active. Enable it with the shell commands from Section 3 before running iio_capture.

Checkpoint
  1. The program prints 100 timestamped samples
  2. Accelerometer Z shows ~9.8 m/s² when flat (gravity)
  3. Timestamps increment by ~5 ms (at 200 Hz sampling)
  4. Gyroscope values are near zero when stationary

5. DMA Verification

Check whether SPI DMA is active during buffered capture:

# Check for SPI DMA channel allocation
dmesg | grep -i dma
# Look for: "spi-bcm2835 ... DMA channel ... allocated"

When DMA Activates

At 200 Hz with 6 channels × 2 bytes = 12 bytes per sample, each individual SPI read is 12 bytes — well below the DMA threshold (~96 bytes). PIO is used for each trigger event.

To trigger DMA, you need bulk reads — for example, reading the BMI160's hardware FIFO in one burst:

  • FIFO watermark set to 50 samples: 50 × 12 = 600 bytes per SPI transaction → DMA
  • Without FIFO: each trigger reads 12 bytes → PIO
# Monitor CPU load during capture
mpstat 1 10

# Compare:
# 1. IIO buffered at 200 Hz (individual reads, PIO) → moderate %sys
# 2. If FIFO burst reads were enabled → lower %sys (DMA)
DMA Threshold

The BCM2835 SPI driver uses DMA for transfers ≥ 96 bytes. Individual sensor reads (2–12 bytes) always use PIO. DMA kicks in when reading the sensor's hardware FIFO in bulk. For the full picture, see DMA Fundamentals.


6. Comparison

Fill in the table with your measurements:

Metric Custom chardev (/dev/bmi160) IIO polled (sysfs) IIO buffered (/dev/iio:device0)
CPU load at 200 Hz ___% ___% ___%
Max samples/sec ___ ___ ___
Timestamp accuracy Manual ktime_get() None (user adds) Kernel iio_get_time_ns()
Driver code lines ~530 0 (mainline) 0 (mainline)
App complexity Simple read() sysfs string parse Binary buffer parse
DMA potential Manual No Automatic (with FIFO)

Key Observations

  • IIO polled has the highest per-read overhead (sysfs open/read/close for each value)
  • Custom chardev reads all axes in one read() call — efficient for polled use
  • IIO buffered has the lowest CPU load at high rates — data accumulates in a kernel ring buffer
  • Timestamps: IIO buffered provides kernel-quality nanosecond timestamps automatically

For a discussion of when each approach is best: Custom Driver vs Mainline IIO.


What Just Happened?

You used the mainline BMI160 IIO driver — zero kernel code written — to achieve high-rate sensor capture with buffered mode:

Step What you did What IIO provided
Switch driver Changed compatible string, loaded mainline module Standard sysfs channels
Polled reads cat in_accel_x_raw One SPI transaction per read
Buffered mode Configured scan elements, trigger, buffer kfifo ring buffer, timestamps
C program Parsed binary stream from /dev/iio:device0 Consistent binary format
DMA check Monitored dmesg and mpstat Automatic DMA for bulk transfers

The IIO framework handles buffering, triggers, timestamps, and DMA — the same features you would need to implement manually in a custom driver.


Challenges

Challenge 1: hrtimer Trigger

If your setup has no data-ready IRQ, use the hrtimer trigger instead. Load iio-trig-hrtimer, create a trigger, and configure the sampling frequency. Compare timestamp jitter between hrtimer and data-ready triggers.

Challenge 2: Log to CSV

Modify iio_capture.c to write samples directly to a CSV file. Capture 10 seconds of movement data and plot with matplotlib or gnuplot. Compare the plot to the custom chardev log from the BMI160 tutorial Challenge 3.

Challenge 3: libiio Capture

Install libiio-dev and rewrite the capture program using the libiio API (iio_create_local_context, iio_device_create_buffer, iio_buffer_refill). This approach handles scan element parsing automatically.


Deliverable

Item Description
IIO device screenshot cat /sys/bus/iio/devices/iio:device0/name and channel listing
Buffered capture output Terminal output of iio_capture showing timestamped samples
CPU load comparison mpstat output during polled vs buffered capture
Filled comparison table Section 6 table with your measurements
DMA verification dmesg output showing SPI DMA channel allocation

Course Overview | Previous: ← SPI DMA Optimization | Next: Custom IIO Driver →