본문 바로가기

Verilog

iic master









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