您的位置:首页 > 编程语言 > MATLAB

Verilog HDL DDS设计(作业3)

2016-12-19 23:00 519 查看

实验内容

在FPGA上设计一个DDS模块,在DE0 开发板上运行,在FPGA芯片内部合成出数字波形即可。不用输出模拟信号,本模块满足以下条件:

使用板载晶振的50MHz时钟,合成以下频率的信号

1、500KHz 正弦波信号。 2、1MHz 正弦波信号。 3、3MHz 正弦波信号。

频率字字长32位,波表ROM尺寸为 10比特地址,1024个word

波形格式为2补码格式,12比特量化

每个CLK输出一个有效样点。

输入信号为频率字和频率字输入使能信号

使用板载的拨码开关(Switch)控制生成的波形信号的不同频率。

注:波表ROM代码是用matlab或C打印生成的。不要手写

实验要求

人工绘制的 电路结构RTL设计图,该图片用于说明你设计电路时的想法,注意要在RTL图中画出Verilog代码中的 生成D触发器 reg 变量

Quartus扫描生成的电路RTL图,该图片用于说明Quartus的电路编译结果

相位累加器的输出,SignalTap截图

波表ROM的输入地址,SignalTap截图

至少捕获 一个完整的输出正弦波形周期的上述数据数值的SignalTap截图。

输出正弦波的样值波形,SignalTap截图

提交Verilog、相关MATLAB 代码,请使用博客中提供的代码块功能

分析输出的正弦波信号的频谱,Matlab 截图

Visio绘制的RTL



Quartus扫描生成的RTL

顶层RTL



SwitchRTL



dds_core RTL



RAM RTL



SignalTap截图

频率控制字FQWD=10:



注:此时正弦波一个周期采样102个点,50MHz下采样周期0.02us,输出正弦波频率约为 f=1102∗0.02≈0.5(MHz)。

频率控制字FQWD=20:



注:此时正弦波一个周期采样52个点,50MHz下采样周期0.02us,输出正弦波频率约为 f=152∗0.02≈1(MHz)。

频率控制字FQWD=40:



注:此时正弦波一个周期采样26个点,50MHz下采样周期0.02us,输出正弦波频率约为 f=126∗0.02≈2(MHz)。

频率控制字FQWD=60:



注:此时正弦波一个周期采样17个点,50MHz下采样周期0.02us,输出正弦波频率约为 f=117∗0.02≈3(MHz)。

matlab频谱分析

将SignalTap中的波形数据抓出来,放进matlab里面进行分析,并绘制频谱图

500KHz





1MHz





3MHz





补零后~

3MHz





代码

1. 基础模块代码(Verilog)

module switch_freq_word(
CLK     ,   //输入时钟
SWCHIN  ,   //输入拨码开关控制字
FQWD    ,   //输出频率字,作为dds_core的递增累加值
FWEN    );  //输出频率字的更新使能,为1时才能更新频率字

parameter VAL_FREQ_BASE = 6'd10;  // 50MHz clock, 500kHz out wave freqword value

input CLK,FWEN;
input [2:0] SWCHIN; //使用3位拨码开关控制8种频率字的选择,最低500kHz,最高3MHz
output reg[31:0] FQWD;  //用来存放VAL_FREQ_BASE以及它的倍数
//output reg FWEN;

always @(posedge CLK) begin
if (FWEN) begin
case(SWCHIN)
3'd0: FQWD <= VAL_FREQ_BASE;    //500kHz

e657
3'd1: FQWD <= VAL_FREQ_BASE * 2;
3'd2: FQWD <= VAL_FREQ_BASE * 3;
3'd3: FQWD <= VAL_FREQ_BASE * 4;
3'd4: FQWD <= VAL_FREQ_BASE * 5;
3'd5: FQWD <= VAL_FREQ_BASE * 6;//3MHz
default: FQWD <= VAL_FREQ_BASE;
endcase
end
else begin
FQWD <= #1 FQWD;
end
// FQWD <= VAL_FREQ_BASE * SWCHIN;
end

endmodule

/*********************************************
带计数增量的计数器
输入:CLK时钟信号、INCR递增累加值
输出:SINOUT计数值
功能:SINOUT作为输出地址,对ROM表进行提取,地址为
多少就提取出相应的ROM值进行输出
*********************************************/
module dds_core(
CLK   ,   // clock
INCR  ,   // 计数增量
SINOUT);  // counter value
input CLK;
input  [31:0] INCR;
output reg[9:0] SINOUT;

always @ (posedge CLK) begin
SINOUT <= INCR + SINOUT;
end

endmodule   // module dds_core


2. DDS ROM表代码(Verilog)

此波表ROM代码是用matlab或C打印生成的(略写)

module DDS_CORE_ROM(
CLK    ,           // clock
RA     ,           // read address
RD     );          // read data
input          CLK;
input  [9  :0] RA;
output [11 :0] RD;
reg    [11 :0] RD;
always @ (posedge CLK)
case(RA)
10'd 0     :RD = #1 12'b 000000000000; //      0 0x0
10'd 1     :RD = #1 12'b 000000001100; //     12 0xC
10'd 2     :RD = #1 12'b 000000011001; //     25 0x19
10'd 3     :RD = #1 12'b 000000100101; //     37 0x25
10'd 4     :RD = #1 12'b 000000110010; //     50 0x32
......
default : RD = #1 0;
endcase
endmodule


3. DDS ROM表生成代码(MATLAB)

此代码原作者为杜伟韬老师,在此向大神杜伟韬老师表示真挚的敬意

function generate_DDS_rom()
clc;
close all;
disp('# generate_DDS_rom() Running~');

%%///////////////////////////////////////////////////
%   set your rom config here
rom_word_len = 12;  % rom data word length in bit
rom_addr_len = 10;  % rom address word length in bit
rom_file_name = 'DDS_CORE_ROM.v';  % rom file name
rom_file_dir  = './';  % rom file dir path
description   = 'DDS CORE ROM FILE' ;% rom description
%%///////////////////////////////////////////////////

rom_vec_len = 2^rom_addr_len;   %2^10=1024
index = (0:rom_vec_len-1) ;     %0~1023
rom_data_vec_float = sin(2*pi*index/rom_vec_len);   %最大值为1的1024点正弦波
figure; plot(rom_data_vec_float);    % for debug
rom_data_vec_int = fix(rom_data_vec_float * (2^(rom_word_len-1) - 1));  %最大值为2047,为了保证最高位为符号位
figure; plot(rom_data_vec_int);      % for debug

rom_cfg.rom_word_len  = rom_word_len   ;
rom_cfg.rom_file_name = rom_file_name  ;
rom_cfg.rom_file_dir  = rom_file_dir   ;
rom_cfg.description   = description    ;
gen_rom_rtl(rom_cfg, rom_data_vec_int);

end % generate_DDS_rom()

% ///////////////////////////////////////////////////////////////////////////////
% gen_rom_rtl()
%   generate synthesizable rom  hdl code(need synthesizer support).
% ///////////////////////////////////////////////////////////////////////////////
% INPUT:
%   data vector, must be integer value
%   rom word len
%   rom file dir string
%   rom file name string
% OUTPUT:
%   verilog format rom file, all data in 2's complement code format
function gen_rom_rtl(rom_cfg, data_vec)

rom_word_len   = rom_cfg.rom_word_len  ;
rom_file_name  = rom_cfg.rom_file_name ;
rom_file_dir   = rom_cfg.rom_file_dir  ;

description    = rom_cfg.description   ;
data_vec_len = length(data_vec);
addr_word_len  = ceil(log2(data_vec_len));

% check input be integer value
data_vec_fixed = fix(data_vec);
diff_sum = sum(data_vec == data_vec_fixed);
% all integer elements will cause the diff_sum be vector length
if(diff_sum < data_vec_len)
fprintf(1,'# ERROR, gen_rom_rtl(), input data_vec must be integer value\n');
return;
end

rom_file_dir_name = strcat(rom_file_dir, rom_file_name);

data_vec_fixed_2c =  data_vec_fixed + (2^rom_word_len) .* (data_vec_fixed < 0);

romNum        = 2^addr_word_len;
data_str_cell  = cell(data_vec_len, 1);

for idx = 1:data_vec_len
data_str_cell{idx} = Dec2BinStr(data_vec_fixed_2c(idx), rom_word_len);
end % for(idx = 1:data_vec_len)

if(romNum > data_vec_len)
for idx = data_vec_len+1:romNum
data_str_cell{idx} = Dec2BinStr(0, rom_word_len);
end
end

fid_rom_file = fopen(rom_file_dir_name, 'w');
if(fid_rom_file == -1)
errMsg = strcat('ERROR, gen_rom_rtl(), create file',rom_file_dir_name, ',failed');
fprintf(1, '%s\n', errMsg);
return;
end

% rom data print
% get rom module name
rom_name = rom_file_name;
len_rom_file_name = length(rom_file_name);
if(strcmp(rom_name(len_rom_file_name-1:len_rom_file_name), '.v'))
rom_name(len_rom_file_name-1:len_rom_file_name) = [];
else
fprintf(1,'#WARNINIG, gen_rom_rtl(), rom_file_name may error, check it!\n');
end
fprintf(fid_rom_file,  ...
'// ************************************************************** //\n');
fprintf(fid_rom_file,  ...
'// FILE    : %s \n', rom_file_name);
fprintf(fid_rom_file,  ...
'// DSCP    : %s\n', description);
fprintf(fid_rom_file,  ...
'// ABOUT   : auto generated rom file by gen_rom_rtl.m\n');
fprintf(fid_rom_file,  ...
'// DATE    : %s \n',  datestr(now));
fprintf(fid_rom_file,  ...
'// ************************************************************** //\n');
% generate the crom module
fprintf(fid_rom_file, ...
'// module %s()\n', rom_name);
fprintf(fid_rom_file, ...
'module %s(\n', rom_name);
fprintf(fid_rom_file, ...
'  CLK    ,           // clock\n');
fprintf(fid_rom_file, ...
'  RA     ,           // read address\n');
fprintf(fid_rom_file, ...
'  RD     );          // read data\n');

fprintf(fid_rom_file, ...
'input          CLK;\n');
fprintf(fid_rom_file, ...
'input  [%-2d :0] RA;\n', addr_word_len-1);
fprintf(fid_rom_file, ...
'output [%-2d :0] RD;\n', rom_word_len-1);
fprintf(fid_rom_file, ...
'reg    [%-2d :0] RD;\n', rom_word_len-1);

fprintf(fid_rom_file, ...
'always @ (posedge CLK)\n');
fprintf(fid_rom_file, ...
'  case(RA)\n');

for addr = 0:1:data_vec_len-1
fprintf(fid_rom_file, ...
'     %-2d''d %-6d:RD = #1 %-2d''b %s; ', ...
addr_word_len,addr, rom_word_len, data_str_cell{addr+1});
fprintf(fid_rom_file, ...
'// %6d 0x%s \n', ...
data_vec_fixed(addr+1), dec2hex(data_vec_fixed_2c(addr+1)));

end
fprintf(fid_rom_file, ...
'  default : RD = #1 0;\n');
fprintf(fid_rom_file, ...
'  endcase\n');

fprintf(fid_rom_file, ...
'endmodule \n');
fclose(fid_rom_file);
fprintf(1,'# File: %s written\n', rom_file_dir_name);

end % function gen_rom_rtl()
% ////////////////////////////////////////////////////////////////////
function str = Dec2BinStr(data, word_len)
str = '';
for idx = word_len-1:-1:0
bit_val = bitand(1, bitshift(data, -idx));
str = strcat(str, int2str(bit_val));
end
end % function Dec2BinStr()


注:这是个函数,在matlab里面键入函数名字即可运行生成ROM文件

4. SignalTap波形频谱分析(MATLAB)

此代码根据SignalTap生成波形的数据(鼠标右击波形名字-Create SignalTapII List File),绘制频谱图(需要对文件进行修改,只保留所需数据列)

以下以3MHz时为例:(略写)

signal_tap_data_3M.m文件

signal_out=[
-2044 ,
-1943 ,
-1582 ,
-1008 ,
-300  ,
448   ,
1137  ,
1673  ,
...
...
];


调用数据并绘图

clear;
signal_tap_data_3M;
signal=transpose(signal_out); %矩阵转置
fs=50E6; %采样频率
N=1024; %采样点数
t=[0:1/fs:(N-1)/fs]; %采样时刻
figure(1);plot(t,signal);
xlabel('Time (s)');
ylabel('Magnitude');
Y = fft(signal,N); %做FFT变换
Ayy = abs(Y); %取模
Ayy=Ayy/(N/2); %换算成实际的幅度
Ayy(1)=Ayy(1)/2;
F=([1:N]-1)*fs/N; %换算成实际的频率值,Fn=(n-1)*Fs/N
figure(2);
stem(F(1:N/2),Ayy(1:N/2)); %显示换算后的FFT模值结果
axis([0 5E6 0 2500]);
title('幅度-频率曲线图');
xlabel('Frequency (Hz)');
ylabel('Magnitude');


带有补零的绘图代码

clear;
signal_tap_data_3M;
signal=transpose(signal_out);   %矩阵转置
b=zeros(1,1024);
signal=[b,signal,b]; %补零,改善频谱
fs=50E6; %采样频率
N=1024*3; %采样点数
Nv=1024;  %有效数据点数
t=[0:1/fs:(N-1)/fs]; %采样时刻
figure(1);plot(t,signal);
xlabel('Time (s)');
ylabel('Magnitude');
Y = fft(signal,N); %做FFT变换
Ayy = abs(Y); %取模
Ayy=Ayy/(Nv/2); %换算成实际的幅度
Ayy(1)=Ayy(1)/2;
F=([1:N]-1)*fs/N; %换算成实际的频率值,Fn=(n-1)*Fs/N
figure(2);
plot(F(1:N/2),Ayy(1:N/2)); %显示换算后的FFT模值结果
axis([0 5E6 0 2500]);
title('幅度-频率曲线图');
xlabel('Frequency (Hz)');
ylabel('Magnitude');
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  fpga dds matlab