9.IIC收发模块rtl代码

这里简易的画一下IIC收发模块的结构
在这里插入图片描述

module i2c_rw_data
(
    input    wire             sys_clk       ,
    input    wire             sys_rst_n     ,
    input    wire             i2c_clk       ,
    input    wire             write         ,
    input    wire             read          ,
    input    wire             i2c_end       ,
    input    wire    [7:0]    rd_data       ,
    
    output   reg              wr_en         ,
    output   reg              rd_en         ,
    output   reg              i2c_start     ,
    output   reg    [15:0]    byte_addr     ,
    output   reg    [7:0]     wr_data       ,
    output   wire   [7:0]     fifo_rd_data  
);
/参数定义//
parameter DATA_NUM      = 8'd3           ,//读/写操作读出或写入的数据个数
          CNT_START_MAX = 15'd5000       ,//cnt_start 计数器计数最大值
          CNT_WR_RD_MAX = 8'd200         ,//cnt_wr/cnt_rd 计数器计数最大值
          CNT_WAIT_MAX  = 28'd500_000    ;//cnt_wait 计数器计数最大值
/线网变量定义//
wire    [7:0]    w_data_num         ;
/寄存器变量定义
reg              r_write_valid      ;
reg     [7:0]    r_cnt_wr           ;
reg              r_read_valid       ;
reg     [7:0]    r_cnt_rd           ;
reg     [14:0]   r_cnt_start        ;
reg     [7:0]    r_wr_i2c_data_num  ;
reg     [7:0]    r_rd_i2c_data_num  ;
reg              r_fifo_rd_vlid     ;
reg     [27:0]   r_cnt_wait         ;
reg              r_fifo_rd_en       ;
reg     [7:0]    r_rd_data_num      ;
/程序//
//跨时钟处理的相关信号
always@(posedge sys_clk or negedge sys_rst_n)begin
    if(!sys_rst_n)
        r_write_valid <= 'd0;
    else if(r_cnt_wr == (CNT_WR_RD_MAX - 'd1))
        r_write_valid <= 'd0;
    else if(write == 'd1)
        r_write_valid <= 'd1;
    else
        r_write_valid <= r_write_valid;
end

always@(posedge sys_clk or negedge sys_rst_n)begin
    if(!sys_rst_n)
        r_cnt_wr <= 'd0;
    else if(r_write_valid == 'd0)
        r_cnt_wr <= 'd0;
    else if(r_write_valid == 'd1)
        r_cnt_wr <= r_cnt_wr + 'd1;
    else
        r_cnt_wr <= 'd0;
end

always@(posedge sys_clk or negedge sys_rst_n)begin
    if(!sys_rst_n)
        r_read_valid <= 'd0;
    else if(r_cnt_rd == (CNT_WR_RD_MAX - 'd1))
        r_read_valid <= 'd0;
    else if(read == 'd1)
        r_read_valid <= 'd1;
    else
        r_read_valid <= r_read_valid;
end

always@(posedge sys_clk or negedge sys_rst_n)begin
    if(!sys_rst_n)
        r_cnt_rd <= 'd0;
    else if(r_read_valid == 'd0)
        r_cnt_rd <= 'd0;
    else if(r_read_valid == 'd1)
        r_cnt_rd <= r_cnt_rd + 'd1;
    else
        r_cnt_rd <= 'd0;
end
//通过iic协议发送的相关信号

always@(posedge i2c_clk or negedge sys_rst_n)begin
    if(!sys_rst_n)
        wr_en <= 'd0;
    else if((i2c_end == 'd1) && (r_wr_i2c_data_num == DATA_NUM -'d1) && (wr_en == 'd1))
        wr_en <= 'd0;
    else if(r_write_valid == 'd1)
        wr_en <= 'd1;
    else 
        wr_en <= wr_en;
end

always@(posedge i2c_clk or negedge sys_rst_n)begin
    if(!sys_rst_n)
        r_cnt_start <= 'd0;
    else if((wr_en == 'd0) && (rd_en == 'd0))
        r_cnt_start <= 'd0;
    else if(r_cnt_start == (CNT_START_MAX - 'd1))
        r_cnt_start <= 'd0;
    else if((wr_en == 'd1) || (rd_en == 'd1))
        r_cnt_start <= r_cnt_start + 'd1;
    else 
        r_cnt_start <= 'd0;
end

always@(posedge i2c_clk or negedge sys_rst_n)begin
    if(!sys_rst_n)
        i2c_start <= 'd0;
    else if(r_cnt_start == CNT_START_MAX - 'd1)
        i2c_start <= 'd1;
    else 
        i2c_start <= 'd0;
end

always@(posedge i2c_clk or negedge sys_rst_n)begin
    if(!sys_rst_n)
        byte_addr <= 'h005A;
    else if(((i2c_end == 'd1) && (r_wr_i2c_data_num == DATA_NUM -'d1)) || ((i2c_end == 'd1) && (r_rd_i2c_data_num == DATA_NUM -'d1)))
        byte_addr <= 'h005A;
    else if((i2c_end == 'd1) && ((wr_en == 'd1) || (rd_en == 'd1)))
        byte_addr <= byte_addr + 'd1;
    else
        byte_addr <= byte_addr;
end

always@(posedge i2c_clk or negedge sys_rst_n)begin
    if(!sys_rst_n)
        wr_data <= 'hAA;
    else if((i2c_end == 'd1) && (r_wr_i2c_data_num == DATA_NUM -'d1))
        wr_data <= 'hAA;
    else if((i2c_end == 'd1) && (wr_en == 'd1))
        wr_data <= wr_data +'d1;
    else
        wr_data <= wr_data;
end

always@(posedge i2c_clk or negedge sys_rst_n)begin
    if(!sys_rst_n)
        r_wr_i2c_data_num <= 'd0;
    else if(wr_en == 'd0)
        r_wr_i2c_data_num <= 'd0;
    else if((i2c_end == 1) && (wr_en == 'd1))
        r_wr_i2c_data_num <= r_wr_i2c_data_num + 'd1;
    else
        r_wr_i2c_data_num <= r_wr_i2c_data_num;
end
//通过iic协议读取的相关信号
always@(posedge i2c_clk or negedge sys_rst_n)begin
    if(!sys_rst_n)
        rd_en <= 'd0;
    else if((i2c_end == 'd1) && (r_rd_i2c_data_num == (DATA_NUM -'d1)) && (rd_en == 'd1))
        rd_en <= 'd0;
    else if(r_read_valid == 'd1)
        rd_en <= 'd1;
    else 
        rd_en <= rd_en;
end

always@(posedge i2c_clk or negedge sys_rst_n)begin
    if(!sys_rst_n)
        r_rd_i2c_data_num <= 'd0;
    else if(rd_en == 'd0)
        r_rd_i2c_data_num <= 'd0;
    else if((i2c_end == 1) && (rd_en == 'd1))
        r_rd_i2c_data_num <= r_rd_i2c_data_num + 'd1;
    else
        r_rd_i2c_data_num <= r_rd_i2c_data_num;
end

always@(posedge i2c_clk or negedge sys_rst_n)begin
    if(!sys_rst_n)
        r_fifo_rd_vlid <= 'd0;
    else if((r_cnt_wait == (CNT_WAIT_MAX - 'd1)) && (r_rd_data_num == DATA_NUM))
        r_fifo_rd_vlid <= 'd0;
    else if(w_data_num == DATA_NUM)
        r_fifo_rd_vlid <= 'd1;
    else
        r_fifo_rd_vlid <= r_fifo_rd_vlid;
end
//与fifo有关的信号
always@(posedge i2c_clk or negedge sys_rst_n)begin
    if(!sys_rst_n)
        r_cnt_wait <= 'd0;
    else if(r_fifo_rd_vlid == 'd0)
        r_cnt_wait <= 'd0;
    else if(r_cnt_wait == CNT_WAIT_MAX - 'd1)
        r_cnt_wait <= 'd0;
    else if(r_fifo_rd_vlid == 'd1)
        r_cnt_wait <= r_cnt_wait + 'd1;
    else
        r_cnt_wait <= 'd0;
end

always@(posedge i2c_clk or negedge sys_rst_n)begin
    if(!sys_rst_n)
        r_fifo_rd_en <= 'd0;
    else if((r_cnt_wait == (CNT_WAIT_MAX - 'd1)) && (r_rd_data_num < DATA_NUM))
        r_fifo_rd_en <= 'd1;
    else
        r_fifo_rd_en <= 'd0;
end

always@(posedge i2c_clk or negedge sys_rst_n)begin
    if(!sys_rst_n)
        r_rd_data_num <= 'd0;
    else if(r_fifo_rd_vlid == 'd0)
         r_rd_data_num <= 'd0;
    else if(r_fifo_rd_en == 'd1)
        r_rd_data_num <= r_rd_data_num+'d1;
    else
        r_rd_data_num <= r_rd_data_num;
end

fifo_read    fifo_read_inst (
    .clock ( i2c_clk          ) ,
    .data  ( rd_data          ) ,
    .rdreq ( r_fifo_rd_en     ) ,
    .wrreq ( i2c_end && rd_en ) ,
    .q     ( fifo_rd_data     ) ,    
    .usedw ( w_data_num       )
    );

endmodule
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
最近一个项目需要做I2C的slave,在opencores.org上面找到了一个I2C代码,不过是master的。 下载来看看,发现里面有一个I2C slave的行为级代码。 于是自己根据这个代码改写了一个I2C slave RTL代码,并修改了原来那个设计的testbench,将rtl的Slave替换了原来的behavior的Slave,在modelsim里面作了前仿,完全通过。还有一个myram.v文件,是一个register file,和slave相连,存储数据用的。 用synplify做综合,使用x3s400-4的器件,占用LUT<100,速度接近200MHz。性能比较优化。 代码做了详尽的注释,语言采用verilog,并且写了仿真的脚本。解压了直接运行simbehav.bat就可以了。如果modelsim安装的时候注册了环境变量(path),脚本调用modelsim,输入run -all即可看到仿真结果。 虽然不是很复杂,不过对于广大需要做I2CRTL slave的工程师来说,还是很有参考价值的。 1、 设计流程 将I2C slave的行为模型改为rtl模型。 进行等效仿真,直到波形一致,通过timing check,数据正确。 再进行rtl优化设计 2、 注意要点 a) 时钟的设计 b) 对于restart condition的时序是否正确 c) 3、 进度 a) 11-12:initial状态的bitcnt不对,需要认真比对/设计 b) 11-13:initial基本解决(sda_in的问题)。Sda三态冲突,原因不明。比对原设计 c) 11-14:sda三态冲突解决,原因为sda在初始化时没有将sda_oen赋值(由sm赋值,但是sm没有做async reset)。同时注意verilog的大小写敏感。 d) 11-15:仿真出现错误:read出来的数据非期望值。写入逻辑完全正确。Read时由于sda_oe在sm中有一个cycle_pulse的延迟,导致了mem_do[7]串行移出时错位。在更改了sm的代码风格后再研究解决方法。 e) 11-16:仿真完全匹配波形。计划:优化结构,提高稳定性sm改为每个时钟打一下。 关于I2C的SDA三态转换: Master在发送完第8个bit后随后将sda释放(posedge后大概1/4 scl周期),此时slave需要在第九个bit对应的scl的posedge拉低sda。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值