// iic master module
module i2c_demo(
input sysClk ,
input sysRst ,
input[7:0] pid_slave_addr ,
input[7:0] pid_op_len ,
input pid_init ,
input[7:0] pid_reg_addr ,//addr
input[7:0] pid_data ,//data
inout pio_sda ,
output reg pod_scl ,
output reg[7:0] pod_rxd ,
output reg pod_rxv ,
output reg pod_rdy
);
reg i2c_sda = 1'b0 ;
reg i2c_wren = 1'b0 ;
reg[7:0] reg_in = 8'd0 ;
reg[7:0] data_in = 8'd0 ;
reg init_in = 4'd0 ;
reg[7:0] op_len = 8'd0 ;
reg[7:0] slave_id = 8'd0 ;
reg op_type = 1'b0 ;
assign pio_sda = i2c_wren ? i2c_sda : 1'bz ;
always@(posedge sysClk)
if(pid_init) reg_in <= pid_reg_addr ;
else reg_in <= reg_in ;
always@(posedge sysClk)
if(pid_init) data_in <= pid_data ;
else data_in <= data_in ;
always@(posedge sysClk) init_in <= pid_init ;
always@(posedge sysClk) op_type <= slave_id[0] ;//1-->READ 0-->WRITE
always@(posedge sysClk)
if(pid_init) slave_id <= pid_slave_addr ;
else slave_id <= slave_id ;
always@(posedge sysClk)
if(pid_init) op_len <= pid_op_len ;
else op_len <= op_len ;
reg[7:0] sclk_cnt = 8'd0 ;
reg[3:0] bit_cnt = 8'd0 ;
reg sclk_en = 1'b0 ;
reg scl_Fedge = 1'b0 ;
reg scl_high = 1'b0 ;
reg slave_ack = 1'b0 ;
reg scl_add = 1'b0 ;
reg[11:0] timer_out = 12'd0 ;
reg[7:0] dly = 8'd0 ;
reg[7:0] op_cnt = 8'd0 ;
reg[7:0] tx_cnt = 8'd0 ;//统计已经发送数据的个数
localparam IDLE = 4'd0 ;
localparam I2C_START = 4'd1 ;
localparam I2C_TXD = 4'd2 ;
localparam S_ACK = 4'd3 ;
localparam I2C_DONE = 4'd4 ;
localparam M_ACK = 4'd5 ;
localparam I2C_STOP = 4'd6 ;
localparam I2C_ADD = 4'd7 ;
localparam I2C_RXD = 4'd8 ;
reg task_done = 1'b0 ;
reg[3:0] STATE = IDLE ;
reg[3:0] NEXT_STATE = IDLE ;
always@(posedge sysClk or posedge sysRst)
if(sysRst) STATE <= IDLE ;
else if(init_in) STATE <= I2C_START ;
else STATE <= NEXT_STATE ;
always@(*)
case(STATE)
IDLE : begin
NEXT_STATE = IDLE ;
end
I2C_START : begin
if(scl_Fedge)
NEXT_STATE = I2C_TXD ;
else NEXT_STATE = I2C_START ;
end
I2C_TXD : begin
if(bit_cnt[3] & bit_cnt[0])
NEXT_STATE = S_ACK ;
else NEXT_STATE = I2C_TXD ;
end
S_ACK : begin
if(~slave_ack)
NEXT_STATE = I2C_DONE ;
else if(timer_out[7])
NEXT_STATE = IDLE ;
else NEXT_STATE = S_ACK ;
end
I2C_DONE : begin //判断是否完成一次操作
if(~scl_Fedge)
NEXT_STATE = I2C_DONE ;
else if(task_done)
NEXT_STATE = I2C_STOP ;
else NEXT_STATE = I2C_ADD ;
end
I2C_RXD : begin
if(bit_cnt[3] & bit_cnt[0])
NEXT_STATE = M_ACK ;
else NEXT_STATE = I2C_RXD ;
end
M_ACK : begin
if(scl_Fedge)
NEXT_STATE = I2C_DONE ;
else NEXT_STATE = M_ACK ;
end
I2C_ADD : begin
if(op_type) NEXT_STATE = I2C_RXD ;
else NEXT_STATE = I2C_TXD ;
end
I2C_STOP : begin
if(&dly[7:4]) NEXT_STATE = IDLE ;
else NEXT_STATE = I2C_STOP ;
end
default : ;
endcase
// 等待128个时钟,如果clk是25M,则已经等待了5us.
always@(posedge sysClk)
if(STATE==I2C_STOP) dly <= dly + 1'b1 ;
else dly <= 8'd0 ;
always@(posedge sysClk)
if(STATE==IDLE) sclk_en <= 1'b0 ;
else sclk_en <= 1'b1 ;
always@(posedge sysClk)
if(sclk_en) sclk_cnt <= sclk_cnt + 1'b1 ;
else sclk_cnt <= 8'h80 ;
//---------------
always@(posedge sysClk) pod_scl <= sclk_cnt[7] ;
reg tx_flg = 1'b0 ;
reg sda = 1'b0 ;
reg get_ack = 1'b0 ;
always@(posedge sysClk)
case(STATE)
I2C_START : sda <= 1'b0 ;
I2C_STOP : sda <= 1'b0 ;
IDLE : sda <= 1'b0 ;
default : ;
endcase
always@(posedge sysClk) begin
scl_Fedge <= sclk_cnt>=8'hfe && sclk_cnt<=8'hff ;
scl_add <= sclk_cnt==8'h40 ;
scl_high <= sclk_cnt>=8'h80 && sclk_cnt<=8'h84 ;
get_ack <= sclk_cnt>=8'h82 && sclk_cnt<=8'h88 ;
end
reg sda_in = 1'b0 ;
always@(posedge sysClk) sda_in <= pio_sda ;
//-------- 只用记录ack即可,可以暂时不用管ack是否回复。
reg ack_in = 1'b0 ;
always@(posedge sysClk)
if(scl_high) ack_in <= sda_in ;
else ack_in <= ack_in ;
always@(posedge sysClk)
if(get_ack) slave_ack <= sda_in ;//sda_in
else slave_ack <= slave_ack ;
always@(posedge sysClk)
if(STATE==S_ACK) timer_out <= timer_out + 1'b1 ;
else timer_out <= 12'd0 ;
always@(posedge sysClk)
if(~tx_flg) bit_cnt <= 4'd0 ;
else if(scl_add) bit_cnt <= bit_cnt + 1'b1 ;
else bit_cnt <= bit_cnt ;
always@(posedge sysClk) task_done <= op_cnt>=op_len ;
always@(posedge sysClk)
case(STATE)
I2C_START : op_cnt <= 4'd0 ;
I2C_ADD : op_cnt <= op_cnt + 1'b1 ;
default : ;
endcase
reg[7:0] tx_data = 8'd0;
always@(posedge sysClk)
case(op_cnt)
8'd0 : tx_data <= slave_id ;
8'd1 : tx_data <= reg_in ;
8'd2 : tx_data <= data_in ;
default : ;
endcase
reg txd = 1'b0 ;
always@(posedge sysClk)
case(bit_cnt)
4'd1 : txd <= tx_data[7] ;
4'd2 : txd <= tx_data[6] ;
4'd3 : txd <= tx_data[5] ;
4'd4 : txd <= tx_data[4] ;
4'd5 : txd <= tx_data[3] ;
4'd6 : txd <= tx_data[2] ;
4'd7 : txd <= tx_data[1] ;
4'd8 : txd <= tx_data[0] ;
default : ;
endcase
always@(posedge sysClk)
if(STATE==I2C_TXD || STATE==I2C_RXD)
tx_flg <= 1'b1 ;
else tx_flg <= 1'b0 ;
always@(posedge sysClk)
if(tx_flg) i2c_sda <= txd ;
else i2c_sda <= 1'b0 ;//sda
always@(posedge sysClk)
if(STATE==IDLE || STATE==S_ACK || STATE==I2C_DONE || STATE==I2C_RXD)
i2c_wren <= 1'b0 ;
else i2c_wren <= 1'b1 ;
reg get_ack_dly;
always @ (posedge sysClk)
get_ack_dly <= get_ack;
reg[7:0] rxd = 8'd0 ;
always@(posedge sysClk)
case(bit_cnt)
4'd1 : rxd[7] <= slave_ack ;
4'd2 : rxd[6] <= slave_ack ;
4'd3 : rxd[5] <= slave_ack ;
4'd4 : rxd[4] <= slave_ack ;
4'd5 : rxd[3] <= slave_ack ;
4'd6 : rxd[2] <= slave_ack ;
4'd7 : rxd[1] <= slave_ack ;
4'd8 : rxd[0] <= slave_ack ;
default : ;
endcase
always@(posedge sysClk)
if(bit_cnt[3] & scl_Fedge)
pod_rxd <= rxd ;
else pod_rxd <= pod_rxd ;
always@(posedge sysClk) pod_rxv <= STATE==M_ACK ;
always@(posedge sysClk)
if(STATE==IDLE) pod_rdy <= 1'b1 ;
else pod_rdy <= 1'b0 ;
endmodule