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

基于Linux IIO接口的波形采集

 2022-5-16     作者:黃志超         

  我們在《Linux IIO接口的低成本8通道AD》這篇文章中,已經介紹了如何通過程序對IIO設備進行單次讀取,接下來我們就介紹波形的實現,關于IIO子系統的詳細說明可以參考資料Linux Industrial I/O Subsystem


  本次測試采用的平臺還是ESM7200主板加上ESMARC通用評估底板,波形采集要求AD能夠進行等時的連續采樣,在IIO子系統的部分需要有較多的設置,所以推薦直接使用ADI公司提供的libiio庫,這個庫文件抽象了和硬件相關的底層細節,并提供了簡單而完整的編程接口,可以省去很多和硬件相關的設置,英創公司已經將libiio移植到了ESM7200主板上。


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


管腳AD通道對應設備名稱索引號連續采集 
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


  同時因為受到CPU內部時鐘分頻的限制,所以ESM7200連續采樣的速率只能夠支持幾個特定的值,可參考下表:


支持頻率(KHz)5809829676150007541

表2


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


  整個程序的基本流程如下:


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


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


static struct iio_context *ctx;  
struct iio_device *dev;  
	  
/* 獲取IIO設備 */  
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子系統中,在連續采樣時,會分配一個可自定義長度的環形緩沖區,這個緩沖區需要一個觸發(trigger)才能夠使用。這里我們可以通過軟件模擬創建一個trigger,通過下面的命令就可以創建一個軟件模擬的trigger:

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


  在ESM7200主板啟動后,輸入一次這個命令即可,可以通過英創公司提供的自啟動腳本來執行。


  創建好trigger后,就可以在程序中為IIO設備指定這個trigger了,libiio提供的API可以獲取創建的trigger并設置到對應的IIO設備中:


static const char *trigger_name = "sysfstrig1";  
struct iio_device *trigger;  
	  
/* 獲取trigger并設置 */  
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),并使能連續采集。因為ESM7200主板只支持單通道的連續采集,所以這里我們只選擇一路來使能:


struct iio_channel *ch;  
	  
/* 使能對應的IIO通道,可以根據實際情況修改成需要的通道 */  
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);

 

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


int sample_freq[4] = {58098, 29676, 15000, 7541};  
	  
/* 設置采樣頻率,因為分頻的原因,只能提供幾組固定的采樣頻率 
 * 可以參考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);  
}

 

  創建一個環形緩沖區用于存儲連續采集的數據,環形緩沖區的大小根據實際情況自行修改,測試代碼中設置為1024:


unsigned int buffer_size = 1024;  
	  
/* 創建一個和指定IIO設備關聯的數據緩沖區 */  
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;  
}


  在讀取數據之前,我們需要先確定需要讀取的通道的樣本大小,以方便我們來判斷緩沖區內的數據,是否均為需要的樣本數據:


/* 獲取IIO設備中當前樣本長度,因為AD的精度為12位,獲取到的值應該為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;  
}


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


/* 主循環,讀取數據和處理 */  
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中兩個sample之間的長度,并判斷和IIO設備的sample_size是否相等 
     * 如果相等,說明全部是需要的樣本,直接讀取 
     * 如果不相等,說明存在其他數據,需要單獨解析處理 
     * */  
    if (iio_buffer_step(buffer) == sample_size) {  
        /* 獲取buffer中的起始地址和結束地址,并計算數據長度 */  
        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;  
  
        /* 數據處理,這里通過fwrite函數將數據直接輸出到stdout中 
         * 用戶可以根據實際的情況進行處理,比如寫入到記錄文件中 
         * */  
        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);  
        }  
	  
        /* 讀取了指定長度(num_samples)的數據后,釋放資源并退出 */  
        if (num_samples) {  
            num_samples -= read_len / sample_size;  
        if (!num_samples)  
            quit_all(EXIT_SUCCESS);  
        }  
        else {  
            /* 如果channel存在其他數據,只能進行單獨處理,一個一個樣本的讀取 
             * 并通過回調函數print_sample來處理,同樣回調函數中也只是通過fwrite函數 
             * 將數據輸出到sdtout中,用戶可以根據自己的需求修改 
             * */  
            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);  
            }  
        }  
    }  
}


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


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


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


  感興趣的客戶可以聯系英創的工程師索要例程的代碼。

主站蜘蛛池模板: 在线观看永久免费视频网站| 一级日本特黄毛片视频| 成年大片免费高清在线观看| 99久久伊人一区二区yy5099| 久久这里有精品| 手机看片一区| 亚洲一区二区三区成人| 一级片一级片一级片| 日本高清免费毛片久久看| 亚洲国产成人久久综合碰碰动漫3d| 欧美日韩一区二区视频免费看| 国产免费jizz在线播放视频| 高清国产一级毛片国语| 精品香蕉99久久久久网站| 青春草在线视频精品| 91成人高清在线播放| 大学生a级毛片免费观看| 日本大片成人免费网址| 中文字幕精品视频在线观看| 在线第一福利视频观看 | 国产在线拍揄自揄视精品不卡| 青青热久免费精品视频在线观看| 亚洲欧美激情综合第一区| 广东东莞一级毛片免费| 中国一级特黄特爽刺激大片| 在线成h人视频网站免费观看| 国产午夜高清一区二区不卡| 福利视频在线播放| 91孕妇精品一区二区三区| 国产chinese在线视频| 国产精品综合一区二区| 国产在线精品视频| 精品一久久香蕉国产二月| 久久亚洲精品成人| 麻豆视频网站在线观看| 亚洲精品不卡在线| 亚洲视频欧美| 亚洲一二三| 亚洲欧美色欧另类欧| 亚洲精品午夜视频| 亚洲国产精品xo在线观看|