2015-12-06 137 views
0

我在verilog中創建I2C協議以從傳感器(BMP180)讀取數據,如您所知,傳感器向我發送了一些ack識別信息。如何使用inout i2c_sda端口進行發送,以及如何接收。inout verilog協議I2C

由於交收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; 


[email protected](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 


[email protected](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 

回答

0

如果你有一個模塊引腳定義爲

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的意見。