性无码一区二区三区在线观看,少妇被爽到高潮在线观看,午夜精品一区二区三区,无码中文字幕人妻在线一区二区三区,无码精品国产一区二区三区免费

手把手教如何用Linux下IIO設備(附代碼)

今天分享一下如何在用戶空間操作IIO設備。IIO設備能實現(xiàn)很多有價值的應用,有興趣的一起來看看~

什么是IIO設備

IIO是 Industrial I/O 的縮寫,是Linux下為工業(yè)輸入輸出所設計的子系統(tǒng)。其主要目的是為模數(shù)轉(zhuǎn)換 (ADC) 或數(shù)模轉(zhuǎn)換 (DAC) 或兩者兼而有之的設備提供設備驅(qū)動支持。Linux下原來有Hwmon以及輸入子系統(tǒng),但這兩個子系統(tǒng)不能很好的涵蓋上面需求。而IIO子系統(tǒng)就是為了填補這一空白而設計的。

什么是Hwmon?針對用于監(jiān)測和控制系統(tǒng)本身的低采樣率傳感器,如風扇速度控制或溫度測量。

而輸入子系統(tǒng)(Input subsystem), 顧名思義,主要抽象人機交互輸入設備(鍵盤、鼠標、觸摸屏)。當然,從這些描述來看,這兩個需求與 IIO 之間存在相當大的重疊。

而IIO子系統(tǒng)則主要管理抽象這些類別的設備:

  • 模數(shù)轉(zhuǎn)換器(ADC)
  • 加速度計(Accelerometers)
  • 陀螺儀(Gyros)
  • 慣性測量單元 IMUs)
  • 電容數(shù)字轉(zhuǎn)換器 (CDC)
  • 壓力傳感器
  • 顏色、光線和接近傳感器
  • 溫度傳感器
  • 磁力計(Magnetometers)
  • 數(shù)模轉(zhuǎn)換器(DAC)
  • 直接數(shù)字合成器(DDS)
  • 鎖相環(huán)(PLL)
  • 可變/可編程增益放大器(VGA、PGA)
  • ....

此類設備,一般會通過I2C/SPI總線連接到處理器,SPI/I2C通常用來傳輸控制信息,而這些設備的輸入輸出應用數(shù)據(jù)則是通過其他的接口與處理器進行通信,比如采用LVDS。以AD9467為例:

三線制SPI則是控制信息,用于配置ADC的寄存器,而采樣數(shù)據(jù)則是通過LVDS上傳給處理器的。

IIO設備長什么樣?

IIO設備一般也會在/dev下創(chuàng)建一個設備文件,比如:

然后在sys下也會創(chuàng)建文件,比如在/sys/bus下就會創(chuàng)建一條名為iio的總線:

進入到iio之后:

在devices下,則有:

如果有多個iio設備,則會這樣編號:

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

進入到iio:device0后

則可以看到有mode,scale,of_node,frequeceny等屬性。進到scan_elements下:

scan_elements用于描述掃描樣本的相關(guān)屬性:

  • in_voltage0_en:使能控制,設置為1為使能,為0則關(guān)閉
  • in_voltage0_index :索引
  • in_voltage0_type:采樣類型,本設備該值為le:S16/16>>0,表示是小端有符號整型

buffer中的屬性為:

  • data_available :有多少數(shù)量的數(shù)據(jù)準備好了
  • enable :激活緩沖區(qū)捕獲,設置為1則開始緩沖區(qū)捕獲
  • length:緩沖區(qū)可以存儲的數(shù)據(jù)樣本總數(shù)
  • length_align_bytes: 對齊要求,用于設置DMA的對齊要求。
  • watermark:此屬性從內(nèi)核版本 4.2 開始可用。它是一個正數(shù),指定阻塞讀取應等待多少個掃描元素。如果使用輪詢,它將阻塞直到達到watermark設定值。只有當watermark大于請求的讀取量時才有意義。它不會影響非阻塞讀取。

在用戶空間讀取iio設備的數(shù)據(jù),有掃描方法或者觸發(fā)方法,這里主要分享一下連續(xù)掃描讀取。

  • 首先將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。驅(qū)動就開始工作了。marked complete 表示一次DMA傳輸結(jié)束。
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了

代碼實現(xiàn)

有了前面的介紹,就有具體實現(xiàn)的思路了。這里以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;
    //用于緩存數(shù)據(jù)
    QByteArray *buffer;
    QMutex *mutex;
    bool m_started;
};

#endif

實現(xiàn)文件如下:

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_en
    QString 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_en
    cmdStr = "echo 0 > /sys/bus/iio/devices/"+fileName+"/scan_elements/in_voltage0_en";
    cmdBuffer = cmdStr.toLocal8Bit();
    cmd = cmdBuffer.data();
    
    system(cmd);
    //3.關(guān)閉文件
    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();
    
  //完全關(guān)閉線程的寫法
  wait();
}

#define TEMP_BUFFER_SIZE 4096
//開辟線程用于讀取
void IIODevice::run()
{
  int bytes = 0;
  unsigned char devBuf[TEMP_BUFFER_SIZE];
  while(1) {
      bytes = 4096;//假定內(nèi)部buffer為4096
      while(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用于線程間數(shù)據(jù)保護,由于該類是一個線程類,實際使用的時候可能是另一個線程讀取IIO設備的采集數(shù)據(jù),用于傳輸或者后續(xù)應用處理,兩個線程操作同一個QByteArray對象,存在并發(fā)競態(tài),所以需要做互斥訪問保護。

如此一來,外界的物理信號就經(jīng)由ADC芯片,進入Linux內(nèi)核設備iio:device0,再由用戶空間的IIODevice類所例化的對象,傳遞到用戶空間,從而可以在Linux下實現(xiàn)采樣應用了,整個信號傳遞可以用下面這個圖來描述。

總結(jié)一下

IIO設備在很多工業(yè)儀器類非常有用,如前所說,不僅僅能實現(xiàn)AD采樣,還可以實現(xiàn)DA,DDS等很多非常有應用價值的設備。要用好IIO設備,可能涉及到設備驅(qū)動、信號鏈設計、用戶空間應用程序編寫等等技術(shù)。本文以一個AD采樣IIO設備為例,分享一下如何從用戶空間訪問控制IIO設備,希望對有興趣的朋友們有所幫助。

聲明:本內(nèi)容為作者獨立觀點,不代表電子星球立場。未經(jīng)允許不得轉(zhuǎn)載。授權(quán)事宜與稿件投訴,請聯(lián)系:editor@netbroad.com
覺得內(nèi)容不錯的朋友,別忘了一鍵三連哦!
贊 1
收藏 3
關(guān)注 79
成為作者 賺取收益
全部留言
0/200
成為第一個和作者交流的人吧