缓冲区

工业 I/O 核心提供了一种基于触发源的连续数据捕获方法。可以从 /dev/iio:deviceX 字符设备节点一次读取多个数据通道,从而降低 CPU 负载。

IIO 缓冲区 sysfs 接口

一个 IIO 缓冲区在 /sys/bus/iio/devices/iio:deviceX/buffer/* 下有一个关联的属性目录。以下是一些现有的属性

  • length,缓冲区可以存储的数据样本总数(容量)。

  • enable,激活缓冲区捕获。

IIO 缓冲区设置

与放置在缓冲区中的通道读取相关的元信息称为扫描元素。配置扫描元素的重要位通过 /sys/bus/iio/devices/iio:deviceX/scan_elements/ 目录暴露给用户空间应用程序。此目录包含以下形式的属性

  • enable,用于启用通道。当且仅当其属性为非 时,触发的捕获才会包含此通道的数据样本。

  • index,通道的 scan_index。

  • type,描述缓冲区内扫描元素数据存储以及从用户空间读取数据的形式。格式为 [be|le]:[s|u]bits/storagebits[Xrepeat][>>shift] 。

    • bele,指定大端或小端。

    • su,指定有符号(补码)或无符号。

    • bits,是有效数据位的数量。

    • storagebits,是在缓冲区中占用的位数(填充后)。

    • repeat,指定位/storagebits 重复的次数。当 repeat 元素为 0 或 1 时,则省略 repeat 值。

    • shift,如果指定,是在屏蔽未使用的位之前需要应用的移位。

例如,一个三轴加速度计的驱动程序,其具有 12 位分辨率,数据存储在两个 8 位寄存器中,如下所示

  7   6   5   4   3   2   1   0
+---+---+---+---+---+---+---+---+
|D3 |D2 |D1 |D0 | X | X | X | X | (LOW byte, address 0x06)
+---+---+---+---+---+---+---+---+

  7   6   5   4   3   2   1   0
+---+---+---+---+---+---+---+---+
|D11|D10|D9 |D8 |D7 |D6 |D5 |D4 | (HIGH byte, address 0x07)
+---+---+---+---+---+---+---+---+

每个轴将具有以下扫描元素类型

$ cat /sys/bus/iio/devices/iio:device0/scan_elements/in_accel_y_type
le:s12/16>>4

用户空间应用程序将解释从缓冲区读取的数据样本为双字节小端有符号数据,在屏蔽掉 12 位有效数据之前需要右移 4 位。

为了实现缓冲区支持,驱动程序应在 iio_chan_spec 定义中初始化以下字段

struct iio_chan_spec {
/* other members */
        int scan_index
        struct {
                char sign;
                u8 realbits;
                u8 storagebits;
                u8 shift;
                u8 repeat;
                enum iio_endian endianness;
               } scan_type;
       };

实现上述加速度计的驱动程序将具有以下通道定义

struct iio_chan_spec accel_channels[] = {
        {
                .type = IIO_ACCEL,
                .modified = 1,
                .channel2 = IIO_MOD_X,
                /* other stuff here */
                .scan_index = 0,
                .scan_type = {
                        .sign = 's',
                        .realbits = 12,
                        .storagebits = 16,
                        .shift = 4,
                        .endianness = IIO_LE,
                },
        }
        /* similar for Y (with channel2 = IIO_MOD_Y, scan_index = 1)
         * and Z (with channel2 = IIO_MOD_Z, scan_index = 2) axis
         */
 }

此处 scan_index 定义了启用的通道在缓冲区内的放置顺序。具有较低 scan_index 的通道将放置在具有较高索引的通道之前。每个通道都需要具有唯一的 scan_index

scan_index 设置为 -1 可用于指示特定通道不支持缓冲捕获。在这种情况下,不会在 scan_elements 目录中为该通道创建任何条目。

更多详细信息

int iio_push_to_buffers_with_timestamp(struct iio_dev *indio_dev, void *data, int64_t timestamp)

将数据和时间戳推送到缓冲区

参数

struct iio_dev *indio_dev

设备的 iio_dev 结构。

void *data

样本数据

int64_t timestamp

样本数据的时间戳

说明

将数据推送到 IIO 设备的缓冲区。如果为设备启用了时间戳,该函数会将提供的时间戳存储为样本数据缓冲区中的最后一个元素,然后再将其推送到设备缓冲区。样本数据缓冲区需要足够大,以便容纳额外的时间戳(通常缓冲区应为 indio->scan_bytes 字节大)。

成功时返回 0,否则返回负错误代码。

bool iio_validate_scan_mask_onehot(struct iio_dev *indio_dev, const unsigned long *mask)

验证是否只选择了一个通道

参数

struct iio_dev *indio_dev

iio 设备

const unsigned long *mask

要检查的扫描掩码

说明

如果扫描掩码中只设置了一个位,则返回 true,否则返回 false。它可以用于一次只能激活一个通道进行采样的设备。

int iio_push_to_buffers(struct iio_dev *indio_dev, const void *data)

推送到注册的缓冲区。

参数

struct iio_dev *indio_dev

设备的 iio_dev 结构。

const void *data

完整扫描。

int iio_push_to_buffers_with_ts_unaligned(struct iio_dev *indio_dev, const void *data, size_t data_sz, int64_t timestamp)

推送到注册的缓冲区,没有对齐或空间要求。

参数

struct iio_dev *indio_dev

设备的 iio_dev 结构。

const void *data

不包括时间戳的通道数据。

size_t data_sz

数据大小。

int64_t timestamp

样本数据的时间戳。

说明

这个 iio_push_to_buffers_with_timestamp() 的特殊变体不需要时间戳的空间,也不需要数据进行 8 字节对齐。但是,它确实需要在第一次调用时进行分配,并在所有调用时进行额外复制,因此应尽可能避免使用。

struct iio_buffer *iio_buffer_get(struct iio_buffer *buffer)

获取缓冲区的引用

参数

struct iio_buffer *buffer

要获取引用的缓冲区,可以为 NULL

说明

返回传递给函数的缓冲区指针。

void iio_buffer_put(struct iio_buffer *buffer)

释放缓冲区的引用

参数

struct iio_buffer *buffer

要释放引用的缓冲区,可以为 NULL

int iio_device_attach_buffer(struct iio_dev *indio_dev, struct iio_buffer *buffer)

将缓冲区附加到 IIO 设备

参数

struct iio_dev *indio_dev

要将缓冲区附加到的设备

struct iio_buffer *buffer

要附加到设备的缓冲区

说明

成功返回 0,错误返回负数。

此函数将缓冲区附加到 IIO 设备。缓冲区会一直附加到设备,直到设备被释放。出于遗留原因,第一个附加的缓冲区也将被分配给 ‘indio_dev->buffer’。 此处分配的数组将通过 iio_device_free() 处理的 iio_device_detach_buffers() 调用释放。