|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?注册
x
我自己通过阅读I2C总线协议和MAX9611规格书,设计了I2C的主机,不过下载到FPGA验证时,通过示波器发现从机应答始终没有,而且不给输出,就是说从机的SDA端一直处于高阻接收状态,无论地址给的对和错出来的应答都是一样。
我不知道原因出在哪里,感觉我设计的时序是满足器件要求和协议要求(单个主机单个从机,没有考虑仲裁、中断等其他条件),各位麻烦看一下我的代码,指导一下,非常感谢!!!
下面我的设计:
module I2C(clk, //20MHz工作时钟
rst, //异步低电平复位
cs, //下降沿触发模块工作
r_w, //0写,1读
add, //从机地址
reg_add, //寄存器地址
data_i, //要写的数据
data_o, //读的数据
scl, //scl
sda, //sda
A0, //MAX9611的设置,0就行了(与总线无关)
A1 //MAX9611的设置,0就行了(与总线无关)
);
input clk,rst;
input cs;
input r_w;
input[6:0] add;
input[7:0] reg_add;
input[7:0] data_i;
output[7:0] data_o;
output scl;
inout sda;
output A0;
output A1;
wire clk,rst;
wire cs;
wire r_w;
wire[6:0] add;
wire[7:0] data_i;
reg[7:0] data_o;
reg scl;
wire sda;
reg cs0,cs1;
wire STA;
reg[3:0] cnt;
reg[2:0] clk_cnt;
reg busy;
reg[4:0] state;
reg ACK;
reg sda_o;
wire sda_i;
reg ctrl;
reg f;
assign A0=0;
assign A1=0;
always@(posedge clk or negedge rst) //cs延迟两个时钟周期,用于采集信号下降沿
if(!rst)
begin
cs0<=1;
cs1<=1;
end
else
begin
cs0<=cs;
cs1<=cs0;
end
assign STA=cs0&!cs1; //下降沿开始
always@(posedge clk or negedge rst) //主机工作
if(!rst) busy<=0;
else if(STA) busy<=1;
else if(state==0) busy<=0;
always@(posedge clk or negedge rst) //采用400KHz的scl频率,其中一个scl时钟分了5段过程
if(!rst)
begin
cnt<=0;
clk_cnt<=0;
end
else if(busy)
begin
if(cnt==4'd9)
begin
cnt <= 0;
if(clk_cnt==3'd4) clk_cnt <= 0;
else clk_cnt <= clk_cnt+1;
end
else cnt<=cnt+1;
end
else
begin
cnt <= 0;
clk_cnt <= 0;
end
always@(posedge clk or negedge rst) //状态机
if(!rst) state<=0;
else case(state)
5'd0: if(STA) state<=5'd1; //起始
5'd1: if(clk_cnt==3'd4&cnt==4'd9) state<=5'd2; //写地址最高位
5'd2: if(clk_cnt==3'd4&cnt==4'd9) state<=5'd3;
5'd3: if(clk_cnt==3'd4&cnt==4'd9) state<=5'd4;
5'd4: if(clk_cnt==3'd4&cnt==4'd9) state<=5'd5;
5'd5: if(clk_cnt==3'd4&cnt==4'd9) state<=5'd6;
5'd6: if(clk_cnt==3'd4&cnt==4'd9) state<=5'd7;
5'd7: if(clk_cnt==3'd4&cnt==4'd9) state<=5'd8;
5'd8: if(clk_cnt==3'd4&cnt==4'd9) state<=5'd9; //写地址最低位
5'd9: if(clk_cnt==3'd4&cnt==4'd9) state<=5'd10; //读写位
5'd10: if(clk_cnt==3'd4&cnt==4'd9) //地址应答
if(ACK==1) state<=5'd29;
else if(f) state<=5'd11;
else state<=5'd20;
5'd11: if(clk_cnt==3'd4&cnt==4'd9) state<=5'd12; //写数据最高位(寄存器地址也是在这写)
5'd12: if(clk_cnt==3'd4&cnt==4'd9) state<=5'd13;
5'd13: if(clk_cnt==3'd4&cnt==4'd9) state<=5'd14;
5'd14: if(clk_cnt==3'd4&cnt==4'd9) state<=5'd15;
5'd15: if(clk_cnt==3'd4&cnt==4'd9) state<=5'd16;
5'd16: if(clk_cnt==3'd4&cnt==4'd9) state<=5'd17;
5'd17: if(clk_cnt==3'd4&cnt==4'd9) state<=5'd18;
5'd18: if(clk_cnt==3'd4&cnt==4'd9) state<=5'd19; //写数据最低位
5'd19: if(clk_cnt==3'd4&cnt==4'd9) //写应答
if(ACK==1) state<=5'd29;
else if(r_w==0) state<=5'd11;
else state<=5'd30;
5'd20: if(clk_cnt==3'd4&cnt==4'd9) state<=5'd21; //读地址最高位
5'd21: if(clk_cnt==3'd4&cnt==4'd9) state<=5'd22;
5'd22: if(clk_cnt==3'd4&cnt==4'd9) state<=5'd23;
5'd23: if(clk_cnt==3'd4&cnt==4'd9) state<=5'd24;
5'd24: if(clk_cnt==3'd4&cnt==4'd9) state<=5'd25;
5'd25: if(clk_cnt==3'd4&cnt==4'd9) state<=5'd26;
5'd26: if(clk_cnt==3'd4&cnt==4'd9) state<=5'd27;
5'd27: if(clk_cnt==3'd4&cnt==4'd9) state<=5'd28; //读地址最低位
5'd28: if(clk_cnt==3'd4&cnt==4'd9) //应答
if(ACK==1) state<=5'd29;
else state<=5'd20;
5'd29: if(clk_cnt==3'd4&cnt==4'd9) state<=5'd0; //结束
5'd30: if(clk_cnt==3'd4&cnt==4'd9) state<=5'd2; //重新开始
default: state<=5'd0;
endcase
//对scl和sda_o的操作,根据规格书的时序要求,这里400Kscl的高度电平的时间设置会比较紧,但没啥问题
always@(posedge clk or negedge rst)
if(!rst)
begin
scl<=1;
sda_o<=1;
f<=1;
ctrl<=0;
end
else case(state)
5'd0: begin
scl<=1;
sda_o<=1;
f<=1;
ctrl<=0;
end
5'd1: if(clk_cnt==3'b000)
begin
scl<=1;
sda_o<=1;
ctrl<=0;
end
else if(clk_cnt==3'b001)
begin
scl<=1;
sda_o<=1;
end
else if(clk_cnt==3'b010)
begin
scl<=1;
sda_o<=0;
end
else if(clk_cnt==3'b011)
begin
scl<=1;
sda_o<=0;
end
else if(clk_cnt==3'b100)
begin
scl<=0;
sda_o<=0;
end
5'd2: begin
ctrl<=0;
sda_o<=add[6];
if(clk_cnt==3'b000) scl<=0;
else if(clk_cnt==3'b001) scl<=0;
else if(clk_cnt==3'b010) scl<=1;
else if(clk_cnt==3'b011) begin if(cnt==4'b0100) scl<=0; end
else if(clk_cnt==3'b100) scl<=0;
end
5'd3: begin
ctrl<=0;
sda_o<=add[5];
if(clk_cnt==3'b000) scl<=0;
else if(clk_cnt==3'b001) scl<=0;
else if(clk_cnt==3'b010) scl<=1;
else if(clk_cnt==3'b011) begin if(cnt==4'b0100) scl<=0; end
else if(clk_cnt==3'b100) scl<=0;
end
5'd4: begin
ctrl<=0;
sda_o<=add[4];
if(clk_cnt==3'b000) scl<=0;
else if(clk_cnt==3'b001) scl<=0;
else if(clk_cnt==3'b010) scl<=1;
else if(clk_cnt==3'b011) begin if(cnt==4'b0100) scl<=0; end
else if(clk_cnt==3'b100) scl<=0;
end
5'd5: begin
ctrl<=0;
sda_o<=add[3];
if(clk_cnt==3'b000) scl<=0;
else if(clk_cnt==3'b001) scl<=0;
else if(clk_cnt==3'b010) scl<=1;
else if(clk_cnt==3'b011) begin if(cnt==4'b0100) scl<=0; end
else if(clk_cnt==3'b100) scl<=0;
end
5'd6: begin
ctrl<=0;
sda_o<=add[2];
if(clk_cnt==3'b000) scl<=0;
else if(clk_cnt==3'b001) scl<=0;
else if(clk_cnt==3'b010) scl<=1;
else if(clk_cnt==3'b011) begin if(cnt==4'b0100) scl<=0; end
else if(clk_cnt==3'b100) scl<=0;
end
5'd7: begin
ctrl<=0;
sda_o<=add[1];
if(clk_cnt==3'b000) scl<=0;
else if(clk_cnt==3'b001) scl<=0;
else if(clk_cnt==3'b010) scl<=1;
else if(clk_cnt==3'b011) begin if(cnt==4'b0100) scl<=0; end
else if(clk_cnt==3'b100) scl<=0;
end
5'd8: begin
ctrl<=0;
sda_o<=add[0];
if(clk_cnt==3'b000) scl<=0;
else if(clk_cnt==3'b001) scl<=0;
else if(clk_cnt==3'b010) scl<=1;
else if(clk_cnt==3'b011) begin if(cnt==4'b0100) scl<=0; end
else if(clk_cnt==3'b100) scl<=0;
end
5'd9: begin
if(f) sda_o<=0;
else sda_o<=1;
if(clk_cnt==3'b000) scl<=0;
else if(clk_cnt==3'b001) scl<=0;
else if(clk_cnt==3'b010) scl<=1;
else if(clk_cnt==3'b011) begin if(cnt==4'b0100) begin scl<=0; ctrl<=1;end end
else if(clk_cnt==3'b100) scl<=0;
end
5'd10: begin
sda_o<=0;
if(clk_cnt==3'b000) scl<=0;
else if(clk_cnt==3'b001) scl<=0;
else if(clk_cnt==3'b010) scl<=1;
else if(clk_cnt==3'b011) begin if(cnt==4'b0100) begin scl<=0; if(f) ctrl<=0; end end
else if(clk_cnt==3'b100) scl<=0;
end
5'd11: begin
ctrl<=0;
if(f) sda_o<=reg_add[7];
else sda_o<=data_i[7];
if(clk_cnt==3'b000) scl<=0;
else if(clk_cnt==3'b001) scl<=0;
else if(clk_cnt==3'b010) scl<=1;
else if(clk_cnt==3'b011) begin if(cnt==4'b0100) scl<=0; end
else if(clk_cnt==3'b100) scl<=0;
end
5'd12: begin
ctrl<=0;
if(f) sda_o<=reg_add[6];
else sda_o<=data_i[6];
if(clk_cnt==3'b000) scl<=0;
else if(clk_cnt==3'b001) scl<=0;
else if(clk_cnt==3'b010) scl<=1;
else if(clk_cnt==3'b011) begin if(cnt==4'b0100) scl<=0; end
else if(clk_cnt==3'b100) scl<=0;
end
5'd13: begin
ctrl<=0;
if(f) sda_o<=reg_add[5];
else sda_o<=data_i[5];
if(clk_cnt==3'b000) scl<=0;
else if(clk_cnt==3'b001) scl<=0;
else if(clk_cnt==3'b010) scl<=1;
else if(clk_cnt==3'b011) begin if(cnt==4'b0100) scl<=0; end
else if(clk_cnt==3'b100) scl<=0;
end
5'd14: begin
if(f) sda_o<=reg_add[4];
else sda_o<=data_i[4];
if(clk_cnt==3'b000) scl<=0;
else if(clk_cnt==3'b001) scl<=0;
else if(clk_cnt==3'b010) scl<=1;
else if(clk_cnt==3'b011) begin if(cnt==4'b0100) scl<=0; end
else if(clk_cnt==3'b100) scl<=0;
end
5'd15: begin
ctrl<=0;
if(f) sda_o<=reg_add[3];
else sda_o<=data_i[3];
if(clk_cnt==3'b000) scl<=0;
else if(clk_cnt==3'b001) scl<=0;
else if(clk_cnt==3'b010) scl<=1;
else if(clk_cnt==3'b011) begin if(cnt==4'b0100) scl<=0; end
else if(clk_cnt==3'b100) scl<=0;
end
5'd16: begin
ctrl<=0;
if(f) sda_o<=reg_add[2];
else sda_o<=data_i[2];
if(clk_cnt==3'b000) scl<=0;
else if(clk_cnt==3'b001) scl<=0;
else if(clk_cnt==3'b010) scl<=1;
else if(clk_cnt==3'b011) begin if(cnt==4'b0100) scl<=0; end
else if(clk_cnt==3'b100) scl<=0;
end
5'd17: begin
ctrl<=0;
if(f) sda_o<=reg_add[1];
else sda_o<=data_i[1];
if(clk_cnt==3'b000) scl<=0;
else if(clk_cnt==3'b001) scl<=0;
else if(clk_cnt==3'b010) scl<=1;
else if(clk_cnt==3'b011) begin if(cnt==4'b0100) scl<=0; end
else if(clk_cnt==3'b100) scl<=0;
end
5'd18: begin
if(f) sda_o<=reg_add[0];
else sda_o<=data_i[0];
if(clk_cnt==3'b000) scl<=0;
else if(clk_cnt==3'b001) scl<=0;
else if(clk_cnt==3'b010) scl<=1;
else if(clk_cnt==3'b011) begin if(cnt==4'b0100) begin scl<=0; ctrl<=1; end end
else if(clk_cnt==3'b100) scl<=0;
end
5'd19: begin
sda_o<=0;
if(clk_cnt==3'b000) begin scl<=0; if(cnt==0) f<=!f; end
else if(clk_cnt==3'b001) scl<=0;
else if(clk_cnt==3'b010) scl<=1;
else if(clk_cnt==3'b011) begin if(cnt==4'b0100) begin scl<=0; ctrl<=0; end end
else if(clk_cnt==3'b100) scl<=0;
end
5'd20: begin
ctrl<=1;
sda_o<=0;
if(clk_cnt==3'b000) scl<=0;
else if(clk_cnt==3'b001) scl<=0;
else if(clk_cnt==3'b010) scl<=1;
else if(clk_cnt==3'b011) begin if(cnt==4'b0100) scl<=0; end
else if(clk_cnt==3'b100) scl<=0;
end
5'd21: begin
ctrl<=1;
sda_o<=0;
if(clk_cnt==3'b000) scl<=0;
else if(clk_cnt==3'b001) scl<=0;
else if(clk_cnt==3'b010) scl<=1;
else if(clk_cnt==3'b011) scl<=1;
else if(clk_cnt==3'b100) scl<=0;
end
5'd22: begin
ctrl<=1;
sda_o<=0;
if(clk_cnt==3'b000) scl<=0;
else if(clk_cnt==3'b001) scl<=0;
else if(clk_cnt==3'b010) scl<=1;
else if(clk_cnt==3'b011) begin if(cnt==4'b0100) scl<=0; end
else if(clk_cnt==3'b100) scl<=0;
end
5'd23: begin
ctrl<=1;
sda_o<=0;
if(clk_cnt==3'b000) scl<=0;
else if(clk_cnt==3'b001) scl<=0;
else if(clk_cnt==3'b010) scl<=1;
else if(clk_cnt==3'b011) begin if(cnt==4'b0100) scl<=0; end
else if(clk_cnt==3'b100) scl<=0;
end
5'd24: begin
ctrl<=1;
sda_o<=0;
if(clk_cnt==3'b000) scl<=0;
else if(clk_cnt==3'b001) scl<=0;
else if(clk_cnt==3'b010) scl<=1;
else if(clk_cnt==3'b011) begin if(cnt==4'b0100) scl<=0; end
else if(clk_cnt==3'b100) scl<=0;
end
5'd25: begin
ctrl<=1;
sda_o<=0;
if(clk_cnt==3'b000) scl<=0;
else if(clk_cnt==3'b001) scl<=0;
else if(clk_cnt==3'b010) scl<=1;
else if(clk_cnt==3'b011) begin if(cnt==4'b0100) scl<=0; end
else if(clk_cnt==3'b100) scl<=0;
end
5'd26: begin
ctrl<=1;
sda_o<=0;
if(clk_cnt==3'b000) scl<=0;
else if(clk_cnt==3'b001) scl<=0;
else if(clk_cnt==3'b010) scl<=1;
else if(clk_cnt==3'b011) begin if(cnt==4'b0100) scl<=0; end
else if(clk_cnt==3'b100) scl<=0;
end
5'd27: begin
sda_o<=0;
if(clk_cnt==3'b000) scl<=0;
else if(clk_cnt==3'b001) scl<=0;
else if(clk_cnt==3'b010) scl<=1;
else if(clk_cnt==3'b011) begin if(cnt==4'b0100) begin scl<=0; ctrl<=0; end end
else if(clk_cnt==3'b100) scl<=0;
end
5'd28: begin
sda_o<=ACK;
if(clk_cnt==3'b000) scl<=0;
else if(clk_cnt==3'b001) scl<=0;
else if(clk_cnt==3'b010) scl<=1;
else if(clk_cnt==3'b011) begin if(cnt==4'b0100) begin scl<=0; if(!ACK) ctrl<=1; end end
else if(clk_cnt==3'b100) scl<=0;
end
5'd29: if(clk_cnt==3'b000)
begin
ctrl<=0;
scl<=0;
sda_o<=0;
f<=1;
end
else if(clk_cnt==3'b001)
begin
scl<=1;
sda_o<=0;
f<=1;
end
else if(clk_cnt==3'b010)
begin
scl<=1;
sda_o<=0;
f<=1;
end
else if(clk_cnt==3'b011)
begin
scl<=1;
sda_o<=1;
f<=1;
end
else if(clk_cnt==3'b100)
begin
scl<=1;
sda_o<=1;
f<=1;
end
5'd30: if(clk_cnt==3'b000)
begin
ctrl<=0;
sda_o<=1;
scl<=0;
end
else if(clk_cnt==3'b001)
begin
sda_o<=1;
if(cnt==4'b0010) scl<=1;
end
else if(clk_cnt==3'b010)
begin
scl<=1;
if(cnt==4'b0110) sda_o<=0;
end
else if(clk_cnt==3'b011)
begin
scl<=1;
sda_o<=0;
end
else if(clk_cnt==3'b100)
begin
scl<=0;
sda_o<=0;
end
default: begin
ctrl<=0;
scl<=1;
sda_o<=1;
end
endcase
//应答信号的采集
always@(posedge clk or negedge rst)
if(!rst) ACK<=0;
else if(state==5'd10||state==5'd19)
begin
if(clk_cnt==3'b010&&sda_i==1'b1) ACK<=1;
end
else if(state==5'd28) ACK<=1;
else ACK<=0;
reg[7:0] data;
always@(posedge scl or negedge rst) //读数据
if(!rst)
data<=0;
else case(state)
5'd10: data<=0;
5'd19: data<=0;
5'd20: data[7]<=sda_i;
5'd21: data[6]<=sda_i;
5'd22: data[5]<=sda_i;
5'd23: data[4]<=sda_i;
5'd24: data[3]<=sda_i;
5'd25: data[2]<=sda_i;
5'd26: data[1]<=sda_i;
5'd27: data[0]<=sda_i;
5'd28: data<=0;
default: data<=0;
endcase
always@(posedge clk or negedge rst)
if(!rst)
data_o<=0;
else if(state==5'd28)
data_o<=data;
assign sda=(ctrl)? 1'bz : sda_o; //三态门
assign sda_i=sda;
endmodule
附上MAX9611的规格书,麻烦大家看看我问题在哪了,谢谢!!!
MAX9611AUB __规格书_Datasheet_资料.pdf
(2.41 MB, 下载次数: 26 )
|
|