lcytms 发表于 2016-11-9 19:04:51

FPGA初级课程第九讲 分频器

本帖最后由 lcytms 于 2016-11-9 21:21 编辑

FPGA初级课程
第九讲 分频器

Hi,大家好!我是至芯科技的李老师。
今天讲课的题目是:分频器。
本节课我先简要地介绍一下分频器的物理原理,然后实际演示一下分频器驱动逻辑电路的建模与仿真,并通过仿真查看效果。


lcytms 发表于 2016-11-9 19:11:03

分频器这个名词或许大家都很熟悉了,运用计数器我们就能轻松地实现分频器设计。

我们打开《23至芯科技奋斗的小孩之altera 系列 第二十三篇 分频器.pdf》文件。


对于每一个的小实验,我们都可以把它看作是一个小项目,逐步的去分析,设计,调试,最后完成功能。
下面我们就开始我们的“小项目”。
项目名称:分频器
具体要求:将本地晶振分频成一定的频率。
架构图如下:

lcytms 发表于 2016-11-9 19:12:10

系统设计:
1. 工程的名称:div_freq。


我们首先来写一个计数器,实现10分频,将至芯科技ZX_1开发板上的50MHz系统时钟变成5MHz时钟输出。

很简单,我就让每隔5个时钟取反一次就行了。这种分频实现起来非常简单,它的特点是占空比为50%,而且是偶数次分频。

lcytms 发表于 2016-11-9 19:13:02

本帖最后由 lcytms 于 2016-11-9 19:15 编辑

新建工程文件夹div_freq。
新建分频模块div_freq2n.v,后面加上2n表示偶数次分频,以区别于我们后面要实现的通用分频模块div_freq.v。通用分频模块div_freq.v不局限于偶数次分频,而且占空比可调。
将分频模块div_freq2n.v设置为顶层模块。
module div_freq2n (clk, rst_n, clk_out);

        input clk, rst_n;
       
        output reg clk_out;
       
        parameter CNT_NUM = 5;// half of 10
       
        reg cnt;

        always @ (posedge clk or negedge rst_n)
                begin
                        if (!rst_n)
                                begin
                                        cnt <= 0;
                                        clk_out <= 1;
                                end
                        else
                                begin
                                        if (cnt < CNT_NUM - 1)
                                                begin
                                                        cnt <= cnt + 26'b1;
                                                end
                                        else
                                                begin
                                                        cnt <= 0;
                                                        clk_out <= ~clk_out;
                                                end
                                end
                end

endmodule

lcytms 发表于 2016-11-9 19:15:49

本帖最后由 lcytms 于 2016-11-9 19:17 编辑

新建Testbench。编写div_freq2n_tb.v模块代码。
`timescale 1ns/1ps

module div_freq2n_tb;

        reg clk, rst_n;
       
        wire clk_out;

        div_freq2n #(.CNT_NUM(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 19:19:26

设置好仿真。
查看仿真波形。与设计要求相符。
通过修改参数CNT_NUM可以实现分频次数的调整。

lcytms 发表于 2016-11-9 19:21:36

本帖最后由 lcytms 于 2016-11-9 19:22 编辑

下面我们要实现的通用分频模块div_freq.v不局限于偶数次分频,而且占空比可调。

我们回到《23至芯科技奋斗的小孩之altera 系列 第二十三篇 分频器.pdf》文件。


2. 状态转移图如下图所示。
HW:高电平所占的周期数
LW:低电平所占的周期数

lcytms 发表于 2016-11-9 19:23:28

本帖最后由 lcytms 于 2016-11-9 19:29 编辑

新建通用分频模块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 19:30:41

本帖最后由 lcytms 于 2016-11-9 19:32 编辑

新建Testbench。编写div_freq_tb.v模块代码。
`timescale 1ns/1ps

module div_freq_tb;

        reg clk, rst_n;
       
        wire clk_out;

        div_freq #(.HW(3), .LW(2)) 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 19:34:27

设置好仿真。
查看仿真波形。与设计要求相符。
通过修改参数HW、LW可以实现分频次数的调整。
高电平为3个周期,低电平为2个周期。本地晶振是50MHz,我们分频出来的时钟为10MHz,并且占空比为60%。

如果本地晶振或者输出的时钟和笔者的设计不同,请自行更改设计,以保证设计的正确性。
页: [1] 2
查看完整版本: FPGA初级课程第九讲 分频器