信号发生器
信号发生器是一种能提供各种频率、输出电平的电信号的设备,又称信号源或振荡器。其在各种
电信系统的振幅、频率、传输特性等电参数以及元器件的特性与参数的测量中得到了广泛的应用。
直接数字式频率合成器
( Direct Digital Synthesizer,DDS)是一项关键的数字化技术,其将先进
的数字处理理论与方法引入频率合成技术,通过数/模转换器将一系列数字量形式的信号转换成模拟
量形式的信号。
DA9709芯片
***DA9709芯片***是双通道,位宽 8bit 的芯片,速率高达 125MSPS,能够满足常用信号发生器、滤波信号输出等需求。
DAC 芯片与 FPGA 相连的信号为: DA_CLKA、 DA_CLKB、 DAC_DA7-0、 DAC_DB7-0、DA_WRA、 DA_WRB 、 DAC_MODE 和 DAC_SLEEP。如下图:
DA9709操作时序
注意
输出电压与 DAC_DA/B 的值成线性反比例关系,最低电压为 0.48V,最高为 2.2V。需要注意的是,此范围的电压是由于外围硬件电路特性的原因导致的,不同电路对应的电压范围有所
不同。
实验实现目标
采用采样率大于 100M 的示波器,将其连接到开发板上,控制 DA 输出不同频率的正弦
波,示波器显示出对应波形。输出方式如下:
连续输出 2 个周期为 6.25MHz 的正弦波,每个正弦波输出 8 个采样点;
连续输出 2 个周期为 3.125MHz 的正弦波,每个正弦波输出 16 个采样点;
连续输出 2 个周期为 1.5625MHz 的正弦波,每个正弦波输出 32 个采样点;
连续输出 2 个周期为 781250Hz 的正弦波,每个正弦波输出 64 个采样点;
连续输出 2 个周期为 390625Hz 的正弦波,每个正弦波输出 128 个采样点;
连续输出 2 个周期为 195312.5Hz 的正弦波,每个正弦波输出 128 个采样点。
正弦波的最高电压是 2.2V,最低电压是 0.48V。
verilog代码
下面是我自己编写的,写法与明德杨的不同,但是大致框架是一样的。
module dac9709(
input wire sys_clk ,
input wire sys_rst_n ,
output wire dac_clk_a ,
output wire dac_mode ,
output reg [7:0] dac_data ,
output wire dac_sleep ,
output wire dac_wr_en
);
reg [1:0] cnt0 ;
reg [7:0] cnt1 ;
reg [1:0] cnt2 ;
reg [2:0] cnt3 ;
reg [7:0] addr ;
reg [7:0] sin_data ;
reg [2:0] sel_gap ;
reg [7:0] sel_point ;
wire flag1 ;
wire flag2 ;
wire flag3 ;
assign flag1 = (cnt0 == (sel_gap - 1'b1))?1'b1:1'b0;
assign flag2 = (cnt1 == (sel_point - 1'b1))?1'b1:1'b0;
assign flag3 = (cnt2 == 1'b1)?1'b1:1'b0;
always@ (posedge sys_clk or negedge sys_rst_n)
if (sys_rst_n == 1'b0)
cnt0 <= 2'd0;
else if(flag1)
cnt0 <= 2'd0;
else
cnt0 <= cnt0 + 1'b1;
always@ (posedge sys_clk or negedge sys_rst_n)
if (sys_rst_n == 1'b0)
cnt1 <= 8'd0;
else if(flag2)
cnt1 <= 8'd0;
else if(flag1)
cnt1 <= cnt1 + 1'b1;
else
cnt1 <= cnt1;
always@ (posedge sys_clk or negedge sys_rst_n)
if (sys_rst_n == 1'b0)
cnt2 <= 2'd0;
else if ((flag3)&&(flag2))
cnt2 <= 2'd0;
else if(flag2)
cnt2 <= cnt2 + 1'b1;
else
cnt2 <= cnt2;
always @ (posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt3 <= 3'd0;
else if ((cnt3 == 3'd5)&&(flag3)&&(flag2))
cnt3 <= 3'd0;
else if ((flag3)&&(flag2))
cnt3 <= cnt3 + 1'b1;
else
cnt3 <= cnt3;
always @ (*)begin
case (cnt3)
0:begin
sel_gap <= 2'd1;
sel_point <= 8'd8;
end
1:begin
sel_gap <= 2'd1;
sel_point <= 8'd16;
end
2:begin
sel_gap <= 2'd1;
sel_point <= 8'd32;
end
3:begin
sel_gap <= 2'd1;
sel_point <= 8'd64;
end
4:begin
sel_gap <= 2'd1;
sel_point <= 8'd128;
end
5:begin
sel_gap <= 2'd2;
sel_point <= 8'd128;
end
default : begin
sel_gap <= 2'd1;
sel_point <= 8'd8;
end
endcase
end
always @ (*) begin
case (cnt3)
0:addr = cnt1 *16;
1:addr = cnt1 *8;
2:addr = cnt1 *4;
3:addr = cnt1 *2;
4:addr = cnt1 *1;
5:addr = cnt1 *1;
default : addr = cnt1 *1;
endcase
end
always @ (*) begin
case(addr)
0 :sin_data<= 8'h7f;
1 :sin_data<= 8'h85;
2 :sin_data<= 8'h8c;
3 :sin_data<= 8'h92;
4 :sin_data<= 8'h98;
5 :sin_data<= 8'h9e;
6 :sin_data<= 8'ha4;
7 :sin_data<= 8'haa;
8 :sin_data<= 8'hb0;
9 :sin_data<= 8'hb6;
10 :sin_data<= 8'hbb;
11 :sin_data<= 8'hc1;
12 :sin_data<= 8'hc6;
13 :sin_data<= 8'hcb;
14 :sin_data<= 8'hd0;
15 :sin_data<= 8'hd5;
16 :sin_data<= 8'hda;
17 :sin_data<= 8'hde;
18 :sin_data<= 8'he2;
19 :sin_data<= 8'he6;
20 :sin_data<= 8'he9;
21 :sin_data<= 8'hed;
22 :sin_data<= 8'hf0;
23 :sin_data<= 8'hf3;
24 :sin_data<= 8'hf5;
25 :sin_data<= 8'hf8;
26 :sin_data<= 8'hf9;
27 :sin_data<= 8'hfb;
28 :sin_data<= 8'hfd;
29 :sin_data<= 8'hfe;
30 :sin_data<= 8'hfe;
31 :sin_data<= 8'hff;
32 :sin_data<= 8'hff;
33 :sin_data<= 8'hff;
34 :sin_data<= 8'hfe;
35 :sin_data<= 8'hfe;
36 :sin_data<= 8'hfd;
37 :sin_data<= 8'hfb;
38 :sin_data<= 8'hf9;
39 :sin_data<= 8'hf8;
40 :sin_data<= 8'hf5;
41 :sin_data<= 8'hf3;
42 :sin_data<= 8'hf0;
43 :sin_data<= 8'hed;
44 :sin_data<= 8'he9;
45 :sin_data<= 8'he6;
46 :sin_data<= 8'he2;
47 :sin_data<= 8'hde;
48 :sin_data<= 8'hda;
49 :sin_data<= 8'hd5;
50 :sin_data<= 8'hd0;
51 :sin_data<= 8'hcb;
52 :sin_data<= 8'hc6;
53 :sin_data<= 8'hc1;
54 :sin_data<= 8'hbb;
55 :sin_data<= 8'hb6;
56 :sin_data<= 8'hb0;
57 :sin_data<= 8'haa;
58 :sin_data<= 8'ha4;
59 :sin_data<= 8'h9e;
60 :sin_data<= 8'h98;
61 :sin_data<= 8'h92;
62 :sin_data<= 8'h8c;
63 :sin_data<= 8'h85;
64 :sin_data<= 8'h7f;
65 :sin_data<= 8'h79;
66 :sin_data<= 8'h72;
67 :sin_data<= 8'h6c;
68 :sin_data<= 8'h66;
69 :sin_data<= 8'h60;
70 :sin_data<= 8'h5a;
71 :sin_data<= 8'h54;
72 :sin_data<= 8'h4e;
73 :sin_data<= 8'h48;
74 :sin_data<= 8'h43;
75 :sin_data<= 8'h3d;
76 :sin_data<= 8'h38;
77 :sin_data<= 8'h33;
78 :sin_data<= 8'h2e;
79 :sin_data<= 8'h29;
80 :sin_data<= 8'h24;
81 :sin_data<= 8'h20;
82 :sin_data<= 8'h1c;
83 :sin_data<= 8'h18;
84 :sin_data<= 8'h15;
85 :sin_data<= 8'h11;
86 :sin_data<= 8'he;
87 :sin_data<= 8'hb;
88 :sin_data<= 8'h9;
89 :sin_data<= 8'h6;
90 :sin_data<= 8'h5;
91 :sin_data<= 8'h3;
92 :sin_data<= 8'h1;
93 :sin_data<= 8'h0;
94 :sin_data<= 8'h0;
95 :sin_data<= 8'h0;
96 :sin_data<= 8'h0;
97 :sin_data<= 8'h0;
98 :sin_data<= 8'h0;
99 :sin_data<= 8'h0;
100 :sin_data<= 8'h1;
101 :sin_data<= 8'h3;
102 :sin_data<= 8'h5;
103 :sin_data<= 8'h6;
104 :sin_data<= 8'h9;
105 :sin_data<= 8'hb;
106 :sin_data<= 8'he;
107 :sin_data<= 8'h11;
108 :sin_data<= 8'h15;
109 :sin_data<= 8'h18;
110 :sin_data<= 8'h1c;
111 :sin_data<= 8'h20;
112 :sin_data<= 8'h24;
113 :sin_data<= 8'h29;
114 :sin_data<= 8'h2e;
115 :sin_data<= 8'h33;
116 :sin_data<= 8'h38;
117 :sin_data<= 8'h3d;
118 :sin_data<= 8'h43;
119 :sin_data<= 8'h48;
120 :sin_data<= 8'h4e;
121 :sin_data<= 8'h54;
122 :sin_data<= 8'h5a;
123 :sin_data<= 8'h60;
124 :sin_data<= 8'h66;
125 :sin_data<= 8'h6c;
126 :sin_data<= 8'h72;
127 :sin_data<= 8'h79;
endcase
end
always @ (posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
dac_data <= 8'd0;
else
dac_data <= 255 - sin_data;
assign dac_mode = 1'b1;
assign dac_clk_a = ~ sys_clk;
assign dac_sleep = 1'b0;
assign dac_wr_en = dac_clk_a;
endmodule
仿真测试代码
`timescale 1ns/1ns
module dac_9709_tb();
reg sys_clk ;
reg sys_rst_n ;
wire dac_clk_a ;
wire dac_mode ;
wire[7:0] dac_data ;
wire dac_sleep ;
wire dac_wr_en ;
initial begin
sys_clk = 1'b1;
sys_rst_n = 1'b0;
#21
sys_rst_n = 1'b1;
#100000
$stop;
end
always #10 sys_clk = ~sys_clk;
dac9709 dac9709_inst(
.sys_clk (sys_clk ),
.sys_rst_n (sys_rst_n ),
.dac_clk_a (dac_clk_a ),
.dac_mode (dac_mode ),
.dac_data (dac_data ),
.dac_sleep (dac_sleep ),
.dac_wr_en (dac_wr_en )
);
endmodule
MATLAB产生波形数据
上图正弦波的数据可以通过matlab产生:
输入以下命令:生成文件,复制即可。
clc; %清除命令行命令
clear all; %清除工作区变量,释放内存空间
F1=1; %信号频率
Fs=2^7; %采样频率
P1=0; %信号初始相位
N=2^7; %采样点数
t=[0:1/Fs:(N-1)/Fs]; %采样时刻
ADC=2^7 - 1; %直流分量
A=2^7; %信号幅度
%生成正弦信号
s=A*sin(2*pi*F1*t + pi*P1/180) + ADC;
plot(s); %绘制图形
%创建mif文件
fild = fopen('sin_128.mif','wt');
%写入mif文件头
fprintf(fild, '%s\n','WIDTH=7;'); %位宽
fprintf(fild, '%s\n\n','DEPTH=128;'); %深度
fprintf(fild, '%s\n','ADDRESS_RADIX=UNS;'); %地址格式
fprintf(fild, '%s\n\n','DATA_RADIX=UNS;'); %数据格式
fprintf(fild, '%s\t','CONTENT'); %地址
fprintf(fild, '%s\n','BEGIN'); %开始
for i = 1:N
s0(i) = round(s(i)); %对小数四舍五入以取整
if s0(i) <0 %负1强制置零
s0(i) = 0
end
fprintf(fild, '\t%g\t',i-1); %地址编码
fprintf(fild, '%s\t',':sin_data<='); %冒号
fprintf(fild, '%x',s0(i)); %数据写入
fprintf(fild, '%s\n',';'); %分号,换行
end
fprintf(fild, '%s\n','END;'); %结束
fclose(fild);
modelsim仿真结果
大家不懂的可以与我交流!!!
***注:以上内容借鉴了《明德杨至简设计原理与应用》***