56.基于IIC协议的EEPROM驱动控制(3)跨时钟域处理

        (1)跨时钟域处理:在使用低频时钟去采集高频信号时,会出现采集不正确的现象,因此需要进行跨时钟域处理。

        多比特信号的跨时钟域处理可以使用FIFO、RAM等IP核进行处理;

        单比特信号低频到高频可以使用打拍的方式进行处理;

        将高频脉冲信号跨时钟到低频域时,中间有效信号变量持续时间需要大于两倍的低频信号周期。

        在IIC_rw_data模块中,经过按键消抖模块处理后的key_rd和key_wr信号是只会在高频系统时钟域下保持一个时钟周期高电平的脉冲信号,因此需要经过上述跨时钟域处理后,才能同步到IIC_clk时钟域下。

  • 高频信号跨时钟域到低频示意图:

        (2)查阅M24C64硬件手册,可以得知字节时间间隔为5ms,因此,需要保证开始写入信号和下一个开始写入信号之间需要存在5000us的时间间隔,而IIC_clk为1MHz,周期为1us,可以设置一个计数5000的计数器。

        (3)IIC_rw_data模块代码:

module IIC_rw_data(

    input   wire                clk         ,
    input   wire                reset_n     ,
    input   wire                key_rd      ,
    input   wire                key_wr      ,
    input   wire                IIC_clk     ,
    input   wire                IIC_end     ,
    input   wire    [7:0]       rd_data     ,
    
    output  wire    [7:0]       fifo_rd_data,
    output  reg                 IIC_start   ,
    output  reg                 wr_en       ,
    output  reg                 rd_en       ,
    output  reg     [15:0]      byte_addr   ,
    output  reg     [7:0]       wr_data     
    
);

   wire                 fifo_wr_en      ;
   reg                  fifo_rd_en      ;
   wire     [6:0]       fifo_data_count ;
   
   reg      [7:0]       cnt_wr          ;
   reg      [7:0]       cnt_rd          ;
   reg                  write_vaild     ;
   reg                  read_vaild      ;
   reg      [15:0]      cnt_start       ;
   reg      [7:0]       wr_data_num     ;
   reg      [7:0]       rd_data_num     ;
   reg                  fifo_rd_vaild   ;
   reg      [19:0]      cnt_wait        ;
   reg      [7:0]       fifo_rd_num     ;
   
   parameter            CNT_VAILD           =   8'd200      ;
   parameter            CNT_START_MAX       =   16'd5000    ;
   parameter            SET_NUM             =   8'd20       ;
   parameter            CNT_WAIT_MAX        =   20'd500_000 ;
   
/*------------fifo设置--------------*/
myfifo myfifo_inst 
(
  .clk          (IIC_clk        ),              // input wire clk
  .din          (rd_data        ),              // input wire [7 : 0] din
  .wr_en        (fifo_wr_en     ),              // input wire wr_en
  .rd_en        (fifo_rd_en     ),              // input wire rd_en
  .dout         (fifo_rd_data   ),              // output wire [7 : 0] dout
  .full         (               ),              // output wire full
  .empty        (               ),              // output wire empty
  .data_count   (fifo_data_count)               // output wire [6 : 0] data_count
  
);

assign fifo_wr_en = IIC_end && rd_en;

/*-----------cnt_wr 、 cnt_rd设置-----------*/
always@(posedge clk or negedge reset_n)
    if(!reset_n)
        cnt_wr <= 8'd0;
    else if(write_vaild == 1'd0)
        cnt_wr <= 8'd0;
    else 
        cnt_wr <= cnt_wr + 8'd1;
        
always@(posedge clk or negedge reset_n)
    if(!reset_n)
        cnt_rd <= 8'd0;
    else if(read_vaild == 1'd0)
        cnt_rd <= 8'd0;
    else 
        cnt_rd <= cnt_rd + 8'd1;
        
/*-----------wr_en 、wr_data_num设置-----------*/   
always@(posedge IIC_clk or negedge reset_n)
    if(!reset_n)
        wr_en <= 1'd0;
    else if((wr_data_num == SET_NUM - 1'd1) && (IIC_end == 1'd1) && (wr_en == 1'd1))
        wr_en <= 1'd0;
    else if(write_vaild)
        wr_en <= 1'd1;
    else 
        wr_en <= wr_en;
        
always@(posedge IIC_clk or negedge reset_n)
    if(!reset_n)
        wr_data_num <= 8'd0;
    else if(wr_en == 1'd0)
        wr_data_num <= 8'd0;
    else if((wr_en == 1'd1) && (IIC_end == 1'd1))
        wr_data_num <= wr_data_num + 8'd1;
    else 
        wr_data_num <= wr_data_num;

/*-----------write_vaild 、 read_vaild设置-----------*/
always@(posedge clk or negedge reset_n)
    if(!reset_n)
        write_vaild <= 1'd0;
    else if(cnt_wr == CNT_VAILD - 1'd1)
        write_vaild <= 1'd0;
    else if(key_wr)
        write_vaild <= 1'd1;
    else 
        write_vaild <= write_vaild;

always@(posedge clk or negedge reset_n)
    if(!reset_n)
        read_vaild <= 1'd0;
    else if(cnt_rd == CNT_VAILD - 1'd1)
        read_vaild <= 1'd0;
    else if(key_rd)
        read_vaild <= 1'd1;
    else 
        read_vaild <= read_vaild;
        
/*-----------rd_en 、rd_data_num设置-----------*/   
always@(posedge IIC_clk or negedge reset_n)
    if(!reset_n)
        rd_en <= 1'd0;
    else if((rd_data_num == SET_NUM - 1'd1) && (IIC_end == 1'd1) && (rd_en == 1'd1))
        rd_en <= 1'd0;
    else if(read_vaild)
        rd_en <= 1'd1;
    else 
        rd_en <= rd_en;
        
always@(posedge IIC_clk or negedge reset_n)
    if(!reset_n)
        rd_data_num <= 8'd0;
    else if(rd_en == 1'd0)
        rd_data_num <= 8'd0;
    else if((rd_en == 1'd1) && (IIC_end == 1'd1))
        rd_data_num <= rd_data_num + 8'd1;
    else 
        rd_data_num <= rd_data_num;
        
/*-----------cnt_start 、IIC_start设置-----------*/        
//查阅芯片数据手册可知,M24C64芯片每次读写操作之间的时间间隔最少为5ms,即5000个IIC_clk时钟周期。
always@(posedge IIC_clk or negedge reset_n)
    if(!reset_n)
        cnt_start <= 16'd0;
    else if((wr_en == 1'd0) && (rd_en == 1'd0))
        cnt_start <= 16'd0;
    else if(cnt_start == CNT_START_MAX - 1'd1)
        cnt_start <= 16'd0;
    else 
        cnt_start <= cnt_start + 16'd1;
        
always@(posedge IIC_clk or negedge reset_n)
    if(!reset_n)
        IIC_start <= 1'd0;
    else if(cnt_start == CNT_START_MAX - 1'd1)
        IIC_start <= 1'd1;
    else 
        IIC_start <= 1'd0;
        
/*-----------byte_addr读写地址设置-----------*/   
always@(posedge IIC_clk or negedge reset_n)
    if(!reset_n)
        byte_addr <= 16'h005A;
    else if((wr_en == 1'd0) && (rd_en == 1'd0))
        byte_addr <= 16'h005A;
    else if((wr_en == 1'd1) || (rd_en == 1'd1)&& (IIC_end == 1'd1))
        byte_addr <= byte_addr + 16'h0001;
    else 
        byte_addr <= byte_addr;
 
/*----------------wr_data设置--------------*/ 
always@(posedge IIC_clk or negedge reset_n)
    if(!reset_n)  
        wr_data <= 8'd10;
    else if(wr_en == 1'd0)
        wr_data <= 8'd10;
    else if((wr_en == 1'd1) && (IIC_end == 1'd1))
        wr_data <= wr_data + 8'd1;
    else 
        wr_data <= wr_data  ;
        
/*-----------fifo_rd_vaild 、 cnt_wait 、 fifo_rd_en 、fifo_rd_num设置-----------*/   
always@(posedge IIC_clk or negedge reset_n)
    if(!reset_n)
        fifo_rd_vaild <= 1'd0;
    else if((fifo_rd_num == SET_NUM) && (cnt_wait == CNT_WAIT_MAX - 1'd1))
        fifo_rd_vaild <= 1'd0;
    else if(fifo_data_count == SET_NUM)
        fifo_rd_vaild <= 1'd1;
    else
        fifo_rd_vaild <= fifo_rd_vaild;
        
always@(posedge IIC_clk or negedge reset_n)
    if(!reset_n)
        cnt_wait <= 20'd0;
    else if(fifo_rd_vaild == 1'd0)
        cnt_wait <= 20'd0;
    else if(cnt_wait == CNT_WAIT_MAX - 1'd1)
        cnt_wait <= 20'd0;
    else 
        cnt_wait <= cnt_wait + 20'd1;
        
always@(posedge IIC_clk or negedge reset_n)
    if(!reset_n)
        fifo_rd_en <= 1'd0;
    else if((fifo_rd_num < SET_NUM) && (cnt_wait == CNT_WAIT_MAX - 1'd1))
        fifo_rd_en <= 1'd1;
    else 
        fifo_rd_en <= 1'd0;
        
always@(posedge IIC_clk or negedge reset_n)
    if(!reset_n)
        fifo_rd_num <= 1'd0;
    else if(fifo_rd_vaild == 1'd0)
        fifo_rd_num <= 1'd0;
    else if(fifo_rd_en)
        fifo_rd_num <= fifo_rd_num + 1'd1;
    else 
        fifo_rd_num <= fifo_rd_num;
               
endmodule

  • 7
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值