这几天一直在做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