DDS与DA

信号发生器

	信号发生器是一种能提供各种频率、输出电平的电信号的设备,又称信号源或振荡器。其在各种

电信系统的振幅、频率、传输特性等电参数以及元器件的特性与参数的测量中得到了广泛的应用。

直接数字式频率合成器

( Direct Digital Synthesizer,DDS)是一项关键的数字化技术,其将先进
的数字处理理论与方法引入频率合成技术,通过数/模转换器将一系列数字量形式的信号转换成模拟
量形式的信号。

DA9709芯片

DDS与DA
***DA9709芯片***是双通道,位宽 8bit 的芯片,速率高达 125MSPS,能够满足常用信号发生器、滤波信号输出等需求。
DAC 芯片与 FPGA 相连的信号为: DA_CLKA、 DA_CLKB、 DAC_DA7-0、 DAC_DB7-0、DA_WRA、 DA_WRB 、 DAC_MODE 和 DAC_SLEEP。如下图:
DDS与DA

DA9709操作时序

DDS与DA

注意

DDS与DA
输出电压与 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产生波形数据

DDS与DA
上图正弦波的数据可以通过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仿真结果

DDS与DA

大家不懂的可以与我交流!!!

															***注:以上内容借鉴了《明德杨至简设计原理与应用》***
上一篇:云图说|DDS读写两步走,带您领略只读节点的风采


下一篇:基于FPGA的DDS在Gowin和combat开发板的实现(序)