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

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

3天内不再提示

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

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

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

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

    关注

    11

    文章

    300

    浏览量

    38269
  • 通信总线
    +关注

    关注

    0

    文章

    44

    浏览量

    9843
  • SDA
    SDA
    +关注

    关注

    0

    文章

    124

    浏览量

    28111
收藏 人收藏

    评论

    相关推荐

    详解IIC总线

    IIC(Inter-Integrated Circuit)集成电路总线,它是种两线式串行通信总线,又叫I
    发表于 06-07 15:38 9638次阅读
    <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 2068次阅读
    <b class='flag-5'>一</b><b class='flag-5'>文</b>详解<b class='flag-5'>IIC</b><b class='flag-5'>总线</b>

    IIC总线串行技术

    IIC总线串行技术的电子书
    发表于 02-19 16:32

    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总线协议,感兴趣的小伙伴们可以看看。
    发表于 07-26 16:29 58次下载

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

    很多数字传感器、数字控制的芯片(DDS、串行ADC、串行DAC)都是通过IIC总线来和控制器通信的。不过IIC
    发表于 05-05 10:17 8217次阅读
    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 1795次阅读
    <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协议3

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