这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 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

            else  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

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

24c02可能是坏的。

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


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

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

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


共5条 1/1 1 跳转至

回复

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