基於FPGA的DDS信號發生器的設計仿真
本文主要介紹利用FPGA和matlab實現任意頻率信號發生器的功能,並進行仿真,使用Quartus Ⅱ+modelsim+matlab實現功能,以正弦波爲例說明,開發芯片頻率50MHz
產生正弦波sin信號的mif文件
採用matlab產生mif文件,具體的代碼如下:
clear;
clc;
width=8;
depth=256;
fid =fopen ('sin.mif','w');
fprintf(fid,'WIDTH=%d;\n',width);
fprintf(fid,'DEPTH=%d;\n',depth);
fprintf(fid,'ADDRESS_RADIX=UNS;\n');
fprintf(fid,'DATA_RADIX=UNS;\n');
fprintf(fid,'CONTENT BEGIN\n');
for i=0:depth-1
sin_data=floor((sin(2*pi*i/depth)+1)*0.5*(2^width-1));
data=sin_data;
fprintf(fid,'%d : %d;\n',i,data);
end
fprintf(fid,'END;\n');
fclose (fid);
通過運行.m文件可以產生一個sin.mif文件用作rom的初始狀態
建立工程並調用ipcore
首先創建工程
調用單個端口的ROM IPcore,位寬爲8,深度爲256,RTL視圖如下
頂層文件如下
module dds_v3(
input wire clk,
input wire rst_n,
output wire [7:0] wave
);
wire [7:0] addr ;
roml256x8 roml256x8_inst (
.address ( addr ),
.clock ( clk ),
.q ( wave )
);
dds_ctrl dds_ctrl_inst(
.clk(clk),
.rst_n(rst_n),
.addr_sin(addr)
);
endmodule
dss_ctrl代碼如下
module dds_ctrl(
input wire clk,
input wire rst_n,
output wire [7:0] addr_sin
);
parameter P_word = 0; //xiangwei
parameter FREQ = 123456; //f
localparam [63:0] F_word = FREQ*(2**32)*20/(10**9);
reg [31:0] cnt;
assign addr_sin=cnt[31:24]+P_word;
always @(posedge clk)begin
if(rst_n==1'b0)
cnt<=32'd0;
else
cnt<=cnt+F_word[31:0];
end
endmodule
主要思路
由於開發芯片頻率爲50MHz,可以知道單個週期的時間爲20ns,由於選擇的cnt的位寬是32位,所以存滿一個週期所需要的時間爲
T=2^32✖20ns
f=1/T
f=(10^9) / (2^32✖20)
假設我們一步的步長爲F_word,那麼
f=F_word✖(10^9) / (2^32✖20)
F_word=f ✖ (2^32) ✖ 20 / (10^9)
我們取cnt寄存器的高8位作爲rom的地址,通過對地址的不斷讀取即可以實現dds功能
仿真
仿真代碼如下
`timescale 1ns/1ps
module dds_v3_tb;
reg clk;
reg rst_n;
wire [7:0] wave;
wire [7:0] wave1;
defparam dds_v3_inst1.dds_ctrl_inst.FREQ=123456;
defparam dds_v3_inst2.dds_ctrl_inst.FREQ=654321;
dds_v3 dds_v3_inst1(
.clk(clk),
.rst_n(rst_n),
.wave(wave)
);
dds_v3 dds_v3_inst2(
.clk(clk),
.rst_n(rst_n),
.wave(wave1)
);
initial clk=1'b0;
always #10 clk=~clk;
initial begin
rst_n=1'b0;
#200;
@(posedge clk)
#2;
rst_n=1'b1;
repeat (20) begin
while (wave != 255)
@(posedge clk);
while (wave != 0)
@(posedge clk);
end
#2000;
$stop;
end
endmodule