由於上一篇已經介紹過了 SPI 的 Timing Diagram,那麼今天就直接進入 I2C Master 狀態機的程式嘍~~
先來定義 8 個狀態(下面會解釋各個狀態的行為)
/*---------parameter---------*/
parameter IDLE = 3'd0;
parameter GO = 3'd1;
parameter START = 3'd2;
parameter WAIT = 3'd3;
parameter SHIFT = 3'd4;
parameter STOP = 3'd5;
parameter FINAL = 3'd6;
parameter END = 3'd7;
再來定義輸入輸出
輸入:
輸出:
module I2C_control_R_W(
clk_sys,
SCLK_100k,
tick_I2C,
rst_n,
en,
count,
countEN,
rstcount,
ACK1,
ACK2,
ACK3,
rstACK,
SCLK,
SCLK_temp,
SHEN,
LDEN,
SDO,
R_W
);
/*---------ports declaration---------*/
input clk_sys;
input rst_n;
input en;
input SCLK_100k;
input tick_I2C;
input R_W;// W---->0, R---->1
input [4:0] count;
output ACK1;
output ACK2;
output ACK3;
output SCLK_temp;
output SHEN;
output LDEN;
output SDO;
output countEN;
output rstcount;
output rstACK;
output SCLK;
reg ACK1;
reg ACK2;
reg ACK3;
reg SCLK_temp;
reg SHEN;
reg LDEN;
reg SDO;
reg countEN;
reg rstcount;
reg rstACK;
wire SCLK;
宣告跑狀態的變數:
/*---------variables---------*/
reg [2:0] fstate;
狀態邏輯:
/*---------fstate state---------*/
always@(posedge clk_sys or negedge rst_n)begin
if(!rst_n)begin
fstate <= IDLE;
end
else begin
case(fstate)
IDLE:begin
if(en) fstate <= GO;
else fstate <= IDLE;
end
GO:begin
if(tick_I2C)fstate <= START;
else fstate <= GO;
end
START:begin
if(tick_I2C)fstate <= WAIT;
else fstate <= START;
end
WAIT:begin
if(tick_I2C)fstate <= SHIFT;
else fstate <= WAIT;
end
SHIFT:begin
if(!R_W)begin//write-->18bit
if(count==5'd16&&tick_I2C)fstate <= STOP;
else fstate <= SHIFT;
end
else begin//read-->27bit
if(count==5'd25&&tick_I2C)fstate <= STOP;
else fstate <= SHIFT;
end
end
STOP:begin
if(tick_I2C)fstate <= FINAL;
else fstate <= STOP;
end
FINAL:begin
if(tick_I2C)fstate <= END;
else fstate <= FINAL;
end
END:begin
if(tick_I2C)fstate <= IDLE;
else fstate <= END;
end
endcase
end
end
輸出邏輯:
/*---------fstate output---------*/
always@(posedge clk_sys or negedge rst_n)begin
if(!rst_n)begin
SCLK_temp <= 1'b1;
LDEN <= 1'b0;
SHEN <= 1'b0;
ACK1 <= 1'b0;
ACK2 <= 1'b0;
ACK3 <= 1'b0;
SDO <= 1'b1;//SDIN_temp control data[26]/raising/falling
countEN <= 1'b0;
rstcount <= 1'b0;
rstACK <= 1'b0;
end
else begin
if(tick_I2C)begin
case(fstate)
IDLE:begin
SCLK_temp <= 1'b1;//high
LDEN <= 1'b0;
SHEN <= 1'b0;
ACK1 <= 1'b0;
ACK2 <= 1'b0;
ACK3 <= 1'b0;
SDO <= 1'b1;//high
countEN <= 1'b0;
rstcount <= 1'b0;
rstACK <= 1'b0;
end
GO:begin
SCLK_temp <= 1'b1;//high
LDEN <= 1'b1;//load data
SHEN <= 1'b0;
ACK1 <= 1'b0;
ACK2 <= 1'b0;
ACK3 <= 1'b0;
SDO <= 1'b1;//high
countEN <= 1'b0;
rstcount <= 1'b0;
rstACK <= 1'b0;
end
START:begin
SCLK_temp <= 1'b1;//high
LDEN <= 1'b0;
SHEN <= 1'b0;
ACK1 <= 1'b0;
ACK2 <= 1'b0;
ACK3 <= 1'b0;
SDO <= 1'b0;//falling(start)
countEN <= 1'b0;
rstcount <= 1'b0;
rstACK <= 1'b0;
end
WAIT:begin
SCLK_temp <= 1'b1;//high
LDEN <= 1'b0;
SHEN <= 1'b0;
ACK1 <= 1'b0;
ACK2 <= 1'b0;
ACK3 <= 1'b0;
SDO <= 1'b0;//low
countEN <= 1'b0;
rstcount <= 1'b0;
rstACK <= 1'b0;
end
SHIFT:begin
SCLK_temp <= 1'b0;//don't care
LDEN <= 1'b0;
SHEN <= 1'b1;//shifting
//ACK1
if(count==5'd7) ACK1 <= 1'b1;
else ACK1 <= 1'b0;
//ACK2
if(count==5'd16)ACK2 <= 1'b1;
else ACK2 <= 1'b0;
//ACK3
if(count==5'd25)ACK3 <= 1'b1;
else ACK3 <= 1'b0;
SDO <= 1'b1;//don't care(data[26])
countEN <= 1'b1;//counting
//rstcount
if(!R_W)begin//write-->18bit
if(count==5'd16)rstcount <= 1'b1;
else rstcount <= 1'b0;
end
else begin//read-->27bit
if(count==5'd25)rstcount <= 1'b1;
else rstcount <= 1'b0;
end
rstACK <= 1'b0;
end
STOP:begin
SCLK_temp <= 1'b0;//stop the clock
LDEN <= 1'b0;
SHEN <= 1'b0;
ACK1 <= 1'b0;
ACK2 <= 1'b0;
ACK3 <= 1'b0;
SDO <= 1'b0;//low
countEN <= 1'b0;
rstcount <= 1'b0;
rstACK <= 1'b0;
end
FINAL:begin
SCLK_temp <= 1'b1;//high
LDEN <= 1'b0;
SHEN <= 1'b0;
ACK1 <= 1'b0;
ACK2 <= 1'b0;
ACK3 <= 1'b0;
SDO <= 1'b0;//low
countEN <= 1'b0;
rstcount <= 1'b0;
rstACK <= 1'b0;
end
END:begin
SCLK_temp <= 1'b1;//high
LDEN <= 1'b0;
SHEN <= 1'b0;
ACK1 <= 1'b0;
ACK2 <= 1'b0;
ACK3 <= 1'b0;
SDO <= 1'b1;//raising
countEN <= 1'b0;
rstcount <= 1'b0;
rstACK <= 1'b1;//reset ACK
end
endcase
end
else begin
SCLK_temp <= SCLK_temp;
LDEN <= LDEN;
SHEN <= SHEN;
ACK1 <= ACK1;
ACK2 <= ACK2;
ACK3 <= ACK3;
SDO <= SDO;
countEN <= countEN;
rstcount <= rstcount;
rstACK <= rstACK;
end
end
end
endmodule
這次的 I2C Master 看起來雖然好像複雜很多,但其實與前面幾篇的 Uart 及 SPI 都有很大的相似之處歐~~
下一篇我們會繼續來完成 I2C Master 的模組~!