linux IIO驱动框架开发流程说明

一、Linux IIO 框架基础

IIO(Industrial I/O)是 Linux 内核专为测量类 / 传感类设备设计的框架,区别于面向人机交互的 Input 框架,主要适配加速度计、陀螺仪、ADC/DAC、压力传感器等模拟 / 数字传感器。

1. IIO 核心组件
组件作用
struct iio_devIIO 设备核心结构体,代表一个 IIO 设备,需分配、初始化并注册到内核
struct iio_chan_spec通道描述结构体,定义传感器的每个测量通道(如 acc_x/gyro_z)
struct iio_info包含 IIO 设备的核心操作函数(如数据读取、参数配置)
sysfs 接口IIO 框架自动导出的用户空间访问接口(路径:/sys/bus/iio/devices/iio:deviceX/
IIO Trigger/Buffer触发机制(中断 / 定时器)+ 数据缓冲区,用于批量采集传感器数据
2. IIO 框架优势
  • 统一的用户空间接口,无需自定义节点;
  • 原生支持传感器的 “测量值读取”“参数配置(量程 / 采样率)”;
  • 支持轮询 / 中断两种数据读取方式,适配不同传感器场景。

二、ACC/GYRO 驱动开发整体流程

ACC(加速度计,输出单位:m/s²)和 GYRO(陀螺仪,输出单位:rad/s)通常为 I2C/SPI 接口,驱动开发核心流程如下:

步骤 1:梳理传感器硬件特性

开发前需明确传感器关键参数:

  • 通信接口:I2C/SPI 地址、寄存器映射(数据寄存器、配置寄存器、中断寄存器);
  • 数据格式:原始数据位宽(如 16 位补码)、量程(如 acc ±2g/±4g,gyro ±250°/s);
  • 工作模式:轮询读取、中断触发读取;
  • 校准参数:硬件 / 软件校准偏移量(可选)。
步骤 2:设备树(DTB)配置

在设备树中定义传感器节点,以 I2C 接口的 MPU6050(集成 acc+gyro)为例:

&i2c1 {
    clock-frequency = <400000>;
    mpu6050@68 {  /* I2C 地址 0x68 */
        compatible = "invensense,mpu6050";
        reg = <0x68>;
        interrupt-parent = <&gpio1>;
        interrupts = <20 IRQ_TYPE_EDGE_RISING>;  /* 中断引脚 */
        avdd-supply = <&vdd_3v3>;  /* 供电 */
        dvdd-supply = <&vdd_1v8>;
    };
};
步骤 3:驱动代码实现(核心)

以 MPU6050(acc+gyro 组合传感器)为例,实现基于 IIO 框架的驱动:

3.1 头文件与结构体定义
#include <linux/i2c.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/module.h>

// 传感器私有数据
struct mpu6050_data {
    struct i2c_client *client;
    struct mutex lock;  // 保护寄存器访问
    u16 acc_range;      // 加速度计量程(±2g/±4g/±8g/±16g)
    u16 gyro_range;     // 陀螺仪量程(±250/±500/±1000/±2000 °/s)
};

// 通道定义:acc(x/y/z) + gyro(x/y/z)
static const struct iio_chan_spec mpu6050_channels[] = {
    // 加速度计 X 轴
    {
        .type = IIO_ACCEL,
        .channel = IIO_X,
        .address = 0x3B,  // ACC_X 数据寄存器起始地址
        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
    },
    {
        .type = IIO_ACCEL,
        .channel = IIO_Y,
        .address = 0x3D,
        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
    },
    {
        .type = IIO_ACCEL,
        .channel = IIO_Z,
        .address = 0x3F,
        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
    },
    // 陀螺仪 X 轴
    {
        .type = IIO_GYRO,
        .channel = IIO_X,
        .address = 0x43,  // GYRO_X 数据寄存器起始地址
        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
    },
    {
        .type = IIO_GYRO,
        .channel = IIO_Y,
        .address = 0x45,
        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
    },
    {
        .type = IIO_GYRO,
        .channel = IIO_Z,
        .address = 0x47,
        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
    },
};

3.2 核心操作函数(数据读取 / 配置)

// 读取原始数据(寄存器值)
static int mpu6050_read_raw(struct iio_dev *indio_dev,
                           struct iio_chan_spec const *chan,
                           int *val, int *val2, long mask)
{
    struct mpu6050_data *data = iio_priv(indio_dev);
    __be16 raw_data;
    int ret;

    mutex_lock(&data->lock);
    switch (mask) {
    case IIO_CHAN_INFO_RAW:
        // 读取 16 位数据寄存器(两个字节)
        ret = i2c_smbus_read_i2c_block_data(data->client, chan->address, 2, (u8 *)&raw_data);
        if (ret < 0) {
            mutex_unlock(&data->lock);
            return ret;
        }
        // 转换为主机字节序(传感器输出大端)
        *val = (s16)be16_to_cpu(raw_data);
        mutex_unlock(&data->lock);
        return IIO_VAL_INT;

    case IIO_CHAN_INFO_SCALE:
        // 转换量程为物理单位(acc: g→m/s²;gyro: °/s→rad/s)
        if (chan->type == IIO_ACCEL) {
            // ±2g 对应 scale=16384 LSB/g → 1g=9.80665 m/s²
            *val = 980665;  // 9.80665 * 10^5
            *val2 = 1638400; // 16384 * 100
        } else if (chan->type == IIO_GYRO) {
            // ±250°/s 对应 scale=131 LSB/(°/s) → 1°/s=0.01745 rad/s
            *val = 1745;    // 0.01745 * 10^5
            *val2 = 13100;  // 131 * 100
        }
        mutex_unlock(&data->lock);
        return IIO_VAL_FRACTIONAL;

    default:
        mutex_unlock(&data->lock);
        return -EINVAL;
    }
}

// IIO 设备操作集
static const struct iio_info mpu6050_iio_info = {
    .read_raw = mpu6050_read_raw,
    .driver_module = THIS_MODULE,
};

3.3 Probe 函数(驱动初始化)

static int mpu6050_probe(struct i2c_client *client)
{
    struct iio_dev *indio_dev;
    struct mpu6050_data *data;
    int ret;

    // 1. 分配 IIO 设备结构体
    indio_dev = devm_iio_device_alloc(&client->dev, sizeof(struct mpu6050_data));
    if (!indio_dev)
        return -ENOMEM;

    // 2. 初始化私有数据
    data = iio_priv(indio_dev);
    data->client = client;
    mutex_init(&data->lock);
    i2c_set_clientdata(client, indio_dev);

    // 3. 硬件初始化(复位、配置量程)
    // 写入电源管理寄存器,唤醒传感器
    ret = i2c_smbus_write_byte_data(client, 0x6B, 0x00);
    if (ret < 0)
        return ret;
    // 配置加速度计量程(±2g)
    ret = i2c_smbus_write_byte_data(client, 0x1C, 0x00);
    if (ret < 0)
        return ret;
    // 配置陀螺仪量程(±250°/s)
    ret = i2c_smbus_write_byte_data(client, 0x1B, 0x00);
    if (ret < 0)
        return ret;

    // 4. 初始化 IIO 设备核心参数
    indio_dev->name = "mpu6050";
    indio_dev->info = &mpu6050_iio_info;
    indio_dev->channels = mpu6050_channels;
    indio_dev->num_channels = ARRAY_SIZE(mpu6050_channels);
    indio_dev->dev.parent = &client->dev;
    indio_dev->modes = INDIO_DIRECT_MODE;  // 直接读取模式(轮询)

    // 5. 注册 IIO 设备
    return devm_iio_device_register(&client->dev, indio_dev);
}

// I2C 驱动匹配表
static const struct i2c_device_id mpu6050_id[] = {
    { "mpu6050", 0 },
    { }
};
MODULE_DEVICE_TABLE(i2c, mpu6050_id);

static const struct of_device_id mpu6050_of_match[] = {
    { .compatible = "invensense,mpu6050" },
    { }
};
MODULE_DEVICE_TABLE(of, mpu6050_of_match);

static struct i2c_driver mpu6050_driver = {
    .driver = {
        .name = "mpu6050",
        .of_match_table = mpu6050_of_match,
    },
    .probe = mpu6050_probe,
    .id_table = mpu6050_id,
};
module_i2c_driver(mpu6050_driver);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("MPU6050 IIO driver for ACC/GYRO");
步骤 4:功能流程说明
4.1 驱动加载流程

4.2 数据读取流程(用户空间→内核)

以读取加速度 X 轴数据为例:

4.3 量程配置扩展(可选)

若需支持动态配置量程,可实现 write_raw 函数:

static int mpu6050_write_raw(struct iio_dev *indio_dev,
                            struct iio_chan_spec const *chan,
                            int val, int val2, long mask)
{
    struct mpu6050_data *data = iio_priv(indio_dev);
    int reg_val = 0;

    if (mask != IIO_CHAN_INFO_SCALE)
        return -EINVAL;

    mutex_lock(&data->lock);
    if (chan->type == IIO_ACCEL) {
        // 根据scale值设置量程寄存器(0x1C)
        if (val == 980665 && val2 == 1638400)
            reg_val = 0x00;  // ±2g
        else if (val == 1961330 && val2 == 1638400)
            reg_val = 0x08;  // ±4g
        // ... 其他量程
        i2c_smbus_write_byte_data(data->client, 0x1C, reg_val);
        data->acc_range = reg_val;
    }
    mutex_unlock(&data->lock);
    return 0;
}
4.4 中断触发读取(可选)

若传感器支持数据就绪中断,可配置 IIO Trigger + Buffer 实现批量采集:

  1. 注册中断处理函数,监听传感器 “数据就绪” 中断;
  2. 初始化 IIO Trigger(中断触发);
  3. 启用 IIO Buffer,中断触发时自动读取数据并写入缓冲区;
  4. 用户空间通过 /dev/iio:deviceX 读取缓冲区数据。

一、中断触发读取的核心原理

中断触发读取是 IIO 框架的进阶用法,核心是利用传感器的 数据就绪中断(DRDY) 替代轮询,实现 “数据准备好才读取”,降低 CPU 占用。整体流程:

二、驱动层开发(基于 MPU6050 扩展中断 + Buffer)

以下是在之前轮询驱动的基础上,新增 中断注册、IIO Trigger、IIO Buffer 相关代码,实现中断触发读取:

步骤 1:扩展私有数据结构体

新增中断号、IIO Trigger、Buffer 相关成员:

#include <linux/interrupt.h>
#include <linux/iio/buffer.h>
#include <linux/iio/trigger.h>
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>

// 扩展私有数据结构体
struct mpu6050_data {
    struct i2c_client *client;
    struct mutex lock;
    u16 acc_range;
    u16 gyro_range;
    int irq;                  // 中断号
    struct iio_trigger *trig; // IIO触发器
    struct completion comp;   // 用于同步(可选)
};

// 定义扫描元素(需要采集的通道,顺序对应数据缓冲区格式)
static const struct iio_chan_spec mpu6050_channels[] = {
    // 加速度计 X 轴
    {
        .type = IIO_ACCEL,
        .channel = IIO_X,
        .address = 0x3B,
        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
        .scan_index = 0,       // 扫描索引(缓冲区中第0个数据)
        .scan_type = {
            .sign = 's',       // 有符号数
            .realbits = 16,    // 有效位宽
            .storagebits = 16, // 存储位宽
            .endianness = IIO_BE, // 传感器输出大端
        },
    },
    {
        .type = IIO_ACCEL,
        .channel = IIO_Y,
        .address = 0x3D,
        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
        .scan_index = 1,
        .scan_type = { .sign = 's', .realbits = 16, .storagebits = 16, .endianness = IIO_BE },
    },
    {
        .type = IIO_ACCEL,
        .channel = IIO_Z,
        .address = 0x3F,
        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
        .scan_index = 2,
        .scan_type = { .sign = 's', .realbits = 16, .storagebits = 16, .endianness = IIO_BE },
    },
    // 陀螺仪 X 轴
    {
        .type = IIO_GYRO,
        .channel = IIO_X,
        .address = 0x43,
        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
        .scan_index = 3,
        .scan_type = { .sign = 's', .realbits = 16, .storagebits = 16, .endianness = IIO_BE },
    },
    {
        .type = IIO_GYRO,
        .channel = IIO_Y,
        .address = 0x45,
        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
        .scan_index = 4,
        .scan_type = { .sign = 's', .realbits = 16, .storagebits = 16, .endianness = IIO_BE },
    },
    {
        .type = IIO_GYRO,
        .channel = IIO_Z,
        .address = 0x47,
        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE),
        .scan_index = 5,
        .scan_type = { .sign = 's', .realbits = 16, .storagebits = 16, .endianness = IIO_BE },
    },
    IIO_CHAN_SOFT_TIMESTAMP(6), // 可选:添加时间戳(索引6)
};

步骤 2:实现中断处理函数 & Trigger 回调

// 中断处理函数(传感器DRDY中断触发)
static irqreturn_t mpu6050_irq_handler(int irq, void *dev_id)
{
    struct mpu6050_data *data = dev_id;
    
    // 触发IIO Trigger(通知Buffer采集数据)
    iio_trigger_poll(data->trig);
    
    return IRQ_HANDLED;
}

// Buffer 数据采集函数(Trigger触发后执行)
static void mpu6050_trigger_handler(struct iio_trigger *trig, void *p)
{
    struct iio_dev *indio_dev = p;
    struct mpu6050_data *data = iio_priv(indio_dev);
    int ret;
    u8 buf[12]; // 6个通道 × 2字节 = 12字节(acc x/y/z + gyro x/y/z)
    
    mutex_lock(&data->lock);
    
    // 一次性读取所有通道数据(0x3B开始,连续12字节)
    ret = i2c_smbus_read_i2c_block_data(data->client, 0x3B, 12, buf);
    if (ret < 0) {
        mutex_unlock(&data->lock);
        dev_err(&data->client->dev, "读取传感器数据失败: %d\n", ret);
        return;
    }
    
    // 将数据写入IIO Buffer(自动处理字节序/格式转换)
    iio_push_to_buffers_from_active(indio_dev, buf);
    
    mutex_unlock(&data->lock);
}

// 注册Trigger的回调函数集
static const struct iio_trigger_ops mpu6050_trigger_ops = {
    .trigger_handler = mpu6050_trigger_handler,
    .owner = THIS_MODULE,
};

步骤 3:扩展 Probe 函数(初始化中断 + Trigger+Buffer)

static int mpu6050_probe(struct i2c_client *client)
{
    struct iio_dev *indio_dev;
    struct mpu6050_data *data;
    int ret;
    
    // 1. 分配IIO设备结构体(同轮询版)
    indio_dev = devm_iio_device_alloc(&client->dev, sizeof(struct mpu6050_data));
    if (!indio_dev)
        return -ENOMEM;
    
    // 2. 初始化私有数据
    data = iio_priv(indio_dev);
    data->client = client;
    data->irq = client->irq; // 从设备树获取中断号
    mutex_init(&data->lock);
    init_completion(&data->comp);
    i2c_set_clientdata(client, indio_dev);
    
    // 3. 硬件初始化(新增:开启DRDY中断)
    ret = i2c_smbus_write_byte_data(client, 0x6B, 0x00); // 唤醒传感器
    if (ret < 0) return ret;
    
    ret = i2c_smbus_write_byte_data(client, 0x1C, 0x00); // ACC量程±2g
    if (ret < 0) return ret;
    
    ret = i2c_smbus_write_byte_data(client, 0x1B, 0x00); // GYRO量程±250°/s
    if (ret < 0) return ret;
    
    // 配置MPU6050中断:开启DRDY中断,中断引脚为高电平触发
    ret = i2c_smbus_write_byte_data(client, 0x38, 0x01); // 使能DRDY中断
    if (ret < 0) return ret;
    ret = i2c_smbus_write_byte_data(client, 0x37, 0x00); // 中断引脚不做其他配置
    if (ret < 0) return ret;
    
    // 4. 注册中断处理函数
    ret = devm_request_irq(&client->dev, data->irq, mpu6050_irq_handler,
                           IRQF_TRIGGER_RISING | IRQF_ONESHOT,
                           "mpu6050_drdy", data);
    if (ret < 0) {
        dev_err(&client->dev, "注册中断失败: %d\n", ret);
        return ret;
    }
    
    // 5. 创建并注册IIO Trigger
    data->trig = devm_iio_trigger_alloc(&client->dev, "%s-dev%d", client->name, indio_dev->id);
    if (!data->trig) return -ENOMEM;
    
    data->trig->dev.parent = &client->dev;
    data->trig->ops = &mpu6050_trigger_ops;
    data->trig->private_data = indio_dev;
    
    ret = devm_iio_trigger_register(&client->dev, data->trig);
    if (ret < 0) {
        dev_err(&client->dev, "注册Trigger失败: %d\n", ret);
        return ret;
    }
    
    // 将Trigger绑定到IIO设备
    iio_trigger_set_drvdata(data->trig, indio_dev);
    indio_dev->trig = data->trig;
    
    // 6. 配置IIO Buffer
    indio_dev->name = "mpu6050";
    indio_dev->info = &mpu6050_iio_info;
    indio_dev->channels = mpu6050_channels;
    indio_dev->num_channels = ARRAY_SIZE(mpu6050_channels);
    indio_dev->dev.parent = &client->dev;
    indio_dev->modes = INDIO_BUFFER_TRIGGERED; // 触发式Buffer模式(区别于轮询)
    
    // 初始化Triggered Buffer(自动创建字符设备/dev/iio:deviceX)
    ret = iio_triggered_buffer_setup(indio_dev, NULL, NULL, NULL);
    if (ret < 0) {
        dev_err(&client->dev, "初始化Buffer失败: %d\n", ret);
        return ret;
    }
    
    // 7. 注册IIO设备
    ret = devm_iio_device_register(&client->dev, indio_dev);
    if (ret < 0) {
        iio_triggered_buffer_cleanup(indio_dev);
        return ret;
    }
    
    return 0;
}

// 移除函数(可选:清理Buffer)
static void mpu6050_remove(struct i2c_client *client)
{
    struct iio_dev *indio_dev = i2c_get_clientdata(client);
    iio_triggered_buffer_cleanup(indio_dev);
}

// 更新I2C驱动结构体(添加remove函数)
static struct i2c_driver mpu6050_driver = {
    .driver = {
        .name = "mpu6050",
        .of_match_table = mpu6050_of_match,
    },
    .probe = mpu6050_probe,
    .remove = mpu6050_remove,
    .id_table = mpu6050_id,
};
步骤 4:驱动编译(新增依赖)

需确保内核配置开启 IIO Buffer 和 Trigger 相关选项:

# 内核配置项(.config)
CONFIG_IIO_BUFFER=y
CONFIG_IIO_TRIGGERED_BUFFER=y
CONFIG_IIO_TRIGGER=y

三、应用层获取中断触发的数据

应用层通过 IIO 框架创建的 字符设备文件(/dev/iio:deviceX) 读取 Buffer 数据,核心流程是 “配置 Buffer→启用 Trigger→读取数据”。

3.1 应用层示例代码(C 语言)
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/ioctl.h>
#include <linux/iio/iio.h>

// 定义数据结构体(对应驱动层的扫描元素顺序)
typedef struct {
    int16_t acc_x;  // 加速度X轴
    int16_t acc_y;  // 加速度Y轴
    int16_t acc_z;  // 加速度Z轴
    int16_t gyro_x; // 陀螺仪X轴
    int16_t gyro_y; // 陀螺仪Y轴
    int16_t gyro_z; // 陀螺仪Z轴
    uint64_t ts;    // 时间戳(可选)
} mpu6050_data_t;

#define IIO_DEV_PATH "/dev/iio:device0" // 根据实际设备号修改

int main() {
    int fd, ret;
    mpu6050_data_t data;
    fd_set rfds;
    struct timeval tv;

    // 1. 打开IIO字符设备
    fd = open(IIO_DEV_PATH, O_RDONLY);
    if (fd < 0) {
        perror("打开设备失败");
        return -1;
    }

    // 2. 配置Buffer(可选:设置单次读取的采样数,这里设为1)
    int buf_len = 1;
    ret = ioctl(fd, IIO_BUFFER_SET_LEN, &buf_len);
    if (ret < 0) {
        perror("设置Buffer长度失败");
        close(fd);
        return -1;
    }

    // 3. 启用Trigger(关联到传感器的DRDY中断)
    // 先将trigger_current指向我们的mpu6050 trigger
    FILE *fp = fopen("/sys/bus/iio/devices/iio:device0/trigger/current_trigger", "w");
    if (!fp) {
        perror("打开trigger配置文件失败");
        close(fd);
        return -1;
    }
    fprintf(fp, "mpu6050-dev0"); // Trigger名称(对应驱动层的命名)
    fclose(fp);

    // 4. 启用Buffer(开始采集数据)
    fp = fopen("/sys/bus/iio/devices/iio:device0/buffer/enable", "w");
    if (!fp) {
        perror("打开buffer enable文件失败");
        close(fd);
        return -1;
    }
    fprintf(fp, "1");
    fclose(fp);

    // 5. 循环读取中断触发的数据
    while (1) {
        FD_ZERO(&rfds);
        FD_SET(fd, &rfds);
        tv.tv_sec = 5;  // 超时5秒
        tv.tv_usec = 0;

        // 等待数据就绪(中断触发后Buffer有数据)
        ret = select(fd + 1, &rfds, NULL, NULL, &tv);
        if (ret < 0) {
            perror("select失败");
            break;
        } else if (ret == 0) {
            printf("超时未收到数据\n");
            continue;
        }

        // 读取Buffer中的数据
        ret = read(fd, &data, sizeof(mpu6050_data_t));
        if (ret != sizeof(mpu6050_data_t)) {
            perror("读取数据失败");
            continue;
        }

        // 打印数据(原始值,可乘以scale转换为物理单位)
        printf("acc_x: %d, acc_y: %d, acc_z: %d | gyro_x: %d, gyro_y: %d, gyro_z: %d\n",
               data.acc_x, data.acc_y, data.acc_z,
               data.gyro_x, data.gyro_y, data.gyro_z);
    }

    // 6. 关闭前清理
    fp = fopen("/sys/bus/iio/devices/iio:device0/buffer/enable", "w");
    fprintf(fp, "0");
    fclose(fp);
    close(fd);

    return 0;
}
3.3 关键说明
  • 设备号确认:通过 ls /sys/bus/iio/devices/ 查看实际的 iio:deviceX 编号;
  • 数据格式匹配:应用层 mpu6050_data_t 的成员顺序必须和驱动层 scan_index 一致;
  • 物理值转换:原始值 × scale = 物理值(如 acc 的 scale 约为 0.000598 m/s²/LSB);
  • 异步读取:推荐用 select/poll/epoll 监听数据就绪,避免轮询占用 CPU。

四、总结

  1. 驱动层核心
    • 注册传感器 DRDY 中断,中断触发后调用 iio_trigger_poll() 通知 Buffer;
    • 创建 IIO Trigger 并绑定回调函数,回调中读取传感器数据并写入 Buffer;
    • 配置 INDIO_BUFFER_TRIGGERED 模式,替代轮询的 INDIO_DIRECT_MODE
  2. 应用层核心
    • 打开 /dev/iio:deviceX 字符设备,配置 Buffer 长度并启用 Trigger;
    • 通过 select/poll 监听数据就绪,读取 Buffer 中的批量数据;
    • 数据格式需与驱动层 scan_index 严格匹配,确保数据解析正确。
  3. 优势:中断触发读取相比轮询,CPU 占用率更低,适合高频数据采集场景(如运动检测、惯性导航)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值