FPGA中的分频器

1.理论部分

板载晶振提供的频率是固定的,为了满足工程需求,需要对时钟分频或者倍频,这里学习基础的分频方法。毫无疑问,分频是通过计数器来实现的。分频器分为偶分频和奇分频,分频的方法这里介绍普通分频降分频。这里需要注意一下两者分频方法的区别:在FPGA中,凡是时钟信号都会连接带全局时钟网络上【又称为全局时钟树】,着使得时钟信号到达每个寄存器的时间都尽可能相同,保持更低的偏斜【skew】和抖动【jitter】,但是普通分频得到的时钟并没有连接到全局时钟网络上,但 系统时钟是由外部晶振直接通过管脚连接到了FPGA的专用时钟管脚上,自然就会连接到全局时钟网络上,所以在高速系统中,系统时钟工作下的信号相对于普通分频得到的时钟下的工作信号要更加稳定。

2.降分频

降分频的方式下可以不用区分奇数和偶数,通过拉高一个标志位来完成对系统时钟的分频,下面以6分频为例:

2.1        当计数器计数到6-1的时候拉高一个标志位clk_flag,那么两个标志位之间则刚好对系统时钟clk完成6分频,画出波形如下:

2.2        代码部分也比较简单

module divider(

input 		wire 		clk,
input 		wire 		rst_n,
output 		reg  		cnt_flag
	);

//6分频,根据分频数对DIVIDER更改参数即可
parameter 				DIVEDER = 'd6;

//根据分频的要求更改位宽以满足计数
reg 		[4:0] 		cnt;

always @(posedge clk or negedge rst_n) begin
	if (rst_n == 1'b0) begin
		cnt <= 'd0;
	end
	else if (cnt == DIVEDER - 1'b1) begin
		cnt <= 'd0;
	end
	else begin
		cnt <= cnt + 1'b1;
	end
end

always @(posedge clk or negedge rst_n) begin
	if (rst_n == 1'b0) begin
		cnt_flag <= 1'b0;
	end
	else if (cnt == DIVEDER - 'd2) begin
		cnt_flag <= 1'b1;
	end
	else begin
		cnt_flag <= 1'b0;
	end
end

endmodule

2.3        建立tb文件

`timescale 1ns/1ns
module tb_divider();

reg 		clk;
reg 		rst_n;
wire 		cnt_flag;

initial begin
	clk = 1;
	rst_n = 0;
	#30
	rst_n = 1;
end

always #10 clk = ~clk;

divider inst_divider (
	.clk(clk), 
	.rst_n(rst_n), 
	.cnt_flag(cnt_flag));


endmodule

2.4        仿真结果如下:

3.普通分频

普通分频中的偶分频比较简单,以6分频为例,当计数器计数到一半时,输出的信号取反一次即可。这里主要了解一下奇数分频的技巧,以5分频为例:

3.1        5分频中,需要根据系统时钟上升沿和下降沿分别变化,才能得到分频的时钟,波形图如下:clk1在系统时钟的上升沿发生翻转,clk2在系统时钟的下降沿发生翻转,翻转是时刻分别在(5-1)/2和5-1,clk1和clk2的相与得到5分频的时钟clk_out。

 3.2        代码如下;

`timescale 1ns / 1ns

module divider(
input		wire 		clk,
input 		wire 		rst_n,
output 		wire  		clk_out
    );

//参数化,设置为5分频
parameter 				DIVIDER = 	'd5;
//5分频读的话计数到2翻转一次
parameter 				HALF 	= 	(DIVIDER-1)>>1;

reg 		[4:0]			cnt;
reg 						clk1;
reg 						clk2;

always @(posedge clk or negedge rst_n) begin
	if (rst_n == 1'b0) begin
		cnt <= 5'b0;
	end
	else if (cnt == DIVIDER-1) begin
		cnt <= 5'b0;
	end
	else begin
		cnt <= cnt + 1'b1;
	end
end


//clk1在clk的上升沿发生翻转
always @(posedge clk or negedge rst_n) begin
	if (rst_n == 1'b0) begin
		clk1 <= 1'b1;
	end
	else if (cnt == HALF) begin
		clk1 <= 1'b0;
	end
	else if (cnt == DIVIDER - 1'b1) begin
		clk1 <= 1'b1;
	end
end

//clk2在clk的下降沿发生翻转
always @(negedge clk or negedge rst_n) begin
	if (rst_n == 1'b0) begin
		clk2 <= 1'b1;
	end
	else if (cnt == HALF) begin
		clk2 <= 1'b0;
	end
	else if (cnt == DIVIDER - 1'b1) begin
		clk2 <= 1'b1;
	end
end

assign clk_out = clk1 & clk2;

endmodule

3.3        建立tb文件

`timescale 1ns/1ns
module tb_divider();

reg 		clk;
reg 		rst_n;
wire 		clk_out;

initial begin
	clk = 1;
	rst_n = 0;
	#30
	rst_n = 1;
end

always #10 clk = ~clk;

	divider inst_divider (
		.clk(clk), 
		.rst_n(rst_n),
		.clk_out(clk_out));



endmodule

3.4        仿真结果如下:

文章内容参考野火FPGA

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小勇study

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值