<strike id="kiyse"></strike>
  • <tr id="kiyse"></tr>
  • <strike id="kiyse"></strike><samp id="kiyse"><tbody id="kiyse"></tbody></samp>
    <strike id="kiyse"><s id="kiyse"></s></strike>
    <tr id="kiyse"></tr>
    <noframes id="kiyse"><code id="kiyse"></code></noframes>
    <th id="kiyse"></th>
    <samp id="kiyse"></samp>
  • <th id="kiyse"><s id="kiyse"></s></th>
  • 基于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)子系統的多通道連續采樣的主板,我們將在后續的文章中繼續介紹。


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

    久久久精品中文字幕麻豆发布| 精品无码国产污污污免费| 中日韩精品视频在线观看 | 久久国产精品一国产精品金尊 | 国产精品久久精品视| 久久精品国产久精国产思思| 精品久人妻去按摩店被黑人按中出| 久久综合鬼色88久久精品综合自在自线噜噜 | 国产精品女同一区二区久久| 2020精品极品国产色在线观看| 中文成人无字幕乱码精品区| 国产成人无码aa精品一区 | 国产精品αv在线观看| 亚洲国产成人精品电影| 久久国产精品99久久久久久老狼| 精品在线一区二区三区| 亚洲国产精品网站在线播放| 91精品国产高清久久久久久| 7777久久久国产精品消防器材| 国产一区精品视频| 午夜精品福利影院| 国产高清国产精品国产专区| 小辣椒福利视频精品导航| 999成人精品视频在线| 国产成人精品午夜福麻豆| 国产精品亚洲专区无码不卡| 亚洲AV永久无码精品放毛片| 久久精品国产四虎| 91精品一区二区三区在线观看| 国产精品jizz视频| 亚洲精品~无码抽插| 久久久久一级精品亚洲国产成人综合AV区 | 精品3d动漫视频一区在线观看 | 国产精品青草久久久久婷婷| 999精品久久久中文字幕蜜桃| 国产精品亚洲精品日韩已满| 久久久久国产精品嫩草影院| 好湿好大硬得深一点动态图91精品福利一区二区 | 亚洲精品午夜久久久伊人| 久久影院综合精品| 性色精品视频网站在线观看|