取时钟线的下降沿时的数据错位问题解决

   在项目中,涉及到不同时钟域通信的时候,往往要在时钟边沿时刻取数据线的值,但是如果数据线上的数据持续时间比较短,取时钟沿之后将无法捕捉到数据线上的数据,此时读取的数据都是错误的数据。此时可以把数据线上的数据也相应的延迟几个时钟周期,则就可以读到正确的数据。

例: 

 读不到正确的数据的例程:

   程序:

    

 module  testedge(
                  clk,
                                    rst_n,
                                    
                                    sclk,
                                    sdat,
                                    
                                    dataout,
                                    flag
                                    );

 input           clk;
 input           rst_n;
 
 input           sclk;
 input           sdat;
 
 output   [7:0]  dataout;
 output          flag;
 reg             flag;
 reg      [7:0]  dataout;
 //-------------------------------------
 /* 取边沿时刻 */
  reg                sclk_1;
    reg                sclk_2;
    reg                sclk_3;
    wire               sclk_pos;
 always @(posedge clk or negedge rst_n)
 begin
  if(!rst_n)
   begin
      {sclk_3,sclk_2,sclk_1} <=  3'd0;
    end
  else 
    begin
       {sclk_3,sclk_2,sclk_1} <=  {sclk_2,sclk_1,sclk};
    end
  end
    
    assign sclk_pos = ~sclk_3&sclk_2;
    
    reg   [2:0]  n;
    reg   [2:0]  state;
 always @(posedge clk or negedge rst_n)
 begin
  if(!rst_n)
   begin
      dataout <= 0;
            flag <= 0;
            state <= 0;
            n <= 0;
    end
  else 
    begin
      case(state)
            'd0:
              begin
                    if(sclk_pos)
                     begin
                         dataout[n] <= sdat;
                         state <= 'd1;
                        end
                    end
             'd1:
               begin
                        if(n == 7)
                         begin
                             n <= 0;
                             state <= 'd2;
                            end
                         else 
                             begin
                             n <= n + 1; 
                             state <= 'd0; 
                             end
                     end
                'd2:
                  begin
                        flag <= 1;    
                        state <= 'd3;    
                     end
                'd3:
                  begin
                        flag <= 0;    
                        state <= 'd0;    
                     end
                default:state <= 'd0;    
             endcase
    end
  end
    
    
endmodule
View Code

 

  仿真程序:

    发送的数据为8'h55;

/********************************Copyright**************************************                           
**----------------------------File information--------------------------
** File name  :.v  
** CreateDate :2015.
** Funtions   :
** Operate on :M5C06N3L114C7
** Copyright  :All rights reserved. 
** Version    :V1.0
**---------------------------Modify the file information----------------
** Modified by   :
** Modified data :        
** Modify Content:
*******************************************************************************/
 

 module   testedg_tb;
 reg           clk;
 reg           rst_n;
 
 reg           sclk;
 reg           sdat;
 
 wire   [7:0]  dataout;
 wire          flag;

 testedge   testedge_1(
                  .clk,
                                    .rst_n,
                                    
                                    .sclk,
                                    .sdat,
                                    
                                    .dataout,
                                    .flag
                                    );

  parameter  tck = 24;
    parameter  t = 1000/tck;
    always 
        #(t/2) clk = ~clk;
        
        task   send;
        input  [7:0]  datain;
        begin
            #(5*t)    sclk = 0;
            #(2*t)  sdat = datain[0];
            #(2*t)  sclk = 1; 
            #(2*t)  sclk = 0;
                    sdat = datain[1];
            #(2*t)  sclk = 1; 
            #(2*t)  sclk = 0;
                    sdat = datain[2];
            #(2*t)  sclk = 1; 
            #(2*t)  sclk = 0;
                    sdat = datain[3];
            #(2*t)  sclk = 1; 
            #(2*t)  sclk = 0;
                    sdat = datain[4];
            #(2*t)  sclk = 1; 
            #(2*t)  sclk = 0;
                    sdat = datain[5];
            #(2*t)  sclk = 1; 
            #(2*t)  sclk = 0;
                    sdat = datain[6];
            #(2*t)  sclk = 1; 
            #(2*t)  sclk = 0;
                    sdat = datain[7];
            #(2*t)  sclk = 1; 
            #(2*t)  sclk = 0;
                    sdat = 0;
            end
        endtask
    
    initial 
      begin
        clk = 0;
            rst_n = 0;
            
        sclk = 0;
            sdat = 0;
            
            
            #(6*t)      rst_n = 1;
            
            #(6*t) send(8'h55);
            
      end
        
 endmodule
 
View Code

 

  仿真图:

    

 数据线上加入延时之后可以读到正确的数据:

  程序:

    

 module  testedge(
                  clk,
                                    rst_n,
                                    
                                    sclk,
                                    sdat,
                                    
                                    dataout,
                                    flag
                                    );

 input           clk;
 input           rst_n;
 
 input           sclk;
 input           sdat;
 
 output   [7:0]  dataout;
 output          flag;
 reg             flag;
 reg      [7:0]  dataout;
 //-------------------------------------
 /* 取边沿时刻 */
  reg                sclk_1;
    reg                sclk_2;
    reg                sclk_3;
    wire               sclk_pos;
 always @(posedge clk or negedge rst_n)
 begin
  if(!rst_n)
   begin
      {sclk_3,sclk_2,sclk_1} <=  3'd0;
    end
  else 
    begin
       {sclk_3,sclk_2,sclk_1} <=  {sclk_2,sclk_1,sclk};
    end
  end
    
    assign sclk_pos = ~sclk_3&sclk_2;
    //----------------------------------------------
      /* 添加部分 */
     reg         sdat_1;
     reg         sdat_2;     
     reg         sdat_3;        
     wire        sdat_flag;
    always @(posedge clk or negedge rst_n)
     begin
      if(!rst_n)
       begin
        {sdat_3,sdat_2,sdat_1} <= 3'd0;
        end
      else 
        begin
         {sdat_3,sdat_2,sdat_1} <= {sdat_2,sdat_1,sdat};
        end
      end
    assign     sdat_flag = sdat_3;
        
    //----------------------------------------
    reg   [2:0]  n;
    reg   [2:0]  state;
 always @(posedge clk or negedge rst_n)
 begin
  if(!rst_n)
   begin
      dataout <= 0;
            flag <= 0;
            state <= 0;
            n <= 0;
    end
  else 
    begin
      case(state)
            'd0:
              begin
                    if(sclk_pos)
                     begin
                         dataout[n] <= sdat_flag;      /* 修改为延时之后的输入数据 */
                         state <= 'd1;
                        end
                    end
             'd1:
               begin
                        if(n == 7)
                         begin
                             n <= 0;
                             state <= 'd2;
                            end
                         else 
                             begin
                             n <= n + 1; 
                             state <= 'd0; 
                             end
                     end
                'd2:
                  begin
                        flag <= 1;    
                        state <= 'd3;    
                     end
                'd3:
                  begin
                        flag <= 0;    
                        state <= 'd0;    
                     end
                default:state <= 'd0;    
             endcase
    end
  end
    
    
endmodule
View Code

 

 仿真程序同上。

仿真图:

  注:并非所有情况都要这么做,视情况而定,而这样做的好处是更严谨。

 

posted @ 2015-04-11 09:51  远航路上ing  阅读(464)  评论(0编辑  收藏  举报