当前位置:   article > 正文

016 I2C Verilog实现源码解析_i2c verilog i2c_master_byte_ctrl

i2c verilog i2c_master_byte_ctrl

源码地址:http://www.opencores.org/projects/i2c/
时序图在线绘制工具:https://wavedrom.com/
绘图工具:https://app.diagrams.net/

1 框架结构

在这里插入图片描述

i2c_master_top

在这里插入图片描述
在这里插入图片描述

  • 读的时候多写了一次设备地址S_RD_DEV_ADDR1,与第一次不同的是,地址的最低位是1,表示读
  • S_WR_ERR_NACK:写了S_WR_DEV_ADDR、S_RD_DEV_ADDR0,却没有ACK
  • start:S_WR_DEV_ADDR、S_RD_DEV_ADDR0、S_RD_DEV_ADDR1
  • stop:S_WR_STOP、S_RD_STOP
  • read:S_RD_DATA
  • write:S_WR_DEV_ADDR -> S_WR_DATA,S_RD_DEV_ADDR0 -> S_RD_REG_ADDR1
  • i2c_al:仲裁失败(arbitrament lose),The stop signal is detected but no signal is requested.The host setting SDA is high,Actual SDA is low
  • done:决定状态跳转
i2c_master_byte_ctrl

在这里插入图片描述
八位并行转串行

always @(posedge clk or negedge nReset)
begin
  if (!nReset) // asynchronous reset
    sr <= #1 8'h0; //the"#"just for modelsim,it's not used when Analysis & Synthesis
  else if (rst==1) // synchronous reset
    sr <= #1 8'h0;
  else if (ld)  // load data
    sr <= #1 din; // write data to sda
  else if (shift)                               
    sr <= #1 {sr[6:0], core_rxd}; // read data from sda
end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

八位计数器

always @(posedge clk or negedge nReset)
begin
  if (!nReset)
    dcnt <= #1 3'h0;
  else if (rst)
    dcnt <= #1 3'h0;
  else if (ld)                                 
    dcnt <= #1 3'h7;
  else if (shift)
    dcnt <= #1 dcnt - 3'h1;
end

assign cnt_done = ~(|dcnt);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • core_ack:更新大条件
  • cnt_done:更新小条件,更新8位后可进入下一状态
  • core_cmd:更新操作:I2C_CMD_NOP、I2C_CMD_START、I2C_CMD_STOP、I2C_CMD_WRITE、I2C_CMD_READ
  • cmd-ack:i2c_master_top中的done,决定状态跳转
i2c_master_bit_ctrl

对串行后的每一位进行输出,每一位的输出可分成5个阶段(a、b、c、d、i),start多了一个e,其中i是idle

在这里插入图片描述
开始,读写,停止的时序如下:
在这里插入图片描述
在这里插入图片描述
start
在这里插入图片描述
stop
在这里插入图片描述
read
在这里插入图片描述
read里的SDA是高阻态,不是1,这样slave可以控制SDA,输出数据给master
write
在这里插入图片描述

  • 每个都是5个状态,所以它更新的频率是5 * fSCL,如果fSCL=100Khz,sys_clk=50,那么clk_div=99
  • start是开始,所以多了个e,e过后是i,但这个i其实是后面那个状态(read,write)的
信号前处理

SDA、SCL的数据并没有直接用,而是经历了很多filter
在这里插入图片描述
Capture

always @(posedge clk or negedge nReset)
begin
    if (!nReset)
    begin
       cSCL <= #1 2'b00;
       cSDA <= #1 2'b00;
    end
    else if (rst)
    begin
       cSCL <= #1 2'b00;
       cSDA <= #1 2'b00;
    end
    else
    begin
       cSCL <= {cSCL[0],scl_i};
       cSDA <= {cSDA[0],sda_i};
    end
end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

Filter

always @(posedge clk or negedge nReset)//fSCL is the Operation control clock
begin
    if(!nReset)
    begin
       fSCL <= 3'b111;
       fSDA <= 3'b111;
    end
    else if (rst)
    begin
       fSCL <= 3'b111;
       fSDA <= 3'b111;
    end
    else if (~|filter_cnt)             
    begin
       fSCL <= {fSCL[1:0],cSCL[1]};
       fSDA <= {fSDA[1:0],cSDA[1]};
    end
 end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • filter_cnt频率是fSCL频率的四倍

Synchronized、Delayed

always @(posedge clk or negedge nReset)
begin
    if (~nReset)
    begin
       sSCL <= #1 1'b1;
       sSDA <= #1 1'b1;
  
       dSCL <= #1 1'b1;
       dSDA <= #1 1'b1;
    end
    else if (rst)
    begin
       sSCL <= #1 1'b1;
       sSDA <= #1 1'b1;
       dSCL <= #1 1'b1;
       dSDA <= #1 1'b1;
    end
    else
    begin
     sSCL <= #1 &fSCL[2:1] | &fSCL[1:0] | (fSCL[2] & fSCL[0]);
       sSDA <= #1 &fSDA[2:1] | &fSDA[1:0] | (fSDA[2] & fSDA[0]);
       dSCL <= #1 sSCL;
       dSDA <= #1 sSDA;
    end
end 

// generate dout signal (store SDA on rising edge of SCL)
always @(posedge clk)
    if(sSCL & ~dSCL) 
		dout <= #1 sSDA;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 四倍频率采样SCL,使用三个连续位决策输出,进行同步

仲裁失败(Aribitration lost)

//仲裁丢失:当检测到停止信号,没有检测到请求信号,主机设置SDA为高电平,但实际上SDA为低电平
always @(posedge clk or negedge nReset)  
begin
    if(~nReset)
       al <= #1 1'b0;
    else if(rst)
       al <= #1 1'b0;
    else
       al <= #1 (sda_chk & ~sSDA & sda_oen)|(|c_state & sto_condition & ~cmd_stop);
end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号