从最基本细节开始:quartus:FPGA利用rom查表法产生DDS

一、DDS原理及结构

DDS(Direct Digital Synthesis)是一种把一系列数字信号通过D/A转换器转换成模拟信号的数字合成技术。它有查表法和计算法两种基本合成方法。由于ROM查询法结构简单,只需要在ROM中存放不同相位对应的幅度序列,然后通过相位累加器的输出对其寻址,经过数/模转换和低通滤波(LPF)输出便可以得到所需要的模拟信号。
ROM查表法。DDS技术实质上是实现了一个数字分频器的功能。对于一个周期的正弦波连续信号,可以沿其相位轴方向,以等量的相位间隔对其进行相位/幅度采样,得到一个周期性的正弦信号的离散相位的幅度序列,对模拟幅度进行量化后的幅值采用二进制数据编码,这样就把一个周期的正弦波连续信号转换成一系列离散的二进制数字量,然后存入存储器RAM中,每个存储器单元的地址即是相位取样地址,存储单元的内容是已经量化了的正弦波幅值。一个这样的只读存储器构成了一个与2π周期相位取样对应的正弦波函数表。DDS的基本原理主要由标准参考频率源、相位累加器、波形存储器和数/模转换器构成。
在时钟脉冲的控制下,频率控制字K由累加器得到相应的相码。相码寻址波形存储器进行相码—幅码变换输出不同的幅度编码,经过数/模变换器得到相应的阶梯波,最后经过低通滤波器对阶梯波进行平滑,即得到由频率控制字K决定的连续变化的输出波形。相位累加器是实现DDS的核心,它由一个N位字长的二进制加法器和一个由固定时钟脉冲取样的N位相位寄存器组成,在每个时钟脉冲到达时,相位寄存器采用上个时钟周期内相位寄存器的值与频率控制字K之和,并作为相位累加器在这一时钟周期的输出。fpga系统框图如图:在这里插入图片描述

二、ROM表的生成

利用matalab产生.mif。.mif文件格式
WIDTH=8;//mif数据的深度,8代表每个数据都是8bit;
DEPTH=512;//数据的宽度,512代表总共有512的数据;
ADDRESS_RADIX=HEX;//地址的格式 HEX即代表以16进制来寻址 (uns–十进制,bin–二进制,hex–十六进制)
DATA_RADIX=HEX;//数据存储的格式,同上
CONTENT BEGIN//
0 : 80;
1 : 86;
2 : 8C;
3 : 92;
4 : 98;
END;//在content begin和end之间就是存储的数据
采用matlab生成.mif

MATALB程序:

clc;
clear all;
close all;

width = 8;   %位宽
depth = 2 ^9; %深度(采样点个数)
x = linspace(0, 2 * pi, depth);
y = sin(x);
y = round(y * (2 ^ (width - 1) - 1) + 2 ^ (width - 1) - 1);%量化
plot(y);

fid = fopen('dds_sin.mif','w');//生成的.mif文件在.m所在路径
fprintf(fid,'DEPTH=%d;\n',depth);
fprintf(fid,'WIDTH=%d;\n',width);
fprintf(fid, 'ADDRESS_RADIX = UNS;\n'); %% 指定地址为十进制
fprintf(fid, 'DATA_RADIX = DEC;\n');    
fprintf(fid, 'CONTENT\t');
fprintf(fid, 'BEGIN\n');
for i = 0 : depth-1
    fprintf(fid, '\t%d\t:\t%d;\n',i,y(i+1));
end
fprintf(fid, 'END;\n'); 


fclose(fid);


1、生成的.mif

和.m文件在同一个路径,如果想生成的.mif在指定文件下,程序修改就行
记事本打开.mif正弦波数据:
在这里插入图片描述
quartus打开.mif文件可以直观看到数据:在这里插入图片描述

2、利用quartusii生成ROM表导入.mif文件
使用的quartus是15版本的,创建好工程,选择tools–>IP catalog
在这里插入图片描述
操作完成后,注意屏幕右侧,在搜索框中,搜索rom,选择ROM:1-PORRT
在这里插入图片描述
page1:根据自己设置的位宽和深度配置,我自己生成的.mif文件中,位宽为8,深度为512然后next,所有如图
在这里插入图片描述
page2:配置如图,此处没有选择rden信号:
在这里插入图片描述
page3:要导入.mif文件,利用其初始化rom,所以需要选择yes,选择browse,找到.mif文件所在位置,导入即可(ps:建议把.mif文件放在工程文件下)
在这里插入图片描述
page4,page5:选择finsh,IP核就生成好了,在左侧project navigator处,找到IP Components,可以看到我们所生成的ip核,同时想要编辑此ip核,鼠标右键选择EdIT in Parameter Editor,就可以进入ip核配置界面。
在这里插入图片描述
在这里插入图片描述

三、程序编写

**思路:**在时钟控制下,每次相位累加器累加一次频率字,rom的地址由频率累加字的高9位[只要高于]与相位字的和决定;利用传参改变相位累加器位宽、产生的波形频率、输入时钟,初始相位。

  1. 频率字F_WORD=需要波形的频率2^N/输入时钟频率(相位N为累加器的位宽)
    如:需要10k的正弦波,带入公式F_WORD=10000
    2^N/50000000=13.1频率字约等于13;

  2. P_WORD:相位字,决定正弦波初始相位

module dds_ip (

						input sys_rst_n,
						input sys_clock,//50Mhz时钟
						output [7:0] wave_out//波形输出
						
						);
//传参改变他们的值
parameter PHASE_SUM_N=5'd16;//相位累加器位宽
parameter  wave_fre =10'd1000;//1khz
parameter  iclock_fre = 26'd50000000;//50mhz模块工作时钟
parameter  P_WORD = 9'd0;//默认初始相位为0

//reg
reg [15:0]PHASE_SUM;//16位相位累加器
reg [31:0]F_WORD;//频率字F_WORD=需要波形的频率*2^N/输入时钟频率(相位N为累加器的位宽),
//wire
wire [8:0] rom_addr;//rom地址
//初始化F_WORD
initial
begin
  F_WORD =(wave_fre<<PHASE_SUM_N)/iclock_fre;
end


always@(posedge sys_clock or negedge sys_rst_n)
		begin   
				if(!sys_rst_n)
						PHASE_SUM <=16'd0;
						
				else if(PHASE_SUM <16'b1111_1111_1111_1111)		
					begin
			        	PHASE_SUM <= PHASE_SUM +  F_WORD;//累加
						end
				else
						PHASE_SUM <= 16'd0;
	
end

assign rom_addr =P_WORD+PHASE_SUM[15:7];//取高九位+初始相位,得rom地址


sin_ip u_sin_ip (
	.address(rom_addr),
	.clock(sys_clock), 
	
	.q(wave_out)
	);

endmodule	

如何查看IP核的传参入口,调用IP核,如下图
在这里插入图片描述

四、Modelsim仿真

quartus与Modelsim联合仿真Tb文件编写(利用quartus生成的tb程序框架)

切记,信号一定要初始化



`timescale 1 ns/ 1 ns
module dds_ip_vlg_tst();
// constants                                           
// general purpose registers

// test vector input registers
reg sys_clock;
reg sys_rst_n;
// wires                                               
wire [7:0]  wave_out;

// assign statements (if any)                          
dds_ip #(.wave_fre(14'd10000),.P_WORD(6'd20))i1_inst (
// port map - connection between master ports and signals/registers   
	.wave_out(wave_out),
	.sys_clock(sys_clock),
	.sys_rst_n(sys_rst_n)
);
initial                                                
begin                                                  

sys_clock=1'b0;

sys_rst_n=1'b0;
#200
sys_rst_n = 1'b1;

                                     
$display("Running testbench");                       
end                                                    
always   #10 sys_clock=~sys_clock;//50MHZ时钟                                              
                                      
                                            
endmodule


仿真结果如图 ,wave_out是16进制的数,我们需要看波形,还需要进行设置;

在这里插入图片描述
wave_out上右键先选择Radix->unsigned;再选择Format->Analog(automatic)。实当缩小,波形就出来了
在这里插入图片描述
此文章,作为本人学习记录,同时希望能够给向我一样的初学者提供一些帮助;后续会优化细节。

  • 14
    点赞
  • 89
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
在实际的FPGA编程过程中,可以使用Quartus软件来进行编程。以下是一个利用Quartus对实际FPGA编程的简单例子。 假设我们要设计一个简单的数字时钟,并在FPGA上实现。首先,我们需要使用Verilog或VHDL等硬件描述语言来编写时钟的逻辑设计。在Quartus中,我们可以创建一个新的工程,并将我们的设计文件添加到工程中。 接下来,我们需要指定FPGA的型号和引脚约束。Quartus提供了FPGA型号库,可以选择我们使用的FPGA型号,并将其添加到我们的工程中。然后,我们可以使用引脚编辑器来选择FPGA的引脚,并为每个引脚指定相应的功能。 完成配置后,我们可以进行逻辑综合和布线。Quartus会根据我们的设计文件生成逻辑电路,并尝试将其映射到FPGA的可用逻辑资源上。然后,在布线阶段,Quartus会分配适当的信号路径来连接逻辑资源。在这个例子中,我们需要将时钟信号连接到FPGA的引脚上。 完成布线后,我们接下来需要进行时序分析和时序优化。时序分析可以帮助我们确保所有信号都在正确的时间到达目标;时序优化可以帮助我们优化信号路径,提高时序性能。Quartus提供了一系列的工具和选项,可以帮助我们完成这些任务。 最后,我们需要将生成的bit文件下载到FPGA上进行验证。Quartus提供了下载工具,可以将bit文件下载到FPGA芯片上。然后,我们可以观察FPGA上的时钟是否按照我们的设计进行工作。 通过以上步骤,我们可以利用Quartus对实际FPGA进行编程,并且实现我们的设计。这只是一个简单的例子,实际的FPGA编程需要更复杂的设计和调试,但Quartus提供了一个强大的工具集,可以帮助我们完成这些任务。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值