一、IP核
IP(Intellectual Property)原指知識產權、著作權等,在IC設計領域通常被理解為實現某種功能的設計。IP模塊則是完成某種比較復雜算法或功能(如FIR濾波器、FFT、SDRAM控制器、PCIe接口、CPU核等)并且參數可修改的電路模塊,又稱為IP核(IP Core)。隨著CPLD/FPGA器件的集成度越來越高,設計越來越復雜,使用IP核是EDA設計的發展趨勢。根據實現方式的不同,IP核可以分為軟核(soft core)、固核(firm core)和硬核(hard core)。
Intel公司以及第三方合作伙伴提供的IP模塊可以分為兩類:可修改參數的IP核(Library of Parameterized Modules, LPM)和需要授權才能在生產設計中使用的IP核(功能更復雜的模塊,也稱為MegaCore)?。這些模塊專門針對不同的器件結構進行了優化,在設計數字系統時,我們可以充分利用這些IP模塊,加快設計進度,同時提高器件資源的利用率。
注:該內容引用自Verilog HDL與FGPGA數字系統設計(第二版)
二、DDS信號發生器設計
1.DDS信號發生器
(1)概念
直接數字頻率合成(Direct Digital Frequency Synthesis,簡稱DDS或DDFS)是一種應用數字技術產生信號波形的方法,它是由美國學者J. Tierncy、C.M. Rader和B. Gold在1971年提出的,他們以數字信號處理理論為基礎,從相位概念出發提出了一種新的直接合成所需波形的全數字頻率合成方法。
DDS系統通常包含以下模塊:
相位累加器(Phase Accumulator)
波形查找表(Waveform ROM/LUT)
數模轉換器(DAC)
??抗混疊濾波器(Anti-Aliasing Filter)
(2)DDS工作流程
2.?DDS信號發生器設計
使用Quartus Prime?Lite創建工程,頂層文件名為DDS_top,芯片選擇EP4CE115F29C7(詳細步驟看其余FPGA文章)。
(1)相位累加器的設計
新建Verilog HDL File文件,文件名為addr_cnt.v(如果與VS Code連用代碼寫好后另存為就好)
//=====相位累加器和數據鎖存器=====
module addr_cnt(CPi,K,ROMaddr,Address);input CPi; //系統基準時鐘(100MHz)input [12:0] K; //13位頻率控制字output reg [9:0] ROMaddr; //10位ROM地址output reg [16:0] Address; //17位相位累加器地址信號always @(posedge CPi)beginAddress = Address + K;ROMaddr = Address[16:7];end
endmodule
在項目中添加addr_cnt.v文件,選擇Files,右鍵點擊Files,點擊添加
找到剛才保存的文件添加
選擇Set as Top-Level Entity將其設為頂層文件,點擊編譯
右鍵點擊addr_cnt.v文件,選擇CreateSymbol Files for Current File命令,生成該模塊的符號
在Quartus中打開生成的addr_cnt.bsf文件,生成的該模塊的符號如圖
(2)波形存儲器ROM的設計
A.方波模塊
步驟跟上面的一樣,文件名為squwave.v,其代碼如下
//=====方波產生模塊:squwave.v ======
module squwave(CPi,RSTn,Address,Qsquare);input CPi; //系統基準時鐘(100MHz)input RSTn; //同步清零input [16:0] Address; //17位地址輸入信號output reg [11:0] Qsquare; //輸出方波信號,12位寬,送至DACalways @(posedge CPi) if(!RSTn) Qsquare=12'h000; //同步清零else begin if(Address<=17'h0FFFF) Qsquare=12'hFFF; //輸出高電平else Qsquare=12'h000; //輸出低電平end
endmodule
打開生成的squwave.bsf文件后該模塊的符號如圖
B.正弦波形存儲器模塊
Quartus Prime軟件接受兩種格式的初始化文件MemoryInitialization File(.mif)和Hexadecimal(Intel-Format)File(.hex)。使用時,將初始化文件放在當前工程項目子目錄中,在配置LPM_ROM時會對其進行初始化。而建立.mif格式文件有兩種方法,一種是直接編輯法,另一種是用C語言等軟件生成初始化文件(初始化儲存單元較多時更加實用)
打開c語言編譯器,建立sinewave.c文件,代碼如下
#include <stdio.h>
#include <math.h>
#define PI 3.141592
#define DEPTH 1024 //數據深度,即存儲單元的個數
#define WIDTH 12 //存儲單元的寬度
int main(void)
{int n,temp;float v;FILE *fp;
/*建立文件名為Sine1024.mif的新文件,允許寫入數據,對文件名沒有特殊要求,但擴展名必須為.mif*/fp=fopen("Sine1024.mif","w+");if(NULL==fp)printf("Can not creat file!\r\n");else{printf("File created successfully!\n");/*生成文件頭,注意不要忘了“;” */fprintf(fp,"DEPTH =%d;\n",DEPTH);fprintf(fp,"WIDTH =%d;\n",WIDTH);fprintf(fp,"ADDRESS_RADIX=HEX;\n");fprintf(fp,"DATA_RADIX=HEX;\n");fprintf(fp,"CONTENT\n");fprintf(fp,"BEGIN\n");/*以十六進制輸出地址和數據*/for(n=0;n<DEPTH;n++){/*周期為1024個點的正弦波*/v=sin(2*PI*n/DEPTH);/*將-1~1之間的正弦波的值擴展到0~4095之間*/temp=(int)((v+1)*4095/2); //v+1將數值平移到0~2之間/*以十六進制輸出地址和數據*/fprintf(fp,"%x\t:\t%x;\n",n,temp);}fprintf(fp,"END;\n");fclose(fp); //關閉文件}
}
運行此文件后會生成sinewave.exe文件,雙擊運行就會生成Sine1024.mif文件
接著,驗證生成的數據是否正確。用記事本打開生成的mif文件,同時用Quartus Prime軟件打開mif文件,若能成功導入數據且數據一致,則說明生成文件正確,將其添加到工程文件中。
在Quartus Prime主界面選擇Tool→IP Catalog
在查找框內輸入ROM, IP核目錄(IP Catalog)欄中會列出相關的IP核,選擇ROM:1-PORT并雙擊
彈出如圖所示的保存IP設置界面,輸入文件名SineROM.v,并選中Verilog,單擊OK按鈕
設置ROM的數據位寬為12,存儲容量(字數)為1024,單擊Next按鈕
點擊Next,配置如下
點擊Browse...選擇生成的Sine1024.mif文件,這是指明初始化ROM所使用的數據文件名
然后Next直到最后一頁,彈出如圖所示的選擇輸出文件的對話框(最重要的是.v文件,其余文件按需要勾選,.bsf文件也可以選上),選擇好后點擊Finish
SineROM.v等相關文件就生成好了
該模塊的符號如下圖所示:
3.鎖相環倍頻電路設計
定制一個名稱為PLL100M_CP的時鐘模塊,該模塊的輸入inclk0為50MHz時鐘信號,輸出c0為100MHz的脈沖信號,占空比為50%,帶有相位鎖定指示輸出端locked。
在右側查找框內輸入ALTPLL(嵌入式鎖相環)?
雙擊打開,輸入文件名PLL100M_CP.v,并選中Verilog,單擊OK按鈕
設置輸入時鐘(inclk0)頻率為50MHz
其余的按如下圖片設置?
最后選擇需要生成的文件
4.頂層電路設計
代碼如下
//========DDS的頂層模塊:DDS_top.v ======
module DDS_top(CLOCK_50, RSTn, WaveSel, K,
WaveValue, LEDG, CLOCK_100);input CLOCK_50; //50MHz時鐘input RSTn; //控制方波清零,低電平有效input [1:0] WaveSel; //波形選擇:SW[17:16]=10時為方波;SW//[17:16]=01時為正弦波input [12:0] K; //頻率控制字SW12..SW0output reg [11:0] WaveValue; //輸出波形數據wire [9:0] ROMaddr; //波形存儲器地址wire [16:0] Address; //17位相位累加器地址wire [11:0] Qsine, Qsquare; //正弦、方波數據輸出output [0:0]LEDG; //鎖相環相位鎖定指示燈,亮表示鎖定output CLOCK_100; //鎖相環輸出時鐘,頻率為100MHzwire CPi =CLOCK_100;PLL100M_CP PLL100M_CP_inst ( //實例引用鎖相環子模塊.inclk0 ( CLOCK_50 ), //50MHz時鐘輸入.c0 ( CLOCK_100 ), //100MHz時鐘輸出.locked ( LEDG[0] ) //相位鎖定指示
);addr_cnt U0_instance(CPi,K,ROMaddr,Address);//實例引用地址累加器SineROM ROM_inst ( //實例引用正弦LPM_ROM子模塊.address (ROMaddr),.clock ( CPi ),.q ( Qsine )
);squwave U1(CPi,RSTn, Address,Qsquare); //實例引用方波子模塊always @(posedge CPi)
begincase(WaveSel) //選擇輸出波形2'b01:WaveValue=Qsine; //輸出正弦波2'b10:WaveValue=Qsquare; //輸出方波default:WaveValue=Qsine;endcase
end
endmodule
寫好后添加到工程中,將此文件設為頂層模塊并進行編譯。
三、設計實現
使用DE2-115開發板來驗證上述設計。用板上的50MHz晶振作為時鐘輸入,用KEY3控制方波清零,用SW12~SW0設置頻率控制字,SW17、SW16用來選擇輸出波形的種類,用LEDG0作為PLL的相位鎖定指示。
有DE2_115_pin_assignments.csv文件可以直接導入不用手動配置引腳,沒有的話參考DE2-115文檔配置。為了方便導入文件DE2_115_pin_assignments.csv進行引腳分配,將使用該文件中的端口名稱代替上述DDS_top.v(代碼如下)中的信號名稱。為此再編寫一個頂層文件DE2_DDS_top.v代碼如下:
//=====在開發板上運行的DDS的頂層模塊:DE2_115_DDS_top.v ======
module DE2_115_DDS_top(CLOCK_50, KEY, SW, GPIO_0, LEDG);input CLOCK_50; //50MHz時鐘input[3:3] KEY; //按鍵KEY3,控制方波清零input[17:0] SW; //撥動開關output [12:0] GPIO_0; //擴展接口,送出波形數據給DACoutput [0:0]LEDG; //綠色LED指示相位是否鎖定wire CLOCK_100; //100MHz時鐘assign GPIO_0[12]=CLOCK_100; //送給DAC的時鐘wire RSTn = KEY[3]; //控制方波清零,低電平有效wire [1:0] WaveSel = SW[17:16]; //選擇輸出波形wire [12:0] K = SW[12:0]; //設置頻率控制字,最小值必須為1wire [11:0] WaveValue;assign GPIO_0[11:0] = WaveValue; //輸出波形數據DDS_top DE2(CLOCK_50, RSTn, WaveSel, K, WaveValue, LEDG, CLOCK_100);
endmodule
對其進行全編譯