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  文件中,结构体内容如下(有省略): 

     

我们需要看一下比较重要的几个成员变量:

第 477 行,modes 为设备支持的模式,可选择的模式如下图所示,我们通常选择的是第一个模式

第 478 行,currentmode 为当前模式。

第 483 行,buffer 为缓冲区。

第 484 行,buffer_list 为当前匹配的缓冲区列表。

第 485 行,scan_bytes 为捕获到,并且提供给缓冲区的字节数。

第 488 行,available_scan_masks 为可选的扫描位掩码,使用触发缓冲区的时候可以通过设置掩码来确定使能哪些通道,使能以后的通道会将捕获到的数据发送到 IIO 缓冲区。

第 490 行,active_scan_mask 为缓冲区已经开启的通道掩码。只有这些使能了的通道数据才能被发送到缓冲区。

第 491 行,scan_timestamp 为扫描时间戳,如果使能以后会将捕获时间戳放到缓冲区里面。

第 493 行,trig 为 IIO 设备当前触发器,当使用缓冲模式的时候。

第 494 行,pollfunc 为一个函数,在接收到的触发器上运行。

第 496 行,channels 为 IIO 设备通道,为 iio_chan_spec 结构体类型,后面会详细讲解 IIO通道。

第 497 行,num_channels 为 IIO 设备的通道数。

第 501 行,name 为 IIO 设备名字。

第 502 行,info为iio_info结构体类型,这个结构体里面有很多的函数,需要驱动开发人员编写,非常重要!我们从用户空间读取IIO设备内部数据,最终调用的就是iio_info里面的函数。
第 504 行,setup_ops 为 iio_buffer_setup_ops 结构体类型,内容如下:

可以看出 iio_buffer_setup_ops 里面都是一些回调函数,在使能或禁用缓冲区的时候会调用这些函数。如果未指定的话就默认使用 iio_triggered_buffer_setup_ops。

2,iio_dev申请与释放

在使用之前肯定要先申请iio_dev,申请函数为iio_device_alloc,函数原型如下:

sizeof_priv:私有数据内存空间大小,一般我们会将我们自己定义的设备结构体变量作为iio_dev的私有数据,这样可以直接通过iio_device_alloc函数同时完iio_dev和设备结构体变量的内存申请。申请成功后,我们可以私有iio_priv函数来得到自定义的设备结构体变量首地址。

返回值:如果申请成功就返回iio_dev首地址,失败返回NULL

一般iio_device_alloc和iio_priv之间的配合使用如下:

第 1 行,icm20608_dev 是自定义的设备结构体。

第 2 行,indio_dev 是 iio_dev 结构体变量指针。也就是我们要申请的变量。
第 5 行,使用 iio_device_alloc 函数来申请 iio_dev,并且一起申请了 icm2060_dev 的内存。
第 10 行,使用 iio_priv 函数从 iio_dev 中提取出私有数据,也就是 icm2608_dev 这个自定义结构体变量首地址。
如果要释放iio_dev,需要使用iio_device_free函数,原型如下:

也可以使用devm_iio_device_alloc来分配iio_dev,这样就不需要我们手动调用iio_device_free函数来完成iio_dev的释放工作。

3,iio_dev注册和注销

前面分配好iio_dev以后就要初始化各种成员变量,初始化完成以后就需要将iio_dev祖册到内核中,需要用到iio_device_register函数,函数原型如下:

indio_dev:需要注册的iio_dev

返回值:0,成功;其他值,失败;

注销iio_dev对应的iio_device_unregister函数,函数原型如下:

 iio_info

        iio_dev有一个成员变量:info,为iio_info结构体指针变量,这个是我们在编写IIO驱动的时候需要去实现的,因为用户空间对设备的具体操作都会反映到iio_info里面。iio_info结构体定义在include/linux/iio/iio.h 中,结构体定义如下:

第 355 行,attrs 是通用的设备属性。

第 357 和 370 行,分别为 read_raw 和 write_raw 函数,这两个函数就是最终读写设备内部数据的操作函数,需要程序编写人员去实现的。比如应用读取一个陀螺仪传感器的原始数据,那么最终完成工作就是read_raw函数,我们需要在read_raw函数里面实现对陀螺仪芯片的读取操作,同理,write_rad是应用程序向陀螺仪写数据,一般用于配置芯片,比如量程,数据速率等。这两个函数的参数都是一样的,我们依次来看一下:
        
        indio_dev:需要读写的IIO设备
        
        chan:需要读取的通道
        val,val2:对于read_raw函数来说val和val2这两个就是应用程序从内核空间读取到数据,一般就是传感器指定通道值,或者传感器的量程,分辨率等。对write_raw来说就是应用程序向设备写数据。val 和 val2 共同组成具体值,val 是整数部分,val2 是小数部分。但是,val2 也是对具体的小数部分扩大 N 倍后的整数值,因为不能直接从内核向应用程序返回一个小数值。扩大的倍数我们不能随便设置,而是要使用 Linux 定义的倍数,Linux 内核里面定义的数据扩大倍数,或者说数据组合形式如下表所示:

mask:掩码,用于指定我们读取的是什么数据,比如ICM20608这样的传感器,他既有原始的测量数据,比如 X,Y,Z 轴的陀螺仪、加速度计等。也有测量范围值,或者分辨率,比如加速度计测量范围设置为(正负)16g,那么分辨率就是32/65536=0.000488,我们只有读出原始值,分辨率。linux内核使用 IIO_CHAN_INFO_RAW 和 IIO_CHAN_INFO_SCALE 这两个宏来表示原始值以及分辨率,这两个宏就是掩码。至于每个通道可以采用哪几种掩码,这个在我们初始化通道的时候需要驱动编写人员设置好。掩码有很多种,稍后讲解 IIO 通道的时候详细讲解!

第 376 行的 write_raw_get_fmt 用于设置用户空间向内核空间写入的数据格式,write_raw_get_fmt 函数决定了 wtite_raw 函数中 val 和 val2 的意义也就是上面表中的组合形式。比如我们需要在应用程序中设置ICM20608加速度计的量程为(正负)8g,那么分辨率就是16/65536=0.000244,我们再write_raw_get_fmt函数里面设置加速度计的护具格式为IIO_VAL_INT_PLUS_MICRO。那么我们再应用程序向指定文件写入0.000244以后,最终传递给内核驱动的就是0.000244*1000000=244,也就是write_raw函数的val参数为0,val2参数为244。(主要就是内核空间和用户空间之间不能传递小数,前面的组合形式都是为了将小数扩大进行两者之间的传输,当设置为上面表中的组合形式,那么小数就会被自动扩大成整数进行两着之间传输,传入完成后内核空间或者用户空间自动将其变为小数)

iio_chan_spec

IIO的核心就是通道,一个传感器可能有多路数据,比如一个ADC芯片支持8路采集,那么这个ADC就有8个通道。例如ICM20608,这是一个六轴传感器,可以输出三轴陀螺仪(X、Y、Z)、三轴加速度计(X、Y、Z)和一路温度,也就是一共有7路数据,因此就有7个通道。

Linux 内核使用 iio_chan_spec 结构体来描述通道,定义在 include/linux/iio/iio.h 文件中,内容如下:

第 224 行,type 为通道类型, iio_chan_type 是一个枚举类型,列举出了可以选择的通道类型,定义在 include/uapi/linux/iio/types.h 文件里面,内容如下:

         像是ICM20608,是一种复合类型的了,陀螺仪部分是 IIO_ANGL_VEL 类型加速度计部分是 IIO_ACCEL 类型,温度部分就是 IIO_TEMP。

第 226 行,当成员变量 modified 为 1 的时候,channel2 为通道修饰符。Linux 内核给出了可用的通道修饰符,定义在 include/uapi/linux/iio/types.h 文件里面。

比如ICM20608的加速度计部分,类型设置为IIO_ACCEL,X,Y,Z这三个轴就用channel2的通道修饰符来区分。IIO_MOD_X、IIO_MOD_Y、IIO_MOD_Z 就分别对应 X、Y、Z 这三个轴。通道修饰符主要是影响 sysfs 下的通道文件名字,后面我们会讲解 sysfs 下通道文件名字组成形式。

第 227 行的 address 成员变量用户可以自定义,但是一般会设置为此通道对应的芯片数据寄存器地址 。比如 ICM20608 的加速度计 X 轴这个通道,它的数据首地址就是 0X3B。address 也可以用作其他功能,自行选择,也可以不使用 address,一切以实 际情况为准。

第 228 行,当使用触发缓冲区的时候,scan_index 是扫描索引。

第 229~236,scan_type 是一个结构体,描述了扫描数据在缓冲区中的存储格式。我们依次来看一下 scan_type 各个成员变量的涵义:

.sign:如果为‘u’表示数据为无符号类型,为‘s’的话为有符号类型。

.realbits:数据真实的有效位数,比如很多传感器说的 10 位 ADC,其真实有效数据就是 10 位。

.storagebits:存储位数,有效位数+填充位。比如有些传感器 ADC 是 12 位的,那么我们存储的话肯定要用到 2 个字节,也就是 16 位,这 16 位就是存储位数。

.shift: 右移位数,也就是存储位数和有效位数不一致的时候,需要右移的位数,这个参数不总是需要,一切以实际芯片的数据手册位数。

.repeat:实际或存储位的重复数量。

.endianness: 数据的大小端模式,可设置为 IIO_CPU、IIO_BE(大端)或 IIO_LE(小端)。

第 237 行,info_mask_separate 标记某些属性专属于此通道,include/linux/iio/types.h 文件中的 iio_chan_info_enum 枚举类型描述了可选的属性值,如下所示:

比如ICM20608加速度计的X,Y,Z这三个轴,在sysfs下这三个轴肯定是对应三个不同的文件,我们通过读取这三个文件就能得到每个轴的原始数据。IIO_CHAN_INFO_RAW这个属性表示原始数据,当我们配置X,Y,Z,这是三个通道的时候,在info_mask_separate中使能IIO_CHAN_INFO_RAW这个属性,那么就表示在sysfs下生成三个不同的文件分别对应X,Y,Z轴,这三个轴的IIO_CHAN_INFO_RAW属性是相互独立的。

第 238 行,info_mask_shared_by_type 标记导出的信息由相同类型的通道共享。也就是 .type 成员变量相同的通道。比如 ICM20608 加速度计的 X、Y、Z 轴他们的 type 都是 IIO_ACCEL,也就是类型相同。而这三个轴的分辨率(量程)是一样的,那么在配置这三个通道的时候就可以在 info_mask_shared_by_type 中使能 IIO_CHAN_INFO_SCALE 这个属性,表示这三个通道的分辨率是共用的,这样在 sysfs 下就会只生成一个描述分辨率的文件,这三个通道都可以使用这一个分辨率文件。

第 246 行,modified 为 1 的时候,channel2 为通道修饰符。
第 247 行,indexed 为 1 的时候,channel 为通道索引。

第 248 行,output 表示为输出通道。

第 249 行,differential 表示为差分通道。

IIO驱动框架搭建

由上面分析IIO子系统的时候大家已经看出来了,IIO驱动框架主要是用于ADC类的传感器,比如陀螺仪、加速度计、磁力计、光强度计等,这些传感器基本都是 IIC 或者 SPI 接口的。因此 IIO 驱动的基础框架就是 IIC 或者 SPI。有些 SOC 内部的 ADC 也会使用 IIO 框架,那么这个时候驱动的基础框架 就是 platfrom。

首先我们需要搭建SPI(IIC)驱动框架,当设备和驱动匹配成功之后,probe函数就会执行。

IIO 设备申请与初始化

        IIO 设备的申请、初始化以及注册在 probe 函数中完成,在注销驱动的时候还需要在 remove函数中注销掉 IIO 设备、释放掉申请的一些内存。

嵌入式linux IIO驱动相关推荐

  1. linux cached释放_正点原子Linux第四十一章嵌入式Linux LED驱动开发实验

    1)资料下载:点击资料即可下载 2)对正点原子Linux感兴趣的同学可以加群讨论:935446741 3)关注正点原子公众号,获取最新资料更新 第四十一章嵌入式Linux LED驱动开发实验 上一章我 ...

  2. linux内核创建字符节点,Tiny6410学习ing—(四)、嵌入式Linux内核驱动进阶—(7)、高级字符设备驱动(自动创建节点)—#931...

    按照国嵌的视频教程上来说的,最后就是-自动创建设备文件! 其实我感觉以前完全可以直接是手动创建了设备文件,然后就可以直接讲述自动创建设备文件,为啥非要拖到最后来讲述,我也就不清楚了!! 不管了,写完收 ...

  3. STM32MP157驱动开发——Linux IIO驱动(上)

    STM32MP157驱动开发--Linux IIO驱动(上 ) 0.前言 一.IIO 子系统简介 1.iio_dev 结构体 2.iio_dev 申请与释放 3.iio_dev 注册与注销 4.iio ...

  4. 【正点原子Linux连载】第四十一章 嵌入式Linux LED驱动开发实验 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0

    1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...

  5. 嵌入式linux设备驱动开发,嵌入式Linux设备驱动开发简介.pdf

    清远见--嵌入式培训专家 http :// "黑色经典"系列之<嵌入式Linux 应用程序开发详解> 11 章 嵌入式Linux 设备驱动开发 本章目标 本书从 6 章 ...

  6. 有限状态机的嵌入式Linux按键驱动设计(转载)

    本文转载自边缘之火<有限状态机的嵌入式Linux按键驱动设计(转载)> 原文链接:  http://www.eccn.com/design_2010052509381340.htm 秦国栋 ...

  7. STM32MP157驱动开发——Linux IIO驱动(下)

    STM32MP157驱动开发--Linux IIO驱动(下) 0.前言 一.IIO 触发缓冲区 1.IIO 触发器 2.申请触发器 3.释放触发器 4.注册触发器 5.注销触发器 6. IIO 缓冲区 ...

  8. 【正点原子MP157连载】第二十一章 嵌入式Linux LED驱动开发实验-摘自【正点原子】STM32MP1嵌入式Linux驱动开发指南V1.7

    1)实验平台:正点原子STM32MP157开发板 2)购买链接:https://item.taobao.com/item.htm?&id=629270721801 3)全套实验源码+手册+视频 ...

  9. 嵌入式 Linux 内核驱动开发【The first day: 36093万字】

    嵌入式 Linux 内核驱动开发[1] 嵌入式 Linux 内核驱动开发前言 第1章 Linux 内核裁剪和定制 [1]Linux 内核开发简介 [2] Linux 源码阅读工具 [1.2.1]Sou ...

最新文章

  1. EEPlat vs saleforce 配置 Knowledge Article 演示样例
  2. PE文件结构 - 数据目录表学习
  3. Python Flask web 项目零改动迁移至阿里云函数计算
  4. 掌握这 25 条小贴士,快速提升数据可视化能力!
  5. 统计字符串每个字符出现的次数
  6. POJ 1581 优先队列 priority_queue -- 比赛胜者求解
  7. 微信或正测试“发送语音过程”转文字功能 部分安卓用户可用
  8. 中判断字符串是否为空_自己动手编写VBA代码,判断一个工作表是否为空,然后删除它...
  9. 管理感悟:谈谈用户和需求
  10. mysql data masking_Percona8.0.17的数据屏蔽插件的使用
  11. ios 热更新可行性分析
  12. PIC单片机-Mplab的使用与实践
  13. 按键精灵---后台按键及鼠标操作
  14. php 调用 百度句法分析,【原创源码】百度新版翻译API调用使用范例
  15. final_cut_pro基础
  16. 石器时代地图->魔力宝贝地图
  17. Kotlin 之 lateinit关键字 与lazy
  18. 最新弹幕播放器源码/支持对接苹果+蓝光接口API
  19. JMeter BeanShell 应用
  20. 金蟾论金:4.13黄金探底回升收复跌势、晚间黄金走势分析指导

热门文章

  1. 1、Mac如何剪切文件
  2. vue keys detected: '1111'. This may cause an update error.
  3. SharePoint Log分析 —— HRESULT: 0x8007007E
  4. 如何用PS(photoshop)给照片加文字
  5. 分析称惠普赶走前任CEO赫德堪比苹果赶走乔布斯
  6. s1 Linux 硬件基础
  7. Windows系统下布置Redis服务器
  8. 汽车电瓶电压12V验证
  9. java 拼音_GitHub - promeG/TinyPinyin: 适用于Java和Android的快速、低内存占用的汉字转拼音库。...
  10. leetcode 58. 最后一个单词的长度(Length of Last Word)