Buffers¶
struct iio_buffer — 通用缓冲区结构
iio_validate_scan_mask_onehot()
— 验证是否只选择了一个通道iio_buffer_get()
— 获取缓冲区的引用iio_buffer_put()
— 释放缓冲区的引用
工业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] 。be或le,指定大端或小端。
s或u,指定有符号(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。 它可以用于一次只能激活一个通道进行采样的设备。
参数
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
参数
struct iio_dev *indio_dev
应将缓冲区附加到的设备
struct iio_buffer *buffer
要附加到设备的缓冲区
描述
如果成功,则返回0,如果出错,则返回负数。
此函数将缓冲区附加到IIO设备。 缓冲区保持附加到设备,直到设备被释放。 由于历史原因,第一个附加的缓冲区也将分配给“indio_dev->buffer”。 此处分配的数组将通过iio_device_detach_buffers()调用释放,该调用由iio_device_free()
处理。