关注、星标嵌入式客栈,精彩及时送达

[导读] 朋友们,大家好,我是逸珺。

今天分享一下如何在用户空间操作IIO设备。IIO设备能实现很多有价值的应用,有兴趣的一起来看看~

什么是IIO设备

IIO是 Industrial I/O 的缩写,是Linux下为工业输入输出所设计的子系统。其主要目的是为模数转换 (ADC) 或数模转换 (DAC) 或两者兼而有之的设备提供设备驱动支持。Linux下原来有Hwmon以及输入子系统,但这两个子系统不能很好的涵盖上面需求。而IIO子系统就是为了填补这一空白而设计的。

什么是Hwmon?针对用于监测和控制系统本身的低采样率传感器,如风扇速度控制或温度测量。

而输入子系统(Input subsystem), 顾名思义,主要抽象人机交互输入设备(键盘、鼠标、触摸屏)。当然,从这些描述来看,这两个需求与 IIO 之间存在相当大的重叠。

而IIO子系统则主要管理抽象这些类别的设备:

  • 模数转换器(ADC)

  • 加速度计(Accelerometers)

  • 陀螺仪(Gyros)

  • 惯性测量单元 IMUs)

  • 电容数字转换器 (CDC)

  • 压力传感器

  • 颜色、光线和接近传感器

  • 温度传感器

  • 磁力计(Magnetometers)

  • 数模转换器(DAC)

  • 直接数字合成器(DDS)

  • 锁相环(PLL)

  • 可变/可编程增益放大器(VGA、PGA)

  • ....

此类设备,一般会通过I2C/SPI总线连接到处理器,SPI/I2C通常用来传输控制信息,而这些设备的输入输出应用数据则是通过其他的接口与处理器进行通信,比如采用LVDS。以AD9467为例:

三线制SPI则是控制信息,用于配置ADC的寄存器,而采样数据则是通过LVDS上传给处理器的。

IIO设备长什么样?

IIO设备一般也会在/dev下创建一个设备文件,比如:

然后在sys下也会创建文件,比如在/sys/bus下就会创建一条名为iio的总线:

进入到iio之后:

在devices下,则有:

如果有多个iio设备,则会这样编号:

iio:device0  iio:device1  iio:device2  ......

进入到iio:device0后

则可以看到有mode,scale,of_node,frequeceny等属性。进到scan_elements下:

scan_elements用于描述扫描样本的相关属性:

  • in_voltage0_en:使能控制,设置为1为使能,为0则关闭

  • in_voltage0_index :索引

  • in_voltage0_type:采样类型,本设备该值为le:S16/16>>0,表示是小端有符号整型

buffer中的属性为:

  • data_available :有多少数量的数据准备好了

  • enable :激活缓冲区捕获,设置为1则开始缓冲区捕获

  • length:缓冲区可以存储的数据样本总数

  • length_align_bytes: 对齐要求,用于设置DMA的对齐要求。

  • watermark:此属性从内核版本 4.2 开始可用。它是一个正数,指定阻塞读取应等待多少个扫描元素。如果使用轮询,它将阻塞直到达到watermark设定值。只有当watermark大于请求的读取量时才有意义。它不会影响非阻塞读取。

在用户空间读取iio设备的数据,有扫描方法或者触发方法,这里主要分享一下连续扫描读取。

  • 首先将scan_elements中in_voltage0_en设置为1

root@idaq:/sys/bus/iio/devices/iio:device0/scan_elements# echo 1 > in_voltage0_en
root@idaq:/sys/bus/iio/devices/iio:device0/scan_elements# cat in_voltage0_en
1
  • 然后将buffer中的enable,也设置为1。驱动就开始工作了。

    marked complete 表示一次DMA传输结束。

root@idaq:/sys/bus/iio/devices/iio:device0/buffer# echo 1 > enable
iio iio:device0: iio_dma_buffer_enable
dma-axi-dmac 43c20000.axi_dmac: vchan (ptrval): txd (ptrval)[2]: submitted
dma-axi-dmac 43c20000.axi_dmac: txd (ptrval)[2]: marked complete
  • 然后就可以标准文件操作直接读取/dev/iio:device0了

代码实现

有了前面的介绍,就有具体实现的思路了。这里以QT为例,设计一个类先进行文件操作,然后不停读取文件即可。

下面是头文件:

#ifndef _IIO_DEVICE_H_
#define _IIO_DEVICE_H_
#include <QObject>
#include <QMutex>
#include <QThread>
//继承自QThread
class IIODevice : public QThread
{Q_OBJECT
public:explicit IIODevice(QObject *parent = 0,QString fName="iio:device0",QByteArray *pBuffer=nullptr,QMutex *pMutex=nullptr);~IIODevice();int  openDevice(void);int  closeDevice(void);void startSample();void stopSample(void);int  readDevice(unsigned char * buffer,int size);bool isStarted(void);public slots:protected:void run();private:int fd;QString fileName;bool m_abort;//用于缓存数据QByteArray *buffer;QMutex *mutex;bool m_started;
};#endif

实现文件如下:

IIODevice::IIODevice(QObject *parent,QString fName,QByteArray *pBuffer,QMutex *pMutex) :QThread(parent),fileName(fName),buffer(pBuffer),mutex(pMutex)
{  m_abort = false;m_started = false;
}int IIODevice::openDevice(void)
{//使能in_voltage0_enQString cmdStr = "echo 1 > /sys/bus/iio/devices/"+fileName+"/scan_elements/in_voltage0_en";QByteArray cmdBuffer = cmdStr.toLocal8Bit();char * cmd = cmdBuffer.data();system(cmd);//使能采集cmdStr = "echo 1 > /sys/bus/iio/devices/"+fileName+"/buffer/enable";cmdBuffer = cmdStr.toLocal8Bit();cmd = cmdBuffer.data();system(cmd);QString path = "/dev/"+fileName;QFile * file = new QFile();file->setFileName(path);if( !file->exists() ){qDebug() << "file does not exist";return -1;}//O_NONBLOCK方式打开文件fd = open(path.toUtf8().data(), O_RDONLY|O_NONBLOCK);if( fd==-1 ){qDebug() << "can not open file";return -2;}return 0;
}int IIODevice::closeDevice(void)
{QString cmdStr;QByteArray cmdBuffer;//1.禁止采样cmdStr = "echo 0 > /sys/bus/iio/devices/"+fileName+"/buffer/enable";cmdBuffer = cmdStr.toLocal8Bit();char * cmd = cmdBuffer.data();system(cmd);//2.禁止in_voltage0_encmdStr = "echo 0 > /sys/bus/iio/devices/"+fileName+"/scan_elements/in_voltage0_en";cmdBuffer = cmdStr.toLocal8Bit();cmd = cmdBuffer.data();system(cmd);//3.关闭文件if(fd) {close(fd);fd = -1;    }   return 0;
}int IIODevice::readDevice(unsigned char * buffer,int size)
{int length = 0;length = read(fd,buffer,size);return length;
}IIODevice::~IIODevice(void)
{if(fd)close(fd);
}void IIODevice::startSample()
{mutex->lock();m_abort = false;m_started = true;if(!buffer->isEmpty())buffer->remove(0,buffer->size());mutex->unlock();openDevice();start();
}bool IIODevice::isStarted()
{return m_started;
}void IIODevice::stopSample()
{mutex->lock();m_abort = true;m_started = false;closeDevice();mutex->unlock();//完全关闭线程的写法wait();
}#define TEMP_BUFFER_SIZE 4096
//开辟线程用于读取
void IIODevice::run()
{int bytes = 0;unsigned char devBuf[TEMP_BUFFER_SIZE];while(1) {bytes = 4096;//假定内部buffer为4096while(bytes==4096){bytes = readDevice(devBuf,TEMP_BUFFER_SIZE);mutex->lock();buffer->append((const char *)devBuf,bytes);mutex->unlock();}if (m_abort)return;//周期性扫描usleep(600);}
}

QMutex用于线程间数据保护,由于该类是一个线程类,实际使用的时候可能是另一个线程读取IIO设备的采集数据,用于传输或者后续应用处理,两个线程操作同一个QByteArray对象,存在并发竞态,所以需要做互斥访问保护。

如此一来,外界的物理信号就经由ADC芯片,进入Linux内核设备iio:device0,再由用户空间的IIODevice类所例化的对象,传递到用户空间,从而可以在Linux下实现采样应用了,整个信号传递可以用下面这个图来描述。

总结一下

IIO设备在很多工业仪器类非常有用,如前所说,不仅仅能实现AD采样,还可以实现DA,DDS等很多非常有应用价值的设备。要用好IIO设备,可能涉及到设备驱动、信号链设计、用户空间应用程序编写等等技术。本文以一个AD采样IIO设备为例,分享一下如何从用户空间访问控制IIO设备,希望对有兴趣的朋友们有所帮助。

—— The End ——

推荐阅读  点击蓝色字体即可跳转

☞ QT容器很香之QList<T>实战举例

☞ 步进电机调速,S曲线调速算法你会吗?

☞ 图文详解Modbus-RTU协议

☞ 傅里叶变换、拉普拉斯变换、Z 变换的联系是什么?为什么要变换?

欢迎转发、留言、点赞、分享,感谢您的支持!

手把手教如何用Linux下IIO设备(附代码)相关推荐

  1. 简单有趣的 NLP 教程:手把手教你用 PyTorch 辨别自然语言(附代码)

     简单有趣的 NLP 教程:手把手教你用 PyTorch 辨别自然语言(附代码) 雷锋网(公众号:雷锋网)按:本文作者甄冉冉,原载于作者个人博客,雷锋网已获授权. 最近在学pyTorch的实际应用 ...

  2. linux按照mysql为何如此简单_手把手教你在Linux下安装MySQL

    在Linux操作系统下,安装MYSQL有两种方式:一种tar安装方式,另外一种是rpm安装方式.这两种安装方式有什么区别呢?尽管我们在Linux下常用tar来压缩/解压缩文件,但MYSQL的tar格式 ...

  3. python代码在线回归中怎么运行_手把手教你用Python进行回归(附代码、学习资料)...

    原标题:手把手教你用Python进行回归(附代码.学习资料) 作者: GURCHETAN SINGH翻译:张逸校对:丁楠雅 本文共5800字,建议阅读8分钟. 本文从线性回归.多项式回归出发,带你用P ...

  4. 实战案例,手把手教你构建电商用户画像 | 附代码

    导读:本文以真实案例,手把手教你搭建电商系统的用户画像. 先来看该电商用户画像用到的标签. 数据内容包括user_id(用户身份).item_id(商品).IDbehavior_type(用户行为类型 ...

  5. 手把手教你配置linux下C++开发工具——vim+ycm(YouCompleteMe),支持基于语义的自动补全和第三方库补全(史上最简单、史上最透彻、史上最全的终极解决方案)

    截止到目前,vim稳定版本已经到了8.2+,ycm(YouCompleteMe的简称)最新版本与几年前的安装配置截然不同了.之前网上很多教程也教不得法,生搬硬套,没有讲透彻.所以,才下定决心写一篇自认 ...

  6. 独家|手把手教你赋能Jupyter Notebooks!(附代码)

    作者:Pranjal Chaubey 翻译:宋文伯 校对:丁楠雅 本文约1700字,建议阅读5分钟. 本文将通过介绍Jupyter Notebook的附加扩展组件和指令,为Jupyter Notebo ...

  7. 手把手教你用Python进行回归(附代码、学习资料)

    作者: GURCHETAN SINGH 翻译:张逸 校对:丁楠雅 本文共5800字,建议阅读8分钟. 本文从线性回归.多项式回归出发,带你用Python实现样条回归. 我刚开始学习数据科学时,第一个接 ...

  8. 手把手教你搭建AI开发环境 !(附代码、下载地址)

    来源:虎贲智能机器 本文长度为1000字,建议阅读5分钟 本文为你介绍基于ubuntu16 Python3 tensorflow的人工智能开发环境的搭建. 人最大的长处就是有厉害的大脑.电脑.手机等都 ...

  9. 怎么用python实现回归_手把手教你用Python进行回归(附代码、学习资料)-阿里云开发者社区...

    我刚开始学习数据科学时,第一个接触到的算法就是线性回归.在把这个方法算法应用在到各种各样的数据集的过程中,我总结出了一些它的优点和不足. 首先,线性回归假设自变量和因变量之间存在线性关系,但实际情况却 ...

最新文章

  1. 带进度条的ASP无组件断点续传下载代码
  2. 一次搞定OpenCV源码及扩展模块的编译与环境配置
  3. 阿里达摩院 AI医疗 「铸剑」四年:上线170家医院,落地57座城市
  4. ALV列(Column)换到行(Row) 之 列上限不固定篇
  5. Mac OS X 下Java开发环境配置
  6. 前端学习(2761):uni-app样式的学习
  7. 视觉SLAM笔记(46) 基本的 VO
  8. js延迟加载优化页面响应速度
  9. 学习Web前端,前景无限光明?
  10. oracle宣传片,会声会影X8震撼的宣传片效果该怎么制作?
  11. 掌握C语言判断素数(质数)相关内容
  12. 一个div里面包含两个div让两个div垂直居中
  13. 三相PWM整流器滞环电流控制仿真
  14. 给文件夹加密的两种方法
  15. PTA题目 : 用指针实现将一个3*3的整型矩阵转置
  16. Element-UI 图标乱码解决方案
  17. whm面板降mysql_WHMCS与Cpanel/WHM面板整合方法-Cpanel/WHM管理使用教程 | 麦田一棵葱...
  18. stm32毕业设计 单片机智能路灯设计与实现
  19. 彻底弄懂base64的编码与解码原理
  20. 多文件断点续传,上传视频自动转MP4和截图,图片格式转换

热门文章

  1. 喜欢这样的游戏---流畅的俯视坦克射击游戏
  2. 大亚湾国土资源数据库异地容灾备份采购项目
  3. 学习用HTML做新闻摘要
  4. AN蜘蛛池V2.0附搜索留痕转码工具SEO工具
  5. 编程猫python讲师面试_【编程猫教师面试】笔试:试题+打字测速-看准网
  6. java 自定义语言 解析_视频讲解 Java 语言基础编程题(自定义异常类,IO 流)
  7. 在项目中实现多数据源和读写分离的配置
  8. godot引擎学习6
  9. bigworld源码分析(1)—— 研究bigworld的意义和目标
  10. 利用word2vec训练词向量