lcytms
发表于 2016-11-21 18:13:28
同时修改dds模块。
在dds模块里面增加一个相位控制字pword参数的调用。
修改dds模块代码如下。
module dds (clk, rst_n, num);
input clk, rst_n;
output num;
wire addr;
control #(.pword(64))
control_inst (
.clk(clk),
.rst_n(rst_n),
.addr(addr)
);
rom rom_inst (
.address ( addr ),
.clock ( clk ),
.q ( num )
);
endmodule
lcytms
发表于 2016-11-21 18:15:17
仿真运行结果
设置好仿真之后,可以看到仿真结果。
将输出的数据格式(radix一项)设置成模拟的数据。
可以看到复位完成后,输出相位为90°的正弦波,周期为195.31 kHz,依次循环。
可见设置pword=64时,相当于相移90°。
lcytms
发表于 2016-11-21 18:18:00
2)波形发生器(可以调频,可以调相)
经过前面两小节的分析,我们了解到,如果采用本地时钟是50M的话,那么频率就是195.31KHZ,根据我们的公式:
频率 = 50M / 256
设想:如果想要改变输出的频率,我们可以选择改变时钟或者输出点的个数!显而易见,我们的设计不能够时时刻刻去改变时钟的频率,那么想要输出别的频率,我们只能改变输出的点的个数,也就是改变有效地址的数量。
之前的设计是每个时钟沿地址增加1,频率是195.31KHz;如果我们每个时钟沿地址增加2,根据公式,输出频率应该是390.62KHz。
lcytms
发表于 2016-11-21 18:19:05
我们来修改control模块。
在control模块里面再增加一个频率控制字fword。
修改control模块代码如下。
module control (clk, rst_n, addr);
input clk, rst_n;
output reg addr;
parameter pword = 0; // phase control word
parameter fword = 1; // frequency control word
always @ (posedge clk or negedge rst_n)
begin
if (!rst_n)
addr <= pword;
else
addr <= addr + fword;
end
endmodule
lcytms
发表于 2016-11-21 18:20:18
同时修改dds模块。
在dds模块里面再增加一个频率控制字fword参数的调用。
修改dds模块代码如下。
module dds (clk, rst_n, num);
input clk, rst_n;
output num;
wire addr;
control #(.pword(64), .fword(2))
control_inst (
.clk(clk),
.rst_n(rst_n),
.addr(addr)
);
rom rom_inst (
.address ( addr ),
.clock ( clk ),
.q ( num )
);
Endmodule
lcytms
发表于 2016-11-21 18:21:20
仿真运行结果
设置好仿真之后,可以看到仿真结果。
将输出的数据格式(radix一项)设置成模拟的数据。
可以看到复位完成后,输出相位为90°的正弦波,周期为390.62 kHz,依次循环。
可见设置fword=2时,相当于频率*2。
lcytms
发表于 2016-11-21 18:22:22
3)最终设计
上一小节的设计,只能设定195.31KHz的整数倍,那就失去了我们设计的意义。为了提高精度,我们可以定义一个位宽为N(N>8)的地址计数器,让地址计数器每次增加一定的值,然后把高八位当作有效地址输送给rom,这样的话,就实现了降低地址改变的频率,进而达到降低输出波形的频率。
地址计数器的原理就是先将地址变量pword的值作为地址的初值,然后每来一个时钟,地址计数器的值就等于地址当前值加上频率控制字fword,( pword = pword + fword )如此循环。例如刚开始fword = 1(假设pword=0),那么第一个时钟周期地址计数器的输出就是1,第二个时钟周期输出的就是2,第三个时钟周期输出的就是3。再例如,我们的频率控制字fword 刚开始等于2,那么地址计数器输出的就依次是0,2,4.....
lcytms
发表于 2016-11-21 18:24:28
也就是说频率控制字fword 越大,地址计数器的输出值间隔也就越大,那么我们假设地址计数器的输出是32位的,如果fword越大,那么地址计数值到2^32 的时间就越短。
我们使用的是50MHz的晶振,周期为20ns,假设fword为1,地址计数器的输出为N位的,那么每20ns,地址计数器加1,要加到2^N,需要20ns x 2^N 时间,这个时间就是输出一个完整信号的周期,那么我们可以知道,输出信号的频率为 Fout = Fclk /2^N,其中,Fclk为我们的晶振频率,再假如,fword = B的时候,地址间隔提高 B 倍,因此计满一个周期的时间缩小了 B 倍,频率提高的 B 倍。综上所述,我们得出了输出信号的频率计算公式:
Fout = B * Fclk / 2^N
lcytms
发表于 2016-11-21 18:25:32
我们来计算一下:当B=1,F大约是0.012Hz。所以我们改变fword的值就基本实现了所有的低于最快频率以下所有的频率值(频率值只能是0.012的倍数,因为0.012太小了,所以基本可以实现所有的频率,若这个精度还是达不到要求的话,大家可以继续增大N的值,根据公式就可以得出最小精度,也可以根据最小精度计算N的值)。
我们取地址计数器的前八位,相当于把一个波形的相位分成了256个点,每个点对应一个数据,正好和我们的波形数据点的个数是一样的。
lcytms
发表于 2016-11-21 18:27:23
我们来修改control模块。
在control模块里面再增加一个32位的地址计数器addr_cnt变量。
修改control模块代码如下。
module control (clk, rst_n, addr);
input clk, rst_n;
output addr;
parameter pword = 0; // phase control word
parameter fword = 100; // frequency control word
reg addr_cnt; // address counter
assign addr = addr_cnt;
always @ (posedge clk or negedge rst_n)
begin
if (!rst_n)
begin
addr_cnt <= pword;
addr_cnt <= 24'd0;
end
else
addr_cnt <= addr_cnt + fword;
end
endmodule