这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界» 论坛首页» DIY与开源设计» 电子DIY» 求助iic读写问题

共5条 1/1 1 跳转至

求助iic读写问题

菜鸟
2013-09-23 21:40:22 打赏

这几天一直在做iic读写,想实现的是通过串口向at24c04的eeprom中存数据,再读取数据通过串口发送回来,在这地方卡住了。

工程三个文件:iictestquartus.v是iic读写模块,maincontrol.v是读写控制模块,实现的是先发出写指令,10ms后发出读指令,还有iic模块的复位控制。main.bdf是顶层文件,有27m时钟倍频45m送给iic模块和控制模块,此外还有控制模块的复位。

现在的问题是:奇数地址除0x01之外读写正常,(通过signaltap ii 查看),偶数地址读操作全部出错,读出来的都是0xfe,0x01地址读出的数据是写进去的数据+0x48.这问题其实是在后来才发现的,由于公司板子只有三个led灯,当时这部分完成的时候测试的是地址0x01,刚好我把读出的数据低三位给了三个led,这个地址读出来的数据是原数据+8‘b0100_1000,巧就巧在这里,低三位不受影响。所以当时以为这部分正常。到后面把串口也加上去了,通过串口把读出的数据送给串口调试助手,才发现读的数据都是错的。

我一开始以为是iic时钟频率(90khz)过高,结果调整至10khz还是一样的问题。求高手帮忙。。。。。

先贴出iic读写模块,工程文件以附件奉上iictestquar2.zip

`timescale 1ns / 1ps
////////////////////////////////////////////////////////////////////////////////
/*the cmd input must hold two scl periods.
one byte writing needs 2(start)+9(device write)+9(data_addr)+9(data)+1(stop),
totally 30 scl periods
one byte reading needs 1(start)+9(device write)+9(data_addr)+1(restart)+9(device write)+8(read data)+2(ack and stop)
totally 39 scl periods*/
module iictest2(clk45m,iic_rst,wr_cmd,rd_cmd,scl,sda,data_out);

input clk45m; // 45M
input iic_rst;
input wr_cmd,rd_cmd;
output reg scl;
inout sda;
output [2:0] data_out;


//---------------------produce the scl wave :90kHZ------------------------

reg [2:0] scl_ph;
reg [8:0] cnt_delay;
parameter scl_hig = 3'd1, scl_neg = 3'd2,
scl_low = 3'd3, scl_pos = 3'd0;


always @ (posedge clk45m or negedge iic_rst)
if(!iic_rst) cnt_delay <= 9'd0;
else if(cnt_delay==9'd499) cnt_delay <= 9'd0;
else cnt_delay <= cnt_delay+1'b1;

always @ (posedge clk45m or negedge iic_rst) begin
if(!iic_rst) scl_ph <= 2'd0;
else begin
case (cnt_delay)
9'd124: scl_ph <= scl_hig; //hig
9'd249: scl_ph <= scl_neg; //neg
9'd374: scl_ph <= scl_low; //low
9'd499: scl_ph <= scl_pos; //pos
default: scl_ph <= 3'd5;
endcase
end
end

always @ (posedge clk45m or negedge iic_rst)//if write scl_ph or iic_rst,has warnnings
begin
if(!iic_rst)
scl <= 1'b0;
else if(scl_ph == scl_pos)
scl <= 1'b1;
else if(scl_ph == scl_neg)
scl <= 1'b0;
else scl <= scl;
end

//---------------------------------------------
parameter dev_rd_cmd = 8'b1010_0001;
parameter dev_wr_cmd = 8'b1010_0000;
reg [7:0] device_add;
reg [7:0] data_addr_r;
reg [7:0] data_in_r;
reg [7:0] data_out_r;
//---------------the main state------------------------------
parameter idle = 2'b00;
parameter write = 2'b01;
parameter read = 2'b11;
/***************************one_hot encode*************************************/
//--------------------write state----------------------------------
parameter start_wr = 8'b0000_0001;
parameter dev_wr = 8'b0000_0010;
parameter ack1_wr = 8'b0000_0100;
parameter data_addr_wr = 8'b0000_1000;
parameter ack2_wr = 8'b0001_0000;
parameter data_wr = 8'b0010_0000;
parameter ack3_wr = 8'b0100_0000;
parameter stop_wr = 8'b1000_0000;
//------------------------read state---------------------------------
parameter start_wrd = 11'b000_0000_0001;
parameter dev_wrd = 11'b000_0000_0010;
parameter ack1_rd = 11'b000_0000_0100;
parameter data_addr_wrd = 11'b000_0000_1000;
parameter ack2_rd = 11'b000_0001_0000;
parameter start_rd = 11'b000_0010_0000;
parameter dev_rd = 11'b000_0100_0000;
parameter ack3_rd = 11'b000_1000_0000;
parameter data_rd = 11'b001_0000_0000;
parameter ack4_rd = 11'b010_0000_0000;
parameter stop_rd = 11'b100_0000_0000;

reg [1:0] state_m;//main state
reg [7:0] state_wr;//write state
reg [10:0] state_rd;//read state
reg sda_r,link;
reg [3:0] num;//count the bits
//reg ack_bit;
always @ (posedge clk45m or negedge iic_rst)
begin
if(!iic_rst)
begin
state_m <= idle;
sda_r <= 1'b1;
link <= 1'b0;
num <= 4'd0;
data_out_r <= 8'b0000_0000;
//ack_bit <= 1'b1;
data_addr_r <= 8'b0000_0001;
data_in_r <= 8'b0001_1101;
device_add <= 8'b0000_0000;
end
else
case (state_m)
idle: begin
link <= 1'b0;
if(!wr_cmd && (scl_ph == scl_hig))
begin
device_add <= dev_wr_cmd;
state_m <= write;
state_wr <= start_wr;
link <= 1'b1;
sda_r <= 1'b1;
end
else if(!rd_cmd && (scl == scl_hig))
begin
state_m <= read;
device_add <= dev_wr_cmd;
link <= 1'b1;
sda_r <= 1'b1;
state_rd <= start_wrd;
end
else state_m <= idle;
end
write: begin
case(state_wr)
start_wr: begin//start
if(scl_ph == scl_hig)
begin
sda_r <= 1'b0;
state_wr <= dev_wr;
num <= 4'd0;
end
else state_wr <= start_wr;
end
dev_wr: begin//write device_address
if(num<=4'd7)
begin
state_wr <= dev_wr;
if(scl_ph == scl_low)
begin
num <= num+1'b1;
sda_r <= device_add[7];
end
else if(scl_ph == scl_pos)
begin
device_add <= {device_add[6:0],device_add[7]};
end
end
else if((num==4'd8) && (scl_ph == scl_low))
begin
device_add <= {device_add[6:0],device_add[7]};//
num <= 4'd0;
link <= 1'b0;
state_wr <= ack1_wr;
end
else state_wr <= dev_wr;
end
ack1_wr: begin
if(scl_ph == scl_neg)
state_wr <= data_addr_wr;
else state_wr <= ack1_wr;
end
data_addr_wr: begin//write data address
if(num<=4'd7)
begin
state_wr <= data_addr_wr;
if(scl_ph == scl_low)
begin
link <= 1'b1;
num <= num + 1'b1;
sda_r <= data_addr_r[7];
end
else if(scl_ph == scl_pos)
data_addr_r <= {data_addr_r[6:0],data_addr_r[7]};
end
else if((num==4'd8) && (scl_ph == scl_low))
begin
data_addr_r <= {data_addr_r[6:0],data_addr_r[7]};//
num <= 4'd0;
link <= 1'b0;
state_wr <= ack2_wr;
end
else state_wr <= data_addr_wr;
end
ack2_wr: begin
if(scl_ph == scl_neg)
state_wr <= data_wr;
else state_wr <= ack2_wr;
end
data_wr: begin//write data
if(num<=4'd7)
begin
state_wr <= data_wr;
if(scl_ph == scl_low)
begin
link <= 1'b1;
num <= num + 1'b1;
sda_r <= data_in_r[7];
end
else if(scl_ph == scl_pos)
data_in_r <= {data_in_r[6:0],data_in_r[7]};
end
else if((scl_ph == scl_low) && (num==4'd8))
begin
data_in_r <= {data_in_r[6:0],data_in_r[7]};
num <= 4'd0;
link <= 1'b0;
state_wr <= ack3_wr;
end
else state_wr <= data_wr;
end
ack3_wr: begin
if(scl_ph == scl_neg)
begin
state_wr <= stop_wr;
sda_r <= 1'b0;
//link <= 1'b1;
end
else state_wr <= ack3_wr;
end
stop_wr: begin
if(scl_ph == scl_hig)
sda_r <= 1'b1;
else if(scl_ph == scl_low)
begin
link <= 1'b1;
if(link)
begin
link <= 1'b0;
state_m <= idle;//********************************important
state_wr <= start_wr;
end
else state_wr <= stop_wr;
end
else state_wr <= stop_wr;
end
default: ;
endcase
end
read: begin
case(state_rd)
start_wrd: begin//start
if(scl_ph == scl_hig)
begin
sda_r <= 1'b0;
state_rd <= dev_wrd;
num <= 4'd0;
end
else state_rd <= start_wrd;
end
dev_wrd: begin//write device_address
if(num<=4'd7)
begin
state_rd <= dev_wrd;
if(scl_ph == scl_low)
begin
num <= num+1'b1;
sda_r <= device_add[7];
end
else if(scl_ph == scl_pos)
device_add <= {device_add[6:0],device_add[7]};
end
else if((num==4'd8) && (scl_ph == scl_low))
begin
device_add <= {device_add[6:0],device_add[7]};
num <= 4'd0;
link <= 1'b0;
state_rd <= ack1_rd;
end
else state_rd <= dev_wrd;
end
ack1_rd: begin
if(scl_ph == scl_neg)
state_rd <= data_addr_wrd;
else state_rd <= ack1_rd;
end
data_addr_wrd: begin//write data address
if(num<=4'd7)
begin
state_rd <= data_addr_wrd;
if(scl_ph == scl_low)
begin
link <= 1'b1;
num <= num + 1'b1;
sda_r <= data_addr_r[7];
end
else if(scl_ph == scl_pos)
data_addr_r <= {data_addr_r[6:0],data_addr_r[7]};
end
else if((num==4'd8) && (scl_ph == scl_low))
begin
data_addr_r <= {data_addr_r[6:0],data_addr_r[7]};
num <= 4'd0;
link <= 1'b0;
state_rd <= ack2_rd;
end
else state_rd <= data_addr_wrd;
end
ack2_rd: begin
if(scl_ph == scl_neg)
begin
link <= 1'b1;
state_rd <= start_rd;
end
else state_rd <= ack2_rd;
end
start_rd: begin//start again
if(scl_ph == scl_hig)
begin
sda_r <= 1'b0;
state_rd <= dev_rd;
num <= 4'd0;
device_add <= dev_rd_cmd;
end
else state_rd <= start_rd;
end
dev_rd: begin//write device
if(num<=4'd7)
begin
state_rd <= dev_rd;
if(scl_ph == scl_low)
begin
num <= num + 1'b1;
sda_r <= device_add[7];
end
else if(scl_ph == scl_pos)
device_add <= {device_add[6:0],device_add[7]};
end
else if((num==4'd8) && (scl_ph == scl_low))
begin
device_add <= {device_add[6:0],device_add[7]};
num <= 4'd0;
link <= 1'b0;
state_rd <= ack3_rd;
end
else state_rd <= dev_rd;
end
ack3_rd: begin
if(scl_ph == scl_low)
state_rd <= data_rd;
else state_rd <= ack3_rd;
end
data_rd: begin//read data
if(num<=4'd7)
begin
state_rd <= data_rd;
if(scl_ph == scl_hig)
begin
num <= num+1'b1;
data_out_r[7] <= sda;
end
else if(scl_ph == scl_neg)
data_out_r <= {data_out_r[6:0],data_out_r[7]};
end
else if((scl_ph == scl_low) && (num==4'd8))
begin
data_out_r <= {data_out_r[6:0],data_out_r[7]};
num <= 4'd0;
state_rd <= ack4_rd;
end
else state_rd <= data_rd;
end
ack4_rd: begin
if(scl_ph == scl_low)
begin//???????stop???????????????scl_ph = 5
sda_r <= 1'b0;
link <= 1'b1;
state_rd <= stop_rd;
end
else state_rd <= ack4_rd;
end
stop_rd: begin//stop read
if(scl_ph == scl_hig)
sda_r <= 1'b1;
else if((scl_ph == scl_low) && link)
begin
link <= 1'b0;
state_m <= idle;
state_rd<= start_wrd;
end
else state_rd <= stop_rd;
end
default: ;
endcase
end
default: ;
endcase

end

assign sda = link ? sda_r:1'bz;
assign data_out = data_out_r[2:0];

endmodule
`resetall




关键词: 求助 读写 问题 start device wri

高工
2013-09-24 11:04:37 打赏
2楼

自己做的板吗?

感觉有点像上拉电阻的问题啊。

大神们,怎么看?


菜鸟
2013-09-24 21:28:44 打赏
3楼

不是自己做的,是公司现成的板子。问题找到了:读时序的第二次开始状态有问题应该加上绿色的这一段,读的时候数据地址写完后另外开始,没有把sda拉高,也就不存在开始写读命令8‘b1010——0001了,至于原来出错为什么读出来是0xfe就不知道了。

另外那个地址0x01确定是板子的问题,改了代码之后换了块板子,全部读写正常,搞不清楚原板子上的24c04为什么数据会和0x48相或。按说坏的话也没有理由只坏地址0x01啊:

start_rd: begin //start again

if(scl_ph == scl_low)

begin

link <= 1'b1;

sda_r<= 1'b1;

end

elseif(scl_ph == scl_hig)
begin
sda_r <= 1'b0;
state_rd <= dev_rd;
num <= 4'd0;
device_add <= dev_rd_cmd;
end
else state_rd <= start_rd;
end

院士
2013-09-24 21:45:59 打赏
4楼

24c02可能是坏的。

这个芯片感觉有的时候还是灰常爱坏的。


高工
2013-09-24 21:53:38 打赏
5楼

不知道我记错没有,I2C总线空闲的时候,默认应该是拉高的。

从这里简单判断,上一版PCB上拉电阻这块,有可能存在缺陷哟。


共5条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册]