(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;elsefifo_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