Buffers

工业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,指定有符号(2的补码)或无符号。

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

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

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

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

例如,一个3轴加速度计的驱动程序,其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_detach_buffers()调用释放,该调用由iio_device_free()处理。