DDS的fpga实现

DDS的fpga实现

DDS的原理可以查找其他资料,本次主要采用matlab生成载波数据,通过存储在ROM中对数据进行读取。
1、先附上matlab代码生成的载波数据

clc;
clear all;
close all;
Nbit=16;%量化位数
Ndata= 4096; 
N_data=0:Ndata-1;
sintheta=sin(pi*2/4/4096*(N_data));
plot(N_data,sintheta);
title('y=sin(\theta)');
xlabel('\theta');
ylabel('sin');

Nor_sin= sintheta/max(abs(sintheta)); % 对数据进行归一化
sinlianghua=round(Nor_sin*2^(Nbit-1)-1);%量化后注意首尾是否溢出
sinlianghua(1)=0;%首位负数-1改成0.

Fix_Nor2=dec2bin(sinlianghua,Nbit);

%% 将处理后数据存储在.coe文件中
fid = fopen('sintheta.coe','w');
fprintf(fid,'MEMORY_INITIALIZATION_RADIX = 2;\r\n');
fprintf(fid,'MEMORY_INITIALIZATION_VECTOR =\r\n'); 
for i=1:Ndata
  fprintf(fid, '%s\r\n', Fix_Nor2(i,:)); 
end
fclose(fid);

可以看出,为了节省寄存器资源,根据正弦函数的对称性,只存储sin函数的四分之一周期。
在这里插入图片描述
上图是取得的需要存储的数据波形。

接下来就是关键的,需要在FPGA中进行取数以及对地址和数据的转换。先附上FPGA程序如下。首先定义控制字以及相位位宽,同时定义好输出DA的位宽(DA的位宽根据实际选用DA器件的位数来定)。共存储4096个数据,因此相位累加器phase_reg(高12位为rom地址) 在第一象限的时候,地址到为4095,此时phase_reg高2bit为00;同时如果相位再次累加,则DDS进入第二象限,phase_reg高2bit为01,此时,取数据时需要在rom中反向取数,因此,取数地址为4095-phase_reg的高12位(注意此时为4095减去地址),完成反向取数。同理在第三象限时,phase_reg高2bit为10,地址从0到4095取数,但是数据在第三象限,因此输出数据cos_out取反,同理第四象限数据取反,rom中反向取数。

module nco_gen
	#(	parameter rom_capacity_width=12,//存储coe个数位宽4096
		parameter coe_capacity=4095,//coe_capacity=2^rom_capacity_width-1
		parameter fw_freq_width=32,//频率字位宽//相位累加位宽
		parameter outwave_width=16//输出波形位宽	
		)
	(
		input sysclk,
		input rstn,
		input en,
		input [fw_freq_width-1:0] fw_freq,//频率字位宽
		output signed [outwave_width-1:0] cos_wave//输出波形位宽
	);
 
 
	reg [rom_capacity_width-1:0] phase_addr;//4096个数据
	reg [fw_freq_width-1:0] phase_reg;//相位累加位宽,最高2位用于象限判断
	reg signed[outwave_width-1:0] cos_out;
	wire signed[outwave_width-1:0] nco_out;
    
	always@(posedge sysclk or negedge rstn)
    begin
        if(!rstn)
            phase_reg <= 0;
        else
        begin
            if(en)
				phase_reg <= phase_reg + fw_freq;  //溢出循环
			else
				phase_reg <= 0;  //溢出循环
        end
    end
	
	
	always@(posedge sysclk or negedge rstn)
    begin
        if(!rstn)
            phase_addr <= 0;
        else
        begin
            if(phase_reg[fw_freq_width-2])//正反向来回循环取地址
				phase_addr <= coe_capacity-phase_reg[fw_freq_width-3:fw_freq_width-14];  //溢出循环
			else
				phase_addr <= phase_reg[fw_freq_width-3:fw_freq_width-14];  //溢出循环
        end
    end
	
	
	
 	always@(posedge sysclk or negedge rstn)
    begin
        if(!rstn)
			cos_out<=0;
		else begin 
				case(phase_reg[fw_freq_width-1:fw_freq_width-2])
					2'b00:	cos_out<=nco_out;
					2'b01:	cos_out<=nco_out;
					2'b10:	cos_out<=0-nco_out;
					2'b11:	cos_out<=0-nco_out;
				endcase
			end
    end
 
   
 rom_ncogen u_NCO_COS (
  .clka(sysclk), // input clka
  .addra(phase_addr), // input [11 : 0] addra
  .douta(nco_out) // output [15 : 0] douta
);  

assign cos_wave=cos_out;
   
endmodule

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学技术得猴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值