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

电子说

1.2w人已加入

描述

2. 组帧模块 (i2c_ctrl):

module i2c_ctrl

(

input rst,

input clk,

input[15:0] clk_div_cnt,

// I2C signals

// i2c clock line

input scl_pad_i, //SCL-line input

output scl_pad_o, //SCL-line output (always 1'b0)

output scl_padoen_o, //SCL-line output enable (active low)

// i2c data line

input sda_pad_i, //SDA-line input

output sda_pad_o, //SDA-line output (always 1'b0)

output sda_padoen_o, //SDA-line output enable (active low)

input i2c_addr_2byte, //register address 16bit or 8bit

input i2c_read_req, //Read register request

output i2c_read_req_ack, //Read register request response

input i2c_write_req, //Write register request

output i2c_write_req_ack, //Write register request response

input[7:0] i2c_slave_dev_addr, //I2c device address

input[15:0] i2c_slave_reg_addr, //I2c register address

input[7:0] i2c_write_data, //I2c write register data

output reg[7:0] i2c_read_data,//I2c read register data

output reg error //The error indication, generally there is no response

);

//State machine definition cascatrix carson

localparam S_IDLE= 0;

localparam S_WR_DEV_ADDR=1;

localparam S_WR_REG_ADDR=2;

localparam S_WR_DATA=3;

localparam S_WR_ACK=4;

localparam S_WR_ERR_NACK=5;

localparam S_RD_DEV_ADDR0=6;

localparam S_RD_REG_ADDR=7;

localparam S_RD_DEV_ADDR1=8;

localparam S_RD_DATA=9;

localparam S_RD_STOP=10;

localparam S_WR_STOP=11;

localparam S_WAIT=12;

localparam S_WR_REG_ADDR1=13;

localparam S_RD_REG_ADDR1=14;

localparam S_RD_ACK=15;

reg start;

reg stop;

reg read;

reg write;

reg ack_in;

reg[7:0] txr;

wire[7:0] rxr;

wire i2c_busy;

wire i2c_al;

wire done;

wire irxack;

reg[3:0] state, next_state;

assign i2c_read_req_ack = (state == S_RD_ACK);

assign i2c_write_req_ack = (state == S_WR_ACK);

always@(posedge clk or posedge rst)

begin

if(rst)

    state <= S_IDLE;

else

    state <= next_state;

end

always@(*)

begin

case(state)

S_IDLE:

//Waiting for read and write requests

    if(i2c_write_req)

        next_state <= S_WR_DEV_ADDR;

    else if(i2c_read_req)

        next_state <= S_RD_DEV_ADDR0;

    else

        next_state <= S_IDLE;

//Write I2C device address

S_WR_DEV_ADDR:

    if(done && irxack)

        next_state <= S_WR_ERR_NACK;

    else if(done)

        next_state <= S_WR_REG_ADDR;

    else

        next_state <= S_WR_DEV_ADDR;

//Write the address of the I2C register

S_WR_REG_ADDR:

    if(done)

//If it is the 8bit register address, it enters the write data state

    next_state<=i2c_addr_2byte? S_WR_REG_AD DR1  : S_WR_DATA;

    else

        next_state <= S_WR_REG_ADDR;

S_WR_REG_ADDR1:

    if(done)

        next_state <= S_WR_DATA;

    else

        next_state <= S_WR_REG_ADDR1; 

//Write data

S_WR_DATA:

    if(done)

        next_state <= S_WR_STOP;

    else

        next_state <= S_WR_DATA;

S_WR_ERR_NACK:

    next_state <= S_WR_STOP;

S_RD_ACK,S_WR_ACK:

    next_state <= S_WAIT;

S_WAIT:

    next_state <= S_IDLE;

S_RD_DEV_ADDR0:

    if(done && irxack)

        next_state <= S_WR_ERR_NACK;

    else if(done)

        next_state <= S_RD_REG_ADDR;

    else

        next_state <= S_RD_DEV_ADDR0;

S_RD_REG_ADDR:

    if(done)

    next_state<=i2c_addr_2byte?S_RD_REG_ADDR1 : S_RD_DEV_ADDR1;

    else

        next_state <= S_RD_REG_ADDR;

S_RD_REG_ADDR1:

    if(done)

        next_state <= S_RD_DEV_ADDR1;

    else

        next_state <= S_RD_REG_ADDR1;               

S_RD_DEV_ADDR1:

    if(done)

        next_state <= S_RD_DATA;

    else

        next_state <= S_RD_DEV_ADDR1;   

S_RD_DATA:

    if(done)

        next_state <= S_RD_STOP;

    else

        next_state <= S_RD_DATA;

S_RD_STOP:

    if(done)

        next_state <= S_RD_ACK;

    else

        next_state <= S_RD_STOP;

S_WR_STOP:

    if(done)

        next_state <= S_WR_ACK;

    else

        next_state <= S_WR_STOP;                

default:

    next_state <= S_IDLE;

endcase

end

always@(posedge clk or posedge rst)

begin

if(rst)

    error <= 1'b0;

else if(state == S_IDLE)

    error <= 1'b0;

else if(state == S_WR_ERR_NACK)

    error <= 1'b1;

end

always@(posedge clk or posedge rst)

begin

if(rst)

    start <= 1'b0;

else if(done)

    start <= 1'b0;

else if(state == S_WR_DEV_ADDR || state == S_RD_DEV_ADDR0 || state == S_RD_DEV_ADDR1)

start <= 1'b1;

end

always@(posedge clk or posedge rst)

begin

if(rst)

    stop <= 1'b0;

else if(done)

    stop <= 1'b0;

else if(state == S_WR_STOP || state == S_RD_STOP)

    stop <= 1'b1;

end

always@(posedge clk or posedge rst)

begin

if(rst)

    ack_in <= 1'b0;

else 

    ack_in <= 1'b1;

end

always@(posedge clk or posedge rst)

begin

if(rst)

    write <= 1'b0;

else if(done)

    write <= 1'b0;

else if(state == S_WR_DEV_ADDR || state == S_WR_REG_ADDR || state == S_WR_REG_ADDR1|| state == S_WR_DATA || state == S_RD_DEV_ADDR0 || state == S_RD_DEV_ADDR1 || state == S_RD_REG_ADDR || state == S_RD_REG_ADDR1)

write <= 1'b1;

end

always@(posedge clk or posedge rst)

begin

if(rst)

    read <= 1'b0;

else if(done)

    read <= 1'b0;

else if(state == S_RD_DATA)

    read <= 1'b1;

end

always@(posedge clk or posedge rst)

begin

if(rst)

    i2c_read_data <= 8'h00;

else if(state == S_RD_DATA && done)

    i2c_read_data <= rxr;

end

always@(posedge clk or posedge rst)

begin

if(rst)

    txr <= 8'd0;

else 

case(state)

S_WR_DEV_ADDR,S_RD_DEV_ADDR0:

    txr <= {i2c_slave_dev_addr[7:1],1'b0};

S_RD_DEV_ADDR1:

    txr <= {i2c_slave_dev_addr[7:1],1'b1};

S_WR_REG_ADDR,S_RD_REG_ADDR:

txr<=(i2c_addr_2byte==1'b1)?i2c_slave_reg_addr[15 :8] : i2c_slave_reg_addr[7:0];

S_WR_REG_ADDR1,S_RD_REG_ADDR1:

    txr <= i2c_slave_reg_addr[7:0];             

S_WR_DATA:

    txr <= i2c_write_data;

default:

    txr <= 8'hff;

endcase

end

i2c_byte_ctrl byte_controller (

.clk ( clk ),

.rst ( rst ),

.nReset ( 1'b1 ),

.ena ( 1'b1 ),

.clk_cnt ( clk_div_cnt ),

.start ( start ),

.stop ( stop ),

.read ( read ),

.write ( write ),

.ack_in ( ack_in ),

.din ( txr ),

.cmd_ack ( done ),

.ack_out ( irxack ),

.dout ( rxr ),

.i2c_busy ( i2c_busy ),

.i2c_al ( i2c_al ),

.scl_i ( scl_pad_i ),

.scl_o ( scl_pad_o ),

.scl_oen ( scl_padoen_o ),

.sda_i ( sda_pad_i ),

.sda_o ( sda_pad_o ),

.sda_oen ( sda_padoen_o )

);

endmodule

3. 字节控制模块(i2c_byte_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_byte_ctrl (

input clk, // master clock

input rst, // synchronous active high reset

input nReset, // asynchronous active low reset

input ena, // core enable signal

input [15:0] clk_cnt, // 4x SCL

// control inputs

input start,

input stop,

input read,

input write,

input ack_in,

input [7:0] din,

// status outputs

output reg cmd_ack,

output reg ack_out,

output i2c_busy,

output i2c_al,

output [7:0] dout,

// I2C signals

input scl_i,

output scl_o,

output scl_oen,

input sda_i,

output sda_o,

output sda_oen

);

//

// Variable declarations cascatrix carson

//

// statemachine

parameter [4:0] ST_IDLE = 5'b0_0000;

parameter [4:0] ST_START = 5'b0_0001;

parameter [4:0] ST_READ = 5'b0_0010;

parameter [4:0] ST_WRITE = 5'b0_0100;

parameter [4:0] ST_ACK = 5'b0_1000;

parameter [4:0] ST_STOP = 5'b1_0000;

// signals for bit_controller

reg [3:0] core_cmd;

reg core_txd;

wire core_ack, core_rxd;

// signals for shift register

reg [7:0] sr; //8bit shift register

reg shift, ld;

// signals for state machine

wire go;

reg [2:0] dcnt;

wire cnt_done;

// bit_controller

i2c_bit_ctrl bit_controller (

.clk ( clk ),

.rst ( rst ),

.nReset ( nReset ),

.ena ( ena ),

.clk_cnt ( clk_cnt ),

.cmd ( core_cmd ),

.cmd_ack ( core_ack ),

.busy ( i2c_busy ),

.al ( i2c_al ),

.din ( core_txd ),

.dout ( core_rxd ),

.scl_i ( scl_i ),

.scl_o ( scl_o ),

.scl_oen ( scl_oen ),

.sda_i ( sda_i ),

.sda_o ( sda_o ),

.sda_oen ( sda_oen )

);

// generate go-signal

assign go = (read | write | stop) & ~cmd_ack;

// assign dout output to shift-register

assign dout = sr;

// generate shift register

always @(posedge clk or negedge nReset)

if (!nReset)

sr <= #1 8'h0;

else if (rst)

sr <= #1 8'h0;

else if (ld)

sr <= #1 din;

else if (shift)

sr <= #1 {sr[6:0], core_rxd};

// generate counter

always @(posedge clk or negedge nReset)

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;

assign cnt_done = ~(|dcnt);

//

// state machine

//

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

always @(posedge clk or negedge nReset)

if (!nReset)

begin

    core_cmd <= #1 `I2C_CMD_NOP;

    core_txd <= #1 1'b0;

    shift    <= #1 1'b0;

    ld       <= #1 1'b0;

    cmd_ack  <= #1 1'b0;

    c_state  <= #1 ST_IDLE;

    ack_out  <= #1 1'b0;

end

else if (rst | i2c_al)

begin

core_cmd <= #1 `I2C_CMD_NOP;

   core_txd <= #1 1'b0;

   shift    <= #1 1'b0;

   ld       <= #1 1'b0;

   cmd_ack  <= #1 1'b0;

   c_state  <= #1 ST_IDLE;

   ack_out  <= #1 1'b0;

end

else

begin

// initially reset all signals

  core_txd <= #1 sr[7];

  shift    <= #1 1'b0;

  ld       <= #1 1'b0;

  cmd_ack  <= #1 1'b0;

  case (c_state) // synopsys full_case parallel_case

    ST_IDLE:

      if (go)

        begin

            if (start)

              begin

                  c_state  <= #1 ST_START;

                  core_cmd <= #1 `I2C_CMD_START;

              end

            else if (read)

              begin

                  c_state  <= #1 ST_READ;

                  core_cmd <= #1 `I2C_CMD_READ;

              end

            else if (write)

              begin

                  c_state  <= #1 ST_WRITE;

                  core_cmd <= #1 `I2C_CMD_WRITE;

              end

            else // stop

              begin

                  c_state  <= #1 ST_STOP;

                  core_cmd <= #1 `I2C_CMD_STOP;

              end

            ld <= #1 1'b1;

        end

    ST_START:

      if (core_ack)

        begin

            if (read)

              begin

                  c_state  <= #1 ST_READ;

                  core_cmd <= #1 `I2C_CMD_READ;

              end

            else

              begin

                  c_state  <= #1 ST_WRITE;

                  core_cmd <= #1 `I2C_CMD_WRITE;

              end

            ld <= #1 1'b1;

        end

    ST_WRITE:

      if (core_ack)

        if (cnt_done)

          begin

              c_state  <= #1 ST_ACK;

              core_cmd <= #1 `I2C_CMD_READ;

          end

        else

          begin

                // stay in same state

              c_state  <= #1 ST_WRITE;       

                // write next bit

              core_cmd <= #1 `I2C_CMD_WRITE; 

              shift    <= #1 1'b1;

          end

    ST_READ:

      if (core_ack)

        begin

            if (cnt_done)

              begin

                  c_state  <= #1 ST_ACK;

                  core_cmd <= #1 `I2C_CMD_WRITE;

              end

            else

              begin

                    // stay in same state

                  c_state  <= #1 ST_READ;       

                     // read next bit

                  core_cmd <= #1 `I2C_CMD_READ;

              end

            shift    <= #1 1'b1;

            core_txd <= #1 ack_in;

        end

    ST_ACK:

      if (core_ack)

        begin

           if (stop)

             begin

                 c_state  <= #1 ST_STOP;

                 core_cmd <= #1 `I2C_CMD_STOP;

             end

           else

             begin

                 c_state  <= #1 ST_IDLE;

                 core_cmd <= #1 `I2C_CMD_NOP;

                 // generate command acknowledge signal

                 cmd_ack  <= #1 1'b1;

             end

             // assign ack_out output to bit_controller_rxd (contains last received bit)

             ack_out <= #1 core_rxd;

             core_txd <= #1 1'b1;

         end

       else

         core_txd <= #1 ack_in;

    ST_STOP:

      if (core_ack)

        begin

            c_state  <= #1 ST_IDLE;

            core_cmd <= #1 `I2C_CMD_NOP;

            // generate command acknowledge signal

            cmd_ack  <= #1 1'b1;

        end

  endcase

end

endmodule

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分