本原創文章由深圳市小眼睛科技有限公司創作,版權歸本公司所有,如需轉載,需授權并注明出處(www.meyesemi.com)
1.實驗簡介
實驗目的:
? 從創建工程到編寫代碼,完成引腳約束,最后生成 bit 流下載到開發板上,完成 Key0 控 制 led0 閃爍,Key1 控制 led1 亮滅。
實驗環境:
? Window11 PDS2022.2-SP6.4 芯片型號: PG2L50H-484
2.實驗原理
通常的時,分,秒的計時進位大家應該不陌生;
1 小時=60 分鐘=3600 秒,當時針轉動 1 小時,秒針跳動 3600 次;
在數字電路中的時鐘信號也是有固定的節奏的,這種節奏的開始到結束的時間,我們通常稱之為周期(T)
在數字系統中通常關注到時鐘的頻率,那頻率與周期的關系如下:
而本次開發板上的晶振提供了一個 25MHZ 的單端時鐘。
所以其周期約為 40ns。而在我們FPGA 的設計中,我們的 always 塊通常都是在時鐘的上升沿時對數據進行賦值,因此我們可以定義一個變量,每到時鐘的上升沿就讓該變量+1,讓其變成一個計數器,該變量每加 1 就表示經過了 40ns,那如果要定時 1s 的話,只需要讓其計數到 24999999 即可,因為從 0 開始計數,所以計數到 24999999 即可,此時就是一秒了。以此類推,12499999 就是 0.5s。
? 錯誤!未定義書簽。為開發板上 2 個 LED 燈的原理圖。
? ? ?錯誤!未定義書簽。為開發板上 2 個按鍵的原理圖。
? ? ?KEY0 控制 LED0 每 1s 更換一次 LED 燈狀態,KE1 控制 LELD1 亮滅狀態。(高電平用 1 表示,低電平用 0 表示)
3.接口列表
? ? ?接口列表 top.v 頂層模塊接口列表:
端口 | I/O | 位寬 | 描述 |
?sys_clk | ?input | 1 | ?系統時鐘 25MHZ |
?key0 | ?input | 1 | ?用戶按鍵 0 |
?key1 | ?input | 1 | ?用戶按鍵 1 |
?led_0 | ?output | 1 | ?led 燈控制信號 |
?led1 | ?output | 1 | ?led 燈控制信號 |
? btn_deb_fix.v 按鍵消抖模塊接口列表:
端口 | I/O | 位寬 | 描述 |
?BTN_WIDTH | ?parameter | 4 | ?案件數量 |
?sys_clk | ?input | 1 | ?系統時鐘 25MHZ |
?rst_n | ?input | 1 | ?全局復位 |
?btn_in | ?input | BTN_WIDTH | ?用戶按鍵輸入 |
?btn_deb_fix | ?output | BTN_WIDTH | ?按鍵消抖后的輸出(脈沖信號) |
4.工程說明
? 該工程框架如下所示:
? ? ??本次工程主要完成按鍵控制 led 的狀態。按鍵 0 控制 led0 閃爍,按鍵 1 控制 led1 亮滅。首先,key0 和 key1 均會經過按鍵消抖模塊,因為開發板上使用的是機械按鍵,所以每次 按下均會產生抖動,如果不進行消抖,會造成誤判。經過消抖后,每次按下按鍵均會產生持續一個 clk 的高電平即key0_flag和key1_flag。key0_flag控制是否打開 1s計數器來開啟 led0 的閃爍,key1_flag 直接控制 LED1 翻轉,每按下一次 key1,led 的狀態翻轉一次。
5.代碼模塊說明
//key0->led0 閃爍//key1->key1 翻轉module top(input wire sys_clk , //系統時鐘 25MHZinput wire key0 , input wire key1 , output reg led_0 , output reg led_1);//--------------------------------parameter-------------------------------- parameter CNT_MAX = 32'd25_000_000 ; //1s 計數//----------------------------------reg---------------------------------- reg [7:0] rsn_cnt =0 ; //復位計數器reg [31:0] cnt_1s ; //計數器reg led0_en ; //led0 閃爍使能//----------------------------------wire---------------------------------- wire rst_n ; //復位信號,低電平有效wire key0_flag ; //按鍵按下后的上升沿wire key1_flag ; //按鍵按下后的上升沿//-----------------------------always & assign----------------------------- //產生復位always@(posedge sys_clk) beginif(rsn_cnt >=100)rsn_cnt <= rsn_cnt;elsersn_cnt <= rsn_cnt + 1'b1;endassign rst_n = (rsn_cnt>=100)?1'b1:1'b0 ;//每按下一次 key0 進行一次翻轉always@(posedge sys_clk) beginif(!rst_n)led0_en <= 1'd0;else if(key0_flag)led0_en <= ~led0_en;end//計數 1salways@(posedge sys_clk) beginif(!rst_n)cnt_1s <= 32'd0;else if(led0_en) //led0 閃爍使能beginif(cnt_1s == CNT_MAX-1) //1 秒cnt_1s <= 32'd0;elsecnt_1s <= cnt_1s + 1'b1;endelsecnt_1s <= 32'd0;end//led0 1s 閃爍always@(posedge sys_clk) beginif(!rst_n)led_0 <= 1'd0;else if(led0_en)beginif(cnt_1s == CNT_MAX-1) //1s 翻轉 ledled_0 <= ~led_0;elseled_0 <= led_0;endelseled_0 <= 1'd0;end//led1 翻轉always@(posedge sys_clk) beginif(!rst_n)led_1 <= 1'd0;else if(key1_flag)led_1 <= ~led_1;end//-----------------------------instance----------------------------- //按鍵消抖模塊btn_deb_fix#(.BTN_WIDTH ( 4'd2 ) //2 個按鍵)u_btn_deb_fix(.sys_clk ( sys_clk ), .rst_n ( rst_n ), .btn_in ( {key1,key0} ), .btn_deb_fix ( {key1_flag,key0_flag} ));endmodule
? ? ?CNT_MAX定義了一個最大的計數值,由于我們的系統時鐘是 25MHZ,也就是25000000,所以要讓 LED 實現 1s 閃爍的話就是從 0 計數到 24999999 的時候讓 led 進行一次翻轉。?
? ? ?在 26-31 行中,利用系統時鐘計數 100 個周期后產生了一個復位信號用來給后續模塊和 時序邏輯提供復位。
? ? ?在 43-55 行中,當 led0_en 拉高時才開始計數一秒。否則計數器一直保持 0。
? ? ?在 82-89 行中,例化了一個按鍵消抖的模塊,按鍵按下并松開后將產生一個脈沖信號即 key0_flag,key1_flag,其中 key_0flag 控制 led0 閃爍,key1_flag 控制 led1 翻轉。
//按鍵消抖`define UD #1module btn_deb_fix#(parameter BTN_WIDTH = 4'd8 //按鍵數量)( input sys_clk , input wire rst_n , input [BTN_WIDTH-1:0] btn_in , output reg [BTN_WIDTH-1:0] btn_deb_fix );//----------------------------parameter---------------------------- parameter CNT_20MS_MAX = 32'd500_000 ; //20MS 計數//-------------------------------reg-------------------------------reg [23:0] cnt[BTN_WIDTH-1:0]; //計數器reg [BTN_WIDTH-1:0] btn_in_reg ; //寄存按鍵信號//打一拍always @(posedge sys_clk) beginbtn_in_reg <= btn_in;end//------------------------ 消 抖 主 要 邏 輯------------------------ genvar i;generatebeginfor(i=0;i<BTN_WIDTH;i=i+1)beginalways @(posedge sys_clk) beginif(!rst_n)cnt[i] <= 24'd0;if (btn_in_reg[i] == 1'b0) //按下時 計數 20ms 時歸零cnt[i] <= 24'd0;else if(cnt[i]==CNT_20MS_MAX) //抖動區間有效時計數cnt[i] <= cnt[i];elsecnt[i] <= cnt[i] + 1'b1;endalways @(posedge sys_clk) beginif(!rst_n)btn_deb_fix[i] <= 1'd0;else if(cnt[i]==CNT_20MS_MAX-1) //消抖后輸出一個 clk 的高電平btn_deb_fix[i] <= 1'b1;elsebtn_deb_fix[i] <= 1'b0;endendendendgenerateendmodule
? ? ? ?該部分為按鍵消抖模塊,parameter 定義了按鍵輸入的數量,模塊的輸出將產生一個脈沖信號即產生一個持續一個 clk 的高電平信號。
? ? ? ?在 30-50 行中,cnt 會不斷進行 20ms 的計數,當按鍵按下時,cnt 歸 0,從 0 開始計數直到 20ms。當計數到 20ms 的時候,就輸出一個 clk 的高電平,即將 btn_deb_fix 置 1,并讓其只保持一個 clk。
6.實驗步驟
? ? ? 這里將會詳細介紹從新建工程到下載程序的具體步驟,后續的工程將不再詳細解釋。
6.1. 打開 PDS 軟件,創建工程
? Step1:打開 PDS 軟件,點擊 NEW Project,然后對其設置完成新建工程。
? Step2:單擊 NEXT
?Step3:創建名為 led_water 的工程到對應的文件目錄,之后單擊 Next。
? ? ?新建工程大致包括設置工程名和工程路徑、工程類型、工程文件及器件信息。
? ? 【Project Name】是工程文件名稱,默認為 project。(只允許字母、數字、下劃線(_)、杠(-)、點(.))。
? ? 【Project Location】用于選擇新工程的工作路徑,文件夾名只允許字母、數字、下劃線
? ? (_)、杠(-)、點(.)、@、~、,、+、=、#、空格( ),但空格不能出現在路徑名首尾,即工程文件放置的路徑。
? ? 【Create Preject Subdirectory】將工程文件名作為工作目錄的一部分。
?Step4:選擇 RTL project,點擊 Next。
? ? 【RTL Project】用于創建 RTL 工程。新建的工程可以執行 synthesize,device map,place& route,report timing,report power,generate netlist 及 generate bitstream 等。
? ? 【Post-Synthesize Project】用于創建綜合后工程。新建的工程可以執行 device map, place& route,report timing,report power, generate netlist 及 generate bitstream 等。
?Step5:單擊 Next
? ? ?該界面可以 Add Files 和 Add Directories 來添加 rtl 源文件及新建 rtl 源文件,以及調整 rtl 文件編譯順序,Add Files 添加選中的文件,Add Directories 添加選中的文件夾下所有合適的文件,若勾選了下方的 Add source from subdirecotires 則添加所有的子目錄下合適的文件,也可直接 NEXT 跳過添加文件。
?Step6:單擊 Next
?Step7:單擊 Next
?Step8:選擇器件系列、型號、封裝、速率、綜合工具,之后單擊 Next
synthesize tool 中可以選擇綜合工具為 Synplify Pro 或 ADS,在實驗中使用 ADS 綜合工具。
?Step9:在 summary 單擊 Finish,完成工程的創建
6.2. 添加設計文件
? PDS 軟件界面如下圖:
? ? ? ?雙擊 Designs,將前面設計的 module 新建到文件中,或者將前面編輯好的 verilog 文件添加到工程中:
? ? ?添加文件到工程:
? ? ?在窗口中點擊 Add Files,選擇添加文件到工程;
? ? 新建文件到工程:
? ? 1)在窗口中點擊 Create File;
? ? ??2)選擇 Verilog Design File,文件名和 module 名一致,默認路徑,點擊 OK;
? ? ? 3)點擊 OK;
? ? ?4)點擊 Cancel;
? ? ?5)默認打開新建文件,將前面設計的 代碼 復制進去,
?6)點擊保存,新建文件完成
?Crtl+s 保存。
雙擊 Designs。
? ? ?點擊 Add Files;
添加 btn_deb_fix.v 模塊,即按鍵消抖模塊。
? ? 點擊 OK。?
6.3. 編譯
??可采用以下方式運行 Compile 流程:
(1)雙擊 Flow 中的 Compile 進行綜合;
(2)右擊 Compile 點擊 Run 進行綜合;
6.4. 工程約束
? ? 點擊 Tools 選擇 User Constraint Editor(Timing and Logic)或者點擊工具欄圖標 ,User Constraint Editor(Timing and Logic) 選擇 Pre Synthesize UCE,如下圖所示。
? ? ?Tools 下的 User Constraint Editor(Timing and Logic)
6.4.1. 時鐘約束
? ? ?打開 UCE 后,選擇 Timing Constraints 后選擇 Create Clock 添加基準時鐘,基準時鐘一般是通過輸入 port 輸入用戶所使用的板上時鐘。
? ? ?在彈窗中對時鐘命名,關聯時鐘管腳,添加時鐘參數,點擊 OK 會創建一條時鐘約束,Reset 重置該頁面。創建完成如下圖所示:
? ? ?提供給開發板的時鐘是 25MHZ,即周期為 40ns。
6.4.2. 物理約束
? ? 打開 UCE 后,選擇 Device 后選擇 I/O,根據原理圖編輯 IO 的分配。
按照原理圖編輯好 IO 分配后,點擊保存,會生成.fdc 文件,完成約束。
6.5. 綜合
? 運行 Synthesize 流程有以下四種方式可以實現:
(1)雙擊 Flow 中的 Synthesize 進行綜合;
(2)右擊 Synthesize 點擊 Run 進行綜合;
完成 Synthesize 操作后,會看到下圖所示:
6.6. Device Map
? ?Device Map 的主要作用是將設計映射到具體型號的子單元上(LUT、FF、Carry 等)。
? ?運行 Device Map 流程有以下方式可以實現:
(1)直接雙擊 Device Map;
(2)右擊 Device Map 點擊 Run;
? 完成 Device Map 操作后,會看到下圖所示:
6.7. Place & Route
? 布局布線(Place & Route)根據用戶約束和物理約束,對設計模塊進行實際的布局及布線。
? 運行 Place & Route 流程有以下方式可以實現:
(1)直接雙擊 Place & Route;
(2)右擊 Place & Route 點擊 Run;
? 完成 Device Map 操作后,會看到下圖所示:
6.8. Generate Bitstream
? Generate Bitstream 生成二進制位流文件。運行 Generate Bitstream 流程有以下方式可以實現: (1)直接雙擊 Generate Bitstream;
(2)右擊 Generate Bitstream 點擊 Run;
? 完成以上操作,將會產生位流文件。
? 運行 Generate Bitstream,可以看到界面如下圖所示:
6.9. 下載生成的位流文件
點擊 Tools 選擇 Configuration 或者點擊工具欄圖標 Configuration,如下圖所示。
Tools 下的 Configuration
? ? 工具欄 Configuration 圖標
? ? 打開 Configuration 后直接選擇 Scan Device 直接進行掃描 Jtag 鏈操作,初始化鏈成功,會將鏈上掃描到的所有器件顯示于工作區內,并在器件屬性窗口顯示當前器件的器件 信息,并彈出對話顯示能夠為器件添加的配置文件:
初始化鏈成功
在對話框中選擇位流文件,添加該配置文件,提示所載入文件的絕對路徑并在信息欄中顯示,如下圖所示:
? ? 下載位流文件
? ? ?當發現這 4 個信號均為 1 時,表示下載成功。
? ? ?同時,開發板也配置了一個外部 flash,其中,若需要將程序固化到板卡上需要將尾流文 件轉化為.sfc 文件。
? ? ?首先點擊 Configuration 頁面的 Operations 選項的 Covert File 選項。
? ? ? ?點擊后會出現如下畫面,在Generate Flash Programing File頁面選擇對應的Flash 器件的廠商名、型號、再在 BitStreamFile 位置選擇位流文件的路徑,點擊 OK。(若使用的 flash 器件不在可選的 flash 列表中,需手動添加對應 flash 型號,操作步驟請參考開發板下載與固化相說明)
? ?轉化.sfc 文件成功后,頁面會如下圖所示,點擊 OK。
頁面會顯示板卡搭載的 Flash 的型號,點擊.sfc 文件,點擊 OPEN。
在下圖位置點擊鼠標右鍵后,點擊 Program。
固化 Flash 成功如下圖所示:
? ? ? 此時將板卡斷電,再重新上電,如果按下 key0 和 key1 能看到對應的實驗現象的話,則表示固化成功。(等大概 15s)