<cite id="15jzx"></cite>
<var id="15jzx"></var>
<ins id="15jzx"></ins>
<menuitem id="15jzx"></menuitem>
<cite id="15jzx"><span id="15jzx"><var id="15jzx"></var></span></cite>
<var id="15jzx"></var>
<cite id="15jzx"><strike id="15jzx"></strike></cite><var id="15jzx"></var>
<var id="15jzx"><video id="15jzx"></video></var>
<var id="15jzx"><video id="15jzx"></video></var>
<var id="15jzx"></var>
<var id="15jzx"></var><var id="15jzx"><video id="15jzx"><thead id="15jzx"></thead></video></var><cite id="15jzx"><span id="15jzx"><var id="15jzx"></var></span></cite><cite id="15jzx"><span id="15jzx"><menuitem id="15jzx"></menuitem></span></cite>

【技術分享】FPGA雜記之基礎篇二Demo案例

日期:2020-12-11 作者:潤欣科技創研社 返回列表

本文接續上一篇《FPGA雜記基礎篇》,繼續為大家分享IP例化和幾個基于FPGA芯片實現的Demo工程。



IP例化


IP即是一個封裝好的模塊,集成在相應的開發環境里面,以安路的TD軟件為例,不同系列的芯片集成了不同的IP模塊,可以通過軟件例化調用。


以下是安路TD4.6.5集成的EF3L40CG332B的相關IP。



1.1 PLL&RAM


以例化PLL和RAM為例,實現兩個異步雙口 RAM。


讀寫時鐘都設置 100Mhz, 兩個 RAM 為 RAMA 和RAMB, 深度為 1024,位寬為 8bit,寫入數據為 8bit,100Mhz 持續數據流, 當 RAMA被寫入 1024 字節數據后切換到寫 RAMB, RAMB 被寫入 1024 字節后切換 RAMA。以此循環類推。


當 RAMA 被寫入 1024 字節時, 給讀時序提供一個啟動信號讀取 RAMA 的數據, 讀取完 RAMA 的 1024 字節數據時, 切換讀 RAMB 以此類推。


這個工程的工程結構如下圖:



首先EF3L40CG332B_DEV開發板提供了25Mhz的晶振時鐘輸入到EF3L40CG332B的時鐘管腳。



想要得到100Mhz的讀寫速率,需要先用PLL得到倍頻時鐘。



在tools目錄下點擊IP Generator進入IP core頁面,并選擇PLL,輸入時鐘填入板子晶振25Mhz。



輸出時鐘填入所需要的100Mhz,并從C0輸出。



設置完成后,生成的module聲明如下(完整模塊可參考代碼)



再生成ram的IP模塊。


在IP core中選擇RAM。



Memory type選擇簡單雙口ram,memory size設置位寬8bit深度1024。


設置完成后,生成的module聲明如下。(完整模塊可參考代碼)



然后編寫頂層文件并且在頂層例化PLL和RAMA、RAMB。


頂層文件中主要是對ram的輸入口進行時序操作,包括ramA、ramB的讀地址,寫地址、使能信號和輸入輸出數據,詳細代碼筆記中不再贅述,可以直接參考代碼。


可綜合模塊編寫完成后,編寫仿真模塊并使用仿真軟件進行仿真。


由于本次工程使用到了安路的IP庫,因此也需要在modelsim中添加相應的安路仿真庫,添加方法如下:


首先在modelsim的安裝目錄下面編輯modelsim的初始化文件modelsim.ini,右鍵屬性后,將它的只讀屬性取消,然后用文本文件(本工程使用的是notepad++)編輯。



在modelsim.ini的[library]列表下添加安路的仿真庫文件目錄,安路所有的仿真庫文件都在安路的編譯軟件TD安裝目錄下的sim文件夾中,此處將其所有的庫文件都復制進了modelsim的文件夾里,若不復制,也可直接輸入安路文件夾的路徑。



保存后退出,打開modelsim并創建工程,編譯通過后,進入仿真步驟,在simulate狀態欄下選擇start simulate,如下圖:



選擇后進入到如下頁面:



選擇仿真的頂層并且關閉優化選項。


同一個窗口打開libraries頁面并在search libraries欄右側選擇add,下拉列表選擇對應的ef3的庫文件。



設置完成后點擊OK進入仿真即可。


本次實驗中遇見問題和調試如下:


01



剛開始pll沒有輸出信號,因此打開了pll查看波形發現pll波形如下:



發現是置位了reset信號導致的,查看代碼發現如下:



復位信號直接連接到了pll的置位信號,由于復位信號是低電平有效而置位信號是高電平有效,因此導致了pll一直處于復位的情況。更改后,直接將pll復位信號置0,代碼和仿真結果正常,如下所示:




02


PLL問題解決后,觀測數據整體讀寫情況。



初步觀測可以發現,rama讀使能信號只轉變了一次,而ramb的讀使能始終未能跳變,返回代碼查看發現:



邏輯判斷時未將rama的寫使能信號置1的條件寫出來。


ramb的寫使能同理:



修改后,代碼如下:



波形仿真如下:



粗看基本符合rama、ramb交替讀寫的功能,觀測rama、ramb時序交替細節。



在rama和ramb寫使能信號轉換時,發現空了一拍,再查看代碼,發現rama、ramb寫使能在條件判斷時,使用的判斷邏輯是不一樣的,導致ramb_wren的置位會在rama_wren置位后的下一拍進行。



因此更改ramb_wren的判斷條件,使之與rama_wren的一樣,都以寫地址為條件判斷再仿真。



可觀測到,時序正常。



quick start & GPIO Demo


本次demo實現功能如下:FPGA控制LED D1閃爍,MCU控制LED D2常亮。


2.1 keil工程環境創建


創建文件夾目錄如下:


圖1


其中板級支持包直接由原廠提供。


先創建keil工程,打開keil,創建工程,保存在對應的MCU→project目錄下。



器件選擇ARM cortex M3器件。



工程建好后,添加必要的BSP包中的文件如下,創建好后的工程目錄如左欄:



其中,startup組下的文件分別來自MCU\ELF2_BSP\Device\ELF2\Source和MCU\ELF2_BSP\Device\ELF2\Source\ARM目錄下;lib組的文件來自MCU\ELF2_BSP\Driver;log組文件保存在MCU\ELF2_BSP\Debug和MCU\ELF2_BSP\Debug\RTT目錄下。


新建main.c文件并保存在圖1所示的總文件目錄瀏覽的MCUàsrc文件夾下并添加main.c到工程main組中。



下面設置一些工程的環境,打開options for target對話框。



切換到user欄,設置如下參數,這些參數會影響輸出keil工程的*.asm 和*.bin 文件,我們需要通過添加這兩條指令得到bin文件并最終提供給FPGA。



添加的語句分別如下:


fromelf -c -v -a --output=@P.asm Objects\%L

fromelf --bin --output=@P.bin Objects\%L


再切換到C/C++欄,設置頭文件路徑如下:



也可以直接添加如下目錄


..\ELF2_BSP;..\ELF2_BSP\CMSIS\Core\Include;..\ELF2_BSP\Debug;..\ELF2_BSP\Debug\RTT;..\ELF2_BSP\Driver;..\ELF2_BSP\Driver\regmap;..\ELF2_BSP\Device\ELF2\Include;..\ELF2_BSP\Device\ELF2\Source\ARM


其余設置如下圖:



添加分散加載文件elf2_example.sct(elf2_example.sct文件具體代碼可參考工程)



環境設置完畢后可以開始編寫工程代碼。


2.2 C代碼編輯


在main函數中編寫對GPIO的操作。



先對GPIO初始化結構體賦值,再調用GPIO初始化函數,HAL_GPIO_WritePin函數對相應的GPIO進行高低賦值。


本次使用C代碼對GPIO1_0的操作是置低,GPIO1_0具體含義會在下一節(1.3)進行說明。


2.3 TD工程創建和代碼編輯


打開TD4.6.5或其他版本創建新的工程。



保存在總目錄的FPGA→project目錄下,并選擇對應的器件類型。



添加或者編輯源文件,本次工程模塊聲明如下:



其中hw_led是由FPGA邏輯控制的led,sw_led是由MCU代碼控制的led(即1.2中的gpio1_0)。hw_led的控制代碼如下,sw_led的控制代碼詳見1.2:



然后例化MCU和PLL,PLL例化主要得到輸入到MCU的系統時鐘,例化過程略,這里貼上在頂層中調用的結果:



輸出的200M的時鐘接到MCU的系統時鐘。


例化MCU界面如下:



如圖所示,MCU支持最大 32 個GPIO,其中低16位,即GPIO_L0~GPIO_L15是直接連接至pad的;而GPIOH0~GPIOH15則是通過FPGA連接至外部,因此,當使用這16個GPIO的時候,需要在FPGA工程的管教約束文件中指定具體連接至哪個腳。


在例化MCU時,使用到哪個腳就可以打開對應的開關,例如本例中,打開了L0、L1和H0,PPM_CLK,其中PPM_CLK是FPGA Fabric 輸入時鐘,連接至FPGA的PLL輸出clk200;L0、L1連接至PAD,觀察原理圖。



GPIO0和GPIO1連接的是調試口;最后H0連接至FPGA 中sw_led并通過管腳約束連接至LED D2。


工程的管教約束文件如下:



查開發板原理圖,D2連接至FPGA的16腳,且從原理圖可觀察,keil工程中對該GPIO的操作是置低,具體顯示是D2常亮。



設置完畢后,完成結果聲明如下:



并在頂層中調用:



2.4 下載


Keil和TD的工程都創建編寫完成后,編譯工程。其中,keil生成的工程bin文件需要與TD關聯并通過TD下載至芯片或開發板中。


關聯的步驟如下:


在HDL2Bit Flow欄右鍵選擇properties。



在generate bitstream的第六項instruct ram中選擇keil工程生成的bin文件的目錄(此時keil工程已經編譯通過),并保存。



保存后,雙擊generate bitstream編譯TD工程,假如在選擇路徑前已經編譯過TD工程了,需要右鍵選擇rerun重新編譯(注意:假如修改了keil的C文件而TD的HDL文件沒有變化,建議也rerun后再將文件下載至開發板)



下載:



板子現象如圖:


D1持續閃爍,D2常亮:



FPGA串口通信


本Demo案例基于安路的EF2M45LG48_MINI_DEV2開發板,通過測試板的uart口和PC機的uart口連接來形成一個閉環回路,即PC機發送數據至FPGA測試板,FPGA接收并返回相同的數據。實驗結果通過PC機的串口調試助手調試查看。


3.1 UART協議


UART 是一種通用串行數據總線,用于異步通信,將數據在串行通信和并行通信間的傳輸轉換。通俗的講就是把多比特的數據轉化為單比特的數據(tx端),或者把單比特的數據轉化為多比特的數據(rx端)。工作原理是將數據的每個 bit 一位接一位地傳輸。


rx,接收端,位寬為 1 比特, pc 機通過串口往 FPGA 發 8 比特數據時,FPGA 通過串口線 rx 一位一位地接收,從最低位到最高位依次接收,最后在 FPGA 里面位拼接成8 比特數據。


tx,發送端,位寬為 1 比特, FPGA 通過串口往 pc 機發 8 比特數據時, FPGA 把 8 比特數據通過 tx 線一位一位的傳給 pc 機,從最低位到最高位依次發送,最后上位機通過串口助手把這一位一位的數據位拼接成 8 比特數據。


注意點:


1、串行數據的發送和接收都是從低位到高位。


2、在不發送或者不接收數據的情況下, rx 和 tx 處于空閑狀態,此時 rx 和 tx 線都保持【高電平】,如果有數據傳遞,首先會有一個起始位0,然后是 8 比特的數據位,接著有 1 比特的停止位(高電平),如果停止位以后不再發數據,將進入空閑狀態,否則又將數據線拉低(進入起始位狀態)。


3、波特率計算:uart傳輸有不同的波特率,使用HDL語言描述時,通常使用計數器來實現不同波特率的數據傳播。計數器的計數值與具體波特率有關,以常見的115200為例,假設系統時鐘是25Mhz,則傳輸1bit所需要的時鐘周期為25 * 1000 *1000 /115200 = 217個,因此計數器計數值即216(從0開始計數)。


3.2 模塊總框架


模塊的總體框架如下:



top層除了時鐘和復位信號的輸入,還有輸入信號rx和輸出信號tx,分別來自PC機和輸出到PC機,形成閉環。子模塊中,Rx信號再作為uart_rx模塊的輸入,經過uart_rx模塊的處理,轉換成八位并行數據o_data輸出;對于uart_tx模塊,主要將輸入的i_data并行信號轉換成串行數據再輸出到PC機。


3.3 代碼實現


1. Rx端



2.Tx端



3.4 頂層



3.5 仿真



本次仿真使用到了task語句,task語句通常在當仿真時需要給輸入變量特定的輸入值時使用,例如本次仿真對rx端進行賦值。


3.6 仿真結果及問題排查


Rx端:


整體波形如圖:



查看細節如下:



當rx=1時,輸出的o_data并行數據在o_flag = 1(即表示傳輸結束)時也為1,結果正常。


Tx端:


整體波形如下:



上圖很明顯可以看出tx端傳輸有問題,當tx發送起始位(即拉低)后,沒有將數據輸出。觀測其他信號波形,基本正常。可見問題大概率出現在tx賦值部分,一開始以為是發送數據位的條件判斷有問題,檢查代碼,數據傳輸時的判斷條件如下:



查看波形發現該條件可以被滿足。



后來查看起始位的發送條件時發現了錯誤:



起始位發送要與tx_en同步。假設條件使用tx_en判斷,則會比tx_en慢一拍。


另外,不能使用tx_en == 1'b1作為發送起始位的判斷條件,因為tx_en 在數據發送時一直為1,這樣tx端會恒為0,修改后代碼如下:



再觀察波形正常。




3.7 上板最終效果


代碼下載進開發板后,在串口調試助手中可以正常收發數據,如下:



返回列表
欧洲亚洲色视频综合在线 - 视频 - 在线播放 - 影视资讯 - 天天看