• Verilog-数字时钟无毛刺切换



    参考博客:https://blog.csdn.net/u014070258/article/details/90052426

    原题(卓胜微电子2020)

    时钟输入clk, sel为时钟控制信号,sel=0输出clk, sel = 1 输出clk的四分频,要求异步复位,保持时钟信号的完整性。

    实现思路

    • 毛刺产生的根本原因:是切换控制信号sel相对于时钟信号可以在任何时间里发生改变,本质是切换信号为异步信号。

    • 解决办法:任何时钟的高电平状态下的切换都需要避免。当两个输入时钟之间是倍数关系时,插入下降沿触发触发器确保切换只发生在本时钟为低电平时候,引入输出反馈确保另外一路的时钟为低电平时候发生切换。

    Verilog代码

    `timescale 1ns / 1ps
    
    module clk_switch(
    	input clk,
    	input rstn,
    	
    	input sel,
    	output clk_o
        );
    
    // 产生4分频时钟
    reg [1:0] cnt;
    wire clk_div4;
    
    always @(posedge clk or negedge rstn) begin
    	if(!rstn) cnt <= 2'd0;
    	else cnt <= cnt + 1'b1;
    end
    
    assign clk_div4 = cnt[1];
    
    // 时钟切换电路: sel=0输出clk, sel=1输出clk_div4
    reg clk_en;
    reg clk_div4_en;
    
    always @(negedge clk or negedge rstn) begin
    	if(!rstn) clk_en <= 1'b0;
    	else clk_en <= ~sel & ~clk_div4_en;
    end
    
    always @(negedge clk_div4 or negedge rstn) begin
    	if(!rstn) clk_div4_en <= 1'b0;
    	else clk_div4_en <= sel & ~clk_en;
    end
    
    // 时钟输出电路
    assign clk_o = (clk_en & clk) | (clk_div4_en & clk_div4);
    
    
    endmodule
    
    

    测试激励

    `timescale 1ns / 1ps
    
    module clk_switch_tb;
    
    	// Inputs
    	reg clk;
    	reg rstn;
    	reg sel;
    
    	// Outputs
    	wire clk_o;
    
    	// Instantiate the Unit Under Test (UUT)
    	clk_switch uut (
    		.clk(clk), 
    		.rstn(rstn), 
    		.sel(sel), 
    		.clk_o(clk_o)
    	);
    
    	initial begin
    		// Initialize Inputs
    		clk = 0;
    		rstn = 0;
    		sel = 0;
    
    		// Wait 100 ns for global reset to finish
    		#500;
    		rstn = 1;
    		
    		#400;
    		sel = 1;
    		
    		#210;
    		sel = 0;
    		
    		#315;
    		sel = 1;
    		
    		#205;
    		sel = 0;
    		
            
    		// Add stimulus here
    
    	end
    	
    	always #20 clk=~clk;
          
    endmodule
    
    
    

    仿真波形

    亚稳态问题

    因为sel为异步信号,为了降低亚稳态,可以再加一级寄存器来帮助稳定数据,然后将数据传递到下一级。首级寄存器正沿触发,次级寄存器负沿触发。

    考虑亚稳态的代码

    reg clk_reg1,clk_en;
    reg clk_div4_reg1,clk_div4_en;
    
    
    // 消亚稳态
    always @(posedge clk or negedge rstn) begin
    	if(!rstn) clk_reg1 <= 1'b0;
    	else clk_reg1 <= ~sel & ~clk_div4_en;
    end
    
    always @(posedge clk_div4 or negedge rstn) begin
    	if(!rstn) clk_div4_reg1 <= 1'b0;
    	else clk_div4_reg1 <= sel & ~clk_en;
    end
    
    // 本时钟低电平切换
    always @(negedge clk or negedge rstn) begin
    	if(!rstn) clk_en <= 1'b0;
    	else clk_en <= clk_reg1;
    end
    
    always @(negedge clk_div4 or negedge rstn) begin
    	if(!rstn) clk_div4_en <=1'b0;
    	else clk_div4_en <= clk_div4_reg1;
    end
    
    assign clk_o = (clk_en & clk) | (clk_div4_en & clk_div4);
    

    仿真波形

  • 相关阅读:
    mongodb的sql日志
    mysql – 在WHERE子句中使用substr的SELECT语句
    MySQL视图
    Linux简单查找log
    转 信号量与PV操作
    二进制小数及 IEEE 浮点表示
    转 :原码,反码,补码
    转:C# Delegate委托 1
    C#中Invoke的用法2
    C#中Invoke的用法1
  • 原文地址:https://www.cnblogs.com/wt-seu/p/12868190.html
Copyright © 2020-2023  润新知