• <progress id="w0lee"></progress>

  • <span id="w0lee"></span>
  • ESM7000異構CPU實時應用之三
    8路并行數采應用程序

     2021-5-14     作者:黃志超    

      英創公司推出了ESM7000異構CPU的實時應用,由高性能的Cortex-A7雙核完成人機交互、數據處理、通訊管理等復雜運算,而對于高速的數據采集、中斷事件響應等實時任務交由i.MX7D的Cotex-M4完成,具體的介紹可以參考文章《ESM7000異構CPU架構實時應用簡介》?;贓SM7000的異構CPU平臺,英創公司實現了多通道的高速數采方案,該方案最高支持100kSPS采樣率的AD轉換。


      關于M4端的AD操作的實現可以參考文章《ESM7000異構CPU實時應用之一 8通道并行100K 16bit AD采集》,本文主要介紹Linux系統中需要做的操作以及程序的實現,文章分為三個部分,第一部分是介紹如何將編譯好的M4程序燒寫到主板中,并設置自動啟動。第二部分是介紹如何加載英創公司提供的RPMsg驅動,RPMsg驅動主要實現了ESM7000中Crotex-A7核心與M4核心之間的通訊。第三部分是介紹Linux系統端User app的實現和性能的測試結果,其中User app正是通過英創公司定義的RPMsg通訊協議來實現的,關于RPMsg和通訊協議具體的介紹可以參考文章《ESM7000異構CPU實時應用之二 基于rpmsg的通訊機制》。


      本文測試硬件平臺基于ESM2001工控機,感興趣的客戶可參考這里:EMX2000系列工控機。


    M4應用程序的燒寫


      首先將編譯好的M4應用程序(這里以英創公司提供的例程emx2001.bin為例)拷貝到主板中的,例如/mnt/mmc中,然后就可以通過英創公司提供的工具flash_opt將程序燒寫到系統中,并設置好隨系統自動啟動。flash_opt工具已經集成在了主板中,可以直接在命令執行。


      M4的應用程序可以選擇三個區域燒寫,分別是TCM、OCRAM 或 DDR 中運行,在TCM中的運行速度最快,但是代碼空間最小,OCRAM中運行速度會慢一些,代碼空間相對更大,而DDR中代碼運行速度最慢,但是代碼空間最大。各個區域提供的程序代碼空間具體數據如下表所示:


    Configure文件名CODE Size
    TCMemx2001_tcm.bin32K
    OCRAMemx2001_ocram.bin128K
    DDRemx2001_ddr.bin1MB

      在燒寫前需要根據不同的燒寫區域對程序重命名,如果需要燒寫到TCM 中,則程序需要命名為 emx2001_tcm.bin,如果燒寫到 OCRAM 中,則命名為 emx2001_ocram.bin,如果是燒寫到 DDR,則為 emx2001_ddr.bin。重命名只是為了滿足 flash_opt 對命令格式的要求,程序在編譯時必須根據運行的位置選擇對應的 ESM7000_M4_*.ld 文件。


      比如我們需要將emx2001.bin放在TCM中,則將程序命名為emx2001_tcm.bin,然后輸入命令#>flash_opt m4 /mnt/mmc/ emx2001_tcm.bin,如下圖:


    ESM7000異構CPU實時應用之三 8路并行數采應用程序.png


      完成之后,每次主板重啟就都會自動啟動燒寫進去的M4應用程序。關于程序放在不同區域的具體的說明和對比,可以參考《ESM7000 Cortex-M4技術開發參考手冊》,這里不再贅述。


    RPMsg驅動的加載


      RPMsg的驅動也同樣集成在了系統中,可以直接通過命令加載,只需要一條命令#>modprobe emx_rpmsg_tty,加載后驅動會生成響應的設備節點/dev/ttyEMx同時會打印出關于AD的信息,如下圖:


    ESM7000異構CPU實時應用之三 8路并行數采應用程序.png


      從驅動打印的信息可以看到AD的詳細參數信息。驅動加載完成后,就可以運行User app來進行采集了。


    User app的實現和測試


      通過《ESM7000異構CPU實時應用之二 基于rpmsg的通訊機制》的介紹,我們已經了解了英創公司設計的基于RPMsg的通訊協議,本文介紹的User app正是使用這一套通訊協議來實現的。


      驅動emx_rpmsg_tty.ko會虛擬出串口設備,所以通信部分的代碼都是使用的串口的標準操作函數來實現的。首先是向M4發送消息,設置好AD的采樣率,然后啟動AD,通過write函數就可以向M4發送數據,英創公司已經封裝好了函數供客戶參考:


    int EM_Adc::setup_adc( int freq )  
    {  
        int ret;  
        struct emx_rpmsg_t  *msg_t;  
      
        //打開虛擬串口ttyEMx,并建立好接收線程  
        ret = OpenPort();  
        if( ret<0 )  
        {  
            printf( "ttyEMx open fail\n");  
            return -1;  
        }  
      
        //發送復位指令  
        ret = Send_cmd(CMD_CODE_RESET, NULL, 0);  
        if( ret<0 )  
        {  
            printf( "send failed\n");  
        }  
          
        //發送設置指令,設置AD的采樣率  
        ret = Send_cmd(CMD_CODE_SETUP, (void *)&freq, sizeof(freq));  
        if( ret<0 )  
        {  
            printf( "send failed\n");  
        }  
      
        //發送啟動指令,開始采集  
        ret = Send_cmd(CMD_CODE_RUN, NULL, 0);  
        if( ret<0 )  
        {  
            printf( "send failed\n");  
        }  
        Dflags = 1;  
      
        return 0;  
    }

     

      啟動了AD之后,M4就會開始進行數據采集,因為多通過告訴采集的數據量十分龐大,所以采用了共享內存的方式來發送數據。例程定義了兩塊32KB大小的共享區域,當M4采集的數據量達到16K之后,就會將數據寫入共享內存中,然后根據通訊協議發送消息通知User app去讀取。我們還是通過一個線程來專門接收采集數據,具體代碼如下:


    int EM_Adc::PackagePro( char* Buf, int len )  
    {  
        int         i1, num;  
        int         buf_len;  
        char        status_buf[100];  
      
        memcpy(&msg, (char *)Buf, sizeof(struct emx_rpmsg_t));  
        if(msg.cmd == CMD_CODE_DATA) {  
            Mlen = msg.len;  
            //判斷數據存放在哪一塊共享區域,然后將數據拷貝出來  
            if(msg.flags == 0) {  
                memcpy(MemBuf, (void *)base0, msg.len);  
            }  
            else {  
                memcpy(MemBuf, (void *)base1, msg.len);  
            }  
            //處理數據,這里是將每個通道的數據保存成文件  
            save_data(MemBuf, Mlen);  
        }  
      
        return 0;  
    }

     

      例程中數據的處理主要是把每個通道的數據分離出來,分別保存在不同的文件中。為了保證寫文件的速度,一開始是寫在內存中,當文件大小超過1MB,就關閉AD,并且將文件拷貝到/mnt/mmc中儲存,處理數據的代碼如下:


    int EM_Adc::save_data(int16_t *data, int len)  
    {  
        FILE    *fp;  
        char filename[20];  
        int     i1, i2, ret;  
      
        for(i1=0; i1<8; i1++) {  
            sprintf( filename, "/tmp/ch%d", i1);  
            fp = fopen(filename, "ab+");  
            if( fp==NULL )  
            {  
                    printf("open %s fail!\n", filename);  
                    ret = -1;  
                    return ret;  
            }  
      
            //將每個通道的數據分離出來,分別保存在文件中  
            for(i2=0; i2<(len/16); i2++) {  
                memcpy(&CHxBuf[i2], ((int16_t *)data + i1 + i2*8), sizeof(int16_t));  
            }  
            fwrite( CHxBuf, (i2-1)*sizeof(int16_t), 1, fp );  
      
            //如果保存數據已經大于1M,則關閉AD,將文件移至/mnt/mmc目錄保存,然后退出程序  
            if(i1 == 7) {  
                fseek(fp, 0, SEEK_END);  
                long length  = ftell(fp);  
                if(length > 1024*1024) {  
                    fclose(fp);  
                    system("cp /tmp/ch* /mnt/mmc");  
                    stop_adc();  
                    return 0;  
                }  
            }  
            fclose(fp);  
        }  
        return 0;  
    }

     

      在實際測試的時候,我們將兩路正弦波信號分別接入通道1和通道2,當采集完成后使用波形繪制工具讀取保存的文件,效果如下:


    ESM7000異構CPU實時應用之三 8路并行數采應用程序.png


      從圖中可以看到采集波形的效果,在實際應用中,客戶可以根據需求自行修改對于數據處理的方式。


      M4端應用程序采用的方式是每采集16000字節發送一次數據,為了驗證這套方案能夠滿足應用需求,我們對M4通過RPMsg發出消息,到Linux系統中User app讀取到共享內存數據的時間做了詳細的測試,響應時間如下表:


    采樣率平均時間(us)最長時間(us)
    5ksps298495
    10ksps300489
    50ksps287488
    100ksps287469

      按照100ksps的采樣率計算,M4端每10us會采集一次,每個通道單次采集數據大小為2Byte,8個通道就為16Byte。所以在100Ksps采樣率的情況下,每10ms就會發送一次數據。按照這個時間間隔來看,ESM7000異構CPU平臺完全可以滿足需求。


      對這套方案感興趣的客戶可以和英創公司的工程師聯系,索取相關例程的代碼。

    强奷漂亮脱肉丝袜无码视频-毛1卡2卡3卡4卡免费视频-亚洲成a∨人片在线观看无码-欧美日韩一区二区综合