[PFGA]计数器、ROM和DDS基础
文章目录
DDS简介
Direct Digital Synthesis,DDS,直接数字频率合成。
相比模拟电路便宜但不是非常精确,数字电路可以精确地控制频率。
DDS基本结构
clk -> cnt -> ROM -> DAC -> LPF
fclk进入cnt计数。
计数结果信号进入ROM。ROM中保存着需要生成的信号的采样值。
将数值输出到DAC里生成模拟信号。
最后低通滤波,将时域阶梯状信号的高次信号滤掉,使曲线更平滑。
设计目标
使用计数器和ROM来设计一个基础的DDS。
本实验只涉及DAC之前的部分,即输出模拟信号的采样值,没有后续DAC和LPF的处理过程。
采用SignalTap来观察输出信号,并观察计数增量值对生成信号产生的影响。
工程设计
模块设计
计数器模块
为了观察不同的计数增量值对生成信号产生的影响,需要设计能够方便更改技术增量值得功能。这里采取外部输入技术增量值,即通过开关SW0至SW6来输入。
module cnt_incr(
CLK , // clock
INCR , // counter increase value
CNTVAL); // counter value
input CLK;
input [7-1:0] INCR;
output [7-1:0] CNTVAL;
reg [7-1:0] CNTVAL;
always @ (posedge CLK) begin
CNTVAL <= INCR + CNTVAL;
end
endmodule
在顶层文件中将INCR分配到开关上即可。
ROM模块
存储器模块其实只是存些值而已,所以只需要写个输入输出的索引表,然后用case来索引。
module sine_rom(
CLK , // clock
RA , // read address
RD ); // read data
input CLK;
input [6 :0] RA;
output [7 :0] RD;
reg [7 :0] RD;
always @ (posedge CLK)
case(RA)
7 'd 0 :RD = #1 8 'b 00000000; // 0 0x0
7 'd 1 :RD = #1 8 'b 00000110; // 6 0x6
7 'd 2 :RD = #1 8 'b 00001100; // 12 0xC
7 'd 3 :RD = #1 8 'b 00010010; // 18 0x12
7 'd 4 :RD = #1 8 'b 00011000; // 24 0x18
7 'd 5 :RD = #1 8 'b 00011110; // 30 0x1E
...(中间部分省略)
7 'd 127 :RD = #1 8 'b 11111010; // -6 0xFA
default : RD = #1 0;
endcase
endmodule
中间选择的部分比较多,可以使用C或者其他编程方式来编程输出结果。
RD的输出值是sin值表。
顶层设计
将模块和输入输出连接。
输入部分需要输入数据,所以要分配管脚。
RAMOUT和RAOUT需要观察,所以添加了探测节点。但因为本工程里不需要输出到DAC,所以不需要指派管脚。
逻辑分析
计数器的RTL视图
从计数器的RTL视图中可以验证逻辑与我们之前设想的是否相同。
注意这里的加法器输入输出均是7位位宽,所以可能会产生溢出。比如输入SW6=1时。
其实溢出也没关系。当输入的计数值大于64时,将加法器输出的最高位舍去,计数值相当于减去(128-后六位的值)。即原本从小到大加值计数等效为从大到小减值计数,新的计数值=(128-原本的计数值)。在计数值的波形上表现为左右翻折,而由于sin函数是对称的,所以相当于相位偏移半周。不看相位的话,不会对生成的sin函数的波形产生其他影响。在后续的采样分析部分里会举例更清晰地说明。
ROM的RTL视图
注意到RTL视图中在输出添加了D触发器。RTLview仅仅是一种“等效时序”概念上的结构,不是真正的结构。可以在Tech Map View里观察真正使用到的资源,但Tech Map View往往很复杂,不是很清晰,所以一般从RTL视图上理解结构。
Tech Map View 中是真正使用的资源,实际上输出是是不带D触发器的,反而是输入地址上带有D触发器。
同步ROM的时序图:
同步ROM指带有时钟输入的ROM。输入的地址被当前CLK上升沿所存,上升沿过后输出对应地址的数据。时序逻辑上理解的是D触发器是在输出端口,所以RTL视图中输出有D触发器。但实际是锁存地址,在上升沿输出数据,所以实际使用的资源中在地址的输入上是有D触发器的。
数据采集及分析
数据显示设置
编译下载电路,使用SignalTap采集数据。拨动SW6到SW0 开关,观察 SignalTap的信号。
因为地址是无符号数,而ROM里存的sin表是有符号数,所以要在数据采集时分别进行设置。
在数据采集界面,右键RAOUT,在Bus Display Format里选择Unsigned Line Chart,即输出为无符号数曲线。而ROMOUT则选择Signed Line Chart。
加法器溢出分析(即计数器增量大于64时)
计数器增量为1时:
计数器增量为128-1=127时:
可以看到计数的波形是左右翻折,而正弦波的波形为相位偏移半轴。
正弦波频率分析
设输出正弦波频率为 f 1 f_1 f1,电路系统时钟为 f s y s = 50 f_{sys}=50 fsys=50MHz, 计数器步进增量为 CNT。
由上文可以得知:ROM中128个存储空间存储着sin的一个周期128个采样点的值。计数最大值为
2
7
=
128
2^7=128
27=128,遍历一遍会输出
128
C
N
T
\frac{128}{CNT}
CNT128个点,需要
128
C
N
T
\frac{128}{CNT}
CNT128个时钟周期,生成信号的一个周期对应
128
C
N
T
\frac{128}{CNT}
CNT128个时钟信号周期,所以生成的信号频率就是clk时钟频率的
128
C
N
T
\frac{128}{CNT}
CNT128分之一。即:
f
1
=
f
s
y
s
×
C
N
T
128
=
390625
×
C
N
T
(
H
z
)
f_1=f_{sys}\times\frac{CNT}{128}=390625\times CNT(Hz)
f1=fsys×128CNT=390625×CNT(Hz)
所以我们可以获得的最低频率的正弦波频率为
f
m
i
n
=
390.625
f_{min}=390.625
fmin=390.625KHz。
优化
如图,把计数器的计数值和输入的计数增量信号都改为9比特, 计数值的高7位连接ROM的地址线,低2位悬空,这样可以获得精确程度更高的计时器增量。
比如当计数增量值为1的时候:
可以看到周期更长了。因为原本的一次地址变化现在需要四个时钟周期,所以现在的周期为原本的四倍。
分析方式与第一个相同,设输出正弦波频率为 f 1 f_1 f1,电路系统时钟为 f s y s = 50 f_{sys}=50 fsys=50MHz, 计数器步进增量为 CNT。
ROM中128个存储空间存储着sin的一个周期128个采样点的值。计数最大值为
2
9
=
512
2^9=512
29=512,遍历一遍会输出
512
C
N
T
\frac{512}{CNT}
CNT512个点,需要
512
C
N
T
\frac{512}{CNT}
CNT512个时钟周期,生成信号的一个周期对应
512
C
N
T
\frac{512}{CNT}
CNT512个时钟信号周期,所以生成的信号频率就是clk时钟频率的
512
C
N
T
\frac{512}{CNT}
CNT512分之一。即:
f
1
=
f
s
y
s
×
C
N
T
512
=
97.65625
×
C
N
T
(
H
z
)
f_1=f_{sys}\times\frac{CNT}{512}=97.65625\times CNT(Hz)
f1=fsys×512CNT=97.65625×CNT(Hz)
所以我们可以获得的最低频率的正弦波频率为
f
m
i
n
=
97.65625
f_{min}=97.65625
fmin=97.65625KHz。
其实这里计算的实际是经过DAC和低通滤波之后生成的模拟信号正弦波的周期。这样计算数字频率并不严谨。但最后是为了生成模拟信号,所以在这里这样计算。数字频率的计算方法一般在数字信号处理课程的第一章都会有讲解。