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

基于PCIE接口的高速大容量數據采集——軟件篇

 2022-5-7     作者:Emtronix         

  高速大容量數據采集方案是一個可實現是連續采集數據率超過10MB/s的應用方案,方案的硬件由支持PCIE高速接口的Linux工控主板(ESM7100、ESM8100等)和基于FPGA的擴展模塊組成,軟件則包括符合Linux DMA Engine架構的DMA Controller驅動、DMA Client驅動及應用程序三個部分。方案的總體介紹請參考《基于PCIE接口的高速大容量數據采集—總體方案》一文。本文將重點介紹針對Xilinx的< DMA/Bridge Subsystem for PCI Express v4.1> FPGA IP核的特性,實現Linux DMA Engine架構驅動程序,并為應用程序提供簡潔方便的API函數,來控制數據采集過程并適時處理已在系統內存中的實時采集數據流。


  目前Xilinx公司為其IP核DMA/Bridge Subsystem for PCI Express v4.1,僅提供基于x86體系的驅動,而沒有在Linux DMA Engine架構上做工作。而事實上,DMA Engine架構已成為ARM嵌入式Linux平臺的DMA應用的事實標準(de facto),因此本方案針對高速大容量數據采集的需求,構建了DMA Engine架構的驅動程序,包括通用DMA Controller驅動和面向應用的DMA Client驅動,應用程序通過標準的字符型設備節點,操作DMA Client驅動,從而實現所需的數據采集。圖1是從軟件開發角度來看的總體功能框圖。


基于PCIE接口的高速大容量數據采集.png

圖1 方案總體功能框圖


  Linux DMA Engine架構的基本思路是把不同的DMA控制器封裝為統一的API接口,供面向應用的DMA Client調用。在本方案中,DMA Client驅動一方面通過DMA Engine的API函數操作PCIE端點的DMA功能,另一方面還要通過PCIE接口控制前端的數據采集邏輯。DMA Client驅動對上層的用戶應用程序,開放了一組標準的字符設備(char dev)API,供User App操作,在本方案中字符設備為“/dev/pcie0”。為了減少數據的搬動,采集數據緩沖區通常以ping-pong buffer的結構配置在Linux的保留存儲器(reserved memory)中,且用戶應用程序可通過mmap獲得ping-pong buffer指針,直接處理DMA傳上來的數據。Ping-pong buffer讓應用程序和DMA交替操作數據buffer,如應用程序處理buffer 0#的數據時,DMA把新數據傳送到buffer 1#,然后按固定時間周期ping-pong切換buffer,從而實現連續的實時數據采集和處理。字符設備“/dev/pcie0”僅傳遞采集硬件的控制與狀態信息。


DMA Engine API


  DMA Engine架構為不同的DMA模式提供不同的API函數,其中最主要的是單次DMA和周期DMA兩種,其API函數分別為:


struct dma_async_tx_descriptor *dmaengine_prep_slave_sg(
           struct dma_chan *chan, struct scatterlist *sgl,
           unsigned int sg_len, enum dma_data_direction direction,
           unsigned long flags);
 
struct dma_async_tx_descriptor *dmaengine_prep_dma_cyclic(
           struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
           size_t period_len, enum dma_data_direction direction);


  DMA Controller驅動要求DMA支持Scatter-gather結構的非連續數據Buffer,但在本方案的應用中,對單次DMA情形,采用單個Buffer是最常見的應用方式,這時可采用DMAEngine的簡化函數:


struct dma_async_tx_descriptor *dmaengine_prep_slave_singl(
           struct dma_chan *chan, dma_addr_t buf, size_t len, 
           enum dma_data_direction direction, unsigned long flags);


  Cyclic DMA模式,是把多個DMA Buffer通過其描述符(dma descriptor)表連接成環狀,當一個buffer的DMA傳送結束后,驅動程序的中斷線程將自動啟動面向下一個描述符的DMA Buffer。由DMA descriptor表描述的邏輯流程如圖2所示:


基于PCIE接口的高速大容量數據采集.png

圖2 Cyclic DMA邏輯流程


  本方案的DMA Controller驅動實現了上述兩種DMA傳輸方式,即單次DMA傳輸和周期DMA傳輸。DMA Controller驅動本質上講,是一種通用的DMA服務器,如何使用DMA的傳輸功能,實現具體的數據傳輸任務,則是由DMA Client來決定的。Linux把DMA服務與具體應用分成兩個部分,有利于DMA Controller驅動面向不同的應用場景。


DMA Client驅動


  DMA Client驅動是一個面向應用的驅動,如圖1所示,它需要與User Space的上層應用程序配合運行,來完成所需的數據采集與處理。


  單次DMA的操作如下所示。


/* prepare a single buffer dma */
desc = dmaengine_prep_slave_single(dchan, edev->dma_phys,
              edev->total_len, DMA_DEV_TO_MEM, 
              DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc) {
    dev_err(edev->dev, "dmaengine_prep_slave_single(..) failed\n");
    ret = -ENODEV;
    goto error_out;
}
 
/* setup dtaker hardware */
eta750_dtaker_setup(edev);
 
/* put callback, and submit dma */
desc->callback = dma_callback;
desc->callback_param = edev;
edev->cookie = dmaengine_submit(desc);
ret = dma_submit_error(edev->cookie);
if (ret) {
dev_err(edev->dev, "DMA submit failed %d\n", ret);
goto error_submit;
}
 
/* init complete, and fire */
reinit_completion(&edev->xdma_chan_complete);
dma_async_issue_pending(dchan);
 
/* simulate input data */
eta750_dtaker_run(edev);
 
/* wait dma complete */
count = wait_for_completion_timeout(&edev->xdma_chan_complete, msecs_to_jiffies(DMA_TIMEOUT));
if (count == 0) {
dev_err(edev->dev, "wait_for_completion_timeout timeout\n");
ret = -ETIMEDOUT;
eta750_dtaker_end(edev);
goto error_submit;
}
 
/* error processing */
eta750_dtaker_error_pro(edev);
 
/* stop front-end daq unit */
count = eta750_dtaker_end(edev);
 
/* dump data */
eta750_dtaker_dump_data(edev);
return edev->total_len;
 
error_submit:
dmaengine_terminate_all(dchan);
 
error_out: 
return ret;


  只有周期DMA方式才能實現連續數據采集,在DMA Client中采用雙DMA Buffer的乒乓結構來實現連續采集,應用程序處理0# Buffer數據時,DMA傳輸數據至1# Buffer,傳輸結束時,進行切換,應用程序處理1# Buffer數據,DMA傳輸新數據至0# Buffer。周期DMA需要指定每個buffer的長度period_len,同時需指定由2個buffer構成的ping-pong buffer的總長度total_len。其DMA流程如下所示。


/* prepare cyclic buffer dma */
desc = dmaengine_prep_dma_cyclic(dchan, edev->dma_phys, edev->total_len, 
edev->period_len, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
if (!desc) {
dev_err(edev->dev, "%s: prep dma cyclic failed!\n", __func__);
ret = -EINVAL;
goto error_out;
}
 
/* in cyclic mode */
edev->cyclic = true;
 
/* setup dtaker hardware */
eta750_dtaker_setup(edev);
 
/* put callback, and submit dma */
desc->callback = dma_callback;
desc->callback_param = edev;
edev->cookie = dmaengine_submit(desc);
ret = dma_submit_error(edev->cookie);
if (ret) {
dev_err(edev->dev, "cyclic dma submit failed %d\n", ret);
goto error_submit;
}
 
/* init complete, and fire */
reinit_completion(&edev->xdma_chan_complete);
dma_async_issue_pending(dchan);
edev->running = true; 
 
/* simulate input data */
eta750_dtaker_run(edev);
edev->data_seed += ((edev->period_len / sizeof(u16)) * edev->data_incr);
 
while(!kthread_should_stop()) {
/* wait dma complete */
count = wait_for_completion_timeout(&edev->xdma_chan_complete, msecs_to_jiffies(DMA_TIMEOUT));
if (count == 0) {
dev_err(edev->dev, "wait_for_completion timeout, transfer %d\n",
edev->transfer_count);
ret = -ETIMEDOUT;
break;
}
 
/* data processing */
eta750_dtaker_error_pro(edev);
edev->transfer_count++;
reinit_completion(&edev->xdma_chan_complete);
 
/* fill more data */
eta750_dtaker_run(edev);
edev->data_seed += ((edev->period_len / sizeof(u16)) * edev->data_incr);
}
 
/* stop front-end daq unit */
count = eta750_dtaker_end(edev);
edev->running = false; 
 
error_submit:
dmaengine_terminate_all(dchan);
edev->cyclic = false;
dev_info(edev->dev, "%s: dma stopped, cyclic %d, running %d\n", __func__,
edev->cyclic, edev->running);
 
error_out:
return ret;


  從上面代碼可見,傳送過程是一個無限循環,DMA Controller驅動會自動進行ping-pong buffer的切換。并通過回調函數通知上層應用程序,新數據已準備就緒。應用程序可通過命令來終止采集傳輸過程。


DTaker前端采集邏輯


  前端數據采集單元DTaker,包括在FPGA芯片XC7A50T-2CSG325中,主要是實現對AD芯片AD7606C的操作,并把數據寫入FPGA中的FIFO緩沖區中。從圖3可看到作為User Logic的DTaker與FIFO的相互關系。


基于PCIE接口的高速大容量數據采集.png

圖3 DTaker功能框圖


  從programming角度看,DTaker就是一組寄存器。代碼通過操作實現:(1)啟動AD轉換;(2)讀取AD數據,并按照一定格式把packed的數據寫入FIFO。具體說,DTaker是由8個32-bit寄存器及相關數字邏輯構成的可編程控制單元,寄存器的定義如下。


Offset寄存器名稱功能簡述
0x00CONTROL控制寄存器
0x04STATUS狀態寄存器
0x08PKG_SIZE采集數據長度寄存器
0x0CDAQ_CFG前端采集控制寄存器
0x10EVENT_CFG前端采集觸發事件配置寄存器
0x14-未定義
0x18CPU_DAT2CPU仿真測試數據
0x1CCPU_DAT3CPU仿真測試數據


  各個寄存器功能定義如下:


  DTaker控制寄存器 CONTROL各bit定義如下:

  D[3 : 0] = LEDOUT[3 : 0]

  D4 = EVENT_IRQEN,置1使能DTAKER觸發中斷,事件=某種觸發條件

  D5 = OVERFLOW_IRQEN,置1使能FIFO寫溢出中斷

  D6 = TIMEOUT_IRQEN,置1使能C2H接口超時中斷,暫不用

  D7 = DMAEN,置1使能AXIS transfer

  D8 = DAQEN,= 0:選擇CPU仿真數據;= 1: 選擇前端AD數據

  D9 = FIFO_RESET,置1清FIFO,軟件清零控制位

  D[31 : 10] = 暫時未用


  狀態寄存器STATUS,各bit狀態標志RO/W1C

  D[1 : 0] = KEY_IN[1:0]

  D2 = EVENT_FLAG,事件標志,W1C

  D3 = OVERFLOW_ERR,FIFO寫溢出錯誤標志,W1C

  D4 = EVENT_IRQ,事件中斷標志,W1C

  D5 = OVERFLOW_IRQ,FIFO寫溢出錯誤中斷標志,W1C

  D6 = TIMEOUT_IRQ,C2H接口超時中斷標志,W1C

  D7 = DEBUG_BIT,調試用,根據情況臨時定義具體內容

  D[17 : 8] = 10’b0000000000,暫時未用

  D18 = FIFO_FULL,=1: FIFO 已滿

  D19 = FIFO_EMPTY,=1: FIFO 已空

  D[22 : 20] = EVENT_CODE[2 : 0],事件編碼信息

  D23 = 1’b0,暫時未用

  D[31 : 24] = Version Info, RO


  DMA傳送長度寄存器PKG_SIZE,字節為單位,需16字節整倍數。每完成一次transfer,PKG_SIZE -= 8字節,直至PKG_SIZE = 0;PKG_SIZE = 8時,表示后續是最后一次transfer,TLAST = 1。


  數據采集配置寄存器DAQ_CFG,用于定義采集的通道、采樣率等參數。

  DAQ_CFG.D0 = RUN,置1啟動前端硬件數據采集。


  觸發事件配置寄存器EVENT_CFG,用于定義采集單元的觸發事件條件,如觸發通道、電平、觸發沿,觸發采集長度等參數。

  

  仿真數據寄存器CPU_DAT2。


  仿真數據寄存器CPU_DAT3,與CPU_DAT2構成一次64-bit的raw_data。由fifo_writer狀態機寫入XPM_FIFO_ASYNC。


應用程序


  從應用程序的角度看,程序的基本架構與《精簡ISA總線實現高速大容量數據采集》一文的描述是一樣的,其要點包括:

  1、使用預先劃定的Linux保留存儲區域作為采集數據buffer,應用程序通過mmap獲得buffer指針。

  2、打開設備文件(節點名稱:“/dev/pcie0”),通過write函數設置啟動數據采集過程,在接收線程通過poll函數等待驅動通知數據就緒信息。

  3、Write函數寫入pcie_dma_info數據結構,定義如下:


struct pcie_dma_info {
    dma_addr_t phys;        /* dma buffer start addr, */
                             /* = 0: internal buffer for testing */
    unsigned long size;     /* total buffer size in byte */
    int period;             /* = 1: single dma, > 1: cyclic dma */
    int count;              /* only for cyclic dma, = 0: free run, */
                            /* > 0: number of period buffer after */
                             /* event happened */
    u32  daq_config;        /* data acquisition config register in */
                             /* dtaker IP */
    u32  event_config;      /* event config register in dtaker IP */
};


  4、由數據就緒信息觸發對采集數據buffer的相應處理。


  對本方案有實際應用需求的客戶,可與英創公司技術支持聯系,以了解進一步的技術細節,進行實際的評估應用。

主站蜘蛛池模板: 欧美黄色网址大全| 日韩精品中文字幕一区二区三区| 国产的大片免费看| 黑色丝袜高跟国产在线91| 一区二区在线视频免费观看| 免费国产不卡午夜福在线观看| 露脸在线| 欧美日韩亚洲一区二区三区| 三上悠亚vr| 多女多p多杂交视频在线观看| 国产精品果冻麻豆精东天美| 国产亚洲综合成人91精品| 尤物综合| 成人国产亚洲| 国产性高清在线观看| 黄网站色网址| 国内自拍videos hd| 日本护士xxxxx极品| 91在线公开视频| 中国一级毛片欧美一级毛片| 欧美成人禁片在线观看俄罗斯| 麻豆国产果冻传媒网站入口| 精品欧美小视频在线观看| 亚洲好色网| 久久久99精品| 亚洲全网成人资源在线观看| 国产 欧美 日产久久| 美国黄色在线观看| 成人影院久久久久久影院| 青草视频在线观看免费视频| 91在线高清| 91频视| 日本xxxwww色视频| 在线观看免费视频黄| 国产一区二区三区不卡在线观看 | 91精品啪在线观看国产色| 日韩欧美一级毛片视频免费| 免费在线观看的黄色网址| 欧美三级不卡视频| 国产精品久久亚洲不卡4k岛国| 影音先锋一区二区三区视频|