一、基本概述
1.1 DDS簡介
DDS信號發生器即直接數字頻率合成(Direct Digital Frequency Synthesis,簡稱DDS)是一種利用數字技術生成信號的方法。它通過數字信號處理技術,將數字信號轉換為模擬信號,從而生成高質量的正弦波、方波、三角波等信號。
1.2 DDS工作原理
1.2.1 核心組成部分
DDS系統主要由以下幾個模塊構成:
相位累加器(Phase Accumulator)
波形查找表(Waveform Look-Up Table, LUT)
數模轉換器(DAC)
低通濾波器(LPF)
1.2.2 工作流程
(1)相位累加
相位累加器是DDS信號發生器的核心部分,用于生成相位信息。它由一個累加器和一個頻率控制字(Frequency Control Word, FCW)組成。每次時鐘周期,頻率控制字會被加到累加器中,累加器的輸出即為當前的相位值。
-
輸入:頻率控制字(Frequency Tuning Word, FTW),由用戶設定。
-
作用:相位累加器在時鐘信號(fclkfclk?)的驅動下,對FTW進行累加,生成線性遞增的相位值(地址)。
-
公式:
?其中,NN?為相位累加器的位數(通常24~32位),決定頻率分辨率。
(2)波形查找
查找表(Lookup Table, LUT)存儲了正弦波或其他波形的幅度值。相位累加器的輸出作為查找表的地址,查找表根據該地址輸出對應的幅度值。查找表通常存儲的是一個完整周期的波形數據。波形選擇模塊用于選擇不同的波形,如正弦波、方波、三角波等。通過改變查找表的內容或邏輯控制,可以生成不同的波形。
波形存儲器(LUT):預存目標波形(如正弦波、方波)的離散采樣值。
尋址:相位累加器的輸出作為地址,從LUT中讀取對應的波形幅值數據。
分辨率:LUT的深度和位寬影響波形精度。
(3)數模轉換(DAC)
DAC將數字幅度值轉換為模擬信號。DAC的分辨率(如8位、12位、16位)決定了輸出信號的精度和質量。
將查找表輸出的數字幅值轉換為模擬電壓信號。
DAC的轉換速度和位數直接影響輸出信號的質量(如信噪比、諧波失真)。
(4)低通濾波
濾除DAC輸出的高頻量化噪聲和時鐘饋通信號。
截止頻率通常略高于所需信號的最大頻率。
1.2.3 輸出頻率計算
DDS的輸出頻率由以下公式決定:
fclkfclk?:系統時鐘頻率(如100 MHz)。
NN:相位累加器位數(如32位)。
FTW:頻率控制字,由用戶編程設置。
比如:?若?fclk=100?MHzfclk?=100MHz,N=32N=32,要輸出?1?MHz1MHz?正弦波:
?1.3?常見的RAM、ROM、FIFO等IP核的參數設置和調用過程
IP軟核是預先設計好的、可重復使用的數字電路模塊,用于簡化復雜系統的設計。它們通常以Verilog HDL或VHDL等硬件描述語言編寫,可以在FPGA或ASIC中實現。
1.3.1?RAM IP核的參數設置和調用過程
RAM 是隨機存取存儲器(Random Access Memory)的簡稱,是一個易失性存儲器。 RAM 工作時可以隨時從任何一個指定的地址寫入或讀出數據,同時我們還能修改其存儲的數據,即寫入新的數據,這是 ROM 所并不具備的功能。在 FPGA 中這也是其與 ROM 的最大區別。ROM 是只讀存儲器,而 RAM 是可寫可讀存儲器,在我們 FPGA 中使用這兩個存儲器主要也是要區分這一點,因為這兩個存儲器使用的都是我們 FPGA 內部的 RAM 資源,不同的是 ROM 是只用到了 RAM 資源的讀數據端口。
?單端口RAM參數:
數據寬度(Data Width):8/16/32/64位等
存儲深度(Depth):根據需求設置(如1024, 2048等)
操作模式:通常為"Write First"、"Read First"或"No Change"
初始化文件:可加載.mif或.hex文件初始化RAM內容
寄存器選項:輸出是否寄存(增加一個時鐘周期延遲但提高時序性能)
雙端口RAM參數:
除單端口參數外還需設置:
端口A和端口B的操作模式
是否允許同時讀寫
沖突解決策略
1.3.2?ROM IP核的參數設置和調用過程
ROM 是只讀存儲器(Read-Only Memory)的簡稱,是一種只能讀出事先所存數據的固態半導體存儲器。其特性是一旦儲存資料就無法再將之改變或刪除,且資料不會因為電源關閉而消失。而事 實上在 FPGA 中通過 IP 核生成的 ROM 或 RAM(RAM 將在下一節為大家講解)調用的都是FPGA 內部的 RAM 資源,掉電內容都會丟失(這也很容易解釋,FPGA 芯片內部本來就沒有掉電非易失存儲器單元)。用 IP 核生成的 ROM 模塊只是提前添加了數據文件(.coe 格式)(.mf/.nex格式),在 FPGA 運行時通過數據文件給 ROM 模塊初始化,才使得 ROM 模塊像個“真正”的掉電非易失存儲器;也正是這個原因,ROM 模塊的內容必須提前在數據文件中寫死,無法在電路中修改。
常見參數設置
數據寬度:同RAM
存儲深度:同RAM
初始化文件:必須提供.mif或.hex文件
輸出寄存器:可選是否寄存輸出
1.3.3?FIFO?IP核的參數設置和調用過程
? ?FIFO(First In First Out,即先入先出),是一種數據緩沖器,用來實現數據先入先出的讀寫方式。與 ROM 或 RAM 的按地址讀寫方式不同,FIFO 的讀寫遵循“先進先出”的原則,即數據按順序寫入 FIFO,先被寫入的數據同樣在讀取的時候先被讀出,所以 FIFO存儲器沒有地址線。FIFO 有一個寫端口和一個讀端口外部無需使用者控制地址,使用方便。
? ? ? ? FIFO 存儲器主要是作為緩存,應用在同步時鐘系統和異步時鐘系統中,在很多的設計中都會使用,后面實例中如:多比特數據做跨時鐘域的轉換、前后帶寬不同步等都用到了FIFO。FIFO 根據讀寫時鐘是否相同,分為 SCFIFO(同步 FIFO)和 DCFIFO(異步FIFO),SCFIFO 的讀寫為同一時鐘,應用在同步時鐘系統中;DCFIFO 的讀寫時鐘不同,應用在異步時鐘系統中。
數據的產生模塊與數據使用模塊不對應時就會使用到FIFO,如兩者的時鐘頻率不同無法在同一時鐘下進行傳輸(多比特數據做跨時鐘域的轉換) ;兩者的數據帶寬不同下傳輸(前后帶寬不同步)。
基本參數:
FIFO實現方式:基于Block RAM或Distributed RAM
數據寬度:8/16/32/64位等
FIFO深度:16/32/64/128/256等
滿/空標志:設置幾乎滿/幾乎空的閾值
高級參數:
讀寫時鐘域:同步或異步FIFO
握手信號:可選是否添加數據有效信號
復位類型:同步或異步復位
二、波形仿真器的設計與制作
2.1 內容與要求
采用數字頻率合成(Direct Digital FrequencySynthesis,簡稱DDS)設計制作一個波形發生器,仿真后,在DE2-115開發板上實踐。要求:
1)利用DDS技術合成正弦波和方波;
2)輸出信號的頻率范圍為10Hz~5MHz,最小頻率分辨率小于1kHz;
3)使用嵌入式邏輯分析儀SignalTap II實時測試輸出波形的離散數據。
2.2 具體步驟
(1)在Quartus中創建新工程,步驟在之前的博客中有具體說明
2.2.1 相位累加器
(2)編寫代碼
module addr_cnt(CPi,K,ROMaddr,Address);input CPi;input [12:0] K;output reg [9:0] ROMaddr;output reg [16:0] Address;always @(posedge CPi) beginAddress=Address+K;ROMaddr=Address[16:7];end
endmodule
(3)將 addr_cnt 設置為頂層文件
將Project Navigator 設置為 Files ,之后右鍵addr_cnt.v ,選中 Set as Top-Level Entity
?
打開生成的.bsf文件如下圖所示:
生成并打開.bsf文件
右鍵addr_cnt.v,在彈出的選項中選擇?Create Symbol Files for Current File,之后生成的?
.bsf
?文件會保存在工程目錄下,找到對應的文件打開即可
2.2.2?波形存儲器ROM
方波模塊
代碼如下:
module squwave(CPi,RSTn,Address,Qsquare);input CPi;input RSTn;input [16:0] Address;output reg [11:0] Qsquare;always @(posedge CPi)if (!RSTn)Qsquare=12'h000; else beginif(Address<=17'h0FFFF)Qsquare=12'hFFF;else Qsquare=12'h000;end
endmodule
將該模塊設置為頂層文件,并編譯生成 .bsf 如下圖:
正弦波形存儲器
首先編譯一個C程序(?Dev C++ 或者別的編譯器都行),編譯之前建議先在對應的Quartus工程目錄下新建一個文件夾,將C程序保存在該文件夾內
/*myMIF.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;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++){v=sin(2*PI*n/DEPTH);temp=(int)((v+1)*4095/2);fprintf(fp,"%04x : %03x;\n",n,temp);}fprintf(fp,"END;\n");fclose(fp);}}
?編譯運行以上代碼,會生成 myMIF.exe文件以及Sine 1024.mif 文件,如下圖:
使用Quartus調用LPM_ROM定制正弦波形存儲器:點擊Tools--->IP Catalog,并在IP Catalog搜索框搜索 ROM ,雙擊 找到 ROM 1-PORT并雙擊
在彈出的彈框里面修改命名,如下圖所示:
點擊OK,會彈出如下界面:
修改以下參數:
取消 ‘q’output port的勾選
點擊 Browse..,并選中之前生成好的 Sine1024.mif
之后一直Next,直到 Finish,ROM配置完成
鎖相環倍頻電路
在IP Catalog 搜索欄中搜索 ALTPLL,選中 ALTPLL 并雙擊
修改如圖所示的參數?
之后一直 Next 默認選項,直到出現以下界面,修改Clock multi...的參數
之后也是一直默認選項,直到 Finish
2.2.3 頂層電路設計
代碼如下:
module DDS_top (CLOCK_50,RSTn,WaveSel,K,
WaveValue,LEDG,CLOCK_100);input CLOCK_50;input RSTn;input [1:0] WaveSel;input [12:0] K;output reg [11:0] WaveValue;wire [9:0] ROMaddr/* synthesis keep */;wire [16:0] Address;wire [11:0] Qsine,Qsquare;output [0:0] LEDG;output CLOCK_100;wire CPi=CLOCK_100;myALTPLL PLL100M_CP_inst(.inclk0(CLOCK_50),.c0(CLOCK_100),.locked(LEDG[0]));addr_cnt U0_instance(CPi,K,ROMaddr,Address);myROM ROM_inst(.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;endcaseend
endmodule
跟之前一樣,將該模塊設置為頂層文件并進行編譯
三、DE2-115設計實現
配置引腳
可以直接導入DE2_115_pin_assignments.csv文件進行配置,也可以手動進行配置
module DE2_115_DDS_top(CLOCK_50,KEY,SW,GPIO_0,LEDG);input CLOCK_50;input [3:3] KEY;input [17:0] SW;output [12:0] GPIO_0;output [0:0] LEDG;wire CLOCK_100;assign GPIO_0[12]=CLOCK_100;wire RSTn=KEY[3];wire [1:0] WaveSel=SW[17:16];wire [12:0] K=SW[12:0];wire [11:0] WaveValue;assign GPIO_0[11:0]=WaveValue;DDS_top DE2(CLOCK_50,RSTn,WaveSel,K,WaveValue,LEDG,CLOCK_100);
endmodule
引腳配置完成要再次編譯運行
接下來就可以使用SignalTap ll實時測試輸出波形的離散數據,選擇Tools-->SignalTap ll Logic Analyzer
右鍵 Setup 上方空白處,點擊 Add Node... 進行添加
全部確認無誤后,保存文件并編譯(要連接開發板)
波形圖如下:
四、總結
通過這次DDS信號發生器的設計和實現,學習了數字信號處理的強大能力和FPGA設計的靈活性。從理論學習到實際操作,我不僅了解到了DDS技術的基本原理和實現方法,還學會了如何在Quartus軟件中進行模塊化設計和引腳配置。這次實踐讓我認識到了細節的重要性,每一個小的配置錯誤都可能導致整個系統無法正常工作。
參考博客:
20【FPGA】FPGA開發中常用的IP核——PLL/ROM/RAM/FIFO_fpga ip核-CSDN博客
【DE2-115】Verilog實現DDS+Quartus仿真波形-CSDN博客