module iic_unit
(
input reset,
input sclk,
input [7:0] address,
input [7:0] command,
input [7:0] data_low,
input [7:0] data_high,
input [3:0] action,
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,
ST16 = 16,
ST17 = 17,
ST18 = 18,
ST19 = 19,
ST20 = 20,
ST21 = 21,
ST22 = 22,
ST23 = 23,
ST24 = 24,
ST25 = 25,
ST26 = 26,
ST27 = 27,
ST28 = 28,
ST29 = 29,
ST30 = 30,
ST31 = 31;
parameter IDLE = 0,
START = 1,
STOP = 2,
WR_DH = 3,
WR_DL = 4,
MYACK = 5,
RCV_ACK = 6,
RCV_NACK = 7;
reg [4: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_reg;
reg scl_reg;
wire ui_rate;
reg [3:0] format_sel;
reg [7:0] sda_rbuf;
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 ( action[0] ) begin
//state <= ST5; // Quick Command
//state <= ST7; // Send Byte protocol
state <= ST11; // Receive Byte protocol
format_sel <= START;
end
else begin
state <= ST4;
format_sel <= IDLE;
end
end
// Quick Command ---------------------------------
ST5:begin
if ( msb_cnt == 0 ) begin
state <= ST6;
msb_cnt <= 7;
sda_wbuf <= address[msb_cnt];
format_sel <= ( address[msb_cnt] ) ? WR_DH:
WR_DL;
end
else begin
state <= ST5;
msb_cnt <= msb_cnt - 1;
sda_wbuf <= address[msb_cnt];
format_sel <= ( address[msb_cnt] ) ? WR_DH:
WR_DL;
end
end
ST6:begin
state <= ST31; // goto STOP sequence
//format_sel <= RCV_ACK; // my clock rcv dat
format_sel <= RCV_NACK; // slave clk rcv dat
end
// Send Byte protocol ----------------------------
ST7:begin
if ( msb_cnt == 0 ) begin // Slave Address
state <= ST8;
msb_cnt <= 7;
sda_wbuf <= address[msb_cnt];
format_sel <= ( address[msb_cnt] ) ? WR_DH:
WR_DL;
end
else begin
state <= ST7;
msb_cnt <= msb_cnt - 1;
sda_wbuf <= address[msb_cnt];
format_sel <= ( address[msb_cnt] ) ? WR_DH:
WR_DL;
end
end
ST8:begin
state <= ST9;
format_sel <= RCV_NACK; // slave clk rcv dat
end
ST9:begin
if ( msb_cnt == 0 ) begin // Send Byte protocol
state <= ST10;
msb_cnt <= 7;
sda_wbuf <= command[msb_cnt];
format_sel <= ( command[msb_cnt] ) ? WR_DH:
WR_DL;
end
else begin
state <= ST9;
msb_cnt <= msb_cnt - 1;
sda_wbuf <= command[msb_cnt];
format_sel <= ( command[msb_cnt] ) ? WR_DH:
WR_DL;
end
end
ST10:begin
state <= ST31; // goto STOP sequence
format_sel <= RCV_NACK;
end
// Receive Byte protocol --------------------------
ST11:begin
if ( msb_cnt == 0 ) begin // Slave Address
state <= ST12;
msb_cnt <= 7;
sda_wbuf <= address[msb_cnt];
format_sel <= ( address[msb_cnt] ) ? WR_DH:
WR_DL;
end
else begin
state <= ST11;
msb_cnt <= msb_cnt - 1;
sda_wbuf <= address[msb_cnt];
format_sel <= ( address[msb_cnt] ) ? WR_DH:
WR_DL;
end
end
ST12:begin
state <= ST13;
format_sel <= RCV_NACK; // slave clk rcv dat
end
ST13:begin
if ( msb_cnt == 0 ) begin // Send Byte protocol
state <= ST14;
msb_cnt <= 7;
format_sel <= RCV_NACK;
sda_rbuf <= {sda_rbuf[6:0],sda};
end
else begin
state <= ST13;
msb_cnt <= msb_cnt - 1;
format_sel <= RCV_NACK;
sda_rbuf <= {sda_rbuf[6:0],sda};
end
end
ST14:begin
state <= ST31; // goto STOP sequence
format_sel <= RCV_ACK; // Master NACK
sda_rbuf <= {sda_rbuf[6:0],sda};
end
// STOP --------------------
ST31:begin
state <= ST3; // IDLE 1 dummy (ST3->ST4)
format_sel <= STOP;
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_reg <= 1;
scl_reg <= 1;
end
else begin
sda_reg <= fmt_sd[ui_cnt_r];
scl_reg <= fmt_sc[ui_cnt_r];
end
end
assign sda = ( sda_reg ) ? 1'bz :
1'b0;
assign scl = ( scl_reg ) ? 1'bz :
1'b0;
endmodule
'Verilog' 카테고리의 다른 글
iic testbench (0) | 2021.02.25 |
---|---|
iic slave model (0) | 2021.02.25 |