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

teleagle   2018-10-8 22:09 楼主
基于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 [DATA_W-1:0] 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 本帖最后由 teleagle 于 2018-10-8 22:19 编辑

回复评论 (5)

//周期采样模块
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 [CNT_W-1:0] t_o;

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

        //---------------------------------------------------------
        // 2D 左移位寄存器,用于检测上升沿或下降沿
        //---------------------------------------------------------
        always @(posedge sys_clk)
        begin
                if(sys_rst)
                        n_edge <= 0;
                else
                  n_edge <= {n_edge[0],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
点赞  2018-10-8 22:12
// 反馈模块

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 [DATA_W-1:0] ti_i;        // 输入时钟周期值
        output clk_o;                                                        // 输出时钟

        //---内部信号---
        wire [DATA_W-1:0] n_to;                // 输出时钟周期值

        //---内部寄存器---
        reg [DATA_W-1:0] n_terr;        // 开环误差,除 M 后的误差值
        reg [DATA_W-1:0] 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
点赞  2018-10-8 22:14
上述代码参数时的时序仿真:

  • 时序仿真.JPG
点赞  2018-10-8 22:38
这个品牌用的人不多。
点赞  2018-10-12 22:12
引用: fsyicheng 发表于 2018-10-12 22:12 这个品牌用的人不多。

纯代码,与用什么器件无关.

点赞  2024-3-8 09:41
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复