DDS直接數字式頻率合成器(Direct Digital Synthesizer)。本文實現一個具有可以頻率可調、相位可調的正餘弦、方波、三角波的DDS。
DDS的原理如下圖,累加器每次累加一個頻率控制字,調節頻率控制字的數值,可以改變累加器的累加速度,進而可以調節從ROM查找表中讀取波形數據的速度。即頻率控制字越大,頻率越高。相位控制字可以用來調節初始相位,即ROM地址自加的初始值。
從查找表讀取出來的數據,經DA轉換晶元可以直接輸出進行濾波或其他操作,最後可使用示波器進行觀察波形變化。
DDS 模塊的輸出頻率是系統工作頻率、相位累加器比特數N以及頻率控制字K三者的一個函數,其數學關係由式如下。
DDS的頻率解析度,即頻率變化間隔。
本設計是調用Xilinx Vivado提供的ROM IP Core來存儲波形數據,首先要生成波形數據並添加至IP Core中,Xilinx的文件類型為coe格式。
此MATLAB代碼提供正餘弦、方波、三角波四種波形的coe文件輸出,MATLAB腳本語言並不是很難,有編程基礎很快就能看懂,MATLAB提供的函數眾多,哪裡不會Google哪裡。
x=linspace(0,2*pi,4096);%6.28為2pi,一個周期採樣點取4096個 y1=cos(x)+1; %將函數平移到縱軸的正半軸。 y2=sin(x)+1; y3=ceil(y1*511); y4=ceil(y2*511); ? %生成cos函數coe文件 fid = fopen(cos_coe.coe,wt); fprintf(fid,MEMORY_INITIALIZATION_RADIX=10; ); fprintf(fid,MEMORY_INITIALIZATION_VECTOR= ); %fprintf(fid,%16.0f ,y3); for i = 1:1:2^12 fprintf(fid,%16.0f,y3(i)); if i==2^12 fprintf(fid,;); else fprintf(fid,,); end if i%15==0 fprintf(fid, ); end end fclose(fid); ? %生成sin函數coe文件 fid = fopen(sin_coe.coe,wt); fprintf(fid,MEMORY_INITIALIZATION_RADIX=10; ); fprintf(fid,MEMORY_INITIALIZATION_VECTOR= ); for i = 1:1:2^12 fprintf(fid,%16.0f,y4(i)); if i==2^12 fprintf(fid,;); else fprintf(fid,,); end if i%15==0 fprintf(fid, ); end end fclose(fid); ? %生成方波 t=1:1:2^12; y=(t<=2047); r=ceil(y*(2^9-1)); fid = fopen(square.coe,w); %寫到square.coe,用來初始化rom_square fprintf(fid,MEMORY_INITIALIZATION_RADIX=10; ); fprintf(fid,MEMORY_INITIALIZATION_VECTOR= ); for i = 1:1:2^12 fprintf(fid,%d,r(i)); if i==2^12 fprintf(fid,;); else fprintf(fid,,); end if i%15==0 fprintf(fid, ); end end fclose(fid); %生成三角波 t=1:1:2^12; y=[0.5:0.5/1024:1-0.5/1024, 1-0.5/1024:-0.5/1024:0, 0.5/1024:0.5/1024:0.5]; r=ceil(y*(2^9-1)); fid = fopen(triangular.coe,w); %寫到triangular.coe,初始化三角波rom fprintf(fid,MEMORY_INITIALIZATION_RADIX=10; ); fprintf(fid,MEMORY_INITIALIZATION_VECTOR= ); for i = 1:1:2^12 fprintf(fid,%d,r(i)); if i==2^12 fprintf(fid,;); else fprintf(fid,,); end if i%15==0 fprintf(fid, ); end end fclose(fid);
生成一個等差數列
y = linspace(x1,x2) y = linspace(x1,x2,n) ? y = linspace(x1,x2) 返回包含 x1 和 x2 之間的 100 個等間距點的行向量。 ? 示例 y = linspace(x1,x2,n) 生成 n 個點。這些點的間距為 (x2-x1)/(n-1)。 ? y1 = linspace(-5,5,7) y1 = 1×7 ? -5.0000 -3.3333 -1.6667 0 1.6667 3.3333 5.0000 ?
生成線性間距向量 - MATLAB linspace - MathWorks 中國?ww2.mathworks.cn
生成coe文件後調用ROM IP Core,需要生成個ROM的讀取地址,主要代碼如下。
//freq_data為頻率控制字,phase_data為相位控制字。 always @(posedge clk_50MHz or negedge rst)begin if(!rst) fcnt <= 32d0; else fcnt <= fcnt + freq_data; end ? assign addra = fcnt[31:20] + phase_data; ? blk_mem_sin blk_mem_sin_inst ( .clka(clk_50MHz), // input wire clka .addra(addra), // input wire [11 : 0] addra .douta(sin) // output wire [11 : 0] douta );
本設計調用了四個IP,將四種波形同時出處,然後用一個四選一的選擇器輸出給DA模塊至示波器顯示,模擬截圖如下。
DA轉換
D/A轉換器採用的是ADI公司的雙通道12位21.3MSPS高速DAC轉換器AD5447,FPGA 輸出的12位數字信號進入AD5447後,經過兩個鎖存器,轉換為差分信號輸出晶元內部結構圖如圖所示。
時序圖如圖所示。可以看到數據寫入晶元的的過程也是十分簡單,只要CS拉低就可以進行讀操作或寫操作。
晶元的輸入數據是並行的,我這裡輸入的數據就是MATLAB的直接生成的12bit的數據,輸出電壓的幅值手冊給出了計算公式,清晰明了。
sin和cos的波形是一樣的,將三種波形輸出用示波器查看。波形很漂亮。
這個工程,我放在GitHub上了。訂閱號後台回復「DDS」即可獲得這個工程。
歡迎持續關注 硅農 訂閱號,隨後持續推出 基於FPGA的無線通信基礎 系列文章。點擊訂閱號左下角,子菜單欄 無線通信基礎,可以把查看所有文章及目錄。