1

I'm creating the I2C protocol in verilog to read data from a sensor (BMP180), AS you know, the sensor sends me a bit of ack recognition. How do I use the inout i2c_sda port to send and how do I receive.

As delivery and receipt i2c_sda the same line, if my variable is declared of type 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 Answer 1

2

If you have a module pin defined as

inout wire pin

then you can access it like so

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

this should infer a tristate buffer.

However, I would be careful when doing this, as if you infer a tristate buffer too early, it can limit what you can do with the module. For example, it would be possible to connect multiple internal I2C components together, such as allowing multiple masters inside the FPGA access to the same pins. However, tristate signals cannot be routed inside the FPGA, so if you implement the tristate inside the I2C master module, this becomes impossible. Instead, what you might consider is implementing each pin as three module pins: input, output, and output enable/tristate. This allows multiple modules to be connected with an emulated tristate bus, and allows them to share one set of tristate buffers to the actual I/O pin on the chip.

For a good example of how this works, see the comments in https://github.com/alexforencich/verilog-i2c/blob/master/rtl/i2c_master.v .

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.