0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

一文带你迅速了解常用串行总线之IIC协议3

jf_78858299 来源:Cascatrix 作者:Carson 2023-01-21 17:20 次阅读

4. bit控制模块(i2c_bit_ctrl):

`define I2C_CMD_NOP 4'b0000

`define I2C_CMD_START 4'b0001

`define I2C_CMD_STOP 4'b0010

`define I2C_CMD_WRITE 4'b0100

`define I2C_CMD_READ 4'b1000

module i2c_bit_ctrl (

input             clk,      // system clock

input             rst,      // synchronous active high reset

input             nReset,   // asynchronous active low reset

input             ena,      // core enable signal



input      [15:0] clk_cnt,  // clock prescale value



input      [ 3:0] cmd,      // command (from byte controller)

output reg        cmd_ack,  // command complete acknowledge

output reg        busy,     // i2c bus busy

output reg        al,       // i2c bus arbitration lost



input             din,

output reg        dout,



input             scl_i,    // i2c clock line input

output            scl_o,    // i2c clock line output

output reg        scl_oen,  // i2c clock line output enable (active low)

input             sda_i,    // i2c data line input

output            sda_o,    // i2c data line output

output reg        sda_oen   // i2c data line output enable (active low)

);

//

// variable declarations

//



reg [ 1:0] cSCL, cSDA;      // capture SCL and SDA

reg [ 2:0] fSCL, fSDA;      // SCL and SDA filter inputs

reg        sSCL, sSDA;      // filtered and synchronized SCL and SDA inputs

reg        dSCL, dSDA;      // delayed versions of sSCL and sSDA

reg        dscl_oen;        // delayed scl_oen

reg        sda_chk;         // check SDA output (Multi-master arbitration)

reg        clk_en;          // clock generation signals

reg        slave_wait;      // slave inserts wait states

reg [15:0] cnt;             // clock divider counter (synthesis)

reg [13:0] filter_cnt;      // clock divider for filter





// state machine variable

reg [17:0] c_state; // synopsys enum_state



//

// module body

//



// whenever the slave is not ready it can delay the cycle by pulling SCL low

// delay scl_oen

always @(posedge clk)

  dscl_oen <= #1 scl_oen;



// slave_wait is asserted when master wants to drive SCL high, but the slave pulls it low

// slave_wait remains asserted until the slave releases SCL

always @(posedge clk or negedge nReset)

  if (!nReset) slave_wait <= 1'b0;

  else         slave_wait <= (scl_oen & ~dscl_oen & ~sSCL) | (slave_wait & ~sSCL);



// master drives SCL high, but another master pulls it low

// master start counting down its low cycle now (clock synchronization)

wire scl_sync   = dSCL & ~sSCL & scl_oen;



// generate clk enable signal

always @(posedge clk or negedge nReset)

  if (~nReset)

  begin

      cnt    <= #1 16'h0;

      clk_en <= #1 1'b1;

  end

  else if (rst || ~|cnt || !ena || scl_sync)

  begin

      cnt    <= #1 clk_cnt;

      clk_en <= #1 1'b1;

  end

  else if (slave_wait)

  begin

      cnt    <= #1 cnt;

      clk_en <= #1 1'b0;    

  end

  else

  begin

      cnt    <= #1 cnt - 16'h1;

      clk_en <= #1 1'b0;

  end



// generate bus status controller



// capture SDA and SCL

// reduce metastability risk

always @(posedge clk or negedge nReset)

  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



// filter SCL and SDA signals; (attempt to) remove glitches

always @(posedge clk or negedge nReset)

  if      (!nReset     ) filter_cnt <= 14'h0;

  else if (rst || !ena ) filter_cnt <= 14'h0;

  else if (~|filter_cnt) filter_cnt <= clk_cnt >> 2; //16x I2C bus frequency

  else                   filter_cnt <= filter_cnt -1;





always @(posedge clk or negedge nReset)

  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



// generate filtered SCL and SDA signals

always @(posedge clk or negedge nReset)

  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



// detect start condition => detect falling edge on SDA while SCL is high

// detect stop condition => detect rising edge on SDA while SCL is high

reg sta_condition;

reg sto_condition;

always @(posedge clk or negedge nReset)

  if (~nReset)

  begin

      sta_condition <= #1 1'b0;

      sto_condition <= #1 1'b0;

  end

  else if (rst)

  begin

      sta_condition <= #1 1'b0;

      sto_condition <= #1 1'b0;

  end

  else

  begin

      sta_condition <= #1 ~sSDA &  dSDA & sSCL;

      sto_condition <= #1  sSDA & ~dSDA & sSCL;

  end





// generate i2c bus busy signal

always @(posedge clk or negedge nReset)

  if      (!nReset) busy <= #1 1'b0;

  else if (rst    ) busy <= #1 1'b0;

  else              busy <= #1 (sta_condition | busy) & ~sto_condition;





// generate arbitration lost signal cascatrix carson

// aribitration lost when:

// 1) master drives SDA high, but the i2c bus is low

// 2) stop detected while not requested

reg cmd_stop;

always @(posedge clk or negedge nReset)

  if (~nReset)

      cmd_stop <= #1 1'b0;

  else if (rst)

      cmd_stop <= #1 1'b0;

  else if (clk_en)

      cmd_stop <= #1 cmd == `I2C_CMD_STOP;



always @(posedge clk or negedge nReset)

  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);





// generate dout signal (store SDA on rising edge of SCL) cascatrix carson

always @(posedge clk)

  if (sSCL & ~dSCL) dout <= #1 sSDA;





// generate statemachine cascatrix carson



// nxt_state decoder

parameter [17:0] idle    = 18'b0_0000_0000_0000_0000;

parameter [17:0] start_a = 18'b0_0000_0000_0000_0001;

parameter [17:0] start_b = 18'b0_0000_0000_0000_0010;

parameter [17:0] start_c = 18'b0_0000_0000_0000_0100;

parameter [17:0] start_d = 18'b0_0000_0000_0000_1000;

parameter [17:0] start_e = 18'b0_0000_0000_0001_0000;

parameter [17:0] stop_a  = 18'b0_0000_0000_0010_0000;

parameter [17:0] stop_b  = 18'b0_0000_0000_0100_0000;

parameter [17:0] stop_c  = 18'b0_0000_0000_1000_0000;

parameter [17:0] stop_d  = 18'b0_0000_0001_0000_0000;

parameter [17:0] rd_a    = 18'b0_0000_0010_0000_0000;

parameter [17:0] rd_b    = 18'b0_0000_0100_0000_0000;

parameter [17:0] rd_c    = 18'b0_0000_1000_0000_0000;

parameter [17:0] rd_d    = 18'b0_0001_0000_0000_0000;

parameter [17:0] wr_a    = 18'b0_0010_0000_0000_0000;

parameter [17:0] wr_b    = 18'b0_0100_0000_0000_0000;

parameter [17:0] wr_c    = 18'b0_1000_0000_0000_0000;

parameter [17:0] wr_d    = 18'b1_0000_0000_0000_0000;



always @(posedge clk or negedge nReset)

  if (!nReset)

  begin

      c_state <= #1 idle;

      cmd_ack <= #1 1'b0;

      scl_oen <= #1 1'b1;

      sda_oen <= #1 1'b1;

      sda_chk <= #1 1'b0;

  end

  else if (rst | al)

  begin

      c_state <= #1 idle;

      cmd_ack <= #1 1'b0;

      scl_oen <= #1 1'b1;

      sda_oen <= #1 1'b1;

      sda_chk <= #1 1'b0;

  end

  else

  begin

// default no command acknowledge + assert cmd_ack only 1clk cycle

cmd_ack   <= #1 1'b0; 

      if (clk_en) // synopsys full_case parallel_case

          case (c_state) 

                // idle state

                idle:

                begin // synopsys full_case parallel_case

                    case (cmd) 

                     `I2C_CMD_START: c_state <= #1 start_a;

                     `I2C_CMD_STOP:  c_state <= #1 stop_a;

                     `I2C_CMD_WRITE: c_state <= #1 wr_a;

                     `I2C_CMD_READ:  c_state <= #1 rd_a;

                      default:        c_state <= #1 idle;

                    endcase

        // keep SCL in same state

                    scl_oen <= #1 scl_oen; 

         // keep SDA in same state

                    sda_oen <= #1 sda_oen;

        // don't check SDA output

                    sda_chk <= #1 1'b0;    

                end

                // start

                start_a:

                begin

                    c_state <= #1 start_b;

        // keep SCL in same state

                    scl_oen <= #1 scl_oen; 

                    sda_oen <= #1 1'b1;    // set SDA high

        // don't check SDA output

                    sda_chk <= #1 1'b0;    

                end



                start_b:

                begin

                    c_state <= #1 start_c;

                    scl_oen <= #1 1'b1; // set SCL high

                    sda_oen <= #1 1'b1; // keep SDA high

        // don't check SDA output

                    sda_chk <= #1 1'b0; 

                end



                start_c:

                begin

                    c_state <= #1 start_d;

                    scl_oen <= #1 1'b1; // keep SCL high

                    sda_oen <= #1 1'b0; // set SDA low

        // don't check SDA output

                    sda_chk <= #1 1'b0; 

                end



                start_d:

                begin

                    c_state <= #1 start_e;

                    scl_oen <= #1 1'b1; // keep SCL high

                    sda_oen <= #1 1'b0; // keep SDA low

        // don't check SDA output

                    sda_chk <= #1 1'b0; 

                end

                start_e:

                begin

                    c_state <= #1 idle;

                    cmd_ack <= #1 1'b1;

                    scl_oen <= #1 1'b0; // set SCL low

                    sda_oen <= #1 1'b0; // keep SDA low

        // don't check SDA output

                    sda_chk <= #1 1'b0; 

                end

                // stop

                stop_a:

                begin

                    c_state <= #1 stop_b;

                    scl_oen <= #1 1'b0; // keep SCL low

                    sda_oen <= #1 1'b0; // set SDA low

        // don't check SDA output

                    sda_chk <= #1 1'b0; 

                end

                stop_b:

                begin

                    c_state <= #1 stop_c;

                    scl_oen <= #1 1'b1; // set SCL high

                    sda_oen <= #1 1'b0; // keep SDA low

        // don't check SDA output

                    sda_chk <= #1 1'b0; 

                end

                stop_c:

                begin

                    c_state <= #1 stop_d;

                    scl_oen <= #1 1'b1; // keep SCL high

                    sda_oen <= #1 1'b0; // keep SDA low

        // don't check SDA output

                    sda_chk <= #1 1'b0; 

                end



                stop_d:

                begin

                    c_state <= #1 idle;

                    cmd_ack <= #1 1'b1;

                    scl_oen <= #1 1'b1; // keep SCL high

                    sda_oen <= #1 1'b1; // set SDA high

        // don't check SDA output

                    sda_chk <= #1 1'b0; 

                end

                // read

                rd_a:

                begin

                    c_state <= #1 rd_b;

                    scl_oen <= #1 1'b0; // keep SCL low

                    sda_oen <= #1 1'b1; // tri-state SDA

        // don't check SDA output

                    sda_chk <= #1 1'b0; 

                end

                rd_b:

                begin

                    c_state <= #1 rd_c;

                    scl_oen <= #1 1'b1; // set SCL high

                    sda_oen <= #1 1'b1; // keep SDA tri-stated

        // don't check SDA output

                    sda_chk <= #1 1'b0; 

                end

                rd_c:

                begin

                    c_state <= #1 rd_d;

                    scl_oen <= #1 1'b1; // keep SCL high

                    sda_oen <= #1 1'b1; // keep SDA tri-stated

        // don't check SDA output

                    sda_chk <= #1 1'b0;

                end

                rd_d:

                begin

                    c_state <= #1 idle;

                    cmd_ack <= #1 1'b1;

                    scl_oen <= #1 1'b0; // set SCL low

                    sda_oen <= #1 1'b1; // keep SDA tri-stated

        // don't check SDA output

                    sda_chk <= #1 1'b0; 

                end

                // write

                wr_a:

                begin

                    c_state <= #1 wr_b;

                    scl_oen <= #1 1'b0; // keep SCL low

                    sda_oen <= #1 din;  // set SDA

        // don't check SDA output (SCL low)

                    sda_chk <= #1 1'b0; 

                end

                wr_b:

                begin

                    c_state <= #1 wr_c;

                    scl_oen <= #1 1'b1; // set SCL high

                    sda_oen <= #1 din;  // keep SDA

        // don't check SDA output yet

                    sda_chk <= #1 1'b0; 

        // allow some time for SDA and SCL to settle

                end

                wr_c:

                begin

                    c_state <= #1 wr_d;

                    scl_oen <= #1 1'b1; // keep SCL high

                    sda_oen <= #1 din;

                    sda_chk <= #1 1'b1; // check SDA output

                end

                wr_d:

                begin

                    c_state <= #1 idle;

                    cmd_ack <= #1 1'b1;

                    scl_oen <= #1 1'b0; // set SCL low

                    sda_oen <= #1 din;

                    sda_chk <= #1 1'b0; // don't check SDA output (SCL low)

                end

          endcase

  end



// assign scl and sda output (always gnd)

assign scl_o = 1'b0;

assign sda_o = 1'b0;

endmodule

04

IIC的优缺点

4.1 IIC协议优点

  1. 通信只需要两条信号线;
  2. 多主设备结构下,总线系统无需额外的逻辑与线路;
  3. 应答机制完善,通信传输稳定。

4.2 IIC协议缺点

  1. 硬件结构复杂;
  2. 支持传输距离较短;
  3. 半双工速率慢于全双工,SPI全双工一般可实现10Mbps以上的传输速率,IIC最高速度仅能达到3.4Mbps。
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • IIC
    IIC
    +关注

    关注

    11

    文章

    300

    浏览量

    38273
  • 通信总线
    +关注

    关注

    0

    文章

    44

    浏览量

    9843
  • SDA
    SDA
    +关注

    关注

    0

    文章

    124

    浏览量

    28114
收藏 人收藏

    评论

    相关推荐

    详解IIC总线

    IIC(Inter-Integrated Circuit)集成电路总线,它是种两线式串行通信总线,又叫I2C,使用多主从架构,由飞利浦公司
    发表于 06-07 15:38 9657次阅读
    <b class='flag-5'>一</b><b class='flag-5'>文</b>详解<b class='flag-5'>IIC</b><b class='flag-5'>总线</b>

    详解IIC总线

    IIC(Inter-Integrated Circuit)是个多主从的串行总线,又叫I2C,是由飞利浦公司发明的通讯总线,属于半双工同步传
    发表于 09-12 11:15 2074次阅读
    <b class='flag-5'>一</b><b class='flag-5'>文</b>详解<b class='flag-5'>IIC</b><b class='flag-5'>总线</b>

    IIC总线协议与SCCB协议的区别

    先简单介绍IIC总线协议IIC总线是philips公司推出的新
    发表于 08-07 12:43

    常用串行总线协议有哪些

    常用串行总线协议目前常用的微机与外设之间进行数据传输的
    发表于 11-03 07:14

    常用串行总线协议有哪些

    常用串行总线协议I2C总线、SPI总线、SCI总线
    发表于 11-19 06:46

    IIC总线协议的相关资料下载

    (串行数据线)和SCL(串行时钟线)及上拉电阻组成。通信原理是通过对SCL和SDA线高低电平时序的控制,来 产生I2C总线协议所需要的信号进行数据的传递。在
    发表于 11-30 08:29

    串行通信中的IIC总线工作原理是什么

    串行通信中的IIC总线工作原理51本身不带IIC总线 ,使用程序模拟IIC通信
    发表于 12-08 07:52

    IIC协议的相关资料推荐

    STM32 IIC实验讲解,从入门到放弃。文章目录STM32 IIC实验讲解,从入门到放弃。前言、IICIIC是什么?IIC协议二、代码部
    发表于 01-17 08:12

    IIC总线接口学习

    在多主设备IIC 总线模式下,多个S3C2440A 微处理器可以从从属设备接收或发送串行数据。主设备S3C2440A 可以初始化和终止
    发表于 04-27 15:31 61次下载
    <b class='flag-5'>IIC</b><b class='flag-5'>总线</b>接口学习

    IIC总线协议

    IIC总线协议,感兴趣的小伙伴们可以看看。
    发表于 07-26 16:29 58次下载

    FPGA基础知识IIC协议读写解析

    很多数字传感器、数字控制的芯片(DDS、串行ADC、串行DAC)都是通过IIC总线来和控制器通信的。不过IIC
    发表于 05-05 10:17 8218次阅读
    FPGA基础知识<b class='flag-5'>之</b><b class='flag-5'>IIC</b><b class='flag-5'>协议</b>读写解析

    IIC总线协议及应用

    (串行数据线)和SCL(串行时钟线)及上拉电阻组成。通信原理是通过对SCL和SDA线高低电平时序的控制,来 产生I2C总线协议所需要的信号进行数据的传递。在
    发表于 11-20 15:21 10次下载
    <b class='flag-5'>IIC</b><b class='flag-5'>总线</b><b class='flag-5'>协议</b>及应用

    STC89C52的IIC总线写EEPROM

    串行通信中的IIC总线工作原理51本身不带IIC总线 ,使用程序模拟IIC通信
    发表于 11-25 15:51 11次下载
    STC89C52的<b class='flag-5'>IIC</b><b class='flag-5'>总线</b>写EEPROM

    带你迅速了解常用串行总线IIC协议1

    集成电路总线** (Inter-Intergrated Circuit),通常称作IICBUS,简称为IIC,是种采用多主从结构的串行通信总线
    的头像 发表于 01-21 17:19 1798次阅读
    <b class='flag-5'>一</b><b class='flag-5'>文</b><b class='flag-5'>带你</b><b class='flag-5'>迅速</b><b class='flag-5'>了解</b><b class='flag-5'>常用</b><b class='flag-5'>串行</b><b class='flag-5'>总线</b><b class='flag-5'>之</b><b class='flag-5'>IIC</b><b class='flag-5'>协议</b>1

    带你迅速了解常用串行总线IIC协议2

    集成电路总线** (Inter-Intergrated Circuit),通常称作IICBUS,简称为IIC,是种采用多主从结构的串行通信总线
    的头像 发表于 01-21 17:20 1032次阅读