1,IIC协议
IIC,即Inter-Integrated Circuit(集成电路总线),这种总线类型是由飞利浦半导体公司在八十年代设计出来的一种简单、双向、二线制、同步串行总线。是当今电子设计中应用最为广泛的串行总线之一。在很多领域有着广泛的应用,如存储器、LED及LCD驱动器、AD/DA转换器、传感器、图像处理领域的摄像头配置(SCCB)等等。
IIC是一种多向控制总线,也就是说多个IIC设备可以连接到同一总线结构下,每个连接到总线的设备都具有唯一的地址,主机可以做为发送器和接收器,这里的发送器指的是主机可以给总线上的IIC设备发送数据,接收器是指主机接收总线上IIC设备发送来的数据。
IIC协议规定数据传输速度为:标准模式下100Kbps,快速模式下400Kbps,高速模式下3.4Mbps。
2,总线结构
IIC总线接口由两根线组成,一根是双向的串行数据线sda(serial data),一根是串行时钟线scl(serial clock)。
在总线不传输数据时,总线上的sda和scl均保持高电平,需要传输数据时,首先是发送开始条件:在scl为高电平期间,数据线sda由“高”变“低”为开始条件;当scl为高电平期间,数据线sda由“低”变“高”为停止条件。在发送数据时,数据线sda必须在scl为高电平期间保持稳定,只有在scl为低电平期间,才允许改变数据sda,发送的数据必须是一个字节,每次发送完一个字节的数据,必须接受来自从设备的一个反馈信号ACK,与应答对应的时钟脉冲由主控制器产生。
3,总线时序
为支持通用设计,该处我们只完成单字节读写。除起始位和停止位之外,每次传输8bit数据加一个ACK,具体读写时序如下:
写时序
读时序
起始位 : SCL高电平时,检测到一个由高到低的电平变化为起始位;
ID数据 : ID一般由7bit数据表示,由高低依次传输,第8位为读写标志位;
写地址数据 : 8bit地址数据由高到低依次传输,如果地址位超过8bit,则由两个字段完成传输;
写数据 : 8bit数据由高到低依次传输;
应答位 : 每发送完8bit数据,由从机反馈一个应答,一般为低电平;
停止位 : SCL高电平时,检测到一个由低到高的电平变化为停止位。
4,FPGA实现IIC主机
FPGA实现IIC主机读写设计,已设计为简单的并行读写控制接口,只要控制改读写接口就能完成IIC接口时序,代码如下:
`timescale 1ns / 1ps
//
// Company:
// Engineer: xy
//
// Create Date: 11:48:53 08/31/2018
// Design Name:
// Module Name: iic_design_host
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module iic_design_host #(
parameter SYSCLK = 50000000,
parameter IICRATE = 200000
)
(
input clk, //50MHZ
input rst,
output reg scl,
inout sda,
input rd_en,
input wr_en,
input [7:0] iic_id,
input [7:0] iic_addr,
input [7:0] wr_data,
output reg wr_done,
output reg [7:0] rd_data,
output reg rd_done
);
localparam IIC_BPS = SYSCLK/IICRATE/2;
localparam IIC_BPS_2 = SYSCLK/IICRATE/4;
reg sda_link;
reg sda_buf;
assign sda = (sda_link == 1) ? sda_buf : 1'bz;
//**********scl输出***************
reg [9:0] clk_cnt; //499,
reg clk_bps;
reg run_en;
always @ (posedge clk) begin //5Ok驱动时钟生成模块
if(rst) begin
clk_cnt <= 0;
clk_bps <= 0;
end
else if(run_en && clk_cnt == IIC_BPS - 1) begin
clk_cnt <= 0;
clk_bps <= ~clk_bps;
end
else if(run_en) begin
clk_cnt <= clk_cnt + 1;
clk_bps <= clk_bps;
end
else begin
clk_bps <= 1;
clk_cnt <= 0;
end
end
always @ (posedge clk) begin
if(rst)
scl <= 1;
else if(run_en) //在有发送有效数据时,发送时钟,空闲状态保持为1
scl <= clk_bps;
else
scl <= 1;
end
wire scl_flag;
assign scl_flag = (clk_cnt == IIC_BPS_2 - 1) ? 1 : 0;
//-------------------------------------------------------------------
///************************************
reg [31:0] cnt_5ms;
wire cnt_5ms_flag;
always @ (posedge clk) begin
if(rst)
cnt_5ms <= 0;
else if(run_en == 0)
cnt_5ms <= cnt_5ms + 1;
else
cnt_5ms <= 0;
end
assign cnt_5ms_flag = (cnt_5ms == 24999999) ? 1 : 0;
//--------------------------------------------------
//*************************IIC时序*************************
localparam idle_state = 'd0 ; //空闲状态,准备发送起始位
localparam startwr_state = 'd1 ; //起始状态,发送起始位
localparam txidwr_state = 'd2 ; //发送器件ID,
localparam txidwr_ack_state = 'd3 ; //接收一个ACK
localparam txaddrwr_state = 'd4 ; //发送寄存器地址,
localparam txaddrwr_ack_state = 'd5 ; //接收一个ACK
localparam readyrd_state = 'd6 ; //准备读数据
localparam startrd_state = 'd7 ; //发送一个开始信号
localparam txidrd_state = 'd8 ; //发送器件ID
localparam txidrd_ack_state = 'd9 ; //接收一个ACK
localparam rxaddrrd_state = 'd10; //接收数据
localparam rxaddrrd_ack_state = 'd11; //发送读数据ACK
localparam readystop_state = 'd12; //准备停止
localparam stop_state = 'd13; //发送停止信号
localparam end_state = 'd14; //结束空闲状态
localparam sel_state = 'd15; //读写选择状态
localparam txdata_state = 'd16; //数据发送状态
localparam txdata_ack_state = 'd17; //发送ACK
reg [4:0] iic_next_state = idle_state;
reg [4:0] iic_current_state = idle_state;
reg [3:0] cnt_shift = 0;
reg [7:0] data_reg = 0;
reg rd_sel = 0;
always @ (posedge clk) begin
if(rst)
iic_current_state <= idle_state;
else
iic_current_state <= iic_next_state;
end
always @ (*) begin
if(rst)
iic_next_state = idle_state;
else case(iic_current_state)
idle_state : if(rd_en || wr_en)
iic_next_state = startwr_state;
else iic_next_state = idle_state;
startwr_state : if(scl == 1 && scl_flag)
iic_next_state = txidwr_state;
else iic_next_state = startwr_state;
txidwr_state : if(scl == 0 && scl_flag && cnt_shift == 8)
iic_next_state = txidwr_ack_state;
else iic_next_state = txidwr_state;
txidwr_ack_state : if(scl == 1 && scl_flag)
iic_next_state = txaddrwr_state;//应答sda == 0
else iic_next_state = txidwr_ack_state;
txaddrwr_state : if(scl == 0 && scl_flag && cnt_shift == 8)
iic_next_state = txaddrwr_ack_state;
else iic_next_state = txaddrwr_state;
txaddrwr_ack_state : if(scl == 1 && scl_flag)
iic_next_state = sel_state;//应答sda == 0
else iic_next_state = txaddrwr_ack_state;
sel_state : if(rd_sel)
iic_next_state = readyrd_state;//应答sda == 0
else
iic_next_state = txdata_state;
txdata_state : if(scl == 0 && scl_flag && cnt_shift == 8)
iic_next_state = txdata_ack_state;
else iic_next_state = txdata_state;
txdata_ack_state : if(scl == 1 && scl_flag)
iic_next_state = readystop_state;//应答sda == 0
else iic_next_state = txdata_ack_state;
readyrd_state : if(scl == 0 && scl_flag)
iic_next_state = startrd_state;
else iic_next_state = readyrd_state;
startrd_state : if(scl == 1 && scl_flag)
iic_next_state = txidrd_state;
else iic_next_state = startrd_state;
txidrd_state : if(scl == 0 && scl_flag && cnt_shift == 8)
iic_next_state = txidrd_ack_state;
else iic_next_state = txidrd_state;
txidrd_ack_state : if(scl == 1 && scl_flag)
iic_next_state = rxaddrrd_state;//应答sda == 0
else iic_next_state = txidrd_ack_state;
rxaddrrd_state : if(scl == 1 && scl_flag && cnt_shift == 7)
iic_next_state = rxaddrrd_ack_state;
else iic_next_state = rxaddrrd_state;
rxaddrrd_ack_state : if(scl == 0 && scl_flag)
iic_next_state = readystop_state;
else iic_next_state = rxaddrrd_ack_state;
readystop_state : if(scl == 0 && scl_flag)
iic_next_state = stop_state;
else iic_next_state = readystop_state;
stop_state : if(scl == 1 && scl_flag)
iic_next_state = end_state;
else iic_next_state = stop_state;
end_state : iic_next_state = idle_state;
default : iic_next_state = idle_state;
endcase
end
always @ (posedge clk) begin
if(rst) begin
cnt_shift <= 0; //数据移位计数器
data_reg <= 0; //发送数据寄存器
sda_buf <= 1; //发送buf
sda_link <= 0; //三态控制
run_en <= 0;
rd_data <= 0;
rd_sel <= 0;
wr_done <= 0;
rd_done <= 0;
end
else case(iic_current_state)
idle_state : if(wr_en) begin
cnt_shift <= 0; //数据移位计数器
data_reg <= 0; //发送数据寄存器
sda_buf <= 1; //发送buf
sda_link <= 1; //三态控制
run_en <= 1;
rd_sel <= 0;
wr_done <= 0;
rd_done <= 0;
end
else if(rd_en) begin
cnt_shift <= 0; //数据移位计数器
data_reg <= 0; //发送数据寄存器
sda_buf <= 1; //发送buf
sda_link <= 1; //三态控制
run_en <= 1;
rd_sel <= 1;
wr_done <= 0;
rd_done <= 0;
end
else begin
cnt_shift <= 0; //数据移位计数器
data_reg <= 0; //发送数据寄存器
sda_buf <= 1; //发送buf
sda_link <= 1; //三态控制
run_en <= 0;
rd_sel <= 0;
wr_done <= 0;
rd_done <= 0;
end
startwr_state : if(scl == 1 && scl_flag) begin
cnt_shift <= 0; //数据移位计数器
data_reg <= {iic_id[7:1],1'b0}; //发送数据寄存器
sda_buf <= 0; //发送buf
sda_link <= 1; //三态控制
run_en <= 1;
end
else begin
cnt_shift <= 0; //数据移位计数器
data_reg <= {iic_id[7:1],1'b0}; //发送数据寄存器
sda_buf <= 1; //发送buf
sda_link <= 1; //三态控制
run_en <= 1;
end
txidwr_state : if(scl == 0 && scl_flag && cnt_shift == 8) begin
data_reg <= 0;
cnt_shift <= 0;
sda_buf <= 0;
sda_link <= 0;
end
else if(scl == 0 && scl_flag && cnt_shift < 8) begin
data_reg <= {data_reg[6:0],data_reg[7]};
cnt_shift <= cnt_shift + 1;
sda_buf <= data_reg[7];
sda_link <= 1;
end
else begin
data_reg <= data_reg;
cnt_shift <= cnt_shift;
sda_buf <= sda_buf;
sda_link <= sda_link;
end
txidwr_ack_state : if(scl == 1 && scl_flag) begin
cnt_shift <= 0;
data_reg <= iic_addr;
sda_buf <= 0;
sda_link <= 0;
end
else begin
data_reg <= iic_addr;
cnt_shift <= cnt_shift;
sda_buf <= sda_buf;
sda_link <= sda_link;
end
txaddrwr_state : if(scl == 0 && scl_flag && cnt_shift == 8) begin
data_reg <= 0;
cnt_shift <= 0;
sda_buf <= 0;
sda_link <= 0;
end
else if(scl == 0 && scl_flag && cnt_shift < 8) begin
data_reg <= {data_reg[6:0],data_reg[7]};
cnt_shift <= cnt_shift + 1;
sda_buf <= data_reg[7];
sda_link <= 1;
end
else begin
data_reg <= data_reg;
cnt_shift <= cnt_shift;
sda_buf <= sda_buf;
sda_link <= sda_link;
end
txaddrwr_ack_state : if(scl == 1 && scl_flag) begin
cnt_shift <= 0;
data_reg <= 0;
sda_buf <= 0;
sda_link <= 0;
end
else begin
data_reg <= data_reg;
cnt_shift <= cnt_shift;
sda_buf <= sda_buf;
sda_link <= sda_link;
end
sel_state : if(rd_sel == 0)
data_reg <= wr_data;
else
data_reg <= 0;
txdata_state : if(scl == 0 && scl_flag && cnt_shift == 8) begin
data_reg <= 0;
cnt_shift <= 0;
sda_buf <= 0;
sda_link <= 0;
end
else if(scl == 0 && scl_flag && cnt_shift < 8) begin
data_reg <= {data_reg[6:0],data_reg[7]};
cnt_shift <= cnt_shift + 1;
sda_buf <= data_reg[7];
sda_link <= 1;
end
else begin
data_reg <= data_reg;
cnt_shift <= cnt_shift;
sda_buf <= sda_buf;
sda_link <= sda_link;
end
txdata_ack_state : if(scl == 1 && scl_flag) begin
cnt_shift <= 0;
data_reg <= 0;
sda_buf <= 0;
sda_link <= 0;
end
else begin
data_reg <= data_reg;
cnt_shift <= cnt_shift;
sda_buf <= sda_buf;
sda_link <= sda_link;
end
readyrd_state : if(scl == 0 && scl_flag) begin
cnt_shift <= 0;
data_reg <= 0;
sda_buf <= 1;
sda_link <= 1;
end
else begin
data_reg <= data_reg;
cnt_shift <= cnt_shift;
sda_buf <= sda_buf;
sda_link <= sda_link;
end
startrd_state : if(scl == 1 && scl_flag) begin
cnt_shift <= 0;
data_reg <= {iic_id[7:1],1'b1}; ;
sda_buf <= 0;
sda_link <= 1;
end
else begin
data_reg <= {iic_id[7:1],1'b1}; ;
cnt_shift <= cnt_shift;
sda_buf <= sda_buf;
sda_link <= sda_link;
end
txidrd_state : if(scl == 0 && scl_flag && cnt_shift == 8) begin
data_reg <= 0;
cnt_shift <= 0;
sda_buf <= 0;
sda_link <= 0;
end
else if(scl == 0 && scl_flag && cnt_shift < 8) begin
data_reg <= {data_reg[6:0],data_reg[7]};
cnt_shift <= cnt_shift + 1;
sda_buf <= data_reg[7];
sda_link <= 1;
end
else begin
data_reg <= data_reg;
cnt_shift <= cnt_shift;
sda_buf <= sda_buf;
sda_link <= sda_link;
end
txidrd_ack_state : if(scl == 1 && scl_flag) begin
cnt_shift <= 0;
data_reg <= 0;
sda_buf <= 0;
sda_link <= 0;
end
else begin
data_reg <= data_reg;
cnt_shift <= cnt_shift;
sda_buf <= sda_buf;
sda_link <= sda_link;
end
rxaddrrd_state : if(scl == 1 && scl_flag && cnt_shift == 7) begin
rd_data <= {rd_data[6:0],sda};
cnt_shift <= 0;
sda_buf <= 0;
sda_link <= 0;
end
else if(scl == 1 && scl_flag && cnt_shift < 7) begin
rd_data <= {rd_data[6:0],sda};
cnt_shift <= cnt_shift + 1;
sda_buf <= 0;
sda_link <= 0;
end
else begin
data_reg <= data_reg;
cnt_shift <= cnt_shift;
sda_buf <= sda_buf;
sda_link <= sda_link;
end
rxaddrrd_ack_state : if(scl == 0 && scl_flag) begin
data_reg <= data_reg;
cnt_shift <= 0;
sda_buf <= 1;
sda_link <= 1;
end
else begin
data_reg <= data_reg;
cnt_shift <= cnt_shift;
sda_buf <= sda_buf;
sda_link <= sda_link;
end
readystop_state : if(scl == 0 && scl_flag) begin
data_reg <= data_reg;
cnt_shift <= 0;
sda_buf <= 0;
sda_link <= 1;
end
else begin
data_reg <= data_reg;
cnt_shift <= cnt_shift;
sda_buf <= sda_buf;
sda_link <= sda_link;
end
stop_state : if(scl == 1 && scl_flag) begin
data_reg <= data_reg;
cnt_shift <= 0;
sda_buf <= 1;
sda_link <= 1;
run_en <= 0;
end
else begin
data_reg <= data_reg;
cnt_shift <= cnt_shift;
sda_buf <= sda_buf;
sda_link <= sda_link;
end
end_state : begin
data_reg <= data_reg;
cnt_shift <= 0;
sda_buf <= 1;
sda_link <= 1;
run_en <= 0;
if(rd_sel == 1) begin
wr_done <= 0;
rd_done <= 1;
end
else begin
wr_done <= 1;
rd_done <= 0;
end
end
endcase
end
endmodule
4,FPGA实现IIC从机
FPGA实现IIC从读写设计,已设计为简单的并行读写控制接口,只要控制改读写接口就能完成IIC接口时序,代码如下:
`timescale 1ns / 1ps
//
// Company:
// Engineer: xy
//
// Create Date: 2020/08/28 13:37:07
// Design Name:
// Module Name: iic_slave_design
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module iic_slave_design (
//external port
input clk,
input rst,
input iic_scl,
inout iic_sda,
//test port
output [7:0] ot_iddata,
output [7:0] ot_addr,
output [7:0] ot_datareg,
output ot_iic_sda,
output ot_iic_scl,
output [3:0] ot_state,
//internal data port
input [7:0] tx_data,
output [7:0] rx_addr,
output [7:0] rx_data,
output rx_data_en
);
reg sda_link = 0;
reg sda_buf = 0;
assign iic_sda = (sda_link == 1) ? sda_buf : 1'bz;
//****************************IIC data detection*******************************************************
reg sda_r1=0,sda_r2=0;
reg scl_r1=0,scl_r2=0;
wire iic_riseing;
wire iic_falling;
wire scl_riseing;
wire scl_falling;
reg [31:0] time_cnt;
wire time_flag;
always @ (posedge clk) begin
scl_r1 <= iic_scl;
scl_r2 <= scl_r1;
sda_r1 <= iic_sda;
sda_r2 <= sda_r1;
end
assign iic_riseing = !sda_r2 && sda_r1; //scl posedge
assign iic_falling = sda_r2 && !sda_r1; //scl negedge
assign scl_riseing = !scl_r2 && scl_r1;
assign scl_falling = scl_r2 && !scl_r1;
always @ (posedge clk) begin //timeout control
if(rst)
time_cnt <= 0;
else if(scl_riseing || scl_falling || time_flag)
time_cnt <= 0;
else
time_cnt <= time_cnt + 1;
end
assign time_flag = (time_cnt == 499999) ? 1 : 0; // 10ms
//------------------------------------------------------------------------------------------------------
localparam [3:0] ildestate = 0;
localparam [3:0] startwrstate = 1;
localparam [3:0] wr_state = 2;
localparam [3:0] wrok_state = 3;
localparam [3:0] wrack_state = 4;
localparam [3:0] startrdstate = 5;
localparam [3:0] rdid_state = 6;
localparam [3:0] rdidok_state = 7;
localparam [3:0] rdidack_state = 8;
localparam [3:0] ready_rdstate = 9;
localparam [3:0] rdda_state = 10;
localparam [3:0] rddaok_state = 11;
localparam [3:0] rddaack_state = 12;
localparam [3:0] rddasel_state = 13;
reg [3:0] iic_next_state = ildestate;
reg [3:0] iic_current_state = ildestate;
reg [3:0] shift_cnt = 0; //sda data shift count
reg [7:0] iic_sel = 0; //data count; 0-ID,1-addr default : data
reg [7:0] shift_reg = 0; //sda data shift reg
reg [7:0] data_reg = 0; //rxdata reg
reg data_reg_en = 0; //rxdata enable
reg [7:0] id_data = 0; //ID
reg [7:0] iic_addr = 0; //iic reg addr
wire [7:0] iic_data; //iic reg data
assign iic_data = tx_data;
//***********************************IIC Slave FSM ***********************************
always @ (posedge clk) begin : FSM_1
if(rst)
iic_current_state <= ildestate;
else
iic_current_state <= iic_next_state;
end
always @ (*) begin : FSM_2
if(rst)
iic_next_state = ildestate;
else case(iic_current_state)
ildestate : if(scl_r2 && iic_falling) //waiting start
iic_next_state = startwrstate;
else
iic_next_state = ildestate;
startwrstate : if(time_flag)
iic_next_state = ildestate;
else if(scl_r2 == 0)
iic_next_state = wr_state;
else if(iic_sel == 2 && scl_r2 && iic_falling)
iic_next_state = startrdstate;
else if(scl_r2 && iic_riseing)
iic_next_state = ildestate;
else
iic_next_state = startwrstate;
wr_state : if(time_flag)
iic_next_state = ildestate;
else if(scl_r2 && shift_cnt == 7)
iic_next_state = wrok_state;
else if(scl_r2 && shift_cnt < 7)
iic_next_state = startwrstate;
else
iic_next_state = wr_state;
wrok_state : if(time_flag)
iic_next_state = ildestate;
else if(scl_r2 == 0)
iic_next_state = wrack_state;
else if(scl_r2 && iic_falling)
iic_next_state = startwrstate;
else if(scl_r2 && iic_riseing)
iic_next_state = ildestate;
else
iic_next_state = wrok_state;
wrack_state : if(time_flag)
iic_next_state = ildestate;
else if(scl_r2 == 1)
iic_next_state = startwrstate;
else
iic_next_state = wrack_state;
startrdstate : if(time_flag)
iic_next_state = ildestate;
else if(scl_r2 == 0)
iic_next_state = rdid_state;
else if(scl_r2 && iic_falling)
iic_next_state = startwrstate;
else if(scl_r2 && iic_riseing)
iic_next_state = ildestate;
else
iic_next_state = startrdstate;
rdid_state : if(time_flag)
iic_next_state = ildestate;
else if(scl_r2 && shift_cnt == 7)
iic_next_state = rdidok_state;
else if(scl_r2 && shift_cnt < 7)
iic_next_state = startrdstate;
else
iic_next_state = rdid_state;
rdidok_state: if(time_flag)
iic_next_state = ildestate;
else if(scl_r2 == 0)
iic_next_state = rdidack_state;
else if(scl_r2 && iic_falling)
iic_next_state = startwrstate;
else if(scl_r2 && iic_riseing)
iic_next_state = ildestate;
else
iic_next_state = rdidok_state;
rdidack_state: if(time_flag)
iic_next_state = ildestate;
else if(scl_r2 == 1 && id_data[0] == 1)
iic_next_state = ready_rdstate;
else if(scl_r2 == 1)
iic_next_state = ildestate;
else
iic_next_state = rdidack_state;
ready_rdstate: if(time_flag)
iic_next_state = ildestate;
else if(scl_r2 == 0)
iic_next_state = rdda_state;
else if(scl_r2 && iic_falling)
iic_next_state = startwrstate;
else if(scl_r2 && iic_riseing)
iic_next_state = ildestate;
else
iic_next_state = ready_rdstate;
rdda_state: if(time_flag)
iic_next_state = ildestate;
else if(scl_r2 && shift_cnt == 7)
iic_next_state = rddaok_state;
else if(scl_r2 && shift_cnt < 7)
iic_next_state = ready_rdstate;
else
iic_next_state = rdda_state;
rddaok_state: if(time_flag)
iic_next_state = ildestate;
else if(scl_r2 == 0)
iic_next_state = rddaack_state;
else
iic_next_state = rddaok_state;
rddaack_state: if(time_flag)
iic_next_state = ildestate;
else if(scl_r2 == 1 && sda_r2 == 1)
iic_next_state = ildestate;
else if(scl_r2 == 1 && sda_r2 == 0)
iic_next_state = ready_rdstate;
else
iic_next_state = rddaack_state;
endcase
end
always @ (posedge clk) begin
if(rst) begin
sda_link <= 0;
sda_buf <= 0;
shift_cnt <= 0;
iic_sel <= 0;
shift_reg <= 0;
id_data <= 0;
iic_addr <= 0;
data_reg <= 0;
data_reg_en <= 0;
end
else case(iic_current_state)
ildestate : begin
sda_link <= 0;
sda_buf <= 0;
iic_sel <= 0;
shift_cnt <= 0;
shift_reg <= 0;
data_reg_en <= 0;
end
startwrstate : if(scl_r2 == 0) begin
sda_link <= 0;
sda_buf <= 0;
iic_sel <= iic_sel;
shift_cnt <= shift_cnt;
shift_reg <= shift_reg;
end
else if(iic_sel == 2 && scl_r2 && iic_falling) begin
sda_link <= 0;
sda_buf <= 0;
iic_sel <= 0;
shift_cnt <= 0;
shift_reg <= 0;
end
else if(scl_r2 && iic_riseing) begin
sda_link <= 0;
sda_buf <= 0;
shift_cnt <= 0;
iic_sel <= 0;
shift_reg <= 0;
end
else begin
sda_link <= sda_link;
sda_buf <= sda_buf;
iic_sel <= iic_sel;
shift_cnt <= shift_cnt;
shift_reg <= shift_reg;
data_reg_en <= 0;
end
wr_state : if(scl_r2 && shift_cnt == 7) begin
sda_link <= 0;
sda_buf <= 0;
iic_sel <= iic_sel + 1;
shift_cnt <= 0;
shift_reg <= {shift_reg[6:0],iic_sda};
end
else if(scl_r2 && shift_cnt < 7) begin
sda_link <= 0;
sda_buf <= 0;
iic_sel <= iic_sel;
shift_cnt <= shift_cnt + 1;
shift_reg <= {shift_reg[6:0],iic_sda};
end
else begin
sda_link <= sda_link;
sda_buf <= sda_buf;
iic_sel <= iic_sel;
shift_cnt <= shift_cnt;
shift_reg <= shift_reg;
data_reg_en <= 0;
end
wrok_state : if(scl_r2 == 0) begin
sda_link <= 1;
sda_buf <= 0;
shift_cnt <= 0;
case(iic_sel)
1 : id_data <= shift_reg;
2 : iic_addr <= shift_reg;
3 : begin data_reg <= shift_reg; data_reg_en <= 1; end
default : begin iic_addr <= iic_addr + 1; data_reg <= shift_reg; data_reg_en <= 1; end
endcase
end
else if(scl_r2 && iic_falling) begin
sda_link <= 0;
sda_buf <= 0;
iic_sel <= 0;
shift_cnt <= 0;
shift_reg <= 0;
end
else if(scl_r2 && iic_riseing) begin
sda_link <= 0;
sda_buf <= 0;
shift_cnt <= 0;
iic_sel <= 0;
shift_reg <= 0;
end
else begin
sda_link <= sda_link;
sda_buf <= sda_buf;
id_data <= id_data;
iic_addr <= iic_addr;
data_reg <= data_reg;
end
wrack_state : begin
sda_link <= 1;
sda_buf <= 0;
iic_sel <= iic_sel;
shift_cnt <= 0;
shift_reg <= 0;
data_reg_en <= 0;
end
startrdstate: if(scl_r2 == 0) begin
sda_link <= 0;
sda_buf <= 0;
shift_cnt <= shift_cnt;
shift_reg <= shift_reg;
end
else if(scl_r2 && iic_falling) begin
sda_link <= 0;
sda_buf <= 0;
iic_sel <= 0;
shift_cnt <= 0;
shift_reg <= 0;
end
else if(scl_r2 && iic_riseing) begin
sda_link <= 0;
sda_buf <= 0;
shift_cnt <= 0;
iic_sel <= 0;
shift_reg <= 0;
end
else begin
sda_link <= sda_link;
sda_buf <= sda_buf;
iic_sel <= 0;
shift_cnt <= shift_cnt;
shift_reg <= shift_reg;
data_reg_en <= 0;
end
rdid_state : if(scl_r2 && shift_cnt == 7) begin
sda_link <= 0;
sda_buf <= 0;
shift_cnt <= 0;
shift_reg <= {shift_reg[6:0],iic_sda};
end
else if(scl_r2 && shift_cnt < 7) begin
sda_link <= 0;
sda_buf <= 0;
shift_cnt <= shift_cnt + 1;
shift_reg <= {shift_reg[6:0],iic_sda};
end
else begin
sda_link <= sda_link;
sda_buf <= sda_buf;
iic_sel <= 0;
shift_cnt <= shift_cnt;
shift_reg <= shift_reg;
data_reg_en <= 0;
end
rdidok_state : if(scl_r2 == 0) begin
sda_link <= 1;
sda_buf <= 0;
shift_cnt <= 0;
id_data <= shift_reg;
end
else if(scl_r2 && iic_falling) begin
sda_link <= 0;
sda_buf <= 0;
iic_sel <= 0;
shift_cnt <= 0;
shift_reg <= 0;
end
else if(scl_r2 && iic_riseing) begin
sda_link <= 0;
sda_buf <= 0;
shift_cnt <= 0;
iic_sel <= 0;
shift_reg <= 0;
end
else begin
sda_link <= sda_link;
sda_buf <= sda_buf;
iic_sel <= 0;
shift_cnt <= shift_cnt;
shift_reg <= shift_reg;
data_reg_en <= 0;
end
rdidack_state: begin
sda_link <= 1;
sda_buf <= 0;
iic_sel <= 0;
shift_cnt <= 0;
shift_reg <= iic_data;
data_reg_en <= 0;
end
ready_rdstate: if(scl_r2 == 0) begin
sda_link <= 1;
sda_buf <= shift_reg[7];
shift_cnt <= shift_cnt;
shift_reg <= shift_reg;
end
else if(scl_r2 && iic_falling) begin
sda_link <= 0;
sda_buf <= 0;
iic_sel <= 0;
shift_cnt <= 0;
shift_reg <= 0;
end
else if(scl_r2 && iic_riseing) begin
sda_link <= 0;
sda_buf <= 0;
shift_cnt <= 0;
iic_sel <= 0;
shift_reg <= 0;
end
else begin
sda_link <= sda_link;
sda_buf <= sda_buf;
iic_sel <= 0;
shift_cnt <= shift_cnt;
shift_reg <= shift_reg;
data_reg_en <= 0;
end
rdda_state: if(scl_r2 && shift_cnt == 7) begin
sda_link <= 1;
sda_buf <= sda_buf;
shift_cnt <= 0;
shift_reg <= {shift_reg[6:0],1'b0};
end
else if(scl_r2 && shift_cnt < 7) begin
sda_link <= 1;
sda_buf <= sda_buf;
shift_cnt <= shift_cnt + 1;
shift_reg <= {shift_reg[6:0],1'b0};
end
else begin
sda_link <= sda_link;
sda_buf <= sda_buf;
iic_sel <= 0;
shift_cnt <= shift_cnt;
shift_reg <= shift_reg;
data_reg_en <= 0;
end
rddaok_state: if(scl_r2 == 0) begin
sda_link <= 0;
sda_buf <= 0;
shift_cnt <= 0;
shift_reg <= shift_reg;
iic_addr <= iic_addr + 8'd1;
end
else begin
sda_link <= sda_link;
sda_buf <= sda_buf;
iic_sel <= 0;
shift_cnt <= shift_cnt;
shift_reg <= shift_reg;
data_reg_en <= 0;
end
rddaack_state: begin
sda_link <= 0;
sda_buf <= 0;
shift_cnt <= 0;
iic_sel <= 0;
shift_reg <= iic_data;
data_reg_en <= 0;
end
endcase
end
//--------------------------------------------------------------------------------------------------------------
assign rx_addr = iic_addr;
assign rx_data = data_reg;
assign rx_data_en = data_reg_en;
assign ot_iddata = id_data;
assign ot_addr = iic_addr;
assign ot_datareg = shift_reg;
assign ot_iic_sda = sda_r2;
assign ot_iic_scl = scl_r2;
assign ot_state = iic_next_state;
endmodule