目录
[DDS 信号源的设计](#DDS 信号源的设计)
基本功能IP
Quartus Prime内嵌的IP按功能可分为基本功能、数字信号处理、接口协议、存储器接口和控制器、处理器和外围设备以及大学计划项目共6种类型。每种类型中包含多个子类型,而子类型中包含为数不等的功能IP。
基本功能IP分为8种子类型,大致来源于两方面:
(1) 原Altera提供的IP,以ALT开开头的,如ALTFP_MULT、ALTFP_DIV和ALTPLL等;
(2) 参数化模块库(Library of Parameterized Modules)中的IP,以LPM标注的,如LPM_COUNTER、LPM_MULT和LPM_DEVIDE等。
IP的定制方法
IP定制完成时,默认输出HDL目标文件,同时还可选择输出原理图符号文件(.bsf)、HDL例化模板文件(_inst.v/vhd)以及Verilog黑盒子文件等多种文件类型。
本节定制锁相环宏功能模块ALTPLL,由50MHz晶振产生4选一数据选择器测试所需要的4路信号以及Signal Tap Logic Analyzer的时钟信号为目标,说明宏功能模块的调用方法。
锁相环(Phase-Locked Loop)是一种闭环电子电路,能够利用外部参考信号控制环路内部振荡器的频率和相位,合成出不同频率的信号,在数字系统中用来实现时钟的倍频、分频、占空比调整和移相等功能。
设四路输入信号的频率为4MHz、3MHz、2MHz和1MHz以及Signal Tap Logic Analyzer时钟信号的频率为100MHz。
定制锁相环ALTPLL的具体步骤如下:
step1: 打开Quartus Prime,选择Tools菜单下的IP Catalog进入定制IP对话框,如图所示。双击Basic Fuctions栏下PLL中的锁相环IP - ALTPLL。
step2: 指定输出文件存放的目录和IP文件名,并选择输出HDL的语言类型。
对于MUX4to1模块的测试: 设置定制的锁相环IP名: PLL_for_MUX4to1_tst 输出语言类型: Verilog HDL
step3: 点击OK按钮进入锁相环工作参数设置参数对话框,指定器件的速度等级、锁相环输入时钟源inclk0的频率值,以及锁相环类型和工作模式。
step4: 点击Next>按钮进入锁相环功能端口配置对话框,选择是否为锁相环设置异步复位端和状态锁定指示信号,如下图所示,根据实际需要选定。
step5: 点击Next>两次进入输出设置对话框。选择使用输出信号c0,并设置频率为4MHz、相位偏 移为0˚,如图所示。
锁相环输出信号的频率也可以通过设置乘法因子和除法因子指定。
输出信号的频率与输入时钟源的频率以及乘法因子和除法因子的关系为
step6: 点击Next>进入下一个输出设置对话页。选择使用输出信号c1,并设置乘法因子为3、除法因子为50,相位偏移为0℃。因此,信号c1频率为3MHz。
step7: 点击Next>进入输出信号c4设置对话页。选择使用输出信号c4,并指定c4频率为100MHz
step8: 点击Next>进入锁相环定制汇总对话页。通过在文件前打√选择需要输出的文件类型,其中灰色为默认输出文件。若需要通过原理图方式调用定制好的锁相环,则需要在原理图符号文件pll_for_MUX4to1_tst.bsf文件前打√。
step9: 在Quartus Prime主界面下,选择Project菜单下的Add/Remove Files in Project命令,在弹出的添加或删除文件对话页中可以看到定制好的锁相环模块pll_for_MUX4to1_tst.qip已经添加到工程中,如下图所示。因此,在设计工程中可以通过原理图符号或者Verilog例化方式调用定制好的锁相环了。
建立MUX4to1测试工程,并搭建顶层设计文件,如图所示。
DDS 信号源的设计
DDS是Direct Digital Synthesizer (直接数字频率合成器) 的缩写。 DDS应用数字技术实现信号源,具有控制灵活、分辨率高和稳定性好等优点。
DDS信号源的工作原理是:相位累加器在时钟的作用下实现相位循环累加,输出新的相位增量。波形ROM用于存储波形的幅值数据,以相位累加器的输出作为波形存储器的地址,从存储器中查得相应的波形幅值数据输出,再经过D/A转换器和低通滤波器转换为模拟信号。
DDS用于产生: (1) 时钟;(2) 信号; (3) 载波; (4) SPWM信号。
正弦相位累加的原理可以通过图形来解释。
将一个正弦周期(0~2π)均匀采样2n个点(对应最小的相位增量为2π/2n),并将采样点的模拟正弦幅度值经过量化编码为数字量后存入ROM中。
采用n位相位累加器(能够访问2n个存储单元)时,DDS输出的正弦信号频率fOUT与频率控制字N、相位累加器的时钟脉冲频率fclk之间的关系为:
将一个正弦周期(0~2π)均匀采样256个点时,需要用256×m的ROM。
本节以设计能够输出100Hz~25.5kHz、步进为100Hz的正弦信号源为目标,讲述ROM IP在DDS信号源中的应用。
分析:(1)频率范围为100Hz~25.5kHz、步进为100Hz的正弦信号共有255种频率值,因此需要用8位频率控制字(因为27<255<28)进行控制; (2)为了保证输出正弦信号无失真,根据Nyquist采样定理,每个正弦周期至少应输出2个及以上的采样点,才能恢复出正弦波,而且输出的采样点数越多,越有利于后续低通滤波器的设计。但是,采样点数越多,所需要的存储容量越大,消耗的FPGA存储资源越多,因此需要折中考虑。当输出25.5kHz正弦波,设计每个周期输出16个采样点时,则DDS信号源的时钟频率至少应取(25.5kHz×16=)408kHz。
设计过程: 根据上述分析,取DDS时钟脉冲fclk为409.6kHz、n=12和8位频率控制字时,能够输出的正弦波信号的频率恰好为100Hz~25.5kHz,步进为100Hz。
【优化设计】为了节约FPGA有限的存储资源,对正弦波进行采样时,只存储第一象限(0~π/2)的正弦采样值,然后利用正弦波结构的对称性,映射出第2~4象限(π/2~2π)的正弦函数值。
按照上述设计思路,满足设计要求的DDS正弦信号源的总体设计方案如图所示。
相位累加器的设计
取n=12时,应采用12位二进制相位累加器。只存储1/4周期正弦采样数据时,相位累加器只需要输出10位相位序列值和正弦数据是否需要反相的标志。因此,实现相位累加的Verilog代码参考如下:
module phase_adder12b(clk,rst_n,phase_step,phase_out,datinv);
input clk,rst_n; // DDS时钟及复位信号
input [7:0] phase_step ; // 频率控制字
output reg [9:0] phase_out; // 相位输出
output reg datinv; // 数据反相标志
// 内部变量定义
reg [11:0] cnt; // 相位累加寄存器
// 时序过程,相位累加
always @( posedge clk or negedge rst_n )
if ( !rst_n ) cnt <= 12'b0;
else
cnt <= cnt + phase_step;
// 组合过程,定义输出
always @( cnt )
case ( cnt[11:10] )
2'b00: begin phase_out = cnt[9:0]; datinv = 0; end // 第一象限
2'b01: begin phase_out = ~cnt[9:0]; datinv = 0; end // 第二象限
2'b10: begin phase_out = cnt[9:0]; datinv = 1; end // 第三象限
2'b11: begin phase_out = ~cnt[9:0]; datinv = 1; end // 第四象限
default: begin phase_out = cnt[9:0]; datinv = 0; end
endcase
endmodule
以phase_adder12b.v文件建立工程并进行编译和综合后,选择Files菜单中Create∠Update栏下的"Create Symbol Files for Current File"生成图形符号文件phase_adder12b.bsf,以便在顶层设计中调用。
正弦波ROM的定制
正弦ROM用于实现"相位-幅值"的转换,根据正弦波的相位值输出相应的幅度值。1024×8位正弦ROM可以定制单口ROM IP实现。 在定制ROM之前,首先需要创建存储器初始化始文件(.mif,.hex),然后才能在定制过程中加载正弦采样数据。
.MIF为Altera定义纯文本格式存储器初始化文件,可以用文本编辑器进行编辑。
在Quartus Prime环境下,选择新建Memory Files中的Memory Initialization File,在弹出的对话框的Number of Words和Word Size窗口栏分别设置存储器单元数和数据的位宽,建立一个空白的.mif格式文件,并保存为sin1024x8b.mif。 将正弦采样数据填入空白的.mif文件中。
#include <math.h> // 包含算术运算库
#include <stdio.h> // 包含标准输入/输出库
#define PI 3.1415926 // 定义PI为3.1415926
// 定义存储器初始化文件名和路径
#define PATH "c:/EDA_lab/sin1024x8b.mif"
int main (void)
{
float x; // 定义浮点变量,用于保存正弦计算值
unsigned char sin8b; /* 定义8位无符号整型变
量,用于保存正弦变换值*/
FILE* fp_mif; // 定义文件指针
unsigned int i; // 定义循环变量
// 打开存储器初始化文件
fp_mif=fopen(PATH, "w+");
// 添加文件信息头
fprintf(fp_mif,"WIDTH=8;\n");
fprintf(fp_mif,"DEPTH=1024;\n");
fprintf(fp_mif,"ADDRESS_RADIX=UNS;\n");
fprintf(fp_mif,"DATA_RADIX=UNS;\n");
fprintf(fp_mif,"CONTENT BEGIN\n");
// 计算并保存地址和正弦数据
for (i=0;i<1024;i++) // 输出1024个点
{
x=sin(2*PI*i/4096); // 采样4096点
sin8b=int((x+1)*255/2); // 转换为8位无符号数
//保存地址和数据;
fprintf(fp_mif,"%4d :
%3d;\n",i,sin8b);
}
// 写入结束标志
fprintf(fp_mif,"END;\n");
// 关闭文件
fclose(fp_mif);
return 0;
}