module slave_iic
(
input reset,
input sclk,
inout sda,
inout scl
);
parameter ST0 = 0,
ST1 = 1,
ST2 = 2,
ST3 = 3,
ST4 = 4,
ST5 = 5,
ST6 = 6,
ST7 = 7,
ST8 = 8,
ST9 = 9,
ST10 = 10,
ST11 = 11,
ST12 = 12,
ST13 = 13,
ST14 = 14,
ST15 = 15;
parameter IDLE = 0,
START = 1,
STOP = 2,
WR_DH = 3,
WR_DL = 4,
MYACK = 5,
RCV_ACK = 6,
RCV_NACK = 7;
wire addr_field;
wire i2c_sss;
wire i2c_ppp;
reg [6:0] SM_SADR;
reg SM_RWn; // R=1, W=0
reg [7:0] bit_cnt;
reg [3:0] sda_reg;
reg [3:0] scl_reg;
reg [7:0] i2c_addr;
reg slave_ack;
reg i2c_run;
always @ (posedge reset or posedge sclk )
begin
if (reset) begin
sda_reg <= 4'hf;
scl_reg <= 4'hf;
end
else begin
sda_reg <= {sda_reg[2:0], sda};
scl_reg <= {scl_reg[2:0], scl};
end
end
assign i2c_sss = ( scl_reg[1:0] == 2'b11 &&
sda_reg[1:0] == 2'b10 ) ? 1 :
0;
assign i2c_ppp = ( scl_reg[1:0] == 2'b11 &&
sda_reg[1:0] == 2'b01 ) ? 1 :
0;
always @ (posedge reset or posedge sclk )
begin
if (reset) begin
i2c_run <= 0;
end
else begin
i2c_run <= ( i2c_sss ) ? 1 :
( i2c_ppp ) ? 0 :
i2c_run ;
end
end
always @ (posedge reset or posedge sclk )
begin
if (reset) begin
SM_SADR <= 0;
//SM_RWn <= 0;
end
else if (bit_cnt == 9) begin
SM_SADR <= i2c_addr[7:1];
//SM_RWn <= i2c_addr[0];
end
end
always @ (posedge reset or posedge sclk )
begin
if (reset) begin
bit_cnt <= 0;
end
else begin
bit_cnt <= ( i2c_sss || i2c_ppp ) ? 0 :
( scl_reg[1:0] == 2'b01 ) ? bit_cnt + 1 :
bit_cnt;
end
end
assign addr_field = ( bit_cnt < 9 ) ? i2c_run :
0;
always @ (posedge reset or posedge sclk )
begin
if (reset) begin
SM_RWn <= 0;
end
else begin
SM_RWn <= ( (bit_cnt == 7) && ( scl_reg[1:0] == 2'b01 ) ) ? sda :
SM_RWn;
end
end
always @ (posedge reset or posedge sclk )
begin
if (reset) begin
i2c_addr <= 0;
end
else if( addr_field ) begin
i2c_addr <= ( scl_reg[1:0] == 2'b01 ) ? { i2c_addr[6:0], sda_reg[2]} :
i2c_addr;
end
end
always @ (posedge reset or posedge sclk )
begin
if (reset) begin
slave_ack <= 0;
end
else begin
slave_ack <= ( bit_cnt == 8 ) ? 1:
0;
end
end
wire ack_time;
assign ack_time = ( bit_cnt == 6 ) ? 1:
( bit_cnt == 14 ) ? 1:
0;
reg [3:0] state;
reg [3:0] fmt_sd;
reg [3:0] fmt_sc;
reg [1:0] ui_cnt;
reg [1:0] ui_cnt_r;
reg [3:0] msb_cnt;
reg sda_wbuf;
reg sda_out_reg;
reg scl_out_reg;
reg [7:0] sda_rbuf;
wire ui_rate;
reg [3:0] format_sel;
wire [7:0] send_byte;
assign send_byte = 8'h89;
always @ (posedge reset or posedge sclk)
begin
if (reset) begin
ui_cnt <= 0;
ui_cnt_r <= 0;
end
else begin
ui_cnt <= ui_cnt - 1;
ui_cnt_r <= ui_cnt;
end
end
assign ui_rate = ( ui_cnt == 2'b11 ) ? 1 :
0;
always @ (posedge reset or posedge sclk)
begin
if (reset) begin
fmt_sd <= 4'b1111;
fmt_sc <= 4'b1111;
end
else if ( ui_rate ) begin
case ( format_sel )
IDLE:begin
fmt_sc <= 4'b1111;
fmt_sd <= 4'b1111;
end
START:begin
fmt_sc <= 4'b1110;
fmt_sd <= 4'b1100;
end
STOP:begin
fmt_sc <= 4'b0111;
fmt_sd <= 4'b0011;
end
WR_DH:begin
fmt_sc <= 4'b0110;
fmt_sd <= 4'b1111;
end
WR_DL:begin
fmt_sc <= 4'b0110;
fmt_sd <= 4'b0000;
end
MYACK:begin
fmt_sc <= 4'b0110;
fmt_sd <= 4'b0000;
end
RCV_ACK:begin // Receive Ack, NACK, Receive DAT
fmt_sc <= 4'b0110;
fmt_sd <= 4'b1111;
end
RCV_NACK:begin
fmt_sc <= 4'b1111;
fmt_sd <= 4'b1111;
end
default: begin
fmt_sc <= 4'b1111;
fmt_sd <= 4'b1111;
end
endcase
end
end
always @ (posedge reset or posedge sclk)
begin
if (reset) begin
state <= ST0;
format_sel <= IDLE;
msb_cnt <= 7;
sda_wbuf <= 0;
sda_rbuf <= 0;
end
else if ( ui_rate ) begin
case ( state )
ST0:begin
state <= ST1;
format_sel <= IDLE;
end
ST1:begin
state <= ST2;
end
ST2:begin
state <= ST3;
end
ST3:begin
state <= ST4;
format_sel <= IDLE;
end
ST4:begin
if ( ack_time ) begin
//state <= (SM_RWn) ? ST5: // SM_RWn: R=1, W=0
// ST8;
state <= ST5;
format_sel <= MYACK;
end
else begin
state <= ST4;
format_sel <= IDLE;
end
end
// Read (Slave -> Master) -----------------------------
ST5:begin
if ( msb_cnt == 0 ) begin // Read
state <= ST6;
msb_cnt <= 7;
sda_wbuf <= send_byte[msb_cnt];
format_sel <= ( send_byte[msb_cnt] ) ? WR_DH :
WR_DL;
end
else begin
state <= ST5;
msb_cnt <= msb_cnt - 1;
sda_wbuf <= send_byte[msb_cnt];
format_sel <= ( send_byte[msb_cnt] ) ? WR_DH :
WR_DL;
end
end
ST6:begin
state <= ST7;
format_sel <= RCV_NACK;
end
ST7:begin
state <= ST3; // IDLE 1 dummy (ST3->ST4)
format_sel <= STOP;
end
// Write (Master -> Slave) -------------------------------
ST8:begin
if ( msb_cnt == 0 ) begin // Read
state <= ST9;
msb_cnt <= 7;
format_sel <= RCV_NACK;
sda_rbuf <= {sda_rbuf[6:0],sda};
end
else begin
state <= ST8;
msb_cnt <= msb_cnt - 1;
format_sel <= RCV_NACK;
sda_rbuf <= {sda_rbuf[6:0],sda};
end
end
ST9:begin
state <= ST10;
format_sel <= MYACK;
sda_rbuf <= {sda_rbuf[6:0],sda};
end
ST10:begin
state <= ST3; // IDLE 1 dummy (ST3->ST4)
format_sel <= IDLE;
sda_rbuf <= {sda_rbuf[6:0],sda};
end
default: begin
state <= ST0;
end
endcase
end
end
always @ (posedge reset or posedge sclk)
begin
if (reset) begin
sda_out_reg <= 0;
scl_out_reg <= 0;
end
else begin
sda_out_reg <= fmt_sd[ui_cnt_r];
scl_out_reg <= fmt_sc[ui_cnt_r];
end
end
assign sda = ( sda_out_reg ) ? 1'bz :
1'b0;
assign scl = ( scl_out_reg ) ? 1'bz :
1'b0;
endmodule
'Verilog' 카테고리의 다른 글
iic testbench (0) | 2021.02.25 |
---|---|
iic master (0) | 2021.02.25 |