uisrc 发表于 2023-12-29 11:11:12

2-3-08 FPGA多路分频器实验

软件版本:VIVADO2021.1操作系统:WIN10 64bit硬件平台:适用XILINX A7/K7/Z7/ZU/KU系列FPGA登录米联客(MILIANKE)FPGA社区-www.uisrc.com观看免费视频课程、在线答疑解惑!1 概述在FPGA中,时钟分频是经常用到的。本节课讲解2分频、3分频、4分频和8分频的Verilog实现并且学习generate语法功能的应用,本文的重点是培养读者对于verilog基础编程的基本功掌握。2 硬件电路分析硬件接口和子卡模块请阅读"附录 1"配套工程的 FPGA PIN 脚定义路径为 fpga_prj/uisrc/04_pin/ fpga_pin.xdc。3 程序设计思路1、整数倍分频,为 2、4、8,这种2^n次方倍数关系的分频最容易实现,所以我们可以把这3种分频方式归为一类。2、3分频是奇数倍分频,这种分频比较麻烦,对于初学者肯定得思考一番。3、2HZ和前文中流水灯的延迟控制方法一样,只要实现每过500ms对寄存器取反操作对于这类基础简单的方案,笔者认为,大家学习主要缺少的是思路,所以我们直接拿程序来分析。Clk_Divider.v文件
`timescale 1ns / 1psmodule Clk_Divider#(parameter DEBUG_ENABLE = 1'b1,parameter REF_CLK      = 32'd50_000_000)(input I_clk,inputI_rst_n,output O_div2,output O_div3,output O_div4,output O_div8,output O_div2hz    );
//2分频代码:只要基于源时钟每个时钟的上升沿对O_div2_r寄存器取反    reg O_div2_r;always@(posedge I_clk)begin    if(!I_rst_n)      O_div2_r <= 1'b0;    else      O_div2_r <= ~O_div2_r;end
//4分频和8分频代码:共同使用了div_cnt1计数器//4分频就是对计数器在div_cnt1==2'b00或者div_cnt1==2'b10的时候对O_div4_r寄存器取反;//而8分频是对div_cnt1==2'b00的时候对O_div8_r取反reg div_cnt1;always@(posedge I_clk)begin    if(!I_rst_n)      div_cnt1 <= 2'b00;    else      div_cnt1 <= div_cnt1+1'b1;end
reg O_div4_r;reg O_div8_r;always@(posedge I_clk)begin    if(!I_rst_n)      O_div4_r <= 1'b0;    else if(div_cnt1==2'b00 || div_cnt1==2'b10)      O_div4_r <= ~O_div4_r;    else      O_div4_r <= O_div4_r;end
always@(posedge I_clk)begin    if(!I_rst_n)      O_div8_r <= 1'b0;    else if(div_cnt1==2'b00)      O_div8_r <= ~O_div8_r;    else      O_div8_r <= O_div8_r;end/*3分频的本质是我们需要在每次1.5倍的时钟周期的时候实现3分频寄存器的翻转,但是我们无法直接实现1.5倍的分频。因此采取分别采取2个计数器pos_cnt和neg_cnt,分别对上升沿和下降沿计数。计数周期是0-1-2,共计3个时钟周期。我们取pos_cnt == 2'd1的时候O_div3_r0输出高电平,neg_cnt == 2'd1的时候O_div3_r1输出高电平。由于O_div3_r0和O_div3_r1输出1个时钟的高电平,但是相位相差180°,因此只要执行O_div3 = O_div3_r0 | O_div3_r1运算,就能实现1.5倍周期的输出高电平,那么剩余的1.5倍源时钟周期就是输出低电平了。*/reg pos_cnt;reg neg_cnt;always@(posedge I_clk)begin    if(!I_rst_n)      pos_cnt <= 2'b00;    else if(pos_cnt == 2'd2)      pos_cnt <= 2'b00;    else      pos_cnt <= pos_cnt + 1'b1;end
always@(negedge I_clk)begin    if(!I_rst_n)          neg_cnt <= 2'b00;    else if(neg_cnt == 2'd2)      neg_cnt <= 2'b00;    else      neg_cnt <= neg_cnt + 1'b1;end
reg O_div3_r0;reg O_div3_r1;always@(posedge I_clk)begin    if(!I_rst_n)      O_div3_r0 <= 1'b0;    else if(pos_cnt < 2'd1)      O_div3_r0 <= 1'b1;    else      O_div3_r0 <= 1'b0;end
always@(negedge I_clk)begin    if(!I_rst_n)      O_div3_r1 <= 1'b0;    else if(neg_cnt < 2'd1)      O_div3_r1 <= 1'b1;    else      O_div3_r1 <= 1'b0;end
reg O_div2hz_r;reg div2hz_cnt;
wire ms250_en = (div2hz_cnt == REF_CLK/4 - 1'b1);always@(posedge I_clk)begin    if(!I_rst_n)      div2hz_cnt <= 0;    else if(div2hz_cnt < REF_CLK/4 - 1'b1)      div2hz_cnt <= div2hz_cnt + 1'b1;    else      div2hz_cnt <= 0;end
always@(posedge I_clk)begin    if(!I_rst_n)      O_div2hz_r <= 0;    else if(ms250_en)      O_div2hz_r <= ~O_div2hz_r;    else      O_div2hz_r <= O_div2hz_r;end
assign O_div2 = O_div2_r;assign O_div3 = O_div3_r0 | O_div3_r1;assign O_div4 = O_div4_r;assign O_div8 = O_div8_r;assign O_div2hz = O_div2hz_r;
generateif(DEBUG_ENABLE == 1'b1) begin : debugcore//添加ila IP ,Chipscope观察信号ila_0 ila_0 (    .clk(I_clk), // input wire clk    .probe0(O_div2hz), // input wire probe0    .probe1({O_div2,O_div3,O_div4,O_div8}) // input wire probe1);endEndgenerate
endmodule



代码解释:2分频代码:只要基于源时钟每个时钟的上升沿对o_div2_r寄存器取反4分频和8分频代码:共同使用了div_cnt1计数器,4分频就是对计数器在div_cnt1==2'b00或者div_cnt1==2'b10的时候对div4_o_r寄存器取反;而8分频是对div_cnt1==2'b00的时候对o_div8_r取反3分频代码:3分频的本质是我们需要在每次1.5倍的时钟周期的时候实现3分频寄存器的翻转,但是我们无法直接实现1.5倍的分频。因此分别采取2个计数器pos_cnt和neg_cnt,分别对上升沿和下降沿计数。计数周期是0-1-2,共计3个时钟周期。我们取pos_cnt == 2'd1的时候div3_o_r0输出高电平,neg_cnt == 2'd1的时候o_div3_r1输出高电平。由于o_div3_r0和o_div3_r1输出1个时钟的高电平,但是相位相差180°,因此只要执行o_div3 =o_ div3_r0 | o_div3_r1运算,就能实现1.5倍周期的输出高电平,那么剩余的1.5倍源时钟周期就是输出低电平了。2HZ分频代码:和前面文章中的流水灯延迟控制的分频方法一样。4 RTL仿真4.1 添加仿真测试源码仿真测试文件存放在工程目录uisrc\02_sim中,源码如下:
`timescale 1ns / 1ps
module Clk_Divider_Tb();// Inputsreg I_clk;reg I_rst_n;// Outputswire O_div2;//wire div3_o;wire O_div4;wire O_div8;wire O_div2hz;
// Instantiate the Unit Under Test (UUT)Clk_Divider#(.DEBUG_ENABLE(1'b0),.REF_CLK(50000000))Clk_Divider_inst(.I_clk(I_clk),.I_rst_n(I_rst_n),.O_div2(O_div2),.O_div4(O_div4),.O_div8(O_div8),.O_div2hz(O_div2hz));

initial begin// Initialize Inputs4    I_clk= 0;    I_rst_n = 0;// Wait 100 ns for global reset to finish    #100;    I_rst_n=1;endalways #10 I_clk =~I_clk;
endmodule


4.2 仿真结果2分频、3分频、4分频、8分频2HZ分频5测试结果5.1 在线逻辑分析仪通过ila在线逻辑分析仪我们也能看出我们的2分频、4分频、8分频信号都分频成功5.2 开发板现象(该教程为通用型教程,教程中仅展示一款示例开发板的连接方式,具体连接方式以所购买的开发板型号以及结合配套代码管脚约束为准。)请确保下载器和开发板已经正确连接,并且开发板已经上电。(注意JTAG端子不支持热插拔,而USB接口支持,所以在不通电的情况下接通好JTAG后,再插入USB到电脑,之后再上电,以免造成JTAG IO损坏)
如下图所示LED闪烁,闪烁频率2Hz
页: [1]
查看完整版本: 2-3-08 FPGA多路分频器实验