/*Copyright belong to afterdm@qq.com
*Create data 2020/11/24
*Last modified data 2020/12/8
*Version v1.1.0.0
*Descriptions IIC drive
*Please delete within 24 hours without special circumstances
*/
/*
*/
module IICdrive(
input clk, //clk signal(50M)
input rst, //reset signal
input [7:0] wdata, //IIC write data
output reg [7:0] rdata, //IIC read data
input enaSignal, //enable siginal
input overFlag, //over state(High level effective)
input wrFlag, //write(0) read(1) state
output reg comSignal, //complete signal
output reg errorFlag, //error signal(High level effective)
output reg SCL, //IIC clk
inout SDA, //IIC data
output reg align_clk
);
//define parameter
/******define state machine*****/
parameter STsetout = 6'b00_0001;
parameter STbaction = 6'b00_0010;
parameter STwrite = 6'b00_0100;
parameter STread = 6'b00_1000;
parameter STawait = 6'b01_0000;
parameter STeaction = 6'b10_0000;
//define reg
/******define div signal******/
reg drive_clk;
reg [6:0] drive_counter;
/******define state machine***/
reg [5:0] STstate, STnstate;
/******define state signal****/
reg STdone;
/******define count***********/
reg [7:0] IICcount;
/******define templete data***/
reg [7:0] tempdata;
/******define IIC SDA(inout)**/
reg SDAswitch, SDAout;
//define wire
wire SDAin;
//define assign
assign SDA = (SDAswitch == 1'b1) ? (SDAout) : (1'bz);
assign SDAin = SDA;
//div clk (the input clk is 50M, generate 0.02M = 2vs)
always @(posedge clk or negedge rst) begin
if(rst == 1'b0) begin
drive_clk <= 1'b0;
align_clk <= 1'b0;
drive_counter <= 7'b0;
end
else begin
if(drive_counter == 7'd99) begin
drive_counter <= 7'b0;
end
else begin
drive_counter <= drive_counter + 1'b1;
end
if(drive_counter == 7'd49) begin
drive_clk <= 1'b1;
end
else begin
drive_clk <= 1'b0;
end
if(drive_counter == 7'd50) begin
align_clk <= 1'b1;
end
else begin
align_clk <= 1'b0;
end
end
end
//state machine
always @(posedge drive_clk or negedge rst) begin
if(rst == 1'b0) begin
STstate <= STsetout;
end
else begin
STstate <= STnstate;
end
end
//state function
always @(*) begin
STnstate = STsetout;
case(STstate)
STsetout : begin
if(enaSignal == 1'b1) begin
STnstate = STbaction;
end
else begin
STnstate = STsetout;
end
end
STbaction : begin
if(STdone == 1'b1) begin
STnstate = STwrite;
end
else begin
STnstate = STbaction;
end
end
STwrite : begin
if(STdone == 1'b1) begin
if(errorFlag == 1'b1) begin
STnstate = STeaction;
end
else begin
STnstate = STawait;
end
end
else begin
STnstate = STwrite;
end
end
STread : begin
if(STdone == 1'b1) begin
STnstate = STawait;
end
else begin
STnstate = STread;
end
end
STawait : begin
if(enaSignal == 1'b1) begin
if(overFlag == 1'b1) begin
STnstate = STeaction;
end
else begin
if(wrFlag == 1'b0) begin
STnstate = STwrite;
end
else begin
STnstate = STread;
end
end
end
else begin
STnstate = STawait;
end
end
STeaction : begin
if(STdone == 1'b1) begin
STnstate = STsetout;
end
else begin
STnstate = STeaction;
end
end
default : begin end
endcase
end
//handle function
always @(posedge drive_clk or negedge rst) begin
if(rst == 1'b0) begin
comSignal <= 1'b0;
errorFlag <= 1'b0;
SCL <= 1'b1;
SDAout <= 1'b1;
SDAswitch <= 1'b1;
rdata <= 8'b0;
STdone <= 1'b0;
IICcount <= 8'b0;
end
else begin
comSignal <= 1'b0;
errorFlag <= 1'b0;
STdone <= 1'b0;
IICcount <= IICcount + 1'b1;
case(STnstate)
STsetout : begin
SDAswitch <= 1'b1;
SCL <= 1'b1;
SDAout <= 1'b1;
IICcount <= 8'b0;
comSignal <= 1'b1;
end
STbaction : begin
case(IICcount)
2'd0 : begin
SDAout <= 1'b0;
end
2'd1 : begin
SCL <= 1'b0;
IICcount <= 8'b0;
STdone <= 1'b1;
end
default : begin end
endcase
end
//cycle : SCL_LO -> outdata -> SCL_HI
STwrite : begin
case(IICcount % 2'd3)
2'd0 : begin
case(IICcount)
8'd0 : begin
tempdata <= wdata;
end
8'd27 : begin
//get subordinate response
errorFlag <= 1'b0;
STdone <= 1'b1;
end
default : begin
SCL <= 1'b0;
tempdata <= {tempdata[6:0], tempdata[7]};
end
endcase
end
2'd1 : begin
case(IICcount)
8'd25 : begin
//three-state gate Prepare to input state
SDAswitch <= 1'b0;
end
default : begin
SDAout <= tempdata[7];
end
endcase
end
2'd2 : begin
SCL <= 1'b1;
end
default : begin end
endcase
end
//cycle : getdata -> SCL_LO -> SCL_HI
STread : begin
case(IICcount % 2'd3)
2'd0 : begin
tempdata <= {tempdata[6:0], SDAin};
case(IICcount)
8'd0 : begin
//three-state gate Prepare to input state
SDAswitch <= 1'b0;
end
8'd24 : begin
SDAout <= 1'b0;
end
default : begin end
endcase
end
2'd1 : begin
SCL <= 1'b0;
if(IICcount == 8'd25) begin
rdata <= tempdata;
//three-state gate Prepare to output state
SDAswitch <= 1'b1;
end
else begin end
end
2'd2 : begin
SCL <= 1'b1;
if(IICcount == 8'd26) begin
STdone <= 1'b1;
end
else begin end
end
default : begin end
endcase
end
STawait : begin
SDAswitch <= 1'b1;
SCL <= 1'b0;
SDAout <= 1'b0;
IICcount <= 8'b0;
comSignal <= 1'b1;
end
STeaction : begin
case(IICcount)
8'd0 : begin
SCL <= 1'b1;
end
8'd1 : begin
SDAout <= 1'b1;
STdone <= 1'b1;
end
default : begin end
endcase
end
default : begin end
endcase
end
end
endmodule