FPGA初级课程第十讲 任意分频器
本帖最后由 lcytms 于 2016-11-9 21:00 编辑FPGA初级课程
第十讲 任意分频器
Hi,大家好!我是至芯科技的李老师。
今天讲课的题目是:任意分频器。
本节课我先简要地介绍一下任意分频器的物理原理,然后实际演示一下任意分频器驱动逻辑电路的建模与仿真,并通过仿真查看效果。
在第九讲 分频器中大家学习了运用计数器实现分频器设计。
我们来回顾一下。
打开第九讲的工程文件。
第九讲先后介绍了两种分频器设计。
第一种是偶数次分频,占空比为50%。
第二种是通用分频,占空比可调。分频次数不局限于偶数次。
貌似第二种分频可以实现任意次分频,但是它有一个局限性,就是奇数次分频时,不能实现50%占空比。
而很多情况下,需要不仅能做到奇数次分频,而且要求为50%占空比,这更接近于晶振的方波信号。
当然了,可以通过锁相环将系统时钟信号先进行二倍频,再做偶数次分频。
我们这里介绍的是不使用锁相环,还是使用计数器的方式,来实现这种奇数次分频,这里我们称之为任意分频器。
我们打开至芯科技编写的《27.炼狱传奇-任意分频之战.pdf》文档。
分频在fpga的设计中一直都担任着很重要的角色,而说到分频,我相信很多人都已经想到了利用计算器来计算达到想要的时钟频率,但问题是仅仅利用计数器来分频,只可以实现偶数分频,而如果我需要三分频,五分频,七分频等等奇数类分频,那究竟怎么办呢?
在这里,让我介绍一个可以实现任意整数分频的方法,这个办法也是同样利用了计数器来计算,当是跟偶数分频不一样的地方是任意整数分频利用了两个计数器来实现。
下面我们来看看三分频实现的时序图:
三分频设计中,由out_clk_1和out_clk_2相或得到最终输出。
out_clk_1可以理解成HW=1、LW=2的通用分频输出。
out_clk_2可以理解成反时钟条件下out_clk_1的输出。
既然原理已经明白,编写代码如下。
先打开第九讲中编写的通用分频模块div_freq.v。
复习div_freq.v代码部分。
module div_freq (clk, rst_n, clk_out);
input clk, rst_n;
output reg clk_out;
parameter HW = 50,
LW = 50; // HW + LW = 100 times
reg state;
localparam s0 = 1'b0,
s1 = 1'b1;
reg cnt;
always @ (posedge clk or negedge rst_n)
begin
if (!rst_n)
begin
cnt <= 0;
clk_out <= 1;
state <= s0;
end
else
begin
case (state)
s0 : begin // HW part
if (cnt < HW - 1)
begin
cnt <= cnt + 26'b1;
clk_out <= 1;
state <= s0;
end
else
begin
cnt <= 0;
clk_out <= 1;
state <= s1;
end
end
s1 : begin // LW part
if (cnt < LW - 1)
begin
cnt <= cnt + 26'b1;
clk_out <= 0;
state <= s1;
end
else
begin
cnt <= 0;
clk_out <= 0;
state <= s0;
end
end
default : state <= s0;
endcase
end
end
endmodule
本帖最后由 lcytms 于 2016-11-9 20:03 编辑
新建任意分频模块divider.v
将任意分频模块divider.v设置为顶层模块。
module divider (clk, rst_n, clk_out);
input clk, rst_n;
output clk_out;
parameter WIDTH = 3; // WIDTH = 3
wire out_clk_1, out_clk_2;
div_freq #(.HW(WIDTH>>1), .LW((WIDTH+1)>>1))
d1 (.clk(clk), .rst_n(rst_n), .clk_out(out_clk_1));
div_freq #(.HW(WIDTH>>1), .LW((WIDTH+1)>>1))
d2 (.clk(~clk), .rst_n(rst_n), .clk_out(out_clk_2));
assign clk_out = (WIDTH & 1'b1) ? (out_clk_1 || out_clk_2) : out_clk_1;
endmodule
本帖最后由 lcytms 于 2016-11-9 20:05 编辑
新建Testbench。编写divider_tb.v模块代码。
`timescale 1ns/1ps
module divider_tb;
reg clk, rst_n;
wire clk_out;
divider #(.WIDTH(5)) dut (.clk(clk), .rst_n(rst_n), .clk_out(clk_out));
initial
begin
clk = 1;
rst_n = 0;
#200.1
rst_n = 1;
#2000 $stop;
end
always #10 clk = ~clk;
endmodule
本帖最后由 lcytms 于 2016-11-9 21:19 编辑
设置好仿真。
查看仿真波形。
WIDTH=5,此时分频次数为奇数次,仿真波形与设计要求相符。
通过修改参数WIDTH可以实现分频次数的调整。
本帖最后由 lcytms 于 2016-11-9 21:19 编辑
修改WIDTH=6,此时分频次数为偶数次。
查看仿真波形,与设计要求相符。
页:
[1]
2