0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

一文帶你迅速了解常用串行總線之IIC協(xié)議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的優(yōu)缺點

4.1 IIC協(xié)議優(yōu)點

  1. 通信只需要兩條信號線;
  2. 多主設(shè)備結(jié)構(gòu)下,總線系統(tǒng)無需額外的邏輯與線路;
  3. 應(yīng)答機(jī)制完善,通信傳輸穩(wěn)定。

4.2 IIC協(xié)議缺點

  1. 硬件結(jié)構(gòu)復(fù)雜;
  2. 支持傳輸距離較短;
  3. 半雙工速率慢于全雙工,SPI全雙工一般可實現(xiàn)10Mbps以上的傳輸速率,IIC最高速度僅能達(dá)到3.4Mbps。
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • IIC
    IIC
    +關(guān)注

    關(guān)注

    11

    文章

    292

    瀏覽量

    38142
  • 通信總線
    +關(guān)注

    關(guān)注

    0

    文章

    43

    瀏覽量

    9817
  • SDA
    SDA
    +關(guān)注

    關(guān)注

    0

    文章

    123

    瀏覽量

    27956
收藏 人收藏

    評論

    相關(guān)推薦

    詳解IIC總線

    IIC(Inter-Integrated Circuit)集成電路總線,它是種兩線式串行通信總線,又叫I2C,使用多主從架構(gòu),由飛利浦公司
    發(fā)表于 06-07 15:38 ?8821次閱讀
    <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,是由飛利浦公司發(fā)明的通訊總線,屬于半雙工同步傳
    發(fā)表于 09-12 11:15 ?1742次閱讀
    <b class='flag-5'>一</b><b class='flag-5'>文</b>詳解<b class='flag-5'>IIC</b><b class='flag-5'>總線</b>

    IIC總線協(xié)議與SCCB協(xié)議的區(qū)別

    先簡單介紹IIC總線協(xié)議。IIC總線是philips公司推出的新
    發(fā)表于 08-07 12:43

    常用串行總線協(xié)議有哪些

    、常用串行總線協(xié)議目前常用的微機(jī)與外設(shè)之間進(jìn)行數(shù)據(jù)傳輸?shù)?b class='flag-5'>
    發(fā)表于 11-03 07:14

    常用串行總線協(xié)議有哪些

    常用串行總線協(xié)議I2C總線、SPI總線、SCI總線
    發(fā)表于 11-19 06:46

    IIC總線協(xié)議的相關(guān)資料下載

    (串行數(shù)據(jù)線)和SCL(串行時鐘線)及上拉電阻組成。通信原理是通過對SCL和SDA線高低電平時序的控制,來 產(chǎn)生I2C總線協(xié)議所需要的信號進(jìn)行數(shù)據(jù)的傳遞。在
    發(fā)表于 11-30 08:29

    串行通信中的IIC總線工作原理是什么

    串行通信中的IIC總線工作原理51本身不帶IIC總線 ,使用程序模擬IIC通信
    發(fā)表于 12-08 07:52

    IIC協(xié)議的相關(guān)資料推薦

    STM32 IIC實驗講解,從入門到放棄。文章目錄STM32 IIC實驗講解,從入門到放棄。前言、IICIIC是什么?IIC協(xié)議二、代碼部
    發(fā)表于 01-17 08:12

    IIC總線接口學(xué)習(xí)

    在多主設(shè)備IIC 總線模式下,多個S3C2440A 微處理器可以從從屬設(shè)備接收或發(fā)送串行數(shù)據(jù)。主設(shè)備S3C2440A 可以初始化和終止
    發(fā)表于 04-27 15:31 ?61次下載
    <b class='flag-5'>IIC</b><b class='flag-5'>總線</b>接口學(xué)習(xí)

    IIC總線協(xié)議

    IIC總線協(xié)議,感興趣的小伙伴們可以看看。
    發(fā)表于 07-26 16:29 ?58次下載

    FPGA基礎(chǔ)知識IIC協(xié)議讀寫解析

    很多數(shù)字傳感器、數(shù)字控制的芯片(DDS、串行ADC、串行DAC)都是通過IIC總線來和控制器通信的。不過IIC
    發(fā)表于 05-05 10:17 ?8147次閱讀
    FPGA基礎(chǔ)知識<b class='flag-5'>之</b><b class='flag-5'>IIC</b><b class='flag-5'>協(xié)議</b>讀寫解析

    IIC總線協(xié)議及應(yīng)用

    (串行數(shù)據(jù)線)和SCL(串行時鐘線)及上拉電阻組成。通信原理是通過對SCL和SDA線高低電平時序的控制,來 產(chǎn)生I2C總線協(xié)議所需要的信號進(jìn)行數(shù)據(jù)的傳遞。在
    發(fā)表于 11-20 15:21 ?10次下載
    <b class='flag-5'>IIC</b><b class='flag-5'>總線</b><b class='flag-5'>協(xié)議</b>及應(yīng)用

    STC89C52的IIC總線寫EEPROM

    串行通信中的IIC總線工作原理51本身不帶IIC總線 ,使用程序模擬IIC通信
    發(fā)表于 11-25 15:51 ?11次下載
    STC89C52的<b class='flag-5'>IIC</b><b class='flag-5'>總線</b>寫EEPROM

    帶你迅速了解常用串行總線IIC協(xié)議1

    集成電路總線** (Inter-Intergrated Circuit),通常稱作IICBUS,簡稱為IIC,是種采用多主從結(jié)構(gòu)的串行通信總線
    的頭像 發(fā)表于 01-21 17:19 ?1678次閱讀
    <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'>協(xié)議</b>1

    帶你迅速了解常用串行總線IIC協(xié)議2

    集成電路總線** (Inter-Intergrated Circuit),通常稱作IICBUS,簡稱為IIC,是種采用多主從結(jié)構(gòu)的串行通信總線
    的頭像 發(fā)表于 01-21 17:20 ?956次閱讀