你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

Linux IIO 子系统入门知识

[复制链接]
gaosmile 发布时间:2020-7-29 11:53

前阵子工作上做了一些关于 ADC 的支持,由于现在 ADC 相关的支持都被移动到了 IIO (Industrial I/O) 子系统下,我查阅了一些关于 IIO 资料,包括书籍、文章、内核文档和代码。个人感觉最好的入门文章应该是 ST WiKi 网站上 的 IIO Overview(2019) 和 Analog Device Wiki 网站上的 Linux Industrial I/O Subsystem(2017),为了方便爱偷懒或者英文不好的小伙伴,我提炼了多篇文章的精华内容并在其基础上进行完善,尽量控制篇幅,希望能给大家提供一点小小的帮助。

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

正文目录:

1. 什么是 IIO 子系统?
5 x" Q% u3 W$ `2 G. i0 D) L  1.1 IIO 概述
* B, I4 s, t0 x  1.2 IIO 相关的组件" {3 X2 h; S) D& e) }2 o
2. IIO 功能特性
; x! G2 Z' X+ d; d2 C3. IIO 相关配置  
8 w- j6 f0 Z6 m. M  Z  3.1 配置内核
, ]0 Y; U' |( O2 Z% |  3.2 配置设备树
/ G, {' M2 O# r    3.2.1 IIO providers/ C9 X" R: |: E. U# x
    3.2.2 IIO consumers
! I- l* E; W, A8 a& d+ y4. IIO API
6 R8 @$ a2 u8 T# F0 l( i  4.1 用户空间 API
2 N+ |1 I, ~7 N' r$ K1 c    4.1.1 4种接口' ?% W1 P9 Q" J' {# @# o% V3 W
    4.1.2 操作实例
! y" U1 L& Y4 L5 ^* m5. 更多值得学习的知识点# I  c+ u8 g% ]7 ^, M) z1 X
6. 相关参考

0 ~  Q! S4 N. F/ X2 x* x: l

写作目的:

  • 整理一些 IIO 子系统的入门知识。5 M1 H, z1 B! i- I. `; I9 J

1. 什么是 IIO 子系统?1.1 IIO 概述

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

简单框图:" _3 @6 u  J7 M2 y9 K4 v' j  ]6 }

微信图片_20200729115135.png

支持的设备包括:
9 a; t  y! i. a6 @+ ]8 ]1 z* |

ADC / DAC
% F6 @: T- K- Z& Z* G7 a加速度计# P" F: G6 O6 `
磁力计# x) `/ ?4 O' R1 q2 P
陀螺仪
, Q' X; Z4 W; i& \2 {压力传感器# i* |6 O5 N, a# y) F: H; c
湿度传感器
0 E% T/ q. x3 \. a' m: a温度传感器
" H, Y7 c4 q2 j...
/ z8 q6 O* l! I+ a

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

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

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

1.2 IIO 相关的组件
微信图片_20200729115141.png
IIO-overview: L; r9 x: v5 b; Q5 X  v

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

1) 客户端应用程序(用户空间):
& [* E$ f% {$ K; `& b6 y2 W/ s

微信图片_20200729115144.png

0 f- z1 I/ R+ P3 |$ H

该组件会使用 libiio 库来配置 IIO 设备,然后从 IIO 设备读数据或者写数据到 IIO 设备中。客户端程序可以细分为 local client 和 remote client。

2) libiio 库(用户空间):2 {/ G5 s/ ~4 C) j" K9 Z! U

微信图片_20200729115147.png

8 d0 K3 a4 u+ }) B

libiio 是 Analog Device 公司发起的一个用于访问 IIO 设备的开源库。

它封装了对 /sys/bus/iio/devices(配置 iio) 和 /dev/iio/deviceX(读写iio) 的访问,并且提供了便于测试的 iio 命令行工具 (iio_info / iio_readdev) 和 iiod server。

iiod server 内含 local backend 和 remote backend 以支持 local client 和 remote client 的访问。

libiio 的源码位于:github libiio

3) 访问接口(用户空间):

iio 支持多种标准的 Linux 设备访问接口:9 A7 Q" `- D2 f6 g' B! W% @( e
char device, sysfs, configfs, debugfs。

4) 内核空间的 iio 消费者(即 IIO consumers):. f5 H. F0 ~9 D0 o* g: A2 h

微信图片_20200729115150.png
$ M( Y2 G6 h( ^0 ?0 Z  R* s, s

除了用户空间的应用程序能访问 iio 设备之外,在内核里也有其他设备驱动需要使用 iio 子系统的 API 来编写符合自身框架的设备驱动。

例如在 iio 子系统里支持了某款 Soc ADC 后,可能会有不同的硬件设备接到该 ADC 通道上,典型的例子是触摸芯片,开发人员需要在 input 子系统的框架下编写 touch driver,在 touch driver的 irq handler 中 调用 iio in-kern API 来读取触摸屏的 X、Y 值。

iio in-kernl API的定义位于头文件:
- |2 }% y. b3 Xinclude/linux/iio/consumer.h

5) IIO framework(内核空间):4 ~4 Q; X: T4 O! m
IIO 子系统的核心实现。

6) IIO device driver(或称 IIO providers):

7) Linux 内核自带的 IIO 调试工具:


2. IIO 的功能特性

相关参考:

  • Linux-4.14/drivers/staging/iio/Documentation/overview.txt6 \% A  B/ t. U( N4 Q& Q+ e

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

  • 类似于 hwmon 子系统,它们都可以通过 sysfs 以轮循的方式访问设备;
    1 Q- ~+ ]! n9 G! L

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

  • 类似于 input 子系统,iio 子系统也可以向应用层上报事件(hardware triggered events),例如阈值检测事件,自由落体检测事件、更复杂的动作检测事件;

  • 目前 event 的格式为:event code + 时间戳;


    9 Z$ t/ j% k6 h3 C

3) 支持硬件 buffer

4) 支持 Trigger 和软件 buffer


3. IIO 相关配置3.1 配置内核

Linux-4.14:

$ make menuconfig
% ?7 r1 t8 [: cDevice Drivers  --->
2 a% f+ i" ^" }; W6 d  z7 z  <*> Industrial I/O support  --->$ C# N8 Z% f, Q# z" S8 x
   
  •    Enable buffer support within IIO
    * L; z7 z, ^5 S9 p& k: y! f  o     < >     IIO callback buffer used for push in-kernel interfaces
    + w$ Z4 }, e9 g0 Q5 f  z$ f- m     <*>     Industrial I/O HW buffering
    % r. ]# S5 c" c     <*>     Industrial I/O buffering based on kfifo
    7 {' z8 }) O' H     < >   Enable IIO configuration via configfs                        0 G$ m& O! U# `6 ?) w& [- m" _+ Q
         
  •    Enable triggered sampling support  \/ ^3 U5 v& G# d3 k/ |
         (2)     Maximum number of consumers per trigger                    
    5 |4 ?* |7 W) ^) u' h     < >   Enable software triggers support                             9 k' ~, K# d/ {  r
               Accelerometers  --->                                         
    9 w' d* Y3 ?. e/ U0 z' O. P           Analog to digital converters  --->                          0 T* [! x6 c( _* N5 e& R9 b
               Amplifiers  --->                                             
    - F: D; L4 ^, t/ P  Q' S  L           Chemical Sensors  --->                                       
    , M( X( a5 Y% @$ ^0 w! Y2 w& ?' }           Hid Sensor IIO Common  ----                                 
    4 o% ^8 T% W6 x           SSP Sensor Common  --->                                      / w2 h- i  q. L! o5 a# w
               Digital to analog converters  --->                           
    ! A& k& \8 q! i- \8 t2 O           IIO dummy driver  --->                                       
    , Q  `% X# U" W/ \! U           Frequency Synthesizers DDS/PLL  --->                         ; Z. Q9 O# i: \1 o: h, f; K$ G
               Digital gyroscope sensors  --->                              & s, t; B. V) ~/ N1 c4 N- z
               Health Sensors  --->                                         
    + U/ H* l+ e7 z6 s8 B# Q* y4 M           Humidity sensors  --->                                       
    ( \% M# V1 P* {$ d& c           Inertial measurement units  --->                             - s  C' x0 Y8 r" \7 p0 `. {# n
               Light sensors  --->                                          ) \: z! m# a( R1 S. V7 y
               Magnetometer sensors  --->                                   
    , n. m2 s8 l( {! L           Inclinometer sensors  ----                                   
    ( H2 p" ]4 S7 A6 T           Triggers - standalone  --->                                 
    * x" G1 w$ ?: k3 j! |) |- `/ M1 \           Digital potentiometers  --->                                 
    4 f( E8 t/ b' f1 }3 h2 r           Pressure sensors  --->                                       # m. W7 c+ S5 j
               Lightning sensors  --->                                      
    6 s* s! f! }' n. S0 `" K4 ]1 Z" q% w% r           Proximity sensors  --->                                      
    - d5 q$ a7 x7 q: T           Temperature sensors  --->
    ; [4 s6 x! F- y% _9 q' ^

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


    3.2 配置设备树

    相关参考:

    • Linux-4.14/Documentation/devicetree/bindings/iio/iio-bindings.txt
      * C$ V, }0 z  H/ w' Y
    3.2.1 IIO providers

    1) 相关要点:

    • IIO channels 源在设备树中用 IIO providers 来指定;
      - D8 J6 H# [7 @0 A9 S4 S1 V+ A- [, N/ l

    2) 必要属性:

    • io-channel-cells,0 表示只有 1 路 IIO output,1 表示有多路 IIO output;

    • io-channel-ranges: 一个 empty 属性(即不用赋值),会在 driver/iio/inkern.c/iio_channel_get() 中被引用,它表明继承了当前节点的子节点可以引用当前节点的 IIO channel;

      / i7 t$ V& e# E9 H

    3) 例子1 (no trigger)

    adc: voltage-sensor@35 {& Q4 A' ^7 X/ s* c6 }
      compatible = "maxim,max1139";
    1 F. f3 }$ a/ L9 b9 N% Y$ {! e  reg = <0x35>;
    6 u5 L; s6 U  q% B/ g1 ^. i/ P* Y  #io-channel-cells = <1>;
    * L- Z/ k7 r2 k$ h2 I* c/ P2 J};
    * R9 e" l3 }4 J( f5 c* k; K4 h& k

    4) 例子2 (with trigger)

    adc@35 {; s1 J# [: q8 X
      compatible = "some-vendor,some-adc";$ i0 }, V2 b, U, L  L0 {
      reg = <0x35>;
    6 Z  D2 v7 v: `$ [* u% _9 ~, M& Q& I& u3 s5 J* G
      adc1: iio-device@0 {% m$ P, l& l; l- y5 K% l& z) r
        #io-channel-cells = <1>;
    1 h) q5 |5 X) t$ U! W+ t0 w* M    /* other properties */4 A7 [6 u; g6 }. |7 d
      };9 \8 G8 u' ?: |/ k/ z9 ]
      adc2: iio-device@1 {' }5 T' T: y" h5 L# m
        #io-channel-cells = <1>;
    - v& a; k' H" x6 U, z- X5 A    /* other properties */
    - n; R" u7 ?' |+ J+ v  };
    " b0 O' i" Q, A- u9 W};

    2 Z2 z) c: s4 i. ?3.2.2 IIO consumers

    1) 相关要点:

    • IIO consumer 节点的形式是 <phandle iio_specifier>;

    • 它的作用是连接 IIO provider 的 input 端到 IIO consumer 的 output 端;

    • 其中,phandle 是 IIO provider 的句柄,specifier 用于选择第几路 channel;

    • 类似 gpio specifier, IIO specifier 是有 1 个或者多个 cells 的数组,用于确定 IIO device的 output 端,即 1 个 cell 对应一个 IIO channel output;

    • IIO specifier 数组的长度由 IIO provider 节点的 #io-channel-cells 属性决定;


      * x4 a' s2 L. e: t: i

    2) 必要属性:

    • io-channels: <phandle iio_specifier> 列表,一个 <phandle iio_specifier> 代表该设备连接着的一路 IIO input。如果 IIO provider 的 io-channel-cells=0 (即只有1路 IIO output), 则省略 iio_specifier。
      : m( {: ^4 S+ @6 p' D

    3) 可选属性:

    • io-channel-names: IIO input 的名称列表,顺序要和 io-channels 属性保持一致,Consumers drivers 会将该名称和 iio_specifier 指定的 IIO input match 到一起。
      + f5 g3 I8 P) [; J/ G! A( t

    4) 例子1

    some_consumer {9 B  |7 E$ @$ l! }/ ^9 N
      io-channels = <&adc 1>, <&ref 0>;8 Y7 V* T( P( u8 _& Q% l( k1 U
      io-channel-names = "vcc", "vdd";9 G  x+ z8 o4 o+ m; I* h" @
    };
    ! n( r) M, v; b; P/ V+ L

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


    4. IIO API4.1 用户空间 API

    相关参考:

    • IIO user space interface
    • How to use the IIO user space interface
      - j' g# K2 K0 |1 m9 T. F: i- t
    4.1.1 4种接口

    1). sysfs interface

    • /sys/bus/iio/devices/iio:deviceX;

    • 可用于配置 /dev/iio:deviceX 接口的 events / data

    • 可用于轮循的方式低速地直接读/写 IIO 设备;

    • Documentation/ABI/testing/sysfs-bus-iio;


      $ D/ U& ~/ A: K, _. {

    2). character device

    • /dev/iio:deviceX,该接口在 IIO 子系统里是可选非必要的;

    • 标准的文件 IO API: open(), read(), write(), close().

    • 用于读取 events 和 data;


      $ Q& Q" l/ m; Q7 _! I( f# E4 W

    3). configfs

    • 用于配置额外的 IIO 特性,例如:软件 triggers 或者 hrtimer triggers;

    • 详细说明:

      2 \; U& {9 @3 D- H. t. h
      • Documentation/ABI/testing/configfs-iio;
      • Documentation/iio/iio_configfs.txt;
        7 P+ G% x" u& `0 J- F: i2 F& }5 u! v

    4). debugfs

    • 一些调试功能,例如 direct_reg_access 节点可用于读写寄存器;0 T0 g+ k( {& e
    4.1.2 操作实例

    IIO direct mode: 通过 sysfs 以轮循的方式读 ADC 或者写 DAC:
    + z; j2 ^0 \# S  A. c' \1) 直接读 ADC
    1 S% X$ F5 x3 f1 a  \; ~确定 sysfs 节点(方式1,不依赖工具)

    $ grep -H "" /sys/bus/iio/devices/*/name | grep adc
      y* o; L" N4 [1 E) @. ?/sys/bus/iio/devices/iio:device0/name:48003000.adc:adc@0& @9 z; N1 O4 T
    /sys/bus/iio/devices/iio:device1/name:48003000.adc:adc@1
    & |" ~/ p7 y6 K! t$ ?2 P  W

    sysfs 中的 iio:device0 sysfs 对应 ADC1;

    $ cd /sys/bus/iio/devices/iio:device0/' Q6 j7 M/ ]4 ^/ E7 n
    $ cat in_voltage6_raw      # Convert ADC1 channel 0 (analog-to-digital): get raw value$ {; A$ y! q" i1 o) M0 s8 t( m% S
    40603& n2 V% C& P) A( ?% W' w
    $ cat in_voltage_scale     # Read scale  B$ k& d' R: J: V
    0.044250488
    : R$ B) Z2 Y$ ?* W3 z4 F! f: L8 v$ cat in_voltage_offset    # Read offset: k1 @* D2 e# ]
    0' `1 x, d' X2 p8 v  w
    $ awk "BEGIN{printf (\"%d\n\", (40603 + 0) * 0.044250488)}"1 M# E6 G- p# ~% ?. O
    1796  

    8 Q; P4 Y! d( j. K  u( [- Z5 C) b2 W

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

    2) 直接写 DAC
    ( R0 c. i2 `. e" E确定 sysfs 节点(方式2)

    $ lsiio | grep dac8 a6 E" W- f8 Z! x/ _
    Device 003: 40017000.dac:dac@1
    7 B: m  ^5 x5 ?2 t5 aDevice 004: 40017000.dac:dac@2

      ]! @7 I% c$ d$ A& b5 {' G. N

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

    $ cd /sys/bus/iio/devices/iio:device3/2 U9 F! X. @. ~- ^) O* s1 Z$ I
    $ cat out_voltage1_scale              # Read scale- z! x$ B* D: k% U; M5 R
    0.708007812
    ' C! w2 p+ F5 v, X4 `$ awk "BEGIN{printf (\"%d\n\", 2000 / 0.708007812)}"  # 假设要输出 2000 mV
    - [! P( G' P& {& i2824
    $ ~% m8 p/ E6 f% o1 P7 b# ~& y$ echo 2824 > out_voltage1_raw        # Write raw value to DAC1! {2 T( S, ^) k- a. [( ^
    $ echo 0 > out_voltage1_powerdown     # Enable DAC1 (out of power-down mode)
    ! Q4 k, a) G' w1 n. Y$ ^
    5. 更多值得学习的知识点
    • 以 timer triggers 和 buffers 的方式读 ADC 或者写 DAC;
    • IIO 内核空间 API;
    • 编写 IIO device driver
    • 编写 IIO consumer driver
    • ...
      ( M% I1 c, ?& r% v. L

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


    6. 相关参考
    • IIO Overview
    • Linux Industrial I/O Subsystem
    • 《Linux Device Drivers Development》3 y, A5 ?0 k0 \; v( |- N

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


    * X7 R% A- B) @: C% v+ j
  • 赞 收藏 评论0 发布时间:2020-7-29 11:53

    举报

    0个回答
    关于
    我们是谁
    投资者关系
    意法半导体可持续发展举措
    创新与技术
    意法半导体官网
    联系我们
    联系ST分支机构
    寻找销售人员和分销渠道
    社区
    媒体中心
    活动与培训
    隐私策略
    隐私策略
    Cookies管理
    行使您的权利
    官方最新发布
    人形机器人运动控制、感知与智能配电
    半导体创新技术与应用方向
    EE架构与软件定义汽车
    12V/48V 汽车智能配电(SPD)
    区域控制单元(ZCU)与分区架构
    关注我们
    st-img 微信公众号
    st-img 手机版