近期,做SRIO switch 调试,需要用I2C接口来 读写switch的寄存器。现将I2C的代码整理如下。
module iic_wr_ctrl
(
input sys_clk,
input rst_n,
input key_wr,
input key_rd,
inout sda,
output reg scl,
output clk,
output ila_clk,
output link_sda,
output reg [7:0] data,
output reg [7:0] data2,
output [7:0] state,
output [3:0] count,
output [7:0] eeprom_data,
// input [6:0] IIC_ADDR,
input [23:0] IIC_ADDRESS ,
input [31:0] write_data
);
reg [6:0] cnt;
reg [6:0] cnt_1;
reg [3:0] count;
reg clk;
reg ila_clk;
reg wr;
reg rd;
reg link_sda;
reg sda_buf;
reg [7:0] eeprom_data;
reg [7:0] state;
reg [3:0] led;
assign sda = (link_sda)? sda_buf : 1'bz;
always@(posedge sys_clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt <= 0;
clk <= 0;
end
else if(cnt < 125)
begin
cnt <= cnt + 1;
end
else
begin
cnt <= 0;
clk <= ~clk;
end
end
always@(posedge sys_clk or negedge rst_n)
begin
if(!rst_n)
begin
cnt_1 <= 0;
ila_clk <= 0;
end
else if(cnt_1 < 62)
begin
cnt_1 <= cnt_1 + 1;
end
else
begin
cnt_1 <= 0;
ila_clk <= ~ila_clk;
end
end
always@(negedge clk or negedge rst_n)
begin
if(!rst_n)
scl <= 0;
else
scl <= ~scl;
end
产生SCL时钟信号
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
state <= 8'h0;
wr <= 0;
rd <= 0;
count <= 0;
link_sda <= 0;
sda_buf <= 0;
eeprom_data <= 0;
data <= 0;
data2 <= 0;
led <= 4'b0000;
end
else
begin
case(state)
8'h0: begin
if(!key_rd)
rd <= 1;
else if(!key_wr)
wr <= 1;
else if(!scl && (rd || wr))
begin
link_sda <= 1;
sda_buf <= 1;
state <= 8'h1;
data <= 0;
data2 <= 0;
end
else
state <= 8'h0;
end
8'h1: begin
if(scl)
begin
sda_buf <= 0;
state <= 8'h2;
eeprom_data <= {7'b1010111,1'b0}; //8'b1000_0100 //device ID
end
else
state <= 8'h1;
end
8'h2: begin
if(!scl && count < 8)
begin
count <= count + 1;
eeprom_data <= {eeprom_data[6:0], eeprom_data[7]};
sda_buf <= eeprom_data[7];
end
else if(count == 8 && !scl)
begin
count <= 0;
// eeprom_data <= 0;
link_sda <= 0;
state <= 8'h3;
end
else
state <= 8'h2;
end
8'h3: begin
if(scl)
begin
if(!sda)
begin
state <= 8'h4;
eeprom_data <= IIC_ADDRESS[23:16]; //addr [23:16]
end
end
end
8'h4: begin
link_sda <= 1;
if(count < 8 && !scl)
begin
count <= count + 1;
eeprom_data <= {eeprom_data[6:0],eeprom_data[7]};
sda_buf <= eeprom_data[7];
end
else if(count == 8 && !scl)
begin
count <= 0;
state <= 8'h23;
link_sda <= 0;
end
else
state <= 8'h4;
end
8'h23: begin
if(scl)
begin
if(!sda)
begin
state <= 8'h24;
eeprom_data <= IIC_ADDRESS[15:8]; addr [15:8]
end
end
end
8'h24: begin
link_sda <= 1;
if(count < 8 && !scl)
begin
count <= count + 1;
eeprom_data <= {eeprom_data[6:0],eeprom_data[7]};
sda_buf <= eeprom_data[7];
end
else if(count == 8 && !scl)
begin
count <= 0;
state <= 8'h25;
link_sda <= 0;
end
else
state <= 8'h24;
end
8'h25: begin
if(scl)
begin
if(!sda)
begin
state <= 8'h26;
eeprom_data <= IIC_ADDRESS[7:0]; addr [7:0]
end
end
end
8'h26: begin
link_sda <= 1;
if(count < 8 && !scl)
begin
count <= count + 1;
eeprom_data <= {eeprom_data[6:0],eeprom_data[7]};
sda_buf <= eeprom_data[7];
end
else if(count == 8 && !scl)
begin
count <= 0;
state <= 8'h5;
link_sda <= 0;
end
else
state <= 8'h26;
end
8'h5: begin
if(scl)
begin
if(!sda)
begin
if(wr == 1)
begin
state <= 8'h6;
eeprom_data <= write_data[31:24]; // data[31:24]
end
else if(rd == 1)
begin
state <= 8'h9;
end
end
end
end
8'h6: begin
link_sda <= 1;
if(!scl && count < 8)
begin
count <= count + 1;
eeprom_data <= {eeprom_data[6:0],eeprom_data[7]};
sda_buf <= eeprom_data[7];
end
else if(!scl && count == 8)
begin
count <= 0;
link_sda <= 0;
state <= 8'h7;
end
else
state <= 8'h6;
end
8'h7: begin
if(scl)
begin
if(!sda)
begin
state <= 8'h14;
eeprom_data <= write_data[23:16]; //data[23:16]
end
end
end
8'h14: begin
link_sda <= 1;
if(!scl && count < 8)
begin
count <= count + 1;
eeprom_data <= {eeprom_data[6:0],eeprom_data[7]};
sda_buf <= eeprom_data[7];
end
else if(!scl && count == 8)
begin
count <= 0;
link_sda <= 0;
state <= 8'h27;
end
else
state <= 8'h14;
end
8'h27: begin
if(scl)
begin
if(!sda)
begin
state <= 8'h28;
eeprom_data <= write_data[15:8]; //data[15:8]
end
end
end
8'h28: begin
link_sda <= 1;
if(!scl && count < 8)
begin
count <= count + 1;
eeprom_data <= {eeprom_data[6:0],eeprom_data[7]};
sda_buf <= eeprom_data[7];
end
else if(!scl && count == 8)
begin
count <= 0;
link_sda <= 0;
state <= 8'h29;
end
else
state <= 8'h28;
end
8'h29: begin
if(scl)
begin
if(!sda)
begin
state <= 8'h2A;
eeprom_data <= write_data[7:0]; //data[7:0]
end
end
end
8'h2A: begin
link_sda <= 1;
if(!scl && count < 8)
begin
count <= count + 1;
eeprom_data <= {eeprom_data[6:0],eeprom_data[7]};
sda_buf <= eeprom_data[7];
end
else if(!scl && count == 8)
begin
count <= 0;
link_sda <= 0;
state <= 8'h8;
end
else
state <= 8'h2A;
end
8'h8: begin
link_sda <= 1;
sda_buf <= 0;
if(scl)
begin
sda_buf <= 1;
led <= 4'b0001;
wr <= 0;
state <= 8'h0;
end
else
state <= 8'h8;
end
8'h9: begin
if(!scl)
begin
link_sda <= 1;
sda_buf <= 1;
state <= 8'hA;
end
else
state <= 8'h9;
end
8'hA: begin
if(scl)
begin
sda_buf <= 0;
state <= 8'hB;
eeprom_data <= {7'b1010111,1'b1}; //8'b1000_0101; //device ID
end
else
state <= 8'hA;
end
8'hB:begin
if(!scl && count < 8)
begin
count <= count + 1;
eeprom_data <= {eeprom_data[6:0], eeprom_data[7]};
sda_buf <= eeprom_data[7];
end
else if(count == 8 && !scl)
begin
count <= 0;
// eeprom_data <= 0;
link_sda <= 0;
state <= 8'hC;
end
else
state <= 8'hB;
end
8'hC:begin
if(scl)
begin
if(!sda)
state <= 8'hD;
end
end
8'hD:begin
if(scl && count < 7) //rd_data[31:24]
begin
count <= count + 1;
data[7 - count] <= sda;
end
else if(scl && count == 7)
begin
data[7 - count] <= sda;
count <= 0;
// led <= 0;
state <= 8'h13;
// sda_buf <= 0;
// link_sda <= 1;
end
else
state <= 8'hD;
end
8'h13:begin
sda_buf <= 0;
link_sda <= 1;
state <= 8'hE;
end
//MASTER 应答信号
8'hE:begin
if(scl)
begin
state <= 8'h12;
end
end
8'h12:begin
link_sda <= 0; //xinjia
// if(!sda)
state <= 8'h3D;
end
8'h3D:begin
if(scl && count < 7) //rd_data[23:16]
begin
count <= count + 1;
data[7 - count] <= sda;
end
else if(scl && count == 7)
begin
data[7 - count] <= sda;
count <= 0;
// led <= 0;
state <= 8'h33;
// sda_buf <= 0;
// link_sda <= 1;
end
else
state <= 8'h3D;
end
8'h33:begin
sda_buf <= 0;
link_sda <= 1;
state <= 8'h3E;
end
//MASTER 应答信号
8'h3E:begin
if(scl)
begin
state <= 8'h32;
end
end
8'h32:begin
link_sda <= 0; //xinjia
// if(!sda)
state <= 8'h4D;
end
8'h4D:begin
if(scl && count < 7)
begin
count <= count + 1; //rd_data[15:8]
data[7 - count] <= sda;
end
else if(scl && count == 7)
begin
data[7 - count] <= sda;
count <= 0;
// led <= 0;
state <= 8'h43;
// sda_buf <= 0;
// link_sda <= 1;
end
else
state <= 8'h4D;
end
8'h43:begin
sda_buf <= 0;
link_sda <= 1;
state <= 8'h4E;
end
//MASTER 应答信号
8'h4E:begin
if(scl)
begin
state <= 8'h42;
end
end
8'h42:begin
link_sda <= 0; //xinjia
// if(!sda)
state <= 8'hF;
end
8'hF:begin
if(scl && count < 8)
begin
count <= count + 1;
data2[7 - count] <= sda;
end
else if(count == 8)
begin
count <= 0;
// led <= 0;
state <= 8'h10;
sda_buf <= 1;
link_sda <= 1;
end
else
state <= 8'hF;
end
8'h10:begin
if(scl)
begin
sda_buf <= 1;
state <= 8'h11;
end
else
state <= 8'h10;
end
8'h11:begin
if(!scl)
sda_buf <= 0;
else if(scl)
begin
sda_buf <= 1;
state <= 8'h0;
rd <= 4'h0;
led <= 4'b0000;
end
else
state <= 8'h11;
end
default: state <= 8'h0;
endcase
end
end
endmodule
此模块主要完成I2C的 读写时序的生成。
module CPS1432_signal(
RESET,
CLK,
WR_START,
RD_START,
RD,
WR,
ADDR,
ACK,
DATA,
sysclk,
SCL,
SDA,
WR_START_temp,
RD_START_temp,
clk_cnt
);
input RESET; //复位信号
input WR_START;
input RD_START;
output CLK; //时钟信号
output RD,WR; //读写信号
output[23:0] ADDR; //11位地址信号
input ACK; //读写周期的应答信号
output[31:0] DATA; //数据线
input sysclk;
input SCL;
inout SDA;
output WR_START_temp;
output RD_START_temp;
output [31:0] clk_cnt;
reg RD,WR;
wire [23:0] ADDR;
wire [31:0] DATA;
assign ADDR = ADDR_USER_WR;
//assign DATA = (RD_START_VIO) ? 32'bz : DATA_USER ;
assign DATA = DATA_USER_WR;
//------------------------------------时钟信号输入------------------------------
reg [9:0] sysclk_cnt;
reg CLK = 1'b0;
always @ (negedge sysclk )
begin
if(sysclk_cnt >= 10'd125)
begin
sysclk_cnt <= 10'd0;
CLK <= !CLK;
end
else
begin
sysclk_cnt <= sysclk_cnt + 1'b1;
CLK <= CLK;
end
end
//
// reg [9:0] sysclk_cnt1;
// reg CLK1 = 1'b0;
// always @ (negedge sysclk )
// begin
// if(sysclk_cnt1 >= 10'd249)
// begin
// sysclk_cnt1 <= 10'd0;
// CLK1 <= !CLK1;
// end
// else
// begin
// sysclk_cnt1 <= sysclk_cnt1 + 1'b1;
// CLK1 <= CLK1;
// end
// end
//----------------------------------- 读写信号输入------------------------------
//-----------------------------------------写操作-----------------------------
always @ (negedge CLK or posedge RESET)
begin
if (RESET)
WR <= 1'b0;
else if (WR_trig)
WR <= 1'b1;
else
WR <= 1'b0;
end
reg WR_START_temp_r;
wire WR_trig;
always @ (negedge CLK or posedge RESET)
begin
if (RESET)
WR_START_temp_r <= 1'b0;
else
WR_START_temp_r <= WR_START_temp;
end
assign WR_trig = WR_START_temp & ! WR_START_temp_r;
//----------------------------------------读操作----------------------------
always @ (negedge CLK or posedge RESET)
begin
if (RESET)
RD <= 1'b0;
else if (RD_trig)
RD <= 1'b1;
else
RD <= 1'b0;
end
wire RD_START;
reg RD_START_temp_r;
wire RD_trig;
always @ (negedge CLK or posedge RESET)
begin
if (RESET)
RD_START_temp_r <= 1'b0;
else
RD_START_temp_r <= RD_START_temp;
end
assign RD_trig = RD_START_temp & ! RD_START_temp_r;
reg WR_START_temp;
reg [23:0] ADDR_USER_WR;
reg [31:0] DATA_USER_WR;
reg [31:0] clk_cnt_WR;
always @ (posedge CLK or posedge RESET)
begin
if (RESET)
begin
WR_START_temp <= 1'b0;
ADDR_USER_WR <= (24'hE0_0004 >>2);
DATA_USER_WR <= 32'h0000_0003;
clk_cnt_WR <= 32'd0;
end
else if(!WR_START)
begin
WR_START_temp <= 1'b0;
ADDR_USER_WR <= (24'hE0_0004 >>2);
DATA_USER_WR <= 32'h0000_0003;
clk_cnt_WR <= 32'd0;
end
else
begin
if(clk_cnt_WR >= 32'd0000 & clk_cnt_WR <32'd300)
begin
WR_START_temp <= 1'b1;
clk_cnt_WR <= clk_cnt_WR + 1'b1;
end
else if(clk_cnt_WR >= 32'd300 & clk_cnt_WR <32'd600)
begin
WR_START_temp <= 1'b0;
clk_cnt_WR <= clk_cnt_WR + 1'b1;
end
else if (clk_cnt_WR >= 32'd600 & clk_cnt_WR < 32'd700 )
begin
WR_START_temp <= 1'b1;
ADDR_USER_WR <= (24'hE0_0008 >>2);
DATA_USER_WR <= 32'h0000_0007;
clk_cnt_WR <= clk_cnt_WR + 1'b1;
end
else if (clk_cnt_WR >= 32'd700 & clk_cnt_WR < 32'd1000 )
begin
WR_START_temp <= 1'b0;
clk_cnt_WR <= clk_cnt_WR + 1'b1;
end
// else if(clk_cnt_WR >= 32'd1000 & clk_cnt_WR <32'd1100)
// begin
// WR_START_temp <= 1'b0;
// clk_cnt_WR <= clk_cnt_WR + 1'b1;
// end
else if (clk_cnt_WR >= 32'd1000 & clk_cnt_WR < 32'd1200 )
begin
WR_START_temp <= 1'b1;
ADDR_USER_WR <= (24'h00_01BC >>2);
DATA_USER_WR <= 32'hD060_0001;
clk_cnt_WR <= clk_cnt_WR + 1'b1;
end
else if (clk_cnt_WR >= 32'd1200 & clk_cnt_WR < 32'd1700 )
begin
WR_START_temp <= 1'b0;
clk_cnt_WR <= clk_cnt_WR + 1'b1;
end
else if (clk_cnt_WR >= 32'd1700 & clk_cnt_WR < 32'd1900 )
begin
WR_START_temp <= 1'b1;
ADDR_USER_WR <= (24'h00_023C >>2);
DATA_USER_WR <= 32'hD060_0001;
clk_cnt_WR <= clk_cnt_WR + 1'b1;
end
else if (clk_cnt_WR >= 32'd1900 & clk_cnt_WR < 32'd2200 )
begin
WR_START_temp <= 1'b0;
clk_cnt_WR <= clk_cnt_WR + 1'b1;
end
else
begin
WR_START_temp <= 1'b0;
clk_cnt_WR <= clk_cnt_WR ;
end
end
end
reg RD_START_temp;
reg [23:0] ADDR_USER_RD;
reg [31:0] DATA_USER_RD;
reg [31:0] clk_cnt_RD;
always @ (posedge CLK or posedge RESET)
begin
if (RESET)
begin
RD_START_temp <= 1'b0;
// ADDR_USER_RD <= 24'hE1_7044;
ADDR_USER_RD <= ASYNC_OUT[26:3];
// DATA_USER_RD <= 32'h0000_0003;
clk_cnt_RD <= 32'd0;
end
else if(!RD_START)
begin
RD_START_temp <= 1'b0;
// ADDR_USER_RD <= 24'hE1_7044;
ADDR_USER_RD <= ASYNC_OUT[26:3];
// DATA_USER_RD <= 32'h0000_0003;
clk_cnt_RD <= 32'd0;
end
else
begin
if(clk_cnt_RD >= 32'd0000 & clk_cnt_RD <32'd300)
begin
RD_START_temp <= 1'b1;
clk_cnt_RD <= clk_cnt_RD + 1'b1;
end
else if(clk_cnt_RD >= 32'd300 & clk_cnt_RD <32'd600)
begin
RD_START_temp <= 1'b0;
clk_cnt_RD <= clk_cnt_RD + 1'b1;
end
else if (clk_cnt_RD >= 32'd600 & clk_cnt_RD < 32'd700 )
begin
// ADDR_USER_RD <= 24'hE1_3084;
ADDR_USER_RD <= ASYNC_OUT[51:28];
DATA_USER_RD <= 32'h0000_0007;
clk_cnt_RD <= clk_cnt_RD + 1'b1;
end
else if (clk_cnt_RD >= 32'd700 & clk_cnt_RD < 32'd1000 )
begin
RD_START_temp <= 1'b1;
clk_cnt_RD <= clk_cnt_RD + 1'b1;
end
else
begin
RD_START_temp <= 1'b0;
clk_cnt_RD <= clk_cnt_RD ;
end
end
end
//
//
//
wire [35:0] CONTROL0;
wire [35:0] CONTROL1;
wire [79:0] ASYNC_OUT;
wire [99:0] ILA_DATA;
wire [7:0] ILA_TRIG0;
wire RD_START_VIO;
wire ADDR_RD_1;
wire ADDR_RD_2;
endmodule
此模块生成I2C读写所需的地址信息和数据信息。
module CPS1432_cfg(
sysclk,
rst_n,
CPS1432_SCL,
CPS1432_SDA,
WR_START,
CPS1432_SPD,
CPS1432_FSEL
// WR_START_temp,
// clk_cnt,
// ADDR,
// DATA
);
inout CPS1432_SDA;
output CPS1432_SCL;
input sysclk;
input rst_n;
input WR_START;
output [2:0] CPS1432_SPD;
output [1:0] CPS1432_FSEL;
wire WR_START_temp;
// output [31:0] clk_cnt;
wire [23:0] ADDR; //24位地址信号
wire [31:0] DATA; //数据线
assign CPS1432_SPD = 3'b101;
assign CPS1432_FSEL = 2'b10;
wire [31:0] clk_cnt;
wire [10:0] main_state;
wire [9:0] sh8in_state;
wire WR_START_VIO;
wire RD_START_VIO;
CPS1432_signal signal(
.RESET(!rst_n),
.CLK(CLK),
.RD(RD),
.WR(WR),
.ADDR(ADDR),
.DATA(DATA),
.sysclk(sysclk),
// .SDA(CPS1432_SDA),
// .SCL(CPS1432_SCL),
// .WR_trig(WR_trig),
// .RD_trig(RD_trig),
// .SYSCLK_cnt(sysclk_cnt),
.WR_START(WR_START ),
.RD_START(RD_START_VIO),
// .ADDR_VIO(ADDR_VIO),
// .DATA_VIO(DATA_VIO)
.WR_START_temp(WR_START_temp),
.RD_START_temp(RD_START_temp),
.clk_cnt(clk_cnt)
);
wire [7:0] rd_data;
wire [7:0] rd_data2;
wire [7:0] eeprom_data;
wire rst_n;
wire key_wr;
wire key_rd;
wire clk;
wire ila_clk;
wire link_sda;
wire [4:0] state;
wire [3:0] count;
// wire [6:0] IIC_ADDR;
wire [23:0] IIC_ADDRESS;
wire [31:0] write_data;
assign key_wr = !WR_START_temp;
assign key_rd = !RD_START_temp;
iic_wr_ctrl iic_wr_ctrl
(
.sys_clk(sysclk),
.clk(clk),
.ila_clk(ila_clk),
.state(state),
.rst_n(rst_n),
.key_rd(key_rd),
.key_wr(key_wr),
.sda(CPS1432_SDA),
.scl(CPS1432_SCL),
.link_sda(link_sda),
.eeprom_data(eeprom_data),
.data(rd_data),
.data2(rd_data2),
.count(count),
// .IIC_ADDR(IIC_ADDR),
.IIC_ADDRESS(ADDR),
.write_data(DATA)
);
wire [35:0] CONTROL0;
wire [35:0] CONTROL1;
wire [79:0] ASYNC_OUT;
wire [99:0] data_group;
icon icon_test
(
.CONTROL0(CONTROL0), // INOUT BUS [35:0]
.CONTROL1(CONTROL1) // INOUT BUS [35:0]
);
vio vio (
.CONTROL(CONTROL0), // INOUT BUS [35:0]
.ASYNC_OUT(ASYNC_OUT) // OUT BUS [79:0]
);
ila ila (
.CONTROL(CONTROL1), // INOUT BUS [35:0]
.CLK(ila_clk), // IN
.TRIG0(data_group) // IN BUS [99:0]
);
/
assign WR_START_VIO = ASYNC_OUT[0] ;
assign RD_START_VIO = ASYNC_OUT[1] ;
// assign key_wr = ASYNC_OUT[1] ;
// assign key_rd = ASYNC_OUT[2] ;
// assign IIC_ADDRESS = ASYNC_OUT[26:3] ;
// assign write_data = ASYNC_OUT[58:27] ;
/
assign data_group[0] = CPS1432_SCL;
assign data_group[1] = CPS1432_SDA;
assign data_group[2] = key_rd;
assign data_group[3] = key_wr;
assign data_group[4] = rst_n;
assign data_group[12:5] = rd_data;
assign data_group[20:13] = state;
assign data_group[44:21] = ADDR;
assign data_group[76:45] = DATA;
assign data_group[77] = WR_START_VIO;
assign data_group[78] = WR_START_temp;
assign data_group[79] = RD_START_VIO;
assign data_group[80] = RD_START_temp;
endmodule
使用时只要将WR_START 信号拉高,即可实现写数据。