|
前阵子工作上做了一些关于 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 子系统?1.1 IIO 概述 1.2 IIO 相关的组件" {3 X2 h; S) D& e) }2 o 2. IIO 功能特性 3. IIO 相关配置 3.1 配置内核 3.2 配置设备树 3.2.1 IIO providers/ C9 X" R: |: E. U# x 3.2.2 IIO consumers 4. IIO API 4.1 用户空间 API 4.1.1 4种接口' ?% W1 P9 Q" J' {# @# o% V3 W 4.1.2 操作实例 5. 更多值得学习的知识点# I c+ u8 g% ]7 ^, M) z1 X 6. 相关参考 写作目的:
1. 什么是 IIO 子系统?1.1 IIO 概述 Industrial I/O 子系统旨在为某种意义上是模数或数模转换器 (ADC,DAC) 的设备提供支持,于2009年由 Huawei 的 Jonathan Cameront 添加。 简单框图:" _3 @6 u J7 M2 y9 K4 v' j ]6 }
支持的设备包括: 加速度计# P" F: G6 O6 ` 磁力计# x) `/ ?4 O' R1 q2 P 陀螺仪 压力传感器# i* |6 O5 N, a# y) F: H; c 湿度传感器 温度传感器 .../ z8 q6 O* l! I+ a 很久以前,对于上述硬件的支持散落在 Linux 源码中的各种地方。 IIO 的出现,提供了一个统一的框架用于访问和控制上述各种类型的传感器,并且为用户态应用访问传感器提供了标准的接口:sysfs/devfs,并且填补了 Hwmon 和 Input 子系统之间的空白。 另外,IIO 不仅可以支持低速的 SoC ADC,还可支持高速、高数据速率的工业设备,例如 100M samples/sec 工业 ADC。 1.2 IIO 相关的组件
上图基于 STM32 MPU,来源见文末。 1) 客户端应用程序(用户空间):
该组件会使用 libiio 库来配置 IIO 设备,然后从 IIO 设备读数据或者写数据到 IIO 设备中。客户端程序可以细分为 local client 和 remote client。 2) libiio 库(用户空间):2 {/ G5 s/ ~4 C) j" K9 Z! U
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 4) 内核空间的 iio 消费者(即 IIO consumers):. f5 H. F0 ~9 D0 o* g: A2 h
$ 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的定义位于头文件: 5) IIO framework(内核空间):4 ~4 Q; X: T4 O! m 6) IIO device driver(或称 IIO providers): 7) Linux 内核自带的 IIO 调试工具: 2. IIO 的功能特性 相关参考:
1) 基础的设备注册和访问
2) 可读取事件的字符设备(Event chrdevs)
3) 支持硬件 buffer 4) 支持 Trigger 和软件 buffer 3. IIO 相关配置3.1 配置内核 Linux-4.14: $ make menuconfigDevice Drivers ---> <*> Industrial I/O support --->$ C# N8 Z% f, Q# z" S8 x < > 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 0 G$ m& O! U# `6 ?) w& [- m" _+ Q (2) Maximum number of consumers per trigger < > Enable software triggers support 9 k' ~, K# d/ { r Accelerometers ---> Analog to digital converters ---> 0 T* [! x6 c( _* N5 e& R9 b Amplifiers ---> Chemical Sensors ---> Hid Sensor IIO Common ---- SSP Sensor Common ---> / w2 h- i q. L! o5 a# w Digital to analog converters ---> IIO dummy driver ---> 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 ---> Humidity sensors ---> Inertial measurement units ---> - s C' x0 Y8 r" \7 p0 `. {# n Light sensors ---> ) \: z! m# a( R1 S. V7 y Magnetometer sensors ---> Inclinometer sensors ---- Triggers - standalone ---> Digital potentiometers ---> Pressure sensors ---> # m. W7 c+ S5 j Lightning sensors ---> Proximity sensors ---> Temperature sensors ---> 从配置项的数目来看,IIO 的用途真的很广泛。 3.2 配置设备树 相关参考:
1) 相关要点:
2) 必要属性:
3) 例子1 (no trigger) adc: voltage-sensor@35 {& Q4 A' ^7 X/ s* c6 }compatible = "maxim,max1139"; reg = <0x35>; #io-channel-cells = <1>; };* R9 e" l3 }4 J( f5 c* k; K4 h& k 4) 例子2 (with trigger) adc@35 {; s1 J# [: q8 Xcompatible = "some-vendor,some-adc";$ i0 }, V2 b, U, L L0 { reg = <0x35>; % _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>; /* 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>; /* other properties */ }; }; 3.2.2 IIO consumers 1) 相关要点:
2) 必要属性:
3) 可选属性:
4) 例子1 some_consumer {9 B |7 E$ @$ l! }/ ^9 Nio-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 相关参考:
1). sysfs interface
2). character device
3). configfs
4). debugfs
IIO direct mode: 通过 sysfs 以轮循的方式读 ADC 或者写 DAC: /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 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 $ 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 计算公式: Scaled value = (raw + offset) * scale = 1796 mV; 2) 直接写 DAC Device 003: 40017000.dac:dac@1 Device 004: 40017000.dac:dac@2 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 $ awk "BEGIN{printf (\"%d\n\", 2000 / 0.708007812)}" # 假设要输出 2000 mV 2824 $ 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) 5. 更多值得学习的知识点
鉴于大多数人的注意力无法在一篇文章里上集中太久,更多的内容请大家先自行去阅读吧,不是自己理解到的东西是消化不了的。有机会的话我会把更多的读书心得放在后面的文章。 6. 相关参考
本文只是一篇入门的文章,仍然有许多细节的知识点没有被描述到。如果本文能让你对 IIO 子系统有个大概的认识,那么本文的目的也就算达成了,以后还会继续写更多 IIO 子系统的文章。知识的学习应该是螺旋上升的,找到一条平缓的学习路线很重要,先有一个整体的概念,然后再不断地去丰富细节会比较好一点。就好像爬山一样,相对于几千米的高山,人类看起来总是显得多么的渺小,但是只要每天平稳地走几百个阶梯,再高的山也能在不知不觉中走完。 |
微信公众号
手机版