teleagle 发表于 2018-10-8 22:09

基于actel fpga的周期反馈式纯数字锁相环

<div class='showpostmsg'> 本帖最后由 teleagle 于 2018-10-8 22:19 编辑


基于actel fpga的周期反馈式纯数字锁相环:
    简单的说就是建立一个状态机,对输入周期参数在产生时钟的每个周期的第一时间更新值,然后进入下一个状态计数,计数到和输入周期一致的时候又回到初始状态。代码综合仿真正确, 过程比较简单, 就不班门弄斧了. 不妥之处, 共同学习交流 ,一起改进,代码如下:

//顶层模块:
module TE_DPLL_B(
      sys_clk,
      sys_rst,
      clk_in,
      clk_out
);


      //---全局参数---
      parameter DATA_W = 16;                        // 周期计数器及数据位宽,根据系统时钟与输入时钟的差值调整
      parameter PN_EDGE = 2'b01;                // 沿检测参数(01=上升沿,10=下降沿)
      parameter DPLL_M = 2;                        // M 参数
      parameter DPLL_N = 10;                        // N 参数


      //---输入输出接口---
      input sys_clk;                        // 系统时钟
      input sys_rst;                        // 系统重置
      input clk_in;                        // 输入时钟
      output clk_out;                        // 输出时钟


      //---内部信号---
      wire n_ti;      // 输入时钟周期值


      //---------------------------------------------------------
      // 输入时钟周期测量模块,对输入时钟采样,测量输出时钟周期Ti
      //---------------------------------------------------------
      TE_DPLL_Figure TE_DPLL_Figure_0(
                .sys_clk(sys_clk),      // 系统时钟
                .sys_rst(sys_rst),      // 系统重置
                .clk_i(clk_in),                // 输入时钟
                .t_o(n_ti)                // 输入时钟周期值
      );
      defparam TE_DPLL_Figure_0.CNT_W = DATA_W;      // 周期计数器位宽
      defparam TE_DPLL_Figure_0.PN_EDGE = PN_EDGE;      // 沿检测参数(01=上升沿,10=下降沿)


      //---------------------------------------------------------
      // 例化反馈模块
      //---------------------------------------------------------
      TE_DPLL_Feed TE_DPLL_Feed_0(
                .sys_clk(sys_clk),      // 系统时钟
                .sys_rst(sys_rst),      // 系统重置
                .ti_i(n_ti),                // 输入时期周期值
                .clk_o(clk_out)                // 输出时钟
      );
      defparam TE_DPLL_Feed_0.DATA_W = DATA_W;      // 数据位宽
      defparam TE_DPLL_Feed_0.PN_EDGE = PN_EDGE;      // 沿检测参数(01=上升沿,10=下降沿)
      defparam TE_DPLL_Feed_0.DPLL_M = DPLL_M;      // M 参数
      defparam TE_DPLL_Feed_0.DPLL_N = DPLL_N;      // N 参数




endmodule
</div><script>                                        var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                                       
                                        if(parseInt(discuz_uid)==0){
                                                                                                (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                        }                </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>

teleagle 发表于 2018-10-8 22:12

//周期采样模块
module TE_DPLL_Figure(
        sys_clk,
        sys_rst,
        clk_i,
        t_o
);

        //---全局参数---
        parameter CNT_W = 16;                                // 周期计数器位宽
        parameter PN_EDGE = 2'b01;        // 沿检测参数(01=上升沿,10=下降沿)

        //---输入输出接口---
        input sys_clk;                // 系统时钟
        input sys_rst;                // 系统重置
        input clk_i;                        // 输入待测时钟
        output t_o;                        // 输出时钟周期

        reg t_o;

        //---内部寄存器---
        reg n_edge;                                // 待测时钟缓冲,用于检测时钟沿
        reg n_cnt;        // 周期计数器
        reg n_state;                                                // 状态

        //---------------------------------------------------------
        // 2D 左移位寄存器,用于检测上升沿或下降沿
        //---------------------------------------------------------
        always @(posedge sys_clk)
        begin
                if(sys_rst)
                        n_edge <= 0;
                else
                n_edge <= {n_edge,clk_i};
        end
        //---------------------------------------------------------
        // 一段状态机
        //---------------------------------------------------------
        always @(posedge sys_clk)
        begin
                if(sys_rst)
                        begin
                                n_state <= 0;
                                n_cnt <= 0;
                                t_o <= 0;
                        end
                else
                        case(n_state)
                                0 : begin
                                                n_state <= (n_edge == PN_EDGE) ? 1 : 0;                // 检测正向沿(由PN_EDGE决定)
                                                n_cnt <= (n_edge == PN_EDGE) ? 1 : 0;
                                        end
                                1 : begin
                                                n_state <= (n_edge == PN_EDGE) ? 0 : 1;                // 非正向沿时(由PN_EDGE决定),跳回状态0
                                                n_cnt <= n_cnt + 1;
                                                t_o <= (n_edge == PN_EDGE) ? n_cnt : t_o;
                                        end
                                default : n_state <= 0;
                        endcase
        end

endmodule

teleagle 发表于 2018-10-8 22:14

// 反馈模块

module TE_DPLL_Feed(
        sys_clk,
        sys_rst,
        ti_i,
        clk_o
);

        //---全局参数---
        parameter DATA_W = 16;                        // 数据位宽
        parameter PN_EDGE = 2'b01;        // 沿检测参数(01=上升沿,10=下降沿)
        parameter DPLL_M = 10;                                                // M 参数
        parameter DPLL_N = 10;                                                // N 参数

        //---输入输出接口---
        input sys_clk;                                                // 系统时钟
        input sys_rst;                                                // 系统重置
        input ti_i;        // 输入时钟周期值
        output clk_o;                                                        // 输出时钟

        //---内部信号---
        wire n_to;                // 输出时钟周期值

        //---内部寄存器---
        reg n_terr;        // 开环误差,除 M 后的误差值
        reg n_err;                // 反馈误差,输入输出时钟周期误差

        //---------------------------------------------------------
        // 反馈误差(To/N)
        // 反馈的时钟周期乘以反馈增益1/N
        //---------------------------------------------------------
        always @(posedge sys_clk)
        begin
                if(sys_rst)
                        n_err <= 0;
                else
            n_err <= ti_i - (n_to / DPLL_N);                // 输入时钟周期 - (输出时钟周期 / N)
        end

        //---------------------------------------------------------
        // 开环误差 (n_err/M)
        // 反馈误差乘以开环增益1/M
        //---------------------------------------------------------
        always @(posedge sys_clk)
        begin
                if(sys_rst)
                        n_terr <= 0;
                else
            n_terr <= n_err / DPLL_M;
        end

        //---------------------------------------------------------
        // 将 n_err/M 值反馈给控制对象
        //---------------------------------------------------------
        TE_DPLL_Gen TE_DPLL_Gen_0(
                .sys_clk(sys_clk),        // 系统时钟
                .sys_rst(sys_rst),        // 系统重置
                .terr_i(n_terr),                // 误差 n_err 除 M 后的值
                .clk_o(clk_o)                                // 输出时钟
        );
        defparam TE_DPLL_Gen_0.DATA_W = DATA_W;                // 数据位宽
        //---------------------------------------------------------
        // 输出时钟周期测量模块,对输出时钟采样,测量输出时钟周期 To
        //---------------------------------------------------------
        TE_DPLL_Figure TE_DPLL_Figure_1(
                .sys_clk(sys_clk),        // 系统时钟
                .sys_rst(sys_rst),        // 系统重置
                .clk_i(clk_o),                        // 输出时钟反馈回周期测量模块
                .t_o(n_to)                                        // 输出时钟周期
        );
        defparam TE_DPLL_Figure_1.CNT_W = DATA_W;                        // 周期计数器位宽
        defparam TE_DPLL_Figure_1.PN_EDGE = PN_EDGE;        // 沿检测参数(01=上升沿,10=下降沿)

endmodule

teleagle 发表于 2018-10-8 22:38

上述代码参数时的时序仿真:

fsyicheng 发表于 2018-10-12 22:12

这个品牌用的人不多。{:1_103:}

teleagle 发表于 2024-3-8 09:41

fsyicheng 发表于 2018-10-12 22:12
这个品牌用的人不多。

<p>纯代码,与用什么器件无关.</p>
页: [1]
查看完整版本: 基于actel fpga的周期反馈式纯数字锁相环