FPGA模块------IIC接口设计
IIC协议
IIC接口代码
c
module iic_drive#(
parameter P_ADDR_WIDTH = 16
)(
input i_clk ,//模块输入时钟
input i_rst ,//模块输入复位-高有效
/*--------用户接口--------*/
input [6 :0] i_drive ,//用户输入设备地址
input [15:0] i_operation_addr ,//用户输入存储地址
input [7 :0] i_operation_len ,//用户输入读写长度
input [1 :0] i_operation_type ,//用户输入操作类型
input i_opeartion_valid ,//用户输入有效信号
output o_operation_ready ,//用户输出准备信号
input [7 :0] i_write_data ,//用户输入写数据
output o_write_req ,//用户写数据请求信号
output [7 :0] o_read_data ,//输出IIC读到的数据
output o_read_valid ,//输出IIC读数据有效
/*--------IIC接口--------*/
output o_iic_scl ,//IIC的时钟
inout io_iic_sda //IIC的双向数据项
);
/***************function**************/
/***************parameter*************/
parameter P_ST_IDLE = 0 ,//状态机-空闲
P_ST_START = 1 ,//状态机-起始
P_ST_UADDR = 2 ,//状态机-设备地址
P_ST_DADDR1 = 3 ,//状态机-存储地址高位
P_ST_DADDR2 = 4 ,//状态机-存储地址地位
P_ST_WRITE = 5 ,//状态机-写数据
P_ST_RESTART= 6 ,
P_ST_READ = 7 ,//状态机-读数据
P_ST_WAIT = 8 ,
P_ST_STOP = 9 ,//状态机-停止
P_ST_EMPTY = 10 ;
localparam P_W = 1 ,//2'b01
P_R = 2 ;//2'b10
/***************port******************/
/***************mechine***************/
reg [7 :0] r_st_current ;//当前状态机
reg [7 :0] r_st_next ;//下一个状态机
reg [7 :0] r_st_cnt ;//状态机计数器
/***************reg*******************/
reg ro_operation_ready ;//操作准备信号
reg ro_write_req ;//写数据请求
reg ro_write_valid ;//写数据有效
reg [7 :0] ro_read_data ;//读数据
reg ro_read_valid ;//读数据有效
reg ro_iic_scl ;//IIC的SCL输出寄存器
reg [7 :0] ri_drive ;//输入的设备地址
reg [15:0] ri_operation_addr ;//输入的存储地址
reg [7 :0] ri_operation_len ;//输入的读写长度
reg [1 :0] ri_operation_type ;//输入读写类型
reg [7 :0] ri_write_data ;//输入的写数据
reg r_iic_st ;//iic时钟状态
reg r_iic_sda_ctrl ;//iic数据三态门控制信号
reg ro_iic_sda ;//iic数据信号
reg [7 :0] r_wr_cnt ;//读写数据bit计数器
reg r_slave_ack ;//iic操作里的从机应答
reg r_ack_valid ;//应答有效
reg r_st_restart ;
reg r_ack_lock ;
reg [7 :0] r_read_drive ;
/***************wire******************/
wire w_operation_active ;//操作激活信号
wire w_st_trun ;//状态机跳转信号
wire w_iic_sda ;//iic数据线输入信号
/***************component*************/
/***************assign****************/
assign o_operation_ready = ro_operation_ready ;//准备信号
assign o_write_req = ro_write_req ;//写数据请求信号
assign o_read_data = ro_read_data ;//读数据
assign o_read_valid = ro_read_valid ;//读数据有效
assign o_iic_scl = ro_iic_scl ;//iic的scl
assign w_operation_active = i_opeartion_valid & o_operation_ready ;//激活信号
assign w_st_trun = r_st_cnt == 8 && r_iic_st ;//状态机跳转条件
//三态门使用
assign io_iic_sda = r_iic_sda_ctrl ? ro_iic_sda : 1'bz ;//三态门输出
assign w_iic_sda = !r_iic_sda_ctrl ? io_iic_sda : 1'b0 ;//三态门输入
// IOBUF #(
// .DRIVE (12 ),
// .IBUF_LOW_PWR ("TRUE" ),
// .IOSTANDARD ("DEFAULT" ),
// .SLEW ("SLOW" )
// )
// IOBUF_u0
// (
// .O (ro_iic_sda ),
// .IO (io_iic_sda ),
// .I (w_iic_sda ),
// .T (!r_iic_sda_ctrl )
// );
/***************always****************/
//第一段状态
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
r_st_current <= P_ST_IDLE;
else
r_st_current <= r_st_next;
end
//状态机跳转
always@(*)
begin
case(r_st_current)
P_ST_IDLE : r_st_next <= w_operation_active ? P_ST_START : P_ST_IDLE ;//空闲,操作激活时跳转到起始状态
P_ST_START : r_st_next <= P_ST_UADDR; //起始状态,跳转设备地址
P_ST_UADDR : r_st_next <= w_st_trun ?
r_st_restart ? P_ST_READ : P_ST_DADDR1 //判断是否时重启,重启转入读状态,不是重启转入写存储地址状态
: P_ST_UADDR ; //写设备地址,写完跳转存储地址
P_ST_DADDR1 : r_st_next <= r_slave_ack ? P_ST_STOP : //存储地址,先等待应答,应答后操作结束跳转存储地址低位
w_st_trun ? P_ST_DADDR2 : P_ST_DADDR1 ;
P_ST_DADDR2 : r_st_next <= w_st_trun & ri_operation_type == P_W ? P_ST_WRITE ://存储地址低位,判断读写,读跳转读状态,写跳转写状态
w_st_trun & ri_operation_type == P_R ? P_ST_RESTART :
P_ST_DADDR2 ;
P_ST_WRITE : r_st_next <= w_st_trun & r_wr_cnt == ri_operation_len - 1
? P_ST_WAIT : P_ST_WRITE ;//写数据状态,写完目标长度跳转结束
P_ST_RESTART: r_st_next <= P_ST_STOP; //读数据时,重启总线状态
P_ST_READ : r_st_next <= w_st_trun ? P_ST_WAIT : P_ST_READ ;//读数据状态,写完目标长度跳转结束
P_ST_WAIT : r_st_next <= P_ST_STOP ;
P_ST_STOP : r_st_next <= r_st_cnt == 1? P_ST_EMPTY : P_ST_STOP;
P_ST_EMPTY : r_st_next <= r_st_restart | r_ack_lock ? P_ST_START : P_ST_IDLE; //空状态,等待IIC成功停止,判断是否重启,重启转入START,不重启转入IDLE
default : r_st_next <= P_ST_IDLE;
endcase
end
//iic应答状态,1为没应答
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
r_ack_lock <= 'd0;
else if(r_ack_valid && !w_iic_sda && r_st_current == P_ST_DADDR1)
r_ack_lock <= 'd0;
else if(r_ack_valid && w_iic_sda && r_st_current == P_ST_DADDR1)
r_ack_lock <= 'd1;
else
r_ack_lock <= r_ack_lock;
end
//读数据时,假写操作后重启信号
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
r_st_restart <= 'd0;
else if(r_st_current == P_ST_READ)
r_st_restart <= 'd0;
else if(r_st_current == P_ST_RESTART)
r_st_restart <= 'd1;
else
r_st_restart <= r_st_restart;
end
//操作准备信号
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
ro_operation_ready <= 'd1;
else if(w_operation_active)
ro_operation_ready <= 'd0;
else if(r_st_current == P_ST_IDLE)
ro_operation_ready <= 'd1;
else
ro_operation_ready <= ro_operation_ready;
end
//寄存操作数据
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst) begin
ri_drive <= 'd0;
ri_operation_addr <= 'd0;
ri_operation_len <= 'd0;
ri_operation_type <= 'd0;
end else if(w_operation_active) begin
ri_drive <= {i_drive,1'b0};
ri_operation_addr <= i_operation_addr ;
ri_operation_len <= i_operation_len ;
ri_operation_type <= i_operation_type ;
end else begin
ri_drive <= ri_drive ;
ri_operation_addr <= ri_operation_addr ;
ri_operation_len <= ri_operation_len ;
ri_operation_type <= ri_operation_type ;
end
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
r_read_drive <= 'd0;
else if(w_operation_active)
r_read_drive <= {i_drive,1'b1};
else
r_read_drive <= r_read_drive;
end
//状态计数器
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
r_st_cnt <= 'd0;
else if(r_st_current != r_st_next || ro_write_valid || ro_read_valid)//状态跳转、写完8bit数、读写8bit数
r_st_cnt <= 'd0;
else if(r_st_current == P_ST_STOP)
r_st_cnt <= r_st_cnt + 1;
else if(r_iic_st)
r_st_cnt <= r_st_cnt + 1;
else
r_st_cnt <= r_st_cnt;
end
//iic时钟
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
ro_iic_scl <= 'd1;
else if(r_st_current >= P_ST_UADDR && r_st_current <= P_ST_WAIT)
ro_iic_scl <= ~ro_iic_scl;
else
ro_iic_scl <= 'd1;
end
//iic时钟状态
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
r_iic_st <= 'd0;
else if(r_st_current >= P_ST_UADDR && r_st_current <= P_ST_WAIT)
r_iic_st <= ~r_iic_st;
else
r_iic_st <= 'd0;
end
//iic数据线三态门控制
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
r_iic_sda_ctrl <= 'd0;
else if(r_st_cnt == 8 || r_st_next == P_ST_IDLE)
r_iic_sda_ctrl <= 'd0;
else if(r_st_current >= P_ST_START && r_st_current <= P_ST_WRITE || r_st_current == P_ST_STOP)
r_iic_sda_ctrl <= 'd1;
else
r_iic_sda_ctrl <= r_iic_sda_ctrl;
end
//iic数据线写数据
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
ro_iic_sda <= 'd0;
else if(r_st_current == P_ST_START)
ro_iic_sda <= 'd0;
else if(r_st_current == P_ST_UADDR)
ro_iic_sda <= r_st_restart ? r_read_drive[7 - r_st_cnt] : ri_drive[7 - r_st_cnt];
else if(r_st_current == P_ST_DADDR1)
ro_iic_sda <= ri_operation_addr[15 - r_st_cnt];
else if(r_st_current == P_ST_DADDR2)
ro_iic_sda <= ri_operation_addr[7 - r_st_cnt];
else if(r_st_current == P_ST_WRITE)
ro_iic_sda <= ri_write_data[7 - r_st_cnt];
else if(r_st_current == P_ST_STOP && r_st_cnt == 1)
ro_iic_sda <= 'd1;
else
ro_iic_sda <= 'd0;
end
//写请求
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
ro_write_req <= 'd0;
else if(r_st_current == P_ST_DADDR2 && ri_operation_type == P_W && r_st_cnt == 7 && r_iic_st)
ro_write_req <= 'd1;
else if(r_st_current >= P_ST_DADDR2 && ri_operation_type == P_W && r_st_cnt == 7 && r_iic_st)
ro_write_req <= r_wr_cnt < ri_operation_len - 1 ? 1'b1 : 1'b0;
else
ro_write_req <= 'd0;
end
//写有效
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
ro_write_valid <= 'd0;
else
ro_write_valid <= ro_write_req;
end
//写数据
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
ri_write_data <= 'd0;
else if(ro_write_valid)
ri_write_data <= i_write_data;
else
ri_write_data <= ri_write_data;
end
//读写计数器
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
r_wr_cnt <= 'd0;
else if(r_st_current == P_ST_IDLE)
r_wr_cnt <= 'd0;
else if((r_st_current == P_ST_WRITE || r_st_current == P_ST_READ) && w_st_trun)
r_wr_cnt <= r_wr_cnt + 1;
else
r_wr_cnt <= r_wr_cnt;
end
//读出数据
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
ro_read_data <= 'd0;
else if(r_st_current == P_ST_READ && r_st_cnt >= 1 && r_st_cnt <= 8 && !r_iic_st)
ro_read_data <= {ro_read_data[6:0],w_iic_sda};
else
ro_read_data <= ro_read_data;
end
//读出数据有效
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
ro_read_valid <= 'd0;
else if(r_st_current == P_ST_READ && r_st_cnt == 8 && !r_iic_st)
ro_read_valid <= 'd1;
else
ro_read_valid <= 'd0;
end
//从机应答信号
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
r_slave_ack <= 'd0;
else if(r_ack_valid)
r_slave_ack <= w_iic_sda;
else
r_slave_ack <= 'd0;
end
//指示应答有效信号
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
r_ack_valid <= 'd0;
else
r_ack_valid <= w_st_trun;
end
endmodule
应用IIC接口的代码
c
module my_ctrl(
input i_clk ,
input i_rst ,
input [2 :0] i_ctrl_eeprom_addr ,
input [15:0] i_ctrl_operation_addr ,
input [1 :0] i_ctrl_operation_type ,
input [7 :0] i_ctrl_operation_len ,
input i_ctrl_opeartion_valid ,
output o_ctrl_operation_ready ,
input [7 :0] i_ctrl_write_data ,
input i_ctrl_write_sop ,
input i_ctrl_write_eop ,
input i_ctrl_write_valid ,
output [7 :0] o_ctrl_read_data ,
output o_ctrl_read_valid ,
/*--------iic dirve--------*/
output [6 :0] o_drive ,//用户输入设备地址
output [15:0] o_operation_addr ,//用户输入存储地址
output [7 :0] o_operation_len ,//用户输入读写长度
output [1 :0] o_operation_type ,//用户输入操作类型
output o_opeartion_valid ,//用户输入有效信号
input i_operation_ready ,//用户输出准备信号
output [7 :0] o_write_data ,//用户输入写数据
input i_write_req ,//用户写数据请求信号
input [7 :0] i_read_data ,//输出IIC读到的数据
input i_read_valid //输出IIC读数据有效
);
/***************function**************/
/***************parameter*************/
localparam P_ST_IDLE = 0 ,
P_ST_WRITE = 1 ,
P_ST_WAIT = 2 ,
P_ST_READ = 3 ,
P_ST_REREAD = 4 ,
P_ST_OREAD = 5 ;
/***************port******************/
/***************mechine***************/
reg [7 :0] r_st_current ;
reg [7 :0] r_st_next ;
/***************reg*******************/
reg ro_ctrl_operation_ready ;
reg [7 :0] ro_ctrl_read_data ;
reg ro_ctrl_read_valid ;
reg [7 :0] ri_ctrl_write_data ;
reg ri_ctrl_write_sop ;
reg ri_ctrl_write_eop ;
reg ri_ctrl_write_valid ;
reg [2 :0] ri_ctrl_eeprom_addr ;
reg [15:0] ri_ctrl_operation_addr ;
reg [1 :0] ri_ctrl_operation_type ;
reg [7 :0] ri_ctrl_operation_len ;
reg ri_operation_ready ;
reg [7 :0] ri_read_data ;
reg ri_read_valid ;
reg [6 :0] ro_drive ;
reg [15:0] ro_operation_addr ;
reg [7 :0] ro_operation_len ;
reg [1 :0] ro_operation_type ;
reg ro_opeartion_valid ;
reg r_fifo_read_en ;
reg [7 :0] r_read_cnt ;
reg [15:0] r_read_addr ;
reg r_read_vld_1d ;
/***************wire******************/
wire w_ctrl_active ;
wire w_drive_end ;
wire w_drive_act ;
wire [7 :0] w_fifo_read_data ;
wire w_fifo_empty ;
/***************component*************/
FIFO_8X1024 FIFO_8X1024_WRITE_U0 (
.clk (i_clk ),
.srst (i_rst ),
.din (ri_ctrl_write_data ),
.wr_en (ri_ctrl_write_valid ),
.rd_en (i_write_req ),
.dout (o_write_data ),
.full (),
.empty ()
);
FIFO_8X1024 FIFO_8X1024_READ_U0 (
.clk (i_clk ),
.srst (i_rst ),
.din (ri_read_data ),
.wr_en (ri_read_valid ),
.rd_en (r_fifo_read_en ),
.dout (w_fifo_read_data ),
.full (),
.empty (w_fifo_empty )
);
/***************assign****************/
assign o_ctrl_operation_ready = ro_ctrl_operation_ready ;
assign o_ctrl_read_data = ro_ctrl_read_data ;
assign o_ctrl_read_valid = r_read_vld_1d ;
assign w_ctrl_active = i_ctrl_opeartion_valid&o_ctrl_operation_ready;
assign w_drive_end = i_operation_ready & !ri_operation_ready;
assign w_drive_act = o_opeartion_valid & i_operation_ready;
assign o_drive = ro_drive ;
assign o_operation_addr = ro_operation_addr ;
assign o_operation_len = ro_operation_len ;
assign o_operation_type = ro_operation_type ;
assign o_opeartion_valid = ro_opeartion_valid;
/***************always****************/
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
r_st_current <= P_ST_IDLE;
else
r_st_current <= r_st_next;
end
always@(*)
begin
case(r_st_current)
P_ST_IDLE :r_st_next = w_ctrl_active && i_ctrl_operation_type == 1 ? P_ST_WRITE :
w_ctrl_active && i_ctrl_operation_type == 2 ? P_ST_WAIT :
P_ST_IDLE;
P_ST_WRITE :r_st_next = w_drive_end ? P_ST_IDLE : P_ST_WRITE;
P_ST_WAIT :r_st_next = P_ST_READ;
P_ST_READ :r_st_next = w_drive_end ?
r_read_cnt == ri_ctrl_operation_len - 1 ? P_ST_OREAD : P_ST_REREAD
: P_ST_READ;
P_ST_REREAD :r_st_next = P_ST_READ;
P_ST_OREAD :r_st_next = w_fifo_empty ? P_ST_IDLE : P_ST_OREAD;
default :r_st_next = P_ST_IDLE;
endcase
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
r_fifo_read_en <= 'd0;
else if(w_fifo_empty)
r_fifo_read_en <= 'd0;
else if(r_st_current != P_ST_OREAD && r_st_next == P_ST_OREAD)
r_fifo_read_en <= 'd1;
else
r_fifo_read_en <= r_fifo_read_en;
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
ro_ctrl_read_data <= 'd0;
else
ro_ctrl_read_data <= w_fifo_read_data;
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
ro_ctrl_read_valid <= 'd0;
else if(w_fifo_empty)
ro_ctrl_read_valid <= 'd0;
else if(r_fifo_read_en)
ro_ctrl_read_valid <= 'd1;
else
ro_ctrl_read_valid <= ro_ctrl_read_valid;
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
r_read_vld_1d <= 'd0;
else
r_read_vld_1d <= ro_ctrl_read_valid;
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst) begin
ri_ctrl_eeprom_addr <= 'd0;
ri_ctrl_operation_addr <= 'd0;
ri_ctrl_operation_type <= 'd0;
ri_ctrl_operation_len <= 'd0;
end else if(w_ctrl_active) begin
ri_ctrl_eeprom_addr <= i_ctrl_eeprom_addr ;
ri_ctrl_operation_addr <= i_ctrl_operation_addr;
ri_ctrl_operation_type <= i_ctrl_operation_type;
ri_ctrl_operation_len <= i_ctrl_operation_len;
end else begin
ri_ctrl_eeprom_addr <= ri_ctrl_eeprom_addr ;
ri_ctrl_operation_addr <= ri_ctrl_operation_addr;
ri_ctrl_operation_type <= ri_ctrl_operation_type;
ri_ctrl_operation_len <= ri_ctrl_operation_len;
end
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst) begin
ri_ctrl_write_data <= 'd0;
ri_ctrl_write_sop <= 'd0;
ri_ctrl_write_eop <= 'd0;
ri_ctrl_write_valid <= 'd0;
end else begin
ri_ctrl_write_data <= i_ctrl_write_data ;
ri_ctrl_write_sop <= i_ctrl_write_sop ;
ri_ctrl_write_eop <= i_ctrl_write_eop ;
ri_ctrl_write_valid <= i_ctrl_write_valid ;
end
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
ro_ctrl_operation_ready <= 'd1;
else if(w_ctrl_active)
ro_ctrl_operation_ready <= 'd0;
else if(r_st_current == P_ST_IDLE)
ro_ctrl_operation_ready <= 'd1;
else
ro_ctrl_operation_ready <= ro_ctrl_operation_ready;
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
ri_operation_ready <= 'd0;
else
ri_operation_ready <= i_operation_ready;
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst) begin
ri_read_data <= 'd0;
ri_read_valid <= 'd0;
end else begin
ri_read_data <= i_read_data ;
ri_read_valid <= i_read_valid;
end
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst) begin
ro_drive <= 'd0;
ro_operation_addr <= 'd0;
ro_operation_len <= 'd0;
ro_operation_type <= 'd0;
ro_opeartion_valid <= 'd0;
end else if(w_drive_act) begin
ro_drive <= 'd0;
ro_operation_addr <= 'd0;
ro_operation_len <= 'd0;
ro_operation_type <= 'd0;
ro_opeartion_valid <= 'd0;
end else if(ri_ctrl_write_eop) begin
ro_drive <= {4'b1010,ri_ctrl_eeprom_addr};
ro_operation_addr <= ri_ctrl_operation_addr;
ro_operation_len <= ri_ctrl_operation_len;
ro_operation_type <= ri_ctrl_operation_type;
ro_opeartion_valid <= 'd1;
end else if(r_st_next == P_ST_READ && r_st_current != P_ST_READ) begin
ro_drive <= {4'b1010,ri_ctrl_eeprom_addr};
ro_operation_addr <= r_read_addr;
ro_operation_len <= 1;
ro_operation_type <= ri_ctrl_operation_type;
ro_opeartion_valid <= 'd1;
end else begin
ro_drive <= ro_drive ;
ro_operation_addr <= ro_operation_addr ;
ro_operation_len <= ro_operation_len ;
ro_operation_type <= ro_operation_type ;
ro_opeartion_valid <= ro_opeartion_valid;
end
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
r_read_addr <= 'd0;
else if(w_ctrl_active)
r_read_addr <= i_ctrl_operation_addr;
else if(r_st_current == P_ST_READ && w_drive_end)
r_read_addr <= r_read_addr + 1 ;
else
r_read_addr <= r_read_addr;
end
always@(posedge i_clk,posedge i_rst)
begin
if(i_rst)
r_read_cnt <= 'd0;
else if(r_st_current == P_ST_IDLE)
r_read_cnt <= 'd0;
else if(r_st_current == P_ST_READ && w_drive_end)
r_read_cnt <= r_read_cnt +1;
else
r_read_cnt <= r_read_cnt;
end
endmodule