激情综合丁香-激情综合六月-激情综合婷婷亚洲图片-激情综合图区-激情综合网五月

基于Linux IIO接口的波形采集

 2022-5-16     作者:黃志超         

  我們?cè)?a href='http://www.huochepiao123.com.cn/article/article20221270.html' target='_blank'>《Linux IIO接口的低成本8通道AD》這篇文章中,已經(jīng)介紹了如何通過程序?qū)IO設(shè)備進(jìn)行單次讀取,接下來我們就介紹波形的實(shí)現(xiàn),關(guān)于IIO子系統(tǒng)的詳細(xì)說明可以參考資料Linux Industrial I/O Subsystem


  本次測(cè)試采用的平臺(tái)還是ESM7200主板加上ESMARC通用評(píng)估底板,波形采集要求AD能夠進(jìn)行等時(shí)的連續(xù)采樣,在IIO子系統(tǒng)的部分需要有較多的設(shè)置,所以推薦直接使用ADI公司提供的libiio庫(kù),這個(gè)庫(kù)文件抽象了和硬件相關(guān)的底層細(xì)節(jié),并提供了簡(jiǎn)單而完整的編程接口,可以省去很多和硬件相關(guān)的設(shè)置,英創(chuàng)公司已經(jīng)將libiio移植到了ESM7200主板上。


  在上一篇文章中已經(jīng)介紹過,ESM7200主板的AD是CPU內(nèi)部自帶的資源,在硬件上只能夠支持單通道的連續(xù)采集,并且最高的速率能夠達(dá)到58kSPS。在ESM7200主板中,提供了8路AD資源,用戶可以指定任意一路AD作為連續(xù)采樣的通道,但同一時(shí)間只能夠使能一路通道進(jìn)行連續(xù)采集。


管腳AD通道對(duì)應(yīng)設(shè)備名稱索引號(hào)連續(xù)采集 
E2AIN_CH1/sys/bus/iio/devices/iio:device0/ in_voltage0_raw0 支持
E3AIN_CH2/sys/bus/iio/devices/iio:device0/ in_voltage1_raw1 支持
E4AIN_CH3/sys/bus/iio/devices/iio:device0/ in_voltage2_raw2 支持
E5AIN_CH4/sys/bus/iio/devices/iio:device0/ in_voltage3_raw3 支持
E6AIN_CH5/sys/bus/iio/devices/iio:device0/ in_voltage4_raw4 支持
E7AIN_CH6/sys/bus/iio/devices/iio:device0/ in_voltage5_raw5 支持
E8AIN_CH7/sys/bus/iio/devices/iio:device0/ in_voltage8_raw8 支持
E9AIN_CH8/sys/bus/iio/devices/iio:device0/ in_voltage9_raw9 支持

表1


  同時(shí)因?yàn)槭艿紺PU內(nèi)部時(shí)鐘分頻的限制,所以ESM7200連續(xù)采樣的速率只能夠支持幾個(gè)特定的值,可參考下表:


支持頻率(KHz)5809829676150007541

表2


  關(guān)于ESM7200主板和ESMARC通用評(píng)估底板的管腳定義介紹,請(qǐng)參考上一篇文章《Linux IIO接口的低成本8通道AD》中的表1和表2。


  整個(gè)程序的基本流程如下:


基于Linux IIO接口的波形采集.png


  下面就是具體的代碼,首先是獲取IIO設(shè)備,代碼如下:


static struct iio_context *ctx;  
struct iio_device *dev;  
	  
/* 獲取IIO設(shè)備 */  
ctx = iio_create_context_from_uri("local:");  
	  
dev = iio_context_get_device(ctx, 0);  
if (!dev) {  
    fprintf(stderr, "Device not found\n");  
    iio_context_destroy(ctx);  
    return EXIT_FAILURE;  
}

 

  在IIO子系統(tǒng)中,在連續(xù)采樣時(shí),會(huì)分配一個(gè)可自定義長(zhǎng)度的環(huán)形緩沖區(qū),這個(gè)緩沖區(qū)需要一個(gè)觸發(fā)(trigger)才能夠使用。這里我們可以通過軟件模擬創(chuàng)建一個(gè)trigger,通過下面的命令就可以創(chuàng)建一個(gè)軟件模擬的trigger:

  echo 1 > /sys/bus/iio/devices/iio_sysfs_trigger/add_trigger


  在ESM7200主板啟動(dòng)后,輸入一次這個(gè)命令即可,可以通過英創(chuàng)公司提供的自啟動(dòng)腳本來執(zhí)行。


  創(chuàng)建好trigger后,就可以在程序中為IIO設(shè)備指定這個(gè)trigger了,libiio提供的API可以獲取創(chuàng)建的trigger并設(shè)置到對(duì)應(yīng)的IIO設(shè)備中:


static const char *trigger_name = "sysfstrig1";  
struct iio_device *trigger;  
	  
/* 獲取trigger并設(shè)置 */  
if (trigger_name) {  
    struct iio_device *trigger = iio_context_find_device(  
        ctx, trigger_name);  
    if (!trigger) {  
        fprintf(stderr, "Trigger %s not found\n", trigger_name);  
        iio_context_destroy(ctx);  
        return EXIT_FAILURE;  
}  
	  
    if (!iio_device_is_trigger(trigger)) {  
        fprintf(stderr, "Specified device is not a trigger\n");  
        iio_context_destroy(ctx);  
        return EXIT_FAILURE;  
    }  
	  
    ret = iio_device_set_trigger(dev, trigger);  
    if (ret < 0) {  
        char buf[256];  
        iio_strerror(-(int)ret, buf, sizeof(buf));  
        fprintf(stderr, "set trigger failed : %s\n", buf);  
    }  
}


  然后就需要獲取我們要采集的通道(channel),并使能連續(xù)采集。因?yàn)镋SM7200主板只支持單通道的連續(xù)采集,所以這里我們只選擇一路來使能:


struct iio_channel *ch;  
	  
/* 使能對(duì)應(yīng)的IIO通道,可以根據(jù)實(shí)際情況修改成需要的通道 */  
ch = iio_device_get_channel(dev, 9);  
if (!iio_channel_is_scan_element(ch) ||  
    iio_channel_is_output(ch)) {  
printf("Can not get channel %d\n", ch);  
return -1;  
}  
iio_channel_enable(ch);

 

  設(shè)置采樣的速率,ESM7200主板上只能夠設(shè)置幾種固定的頻率,可參考表2:


int sample_freq[4] = {58098, 29676, 15000, 7541};  
	  
/* 設(shè)置采樣頻率,因?yàn)榉诸l的原因,只能提供幾組固定的采樣頻率 
 * 可以參考sample_freq變量 
 * */  
freq = malloc(10);  
sprintf(freq, "%d", sample_freq[0]);  
ret = iio_channel_attr_write(ch, attr, freq);  
if (ret <= 0) {  
    printf("ERROR: while writing '%s' with '%s'\n",  
        attr, freq);  
}

 

  創(chuàng)建一個(gè)環(huán)形緩沖區(qū)用于存儲(chǔ)連續(xù)采集的數(shù)據(jù),環(huán)形緩沖區(qū)的大小根據(jù)實(shí)際情況自行修改,測(cè)試代碼中設(shè)置為1024:


unsigned int buffer_size = 1024;  
	  
/* 創(chuàng)建一個(gè)和指定IIO設(shè)備關(guān)聯(lián)的數(shù)據(jù)緩沖區(qū) */  
buffer = iio_device_create_buffer(dev, buffer_size, false);  
if (!buffer) {  
    char buf[256];  
    iio_strerror(errno, buf, sizeof(buf));  
    fprintf(stderr, "Unable to allocate buffer: %s\n", buf);  
    iio_context_destroy(ctx);  
    return EXIT_FAILURE;  
}


  在讀取數(shù)據(jù)之前,我們需要先確定需要讀取的通道的樣本大小,以方便我們來判斷緩沖區(qū)內(nèi)的數(shù)據(jù),是否均為需要的樣本數(shù)據(jù):


/* 獲取IIO設(shè)備中當(dāng)前樣本長(zhǎng)度,因?yàn)锳D的精度為12位,獲取到的值應(yīng)該為2(byte) */  
sample_size = iio_device_get_sample_size(dev);  
/* Zero isn't normally an error code, but in this case it is an error */  
if (sample_size == 0) {  
    fprintf(stderr, "Unable to get sample size, returned 0\n");  
    iio_context_destroy(ctx);  
    return EXIT_FAILURE;  
} else if (sample_size < 0) {  
    char buf[256];  
    iio_strerror(errno, buf, sizeof(buf));  
    fprintf(stderr, "Unable to get sample size : %s\n", buf);  
    iio_context_destroy(ctx);  
    return EXIT_FAILURE;  
}


  接下來就可以開始讀取數(shù)據(jù)了,讀取的時(shí)候可以指定需要讀取的數(shù)據(jù)長(zhǎng)度。讀取的數(shù)據(jù)可以根據(jù)實(shí)際的需求進(jìn)行處理,比如保存到文件中,例子中是直接通過fwrite將數(shù)據(jù)寫到stdout中,其實(shí)就是直接打印到串口終端中:


/* 主循環(huán),讀取數(shù)據(jù)和處理 */  
while(app_running) {  
    /*  獲取通道更多樣本 */  
    ret = iio_buffer_refill(buffer);  
    if (ret < 0) {  
        if (app_running) {  
            char buf[256];  
            iio_strerror(-(int)ret, buf, sizeof(buf));  
            fprintf(stderr, "Unable to refill buffer: %s\n", buf);  
            break;  
        }  
    }  
  
    /* 獲取channel中兩個(gè)sample之間的長(zhǎng)度,并判斷和IIO設(shè)備的sample_size是否相等 
     * 如果相等,說明全部是需要的樣本,直接讀取 
     * 如果不相等,說明存在其他數(shù)據(jù),需要單獨(dú)解析處理 
     * */  
    if (iio_buffer_step(buffer) == sample_size) {  
        /* 獲取buffer中的起始地址和結(jié)束地址,并計(jì)算數(shù)據(jù)長(zhǎng)度 */  
        void *start = iio_buffer_start(buffer);  
        size_t read_len, len = (intptr_t) iio_buffer_end(buffer)  
        - (intptr_t) start;  
  
        if (num_samples && len > num_samples * sample_size)  
            len = num_samples * sample_size;  
  
        /* 數(shù)據(jù)處理,這里通過fwrite函數(shù)將數(shù)據(jù)直接輸出到stdout中 
         * 用戶可以根據(jù)實(shí)際的情況進(jìn)行處理,比如寫入到記錄文件中 
         * */  
        for (read_len = len; len; ) {  
            size_t nb = fwrite(start, 1, len, stdout);  
            if (!nb)  
                goto err_destroy_buffer;  
  
            len -= nb;  
            start = (void *)((intptr_t) start + nb);  
        }  
	  
        /* 讀取了指定長(zhǎng)度(num_samples)的數(shù)據(jù)后,釋放資源并退出 */  
        if (num_samples) {  
            num_samples -= read_len / sample_size;  
        if (!num_samples)  
            quit_all(EXIT_SUCCESS);  
        }  
        else {  
            /* 如果channel存在其他數(shù)據(jù),只能進(jìn)行單獨(dú)處理,一個(gè)一個(gè)樣本的讀取 
             * 并通過回調(diào)函數(shù)print_sample來處理,同樣回調(diào)函數(shù)中也只是通過fwrite函數(shù) 
             * 將數(shù)據(jù)輸出到sdtout中,用戶可以根據(jù)自己的需求修改 
             * */  
            ret = iio_buffer_foreach_sample(buffer, print_sample, NULL);  
            if (ret < 0) {  
                char buf[256];  
                iio_strerror(-(int)ret, buf, sizeof(buf));  
                fprintf(stderr, "buffer processing failed : %s\n", buf);  
            }  
        }  
    }  
}


  在實(shí)際測(cè)試中,我們接入了一個(gè)頻率為1KHz,幅度為0-3.3V的正弦波,使用程序采樣了1024個(gè)點(diǎn)存入了文件中,然后使用gnuplot軟件繪制波形如下:


基于Linux IIO接口的波形采集.png


  多通道和單通道的連續(xù)采集在軟件上是類似的,區(qū)別只在于使能的通道數(shù)量不一樣。英創(chuàng)公司也即將推出支持基于IIO(Industrial I/O)子系統(tǒng)的多通道連續(xù)采樣的主板,我們將在后續(xù)的文章中繼續(xù)介紹。


  感興趣的客戶可以聯(lián)系英創(chuàng)的工程師索要例程的代碼。

主站蜘蛛池模板: 日韩欧美亚洲精品| 成人午夜在线| 久久综合九色综合97婷婷女人| 国产在线观看免费一级| 99久久综合给久久精品| 久久久久久全国免费观看| 免费一级特黄视频| 精品91自产拍在线| 亚洲女教师| 一级美国片免费看| 日本综合久久| 亚洲国产精品一区二区第四页| 国产美女无遮挡免费视频 | 伊人色在线观看| 国产大片www| 精品免费久久| 国产精品成人在线播放| 久久视频精品线视频在线网站| 91精品国产高清久久久久久 | 美女18一级毛片免费看| 免费看片在线| 香蕉国产在线观看免费| 日本一区二区不卡在线| 永久在线观看www免费视频| 国产一区二区视频免费| 国产精品素人搭讪在线播放| 韩国特黄毛片一级毛片免费| 国产刚刚发育被强j在线播放| 日韩欧美精品| 亚洲欧美自拍视频| 久久国产a| 亚洲最大的黄色网址| 免费一级黄色片| 免费黄毛片| 欧美久久超级碰碰碰二区三区| 大陆精品自在线拍国语| 日韩精品首页| 日韩在线一区高清在线| 香蕉视频色板| 亚洲 欧美 另类 综合 日韩| 亚洲视频在线不卡|