inout verilog协议I2C

时间:2015-12-06 19:23:48

标签: verilog fpga i2c

我在verilog中创建I2C协议以从传感器(BMP180)读取数据,如您所知,传感器向我发送了一些ack识别。如何使用inout i2c_sda端口发送以及如何接收。

当交付和收货i2c_sda在同一行时,如果我的变量被声明为inout类型。

module stepPrueba( 
    input wire      clk1,
    input wire  reset,
     input wire     start,
    inout           i2c_sda,
    inout           i2c_scl,
     output wire    ready,
     output reg led1,
     output reg led2
    );



    reg i2c_scl_out;
    assign i2c_scl1= (i2c_scl_out == 1'b0) ? 1'b0 : 1'bz;
     wire i2c_scl_in = i2c_scl;

     assign i2c_scl = (i2c_scl_enable == 0) ? i2c_scl1 : clk1;  
    reg clk;


     assign clk1 = (clk == 1)? 1'bz:1'b0;

    reg i2c_sda_out;
    assign i2c_sda = (i2c_sda_out == 1'b0) ? 1'b0 : 1'bz;
    wire i2c_sda_in = i2c_sda ;




     reg    [6:0] addr;
     reg    [7:0] data;
     reg enable; //(read=1, write=0)
    reg datas;
     reg enable2; //(read=1, write = 0)
     reg [7:0] state;
     reg [7:0] count;
     reg i2c_scl_enable = 0;
     reg [6:0] saved_addr;
     reg [7:0] saved_data;





//goal es escribir al dispositivo direccion 0X55, 0Xaa
    localparam STATE_IDLE = 0;
    localparam STATE_START = 1;
    localparam STATE_ADDR =2;
    localparam STATE_RW = 3;    
    localparam STATE_WACK = 4;  
    localparam STATE_DATA = 5;  
    localparam STATE_WACK2 = 6;
    localparam STATE_STOP = 7;  


always@(posedge clk) 
    begin
      //enable2 <= 0; //i2c_scl==zetas & c_lectura=z;
      if(reset == 1) 
         begin
           i2c_scl_out<=1; 
           i2c_scl_enable <= 0; 
         end
        else 
          begin
             if((state == STATE_IDLE) || (state == STATE_START) ) 
              begin
                //i2c_scl_enable <= 0; //dats == 1 --> ztas == z
                 i2c_scl_out<=1; 
               i2c_scl_enable <= 0; 
              end
            else 
              begin
                i2c_scl_enable <= 1; // dats==clk;
                 clk<=clk1;
             end
         end 
    end


always@(posedge clk) 
    begin
       if(reset == 1) 
          begin
            led1 <=0;
            led2 <=0;
            state <=0;
             i2c_sda_out <= 1;// i2c_sda ==z;
            addr <= 7'b1110111; // direccion del sensor
            count <= 8'd0;
            data <= 8'b11110100; //direccion interna PRESION
         end
       else //reset ==0
          begin

            case (state)

             STATE_IDLE: 
                begin //idle
                   //datas <= 1;  //zetas==z
                    i2c_scl_out<=1; 
                 i2c_scl_enable <= 0; 

                    i2c_sda_out <= 1;
                   if(start) 
                     begin
                        state <= STATE_START;
                        saved_addr <= addr;
                        saved_data <= data;



                 // reg i2c_scl_out;
              // assign i2c_scl1= (i2c_scl_out == 1'b0) ? 1'b0 : 1'bz;
               // wire i2c_scl_in = i2c_scl;
               // assign i2c_scl = (i2c_scl_enable == 0) ? i2c_scl1 : ~clk;  


                     end
                   else 
                     begin
                       state <= STATE_IDLE;
                     end
                end

            STATE_START: 
               begin // start
                  //enable <= 0; // lectura==z; --> i2c_sda==zetas
                  i2c_sda_out <= 0;
                  //datas <= 0; // zetas==0 
                  state<= STATE_ADDR;
                  count <= 6;               
               end

            STATE_ADDR: 
               begin //msb addres bit
                  //enable <= 0; // lectura==z; --> i2c_sda==zetas
                  i2c_sda_out <= saved_addr[count]; // datas ==0 --> zetas==0 || datas==1 --> zetas==z
                  if (count == 0) 
                    begin
                       state <= STATE_RW;
                     end
                  else 
                    begin
                       count <= count - 1;
                     end
               end

            STATE_RW: 
               begin
                  //enable <= 0; //enable==0 --> i2c_sda==zetas
                  i2c_sda_out <= 0;//datas <= 0;
                  state <= STATE_WACK;
               end

            STATE_WACK: 
               begin
                  //enable <= 1; //enable==1 lee  i2c_sda==z & lectura==i2c_sda

                   //enable <= 0; 
                   //if(APA)
                  if(i2c_sda_in==1)
                    begin
                       state <= STATE_IDLE;
                    end 
                  else 
                    begin
                   state <= STATE_DATA;
                       led1 <= 1;
                   end
                  count <= 7;
               end

            STATE_DATA: 
               begin
                  //enable <= 0;
                  i2c_sda_out <= saved_data[count];
                  if(count ==0) 
                    begin
                      state <= STATE_WACK2;
                    end
                  else 
                    begin 
                      count <= count - 1;
                end                  
               end

            STATE_WACK2: 
               begin
                  //enable <= 1;
                  if(i2c_sda_in ==1)
                    begin
                       state <= STATE_IDLE;
                     end 
                  else 
                    begin
                       state <= STATE_STOP;
                       led2 <= 1;
                     end
               end

            STATE_STOP: 
               begin
                  //enable <= 0;
                  i2c_sda_out <= 0;
                  state <= STATE_IDLE;
               end
       endcase
   end
end
endmodule

1 个答案:

答案 0 :(得分:1)

如果您将模块引脚定义为

inout wire pin

然后您可以像这样访问它

wire pin_input = pin;
assign pin = pin_oe ? pin_output : 1'bz;

这应该推断出一个三态缓冲区。

但是,在这样做时我会小心,就好像你过早地推断出三态缓冲区一样,它可以限制你可以用模块做什么。例如,可以将多个内部I2C组件连接在一起,例如允许FPGA内部的多个主器件访问相同的引脚。但是,三态信号不能在FPGA内部路由,因此如果在I2C主模块内部实现三态,则无法实现。相反,您可能会考虑将每个引脚实现为三个模块引脚:输入,输出和输出使能/三态。这允许多个模块与模拟的三态总线连接,并允许它们将一组三态缓冲器共享到芯片上的实际I / O引脚。

有关其工作原理的一个很好的示例,请参阅https://github.com/alexforencich/verilog-i2c/blob/master/rtl/i2c_master.v中的注释。