嵌入式linux IIO驱动

article/2025/9/25 7:08:23

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,这是一个六轴传感器,可以输出三轴陀螺仪(XYZ)、三轴加速度计(XYZ)和一路温度,也就是一共有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_XIIO_MOD_YIIO_MOD_Z 就分别对应 XYZ 这三个轴。通道修饰符主要是影响 sysfs 下的通道文件名字,后面我们会讲解 sysfs 下通道文件名字组成形式。

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

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

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

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

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

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

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

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

        .endianness: 数据的大小端模式,可设置为 IIO_CPUIIO_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 加速度计的 XYZ 轴他们的 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 设备、释放掉申请的一些内存。


http://chatgpt.dhexx.cn/article/q9eNoqFg.shtml

相关文章

嵌入式Linux设备驱动程序开发指南17(IIO子系统一)——读书笔记

IIO子系统一 十七、IIO子系统(一)17.1 简介17.2 数模转换——DAC实验17.2.1 IIO缓冲区17.2.2 触发器17.2.3 工业I/O事件17.2.4 iio工具17.2.5 LTC2607——DAC模块介绍17.2.5.1 设备树17.2.5.2 LTC2607驱动模块介绍17.2.5.2.1 用作I2C交互的工业框架17.2.5.2.2 用作IIO设备的工业…

LINUX IIO子系统分析之一 IIO子系统概述

从本章开始,我们进行IIO子系统专栏的分析文档,本次IIO子系统专栏分析文档大概包含如下几章: 一、 IIO子系统概述 二、IIO子系统相关数据结构分析 三、iio trigger 介绍 四、iio event介绍 五、iio buffer介绍 六、iio device的注册与注销介绍…

linux iio子系统

//\\ || 系 统:WindowsXP & Ubuntu14.04 || 工 具: Source Insight 3.5 || 作 者:疯狂的三极管 \\// 最近由于工作的需要,接触了Linux iio子系统,对于这个目录其实以前是很少接触,接…

RK3399平台开发系列讲解(IIO子系统)4.38、什么是IIO(Industrial I/O)

平台内核版本安卓版本RK3399Linux4.4Android7.1🚀返回专栏总目录 文章目录 一、什么是IIO?沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将介绍什么是IIO 一、什么是IIO? 工业I/O (Industrial I/O,IIO)是专用于模数转换器 (ADC)和数模转换器(DAC)的内…

iio驱动

1.简介 由于客户提供的板子有一个ti081c的adc芯片所有在这里简单学习一下;   工业I / O(IIO)是专用于模数转换器(ADC)和数模转换器(DAC)的内核子系统。随着越来越多的具有不同代码实现的传感…

iio子系统框架分析

学习目的 iio子系统主要提供对ADC、DAC相关的设备驱动框架。面向的设备包括: 1.ADC芯片;2.DAC芯片;3.温度传感器;4.光感器;5.陀螺仪;6.加速度传感器;7.CDCs;​8.IMUs;9…

Linux设备驱动之IIO子系统——IIO框架及IIO数据结构

由于需要对ADC进行驱动设计,因此学习了一下Linux驱动的IIO子系统。本文翻译自《Linux Device Drivers Development 》--John Madieu,本人水平有限,若有错误请大家指出。 IIO Framework 工业I / O(IIO)是专用于模数转换器(ADC)和数模转换器(DAC)的内核子系统。随着越来…

Linux IIO 子系统简介

IIO 子系统系统框架 而在IIO子系统内部,则主要包括如下四部分的内容: iio buffer用于处理需要进行连续采集的数据,当一个IIO device的各通道数据支持连续采集时,则调用iio buffer模块提供的接口,创建iio buffer用于存…

LINUX IIO子系统分析之五IIO BUFFER子模块实现分析

上一章我们介绍了iio子系统中的iio event模块,本章我们将介绍iio buffer模块,iio buffer主要用于连续数据采集与缓存功能。IIO buffer模块借助IIO DEVICE字符设备文件与应用程序通信,同时借助iio trigger模块与iio device进行交互&#xff0c…

kudu教程(一)——简介

##kudu教程(一)——简介 学习kudu先从kudu官网开始,进入主页https://kudu.apache.org/ 我们看到的第一句话就是 A new addition to the open source Apache Hadoop ecosystem, Apache Kudu completes Hadoop’s storage layer to enable fas…

kudu介绍:为什么要使用?

前言 近两年,KUDU 在大数据平台的应用越来越广泛。在阿里、小米、网易等公司的大数据架构中,KUDU 都有着不可替代的地位。本文通过分析 KUDU 的设计, 试图解释为什么 KUDU 会被广泛应用于大数据领域,因为还没有研究过 KUDU 的代码…

Kudu 的架构概述

Kudu 的架构概述 目录 Kudu 的架构概述 体系结构概述 Kudu 的特点 Kudu 的概念和术语 体系结构概述 下图显示了一个Kudu集群,其中有三个主机和多个 tablet servers,每个tablet server 都服务于多个tablet Kudu 的特点 特点一:主从架构…

Outline Of Sodoku

第一步:确定所需要实现的目标 1.数独程序的界面: 1.1初始界面边框 1.1.1边框上的Sodoku标题 1.2初始界面背景图片 1.3初始界面开始键 1.4初始界面难度设置 \\数独界面始终为99的矩阵,可以通过改变初始给定格数来改变难度 1.5响应键盘和鼠标指…

Apache Kudu架构

目录 1. Kudu架构 1. Kudu架构 下图显示了一个具有三个master和多个tablet server的Kudu集群 Kudu采用Raft一致性算法,当写入一条数据,被至少一半replica保存,就可以让客户端访问该条数据。但所有的replica的数据会最终一致 Table&#xff…

kudu的相关介绍

目录 前言 背景 概览 数据模型 核心 API 一致性模型 架构 整体架构 数据分区策略 存储 存储设计目标 存储方式 存储实现 读写过程 应用案例 前言 近两年,KUDU 在大数据平台的应用越来越广泛。在阿里、小米、网易等公司的大数据架构中,KUD…

大数据入门-什么是Kudu

目录 一、概念 二、架构 1.Master Server 2.Tablet Server 3.Table 4.Tablet 三、特性 1.重要性 2.易用性 3.优势 4.与传统关系型数据库比较 5.与其他大数据组件比较 四、常用语句 1.建表 1.建普通表 2.建分区表 2.删除表 3.查询数据 4.添加数据 5.更新数据…

Kudu初入门

目录 介绍: 基础架构: 关于Tablet: Kudu与Impala集成 安装Kudu 配置Impala支持Kudu: 使用案例: 创建表: 查询Impala中现有的Kudu表 使用CREATE TABLE AS SELECT语句查询Impala中的任何其他表或来…

kudu-- 分布式数据库

一、前言 近两年,KUDU 在大数据平台的应用越来越广泛。在阿里、小米、网易等公司的大数据架构中,KUDU 都有着不可替代的地位。本文通过分析 KUDU 的设计, 试图解释为什么 KUDU 会被广泛应用于大数据领域,因为还没有研究过 KUDU 的…

Apache Kudu的介绍

一、Apache Kudu的介绍 1.1、背景介绍 在kudu之前,大数据主要以两种方式存储; (1)静态数据 : 以HDFS引擎作为存储,适用于高吞吐量的离线大数据分析场景。 这类存储的局限性是数据无法进行随机读写。 &…

kudu compaction操作

与hbase相同,kudu也需要定期进行compaction操作。kudu中的compaction操作有两种,一是合并delta文件。二是将一个tablet中的多个diskRowset进行重排。下面分别对这两者进行介绍。 之前在kudu的update操作中讲到,update操作的数据会先写入delt…