1. 什么是 IIO 子系统?

1.1 IIO 概述

Industrial I/O 子系统旨在为某种意义上是模数或数模转换器 (ADC,DAC) 的设备提供支持,于2009年由 Huawei 的 Jonathan Cameront 添加。

简单框图:

Linux 驱动开发 / IIO子系统入门1-LMLPHP

支持的设备包括:

ADC / DAC
加速度计
磁力计
陀螺仪
压力传感器
湿度传感器
温度传感器
...

很久以前,对于上述硬件的支持散落在 Linux 源码中的各种地方。

IIO 的出现,提供了一个统一的框架用于访问和控制上述各种类型的传感器,并且为用户态应用访问传感器提供了标准的接口:sysfs/devfs,并且填补了 Hwmon 和 Input 子系统之间的空白

另外,IIO 不仅可以支持低速的 SoC ADC,还可支持高速、高数据速率的工业设备,例如 100M samples/sec 工业 ADC。

1.2 IIO 相关的组件

上图基于 STM32 MPU,来源见文末。

1) 客户端应用程序(用户空间):

Linux 驱动开发 / IIO子系统入门1-LMLPHP

Linux 驱动开发 / IIO子系统入门1-LMLPHP

Linux 驱动开发 / IIO子系统入门1-LMLPHP

1) 基础的设备注册和访问

2) 可读取事件的字符设备(Event chrdevs)

3) 支持硬件 buffer

4) 支持 Trigger 和软件 buffer


3. IIO 相关配置

3.1 配置内核

Linux-4.14:

$ make menuconfig
Device Drivers  --->
  <*> Industrial I/O support  --->
    [*]   Enable buffer support within IIO
     < >     IIO callback buffer used for push in-kernel interfaces
     <*>     Industrial I/O HW buffering
     <*>     Industrial I/O buffering based on kfifo
     < >   Enable IIO configuration via configfs                        
     [*]   Enable triggered sampling support
     (2)     Maximum number of consumers per trigger                    
     < >   Enable software triggers support                             
           Accelerometers  --->                                         
           Analog to digital converters  --->                          
           Amplifiers  --->                                             
           Chemical Sensors  --->                                       
           Hid Sensor IIO Common  ----                                  
           SSP Sensor Common  --->                                      
           Digital to analog converters  --->                           
           IIO dummy driver  --->                                       
           Frequency Synthesizers DDS/PLL  --->                         
           Digital gyroscope sensors  --->                              
           Health Sensors  --->                                         
           Humidity sensors  --->                                       
           Inertial measurement units  --->                             
           Light sensors  --->                                          
           Magnetometer sensors  --->                                   
           Inclinometer sensors  ----                                   
           Triggers - standalone  --->                                  
           Digital potentiometers  --->                                 
           Pressure sensors  --->                                       
           Lightning sensors  --->                                      
           Proximity sensors  --->                                      
           Temperature sensors  --->

从配置项的数目来看,IIO 的用途真的很广泛。


3.2 配置设备树

相关参考:

3.2.1 IIO providers

1) 相关要点:

2) 必要属性:

3) 例子1 (no trigger)

adc: voltage-sensor@35 {
  compatible = "maxim,max1139";
  reg = <0x35>;
  #io-channel-cells = <1>;
};

4) 例子2 (with trigger)

adc@35 {
  compatible = "some-vendor,some-adc";
  reg = <0x35>;

  adc1: iio-device@0 {
    #io-channel-cells = <1>;
    /* other properties */
  };
  adc2: iio-device@1 {
    #io-channel-cells = <1>;
    /* other properties */
  };
};

3.2.2 IIO consumers

1) 相关要点:

2) 必要属性:

3) 可选属性:

4) 例子1

some_consumer {
  io-channels = <&adc 1>, <&ref 0>;
  io-channel-names = "vcc""vdd";
 };

上述例子的引用了provider &adc 的第1路 channel,和proiver &ref 的第0路 channel。


4. IIO API

4.1 用户空间 API

相关参考:

4.1.1 4种接口

1). sysfs interface

2). character device

3). configfs

4). debugfs

4.1.2 操作实例

IIO direct mode: 通过 sysfs 以轮循的方式读 ADC 或者写 DAC:
1) 直接读 ADC
确定 sysfs 节点(方式1,不依赖工具)

$ grep -H "" /sys/bus/iio/devices/*/name | grep adc
/sys/bus/iio/devices/iio:device0/name:48003000.adc:adc@0
/sys/bus/iio/devices/iio:device1/name:48003000.adc:adc@1

sysfs 中的 iio:device0 sysfs 对应 ADC1;

$ cd /sys/bus/iio/devices/iio:device0/
$ cat in_voltage6_raw      # Convert ADC1 channel 0 (analog-to-digital): get raw value
40603
$ cat in_voltage_scale     # Read scale
0.044250488
$ cat in_voltage_offset    # Read offset
0
$ awk "BEGIN{printf (\"%d\n\", (40603 + 0) * 0.044250488)}"
1796  

计算公式: Scaled value = (raw + offset) * scale = 1796 mV;

2) 直接写 DAC
确定 sysfs 节点(方式2)

$ lsiio | grep dac
Device 00340017000.dac:dac@1
Device 00440017000.dac:dac@2

sysfs 中的 iio:device3 sysfs 对应 DAC1,lsiio 来源于Linux 内核源码(tools/iio/)。

$ cd /sys/bus/iio/devices/iio:device3/
$ cat out_voltage1_scale              # Read scale
0.708007812
$ awk "BEGIN{printf (\"%d\n\", 2000 / 0.708007812)}"  # 假设要输出 2000 mV
2824
$ echo 2824 > out_voltage1_raw        # Write raw value to DAC1
$ echo 0 > out_voltage1_powerdown     # Enable DAC1 (out of power-down mode)

5. 更多值得学习的知识点

鉴于大多数人的注意力无法在一篇文章里上集中太久,更多的内容请大家先自行去阅读吧,不是自己理解到的东西是消化不了的。有机会的话我会把更多的读书心得放在后面的文章。


6. 相关参考

本文只是一篇入门的文章,仍然有许多细节的知识点没有被描述到。如果本文能让你对 IIO 子系统有个大概的认识,那么本文的目的也就算达成了,以后还会继续写更多 IIO 子系统的文章。知识的学习应该是螺旋上升的,找到一条平缓的学习路线很重要,先有一个整体的概念,然后再不断地去丰富细节会比较好一点。就好像爬山一样,相对于几千米的高山,人类看起来总是显得多么的渺小,但是只要每天平稳地走几百个阶梯,再高的山也能在不知不觉中走完。


思考技术,也要思考人生

学习技术,更要学习如何生活

你和我各有一个苹果,如果我们交换苹果的话,我们还是只有一个苹果。但当你和我各有一个想法,我们交换想法的话,我们就都有两个想法了。

Linux 驱动开发 / IIO子系统入门1-LMLPHP

如果你也对 嵌入式系统 (Linux、RTOS、OpenWrt、Android) 和 开源软件 感兴趣,并且想和更多人互相交流学习的话,请关注我的公众号:嵌入式Hacker,一起来学习吧。

无论是关注或转发,还是打赏,都是对作者莫大的支持。对了,记得点 在看和点赞 ,如果你还想看到我的推送的话。

ps:
欢迎加入我的微信群:加我微信,我拉你进群,暗号(加群)。

祝各位工作顺利,家庭幸福,财源滚滚~


本文分享自微信公众号 - 嵌入式客栈(embInn)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

09-03 12:09