該項(xiàng)目介紹了如何在 PL 中的 HDL 與 FPGA 中的處理器上運(yùn)行的嵌入式 C 之間傳輸數(shù)據(jù)的基本結(jié)構(gòu)。
介紹
鑒于機(jī)器學(xué)習(xí)和人工智能等應(yīng)用的 FPGA 設(shè)計(jì)中硬件加速的興起,現(xiàn)在是剝開幾層“云霧”并討論 HDL 之間來回傳遞數(shù)據(jù)(主要指FPGA 的可編程邏輯 (PL) 中運(yùn)行的代碼以及 FPGA 中的硬核或軟核處理器上運(yùn)行的相應(yīng)軟件之間傳輸數(shù)據(jù))的基礎(chǔ)知識(shí)的好時(shí)機(jī)。
硬件加速可以總結(jié)為在硬件(也稱為 FPGA 的可編程邏輯)中實(shí)現(xiàn)某些功能的基本思想,這些功能之前在位于主機(jī) PC 上或在 FPGA 上處理器(軟核或者硬核)運(yùn)行的軟件。因此,要成為一名高效的設(shè)計(jì)人員,就必須掌握如何在硬件和軟件之間來回傳遞數(shù)據(jù)的技巧。
在本例中,使用的是 Zynq SoC(片上系統(tǒng))FPGA,它具有硬核 ARM 處理器。該 ARM 核心和外設(shè)稱為處理系統(tǒng)或 PS。
雖然有幾種不同的方法可以完成 PL 和 PS 之間的數(shù)據(jù)傳輸,包括編寫自己的自定義接口,但我認(rèn)為最常見的機(jī)制是通過直接內(nèi)存訪問 (DMA) 傳輸。這是因?yàn)?DMA 允許 ARM 內(nèi)核的 CPU 簡單地啟動(dòng)自身與 DDR 之間的數(shù)據(jù)傳輸,而 CPU 無需等待傳輸完成后再執(zhí)行任何其他任務(wù)。DMA 還允許 CPU 啟動(dòng)外部設(shè)備和 DDR 之間的傳輸。
在此項(xiàng)目中,將通過使用 Xilinx DMA IP 演示 DMA 的功能,該IP可通過 AXIS 總線將內(nèi)存映射接口轉(zhuǎn)換為stream接口。將 32 字節(jié)寫入嵌入式 C 中的內(nèi)存,然后通過內(nèi)存映射將其傳輸?shù)?PL 到流 (MM2S) AXIS,通過寄存器處理每個(gè)值,然后通過流將數(shù)據(jù)傳輸回內(nèi)存DMA IP 的內(nèi)存映射 (S2MM) 端口。
雖然這個(gè)示例對(duì)于重型硬件加速應(yīng)用來說過于簡單,但當(dāng)剛接觸 FPGA 時(shí),這種高速數(shù)據(jù)傳輸水平可能會(huì)變得非常復(fù)雜/難以學(xué)習(xí)。該項(xiàng)目重點(diǎn)介紹 DMA 的使用及其行為。雖然打算讓這個(gè)項(xiàng)目更多地關(guān)注數(shù)據(jù)處理方面,但在 DMA 事務(wù)實(shí)現(xiàn)中發(fā)現(xiàn)了很多小“陷阱”,因此不得不將數(shù)據(jù)處理重點(diǎn)留給另一個(gè)項(xiàng)目。
使用 AXI DMA 控制 PL 中的 HDL 與 PS 中的 C 代碼之間的數(shù)據(jù)傳輸有兩個(gè)主要層:
Memory Map to Stream (MM2S) 和 Stream to Memory Map (S2MM) 通道上 PL 的 HDL 代碼中的 AXI 流握手信號(hào)(DMA 的控制通道是使用普通 AXI 寫入的,但這就是全部由 Vivado 自動(dòng)處理,因此在這里只關(guān)注 AXI stream接口)。
PS 的 C 代碼中寄存器讀/寫 DMA 的順序。
Verilog 中的 AXI-Stream握手
AXI stream接口使用一組簡單的握手信號(hào)機(jī)制,用于嵌入式設(shè)計(jì)中的數(shù)據(jù)交換。AXI stream接口中有許多可選信號(hào),但與 DMA MM2S 和 S2MM 數(shù)據(jù)交換相關(guān)且必需的信號(hào)是 tdata、tvalid、tready、tlast 和 tkeep。AXI stream中發(fā)送數(shù)據(jù)為主接口,接收數(shù)據(jù)為從接口。
tdata:數(shù)據(jù)總線
tvalid:當(dāng)放置在 tdata 總線上的數(shù)據(jù)有效時(shí),由主接口置位
tredy:當(dāng)從機(jī)處于準(zhǔn)備接收 tdata 總線上的數(shù)據(jù)的狀態(tài)時(shí),由從機(jī)置位
tlast:由主設(shè)備在 tdata 總線上流中最后一個(gè)數(shù)據(jù)包的持續(xù)時(shí)間內(nèi)斷言,以告訴從設(shè)備該數(shù)據(jù)包之后不會(huì)有數(shù)據(jù)
tkeep:由主設(shè)備設(shè)置的 tdata 總線上數(shù)據(jù)包的二次驗(yàn)證,指示數(shù)據(jù)包是否是流的一部分
AXI DMA IP 究竟如何實(shí)現(xiàn)此握手接口將數(shù)據(jù)傳輸出內(nèi)存 (MM2S) 并傳輸?shù)絻?nèi)存 (S2MM),這一點(diǎn)非常變化無常,尤其是在 S2MM 方面……
然而,我們首先需要了解的是有關(guān) AXI DMA 的 S2MM 事務(wù)的信息,大部分可以總結(jié)為一句話:必須設(shè)置 S2MM 事務(wù),并且在嘗試向 DMA 發(fā)送任何數(shù)據(jù)之前,以適當(dāng)?shù)捻樞驅(qū)懭?DMA 中的適當(dāng)控制寄存器來啟動(dòng)事務(wù),一旦 S2MM 通道看到 tlast 信號(hào),它就會(huì)停止事務(wù)。
數(shù)據(jù)傳輸發(fā)生在每個(gè)時(shí)鐘周期的 S2MM 和 MM2S 事務(wù)中的 tdata 總線上,其中tready 和 tvalid 均被置位(true)。因此,當(dāng)負(fù)責(zé)斷言 tvalid 時(shí),在 AXI 接口的主端必須小心,當(dāng)從從機(jī)傳入的 trety 信號(hào)也為 tvalid 斷言時(shí),不要讓 tvalid 斷言超過一個(gè)時(shí)鐘周期。否則,從設(shè)備將在同一個(gè)數(shù)據(jù)包計(jì)時(shí)兩次,作為兩個(gè)單獨(dú)的數(shù)據(jù)包。并且因?yàn)楸仨氃诳刂萍拇嫫髦兄付▊鬏斨杏卸嗌僮止?jié),所以 DMA 通道(在本例中為 S2MM)會(huì)在看到提供 tlast 信號(hào)之前認(rèn)為交換已結(jié)束,因?yàn)橛?jì)數(shù)已關(guān)閉。
我用 Verilog 編寫了一個(gè)簡單的狀態(tài)機(jī),它實(shí)現(xiàn)了一個(gè)從 AXI stream接口來從 DMA 的 MM2S 通道接收數(shù)據(jù),通過寄存器傳遞stream中的每個(gè)數(shù)據(jù)包,然后實(shí)現(xiàn)一個(gè)主 AXI strean接口來將數(shù)據(jù)流發(fā)回到S2MM通道。來自 tdata 總線的數(shù)據(jù)通過的寄存器旨在充當(dāng)占位符,用于為硬件加速進(jìn)行任何自定義數(shù)據(jù)處理。
從 Vivado 中的 ILA 中截取了一張屏幕截圖,顯示使用狀態(tài)機(jī)實(shí)現(xiàn)的時(shí)序圖。頂部是 MM2S 側(cè),底部是 S2MM 側(cè)。
這是 Verilog 狀態(tài)機(jī)的流程圖,實(shí)際文件附在本文末尾。值得注意的是,流程圖中的主/從接口是從 Verilog 狀態(tài)機(jī)的角度來看的。
對(duì)于 DMA IP 的具體設(shè)置,因?yàn)樵谥苯蛹拇嫫髂J较率褂?DMA,所以未選中分散收集選項(xiàng)。然后,將其他所有設(shè)置保留為默認(rèn)設(shè)置,并選中允許未對(duì)齊傳輸?shù)倪x項(xiàng),我發(fā)現(xiàn)在將自定義 AXI 流接口寫入 DMA 時(shí),這給了更多的自由空間。
為了將 Verilog 狀態(tài)機(jī)添加到模塊設(shè)計(jì)中,我右鍵單擊模塊設(shè)計(jì)的空白區(qū)域,然后選擇“添加模塊...”選項(xiàng),該選項(xiàng)將顯示 Vivado 可以在設(shè)計(jì)源中找到的所有有效 Verilog 模塊在BD中使用的文件。
值得注意的是,信號(hào)命名約定分別遵循從接口和主接口的“s_axis”和“m_axis”標(biāo)準(zhǔn)。
DMA 寄存器讀/寫控制序列
以下是裸機(jī)使用 DMA 時(shí)更簡單的順序:
1.通過將 1 寫入 MM2S(偏移量 0x00)和 S2MM(偏移量 0x30)控制寄存器的位 2 來復(fù)位 DMA。
2.將 S2MM 通道要寫入數(shù)據(jù)的 DDR 中位置的目標(biāo)地址寫入 S2MM DMA 目標(biāo)地址寄存器(偏移量 0x48)。
3.通過將 1 寫入 S2MM 控制寄存器(偏移量 0x30)的位 0 來啟動(dòng) DMA S2MM 通道。
4.通過將 S2MM 通道上要讀入內(nèi)存的總字節(jié)數(shù)值寫入 S2MM 緩沖區(qū)長度寄存器(偏移量 0x58),寫入 S2MM 通道緩沖區(qū)的長度。這將啟動(dòng) S2MM 傳輸,以便 DMA 準(zhǔn)備好從 FPGA 邏輯中的設(shè)備接收數(shù)據(jù)流(直到實(shí)際饋送數(shù)據(jù)并且 AXI 流總線上的 tvalid 由 FPGA 邏輯中的設(shè)備斷言后,該過程才會(huì)真正啟動(dòng))邏輯)。
5.將 MM2S 通道要讀取的數(shù)據(jù)的 DDR 中的源地址寫入 MM2S DMA 源地址寄存器(偏移量 0x18)。
6.通過將 1 寫入 MM2S 控制寄存器的位 0(偏移量 0x00)來啟動(dòng) DMA MM2S 通道。
7.通過將要發(fā)送的總字節(jié)數(shù)值寫入 MM2S 傳輸長度寄存器(偏移量 0x28),寫入 MM2S 通道的傳輸長度。這將啟動(dòng)從 DMA 到 FPGA 邏輯中的接收設(shè)備的 MM2S 傳輸。
還記得之前提到過,在 PL 中的設(shè)備嘗試向 S2MM 通道發(fā)送數(shù)據(jù)之前,必須啟動(dòng)并運(yùn)行 S2MM 通道嗎?嗯,這就是為什么要按順序執(zhí)行上述步驟。步驟 2 - 4 配置并啟動(dòng) S2MM 通道,步驟 5 - 7 配置并啟動(dòng) MM2S 通道。
在步驟 4 和 5 之間發(fā)生一些其他進(jìn)程是可以的,但步驟 2 - 4 必須在步驟 5 - 7 之前發(fā)生。執(zhí)行步驟 4 后,S2MM AXI 流通道將斷言其 Tready 信號(hào),此時(shí) HDL 代碼可以開始向其發(fā)送數(shù)據(jù)。
這也解釋了當(dāng)我第一次開始使用 DMA 時(shí),在 SDK/Vitis 中的示例 DMA 項(xiàng)目中注意到的一些事情??偸钦J(rèn)為示例代碼似乎是在使用 MM2S - XAXIDMA_DMA_TO_DEVICE 傳輸從 DDR 中寫入任何內(nèi)容之前嘗試將數(shù)據(jù)拉入 DDR(通過首先執(zhí)行 S2MM - XAXIDMA_DEVICE_TO_DMA 傳輸)。然而,S2MM 通道必須準(zhǔn)備好并等待接收數(shù)據(jù)才能正常工作并且不會(huì)鎖定。
在 FPGA 設(shè)計(jì)中,DMA 似乎是一種棘手的入門方法,但一旦你弄清楚它就會(huì)非常有幫助。
審核編輯:劉清
-
FPGA
+關(guān)注
關(guān)注
1629文章
21744瀏覽量
603665 -
嵌入式
+關(guān)注
關(guān)注
5083文章
19131瀏覽量
305549 -
HDL
+關(guān)注
關(guān)注
8文章
327瀏覽量
47398 -
片上系統(tǒng)
+關(guān)注
關(guān)注
0文章
186瀏覽量
26823 -
dma
+關(guān)注
關(guān)注
3文章
561瀏覽量
100604
原文標(biāo)題:使用 DMA 在 FPGA 中的 HDL 和嵌入式 C 之間傳輸數(shù)據(jù)
文章出處:【微信號(hào):Open_FPGA,微信公眾號(hào):OpenFPGA】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論