본문 바로가기

Verilog

iic slave model








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