一文带你深入了解Linux IIO 子系统
【推荐阅读】
一文剖析Linux内核中内存管理
分析linux启动内核源码
关于如何快速学好,学懂Linux内核。内含学习路线
工业场合里面也有大量的模拟量和数字量之间的转换,也就是我们常说的 ADC 和 DAC。而且随着手机、物联网、工业物联网和可穿戴设备的爆发,传感器的需求只持续增强。比如手机或者手环里面的加速度计、光传感器、陀螺仪、气压计、磁力计等,这些传感器本质上都是ADC,大家注意查看这些传感器的手册,会发现他们内部都会有个 ADC,传感器对外提供 IIC或者 SPI 接口,SOC 可以通过 IIC 或者 SPI 接口来获取到传感器内部的 ADC 数值,从而得到想要测量的结果。Linux 内核为了管理这些日益增多的 ADC 类传感器,特地推出了 IIO 子系统,我们学习如何使用 IIO 子系统来编写 ADC 类传感器驱动。
1、IIO 子系统简介
IIO 全称是 Industrial I/O,翻译过来就是工业 I/O,大家不要看到“工业”两个字就觉得 IIO 是只用于工业领域的。大家一般在搜索 IIO 子系统的时候,会发现大多数讲的都是 ADC,这是因为 IIO 就是为 ADC 类传感器准备的,当然了 DAC 也是可以的。大家常用的陀螺仪、加速度计、电压/电流测量芯片、光照传感器、压力传感器等内部都是有个 ADC,内部 ADC 将原始的模拟数据转换为数字量,然后通过其他的通信接口,比如 IIC、SPI 等传输给 SOC。
因此,当你使用的传感器本质是 ADC 或 DAC 器件的时候,可以优先考虑使用 IIO 驱动框架。
1、iio_dev 结构体
IIO 子系统使用结构体 iio_dev 来描述一个具体 IIO 设备,此设备结构体定义在include/linux/iio/iio.h 文件中
2、iio_dev 申请与释放
在使用之前要先申请 iio_dev,申请函数为 iio_device_alloc,函数原型如下:
struct iio_dev *iio_device_alloc(int sizeof_priv)
sizeof_priv:私有数据内存空间大小,一般我们会将自己定义的设备结构体变量作为 iio_dev 的私有数据,这样可以直接通过 iio_device_alloc 函数同时完成 iio_dev 和设备结构体变量的内存申请。申请成功以后使用 iio_priv 函数来得到自定义的设备结构体变量首地址。
返回值:如果申请成功就返回 iio_dev 首地址,如果失败就返回 NULL。
3、iio_dev 注册与注销
前面分配好 iio_dev 以后就要初始化各种成员变量,初始化完成以后就需要将 iio_dev 注册 到内核中,需要用到 iio_device_register 函数
4、iio_info
iio_dev 有个成员变量:info,为 iio_info 结构体指针变量,这个是我们在编写 IIO 驱动的时候需要着重去实现的,因为用户空间对设备的具体操作最终都会反映到 iio_info 里面。iio_info结构体定义在 include/linux/iio/iio.h 中
5、iio_chan_spec
IIO 的核心就是通道,一个传感器可能有多路数据,比如一个 ADC 芯片支持 8 路采集,那么这个 ADC 就有 8 个通道。Linux 内核使用 iio_chan_spec 结构体来描述通道,定义在 include/linux/iio/iio.h 文件中。
2、IIO 驱动框架创建
分析 IIO 子系统的时候大家应该看出了,IIO 框架主要用于 ADC 类的传感器,比如陀螺仪、加速度计、磁力计、光强度计等,这些传感器基本都是 IIC 或者 SPI 接口的。因此 IIO 驱动的基础框架就是 IIC 或者 SPI,我们可以在 IIC 或 SPI 驱动里面在加上 regmap。当然了,有些 SOC 内部的 ADC 也会使用 IIO 框架,那么这个时候驱动的基础框架就是 platfrom。
IIO 设备的申请、初始化以及注册在 probe 函数中完成,在注销驱动的时候还需要在 remove 函数中注销掉 IIO 设备、释放掉申请的一些内存。
以 SPI 接口为例,demo 如下
/* 自定义设备结构体 */
struct xxx_dev { struct spi_device *spi; /* spi 设备 */struct regmap *regmap; /* regmap */struct regmap_config regmap_config;struct mutex lock;
};/*
* 通道数组
*/
static const struct iio_chan_spec xxx_channels[] = {};/*
* @description : 读函数,当读取 sysfs 中的文件的时候最终此函数会执行,
* :此函数里面会从传感器里面读取各种数据,然后上传给应用。
* @param - indio_dev : IIO 设备
* @param - chan : 通道
* @param - val : 读取的值,如果是小数值的话,val 是整数部分。
* @param - val2 : 读取的值,如果是小数值的话,val2 是小数部分。
* @param - mask : 掩码。
* @return : 0,成功;其他值,错误
*/
static int xxx_read_raw(struct iio_dev *indio_dev,struct iio_chan_spec const *chan,int *val, int *val2, long mask)
{return 0;
} /*
* @description : 写函数,当向 sysfs 中的文件写数据的时候最终此函数
* :会执行,一般在此函数里面设置传感器,比如量程等。
* @param - indio_dev : IIO 设备
* @param - chan : 通道
* @param - val : 应用程序写入值,如果是小数的话,val 是整数部分。
* @param - val2 : 应用程序写入值,如果是小数的话,val2 是小数部分。
* @return : 0,成功;其他值,错误
*/
static int xxx_write_raw(struct iio_dev *indio_dev,struct iio_chan_spec const *chan,int val, int val2, long mask)
{return 0;
}/*
* @description : 用户空间写数据格式,比如我们在用户空间操作 sysfs 来设
* :置传感器的分辨率,如果分辨率带小数,那么这个小数传递到
* : 内核空间应该扩大多少倍,此函数就是用来设置这个的。
* @param - indio_dev : iio_dev
* @param - chan : 通道
* @param - mask : 掩码
* @return : 0,成功;其他值,错误
*/
static int xxx_write_raw_get_fmt(struct iio_dev *indio_dev,struct iio_chan_spec const *chan, long mask)
{return 0;
}/*
* iio_info 结构体变量
*/
static const struct iio_info xxx_info = {.read_raw = xxx_read_raw,.write_raw = xxx_write_raw,.write_raw_get_fmt = &xxx_write_raw_get_fmt,
};/*
* @description : spi 驱动的 probe 函数,当驱动与
* 设备匹配以后此函数就会执行
* @param - spi : spi 设备
*
*/
static int xxx_probe(struct spi_device *spi)
{int ret;struct xxx_dev *data;struct iio_dev *indio_dev;/* 1、申请 iio_dev 内存 */indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*data));if (!indio_dev)return -ENOMEM;/* 2、获取 xxx_dev 结构体地址 */data = iio_priv(indio_dev);data->spi = spi;spi_set_drvdata(spi, indio_dev);mutex_init(&data->lock);/* 3、初始化 iio_dev 成员变量 */indio_dev->dev.parent = &spi->dev;indio_dev->info = &xxx_info;indio_dev->name = "xxx";indio_dev->modes = INDIO_DIRECT_MODE; /* 直接模式 /indio_dev->channels = xxx_channels;indio_dev->num_channels = ARRAY_SIZE(xxx_channels);iio_device_register(indio_dev);/* 4、regmap 相关设置 *//* 5、SPI 相关设置*//* 6、芯片初始化 */return 0;}/*
* @description : spi 驱动的 remove 函数,移除 spi 驱动的时候此函数会执行
* @param - spi : spi 设备
* @return : 0,成功;其他负值,失败
*/
static int xxx_remove(struct spi_device *spi)
{struct iio_dev *indio_dev = spi_get_drvdata(spi);struct xxx_dev *data;data = iio_priv(indio_dev); ;/* 1、其他资源的注销以及释放 *//* 2、注销 IIO */iio_device_unregister(indio_dev);return 0;
}
3、使能内核 IIO 相关配置
Linux 内核默认使能了 IIO 子系统,但是有一些 IIO 模块没有选择上,这样会导致我们编译 驱动的时候会提示某些 API 函数不存在,需要使能的项目如下:
-> Device Drivers -> Industrial I/O support (IIO [=y])-> [*]Enable buffer support within IIO //选中-> <*>Industrial I/O buffering based on kfifo //选中
IIO 驱动框架提供了 sysfs 接口,因此加载成功以后我们可以在用户空间访问对应的 sysfs 目录项,进入目录“/sys/bus/iio/devices/”目录里面,此目录下都是 IIO 框架设备。
一文带你深入了解Linux IIO 子系统相关推荐
- 【转】 linux iio子系统
原文网址:http://blog.csdn.net/tsy20100200/article/details/47101661 最近由于工作的需要,接触了Linux iio子系统,对于这个目录其实以前是 ...
- Linux的iio数据流程,linux iio子系统
转自http://blog.csdn.net/tsy20100200/article/details/47101661 最近由于工作的需要,接触了Linux iio子系统,对于这个目录其实以前是很少接 ...
- LINUX IIO子系统分析之一 IIO子系统概述
从本章开始,我们进行IIO子系统专栏的分析文档,本次IIO子系统专栏分析文档大概包含如下几章: 一. IIO子系统概述 二.IIO子系统相关数据结构分析 三.iio trigger 介绍 四.iio ...
- LINUX IIO子系统分析之五IIO BUFFER子模块实现分析
上一章我们介绍了iio子系统中的iio event模块,本章我们将介绍iio buffer模块,iio buffer主要用于连续数据采集与缓存功能.IIO buffer模块借助IIO DEVICE字符 ...
- LINUX IIO子系统分析之二 IIO子系统相关数据结构分析
上一章我们简要说明了IIO子系统的架构,本章我们通过数据结构的定义,分析IIO子系统的设计实现,本章的主要内容如下: 一.IIO子系统各数据结构说明 二.数据结构间的关联说明 一.IIO子系统各数据结 ...
- LINUX IIO子系统分析之七 虚拟iio device驱动实现
前面几章我们基本完成了IIO子系统的所有内容,而该章即为本专栏的结束篇,主要用来实现一个虚拟的IIO DEVICE DRIVER,本章的内容主要包括如下几部分: 一. 虚拟IIO DEVICE的说明 ...
- LINUX IIO子系统分析之四 IIO EVENT介绍
上一章我们介绍了iio子系统中的iio trigger模块,本章我们将介绍iio event模块,iio event主要用于阈值监测.自由落体监测等监测功能.因为IIO EVENT涉及IIO DEVI ...
- LINUX IIO子系统分析之六 iio device的驱动开发流程说明
前面五章我们基本上把IIO 子系统的内部设计实现均作了说明,本章我们将说明iio device的驱动开发流程,本章的主要内容大致安排如下: 一.IIO子系统的关键技术点总结 二.IIO DEVICE的 ...
- linux IIO子系统使用说明
新的内核将ADC/DAC/G_sensor这样的设备统一成IIO子系统,用户层通过访问IIO的接口来实现如ADC的触发.采样等操作. 下面给出IIO接口用户层的接口使用实例(以ADC的采样为例) 1. ...
最新文章
- 职中计算机应用教学方法,职中《计算机应用基础》教学心得体会
- oralce中级OCP考试时间和题量以及通过率
- 物理光学8 多波束干涉
- 成功解决NameError: name ‘norm‘ is not defined
- Busy Dialog init - hashchange will call BusyDialog.open - flower
- 69 session和cookie的区别
- java 并发 set_高并发下的Java数据结构(List、Set、Map、Queue)
- 2016 Multi-University Training Contest 1 T4
- apache自定义虚拟主机日志格式
- 【面经】关于逻辑回归,面试官们都怎么问
- 安利一款倒计时插件---雨滴桌面
- 《人月神话》7(The Mythical Man-Month)为什么巴比伦塔会失败?
- Windows11 正式版 iso镜像下载
- 大数据时代网络舆情与社会治理研究
- 【js】判断时间段之间是否有重叠
- win10移动桌面图标字体发虚
- EasyPlayerPro RTMP播放器助力远程娃娃机直播抓娃娃技术方案
- 基于Redission实现分布式锁
- 【全套资料.zip下载】数电课设-数字频率计Multisim仿真设计【Multisim仿真+报告+讲解视频.zip下载】
- 面向儿童的简易编程工具---Scratch
热门文章
- Kaggle 注册问题
- 一种更简单的求最小平方均值函数(MSE)的方法 -- 梯度下降法。
- 半小时读懂互联网广告新生态
- 使用动态规划求解算法问题的五大特点总结(附基于Python的参考代码)
- 抖音怎么知道自己上热门 手机视频md5值修改
- handsontable 给单元格设置下拉 菜单
- 天冷服务器自动关机,天冷iphone自动关机怎么办 天冷iphone自动关机解决办法【详解】...
- 阿卡迪亚大学计算机专业好考吗,普通高中学生如何考取阿卡迪亚大学?
- SEM竞价推广创意快速撰写的方法,智能创意制作
- uploadify html5 java_工作中碰到uploadify插件两个版本:HTML5和Flash