<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     作者:黃志超          524次

      我們在《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(  
            ctxtrigger_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] = {5809829676150007541};  
      
    /* 設置采樣頻率,因為分頻的原因,只能提供幾組固定的采樣頻率 
     * 可以參考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)子系統的多通道連續采樣的主板,我們將在后續的文章中繼續介紹。


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

    精品精品国产自在97香蕉| 国产精品免费一区二区三区四区| 91精品婷婷国产综合久久| 奇米精品一区二区三区在| 麻豆国产精品一二三在线观看| 久久精品国产第一区二区三区| 99久久精品国产免看国产一区| 国产精品久久久久久影视| 免费精品国偷自产在线在线| 人妻少妇精品视中文字幕国语| 91精品国产自产在线观看永久| 精品一区二区三区四区电影| 亚洲国产精品日韩av不卡在线| 无码国产69精品久久久久网站| 日韩精品无码一区二区三区AV| 亚洲av午夜精品一区二区三区| 日韩精品中文字幕无码专区| 无码国产精品一区二区免费式影视| 99久久精品国产亚洲| 国产成人精品午夜福利| 中文国产成人精品久久一区 | 亚洲国产高清在线精品一区| 久久精品国产99国产电影网 | 精品久久洲久久久久护士| 2020天堂在线亚洲精品专区| 久久无码国产专区精品| 久久99精品久久水蜜桃| 久久国产精品岛国搬运工| 久久精品九九亚洲精品天堂 | 久久久久国产精品免费免费不卡| 国产午夜福利精品久久2021| 精品国产一区二区22| 久久九九久精品国产| 一本色道久久综合亚洲精品高清| 久久国产精品一区| 九九热这里只有国产精品| AV无码精品一区二区三区宅噜噜| 惠民福利中文字幕人妻无码乱精品| 国产韩国精品一区二区三区| 国产精品龙口护士门在线观看| 国产精品黄页免费高清在线观看|