集成电路技术分享

 找回密码
 我要注册

QQ登录

只需一步,快速开始

搜索
查看: 2769|回复: 6

雾盈FPGA笔记(十二)IIC协议应用之二EEPROM随机读出

[复制链接]
雾盈 发表于 2016-8-6 13:54:20 | 显示全部楼层 |阅读模式
本帖最后由 雾盈 于 2016-8-28 13:41 编辑

雾盈FPGA笔记(十二)

IIC协议应用之二EEPROM随机读出(random read)

                                                               
        雾盈        2016-8-5



雾盈FPGA笔记汇总目录

写在前面:

这是我写的第二篇关于IIC协议应用的帖子。在第一篇贴子里,我略详细的介绍了IIC 总线协议及其工作原理,并把IIC协议的基础应用—EEPROM 字写入(byte write)讲解了一下。
我把第一篇帖子的链接挂在下面,初学者或者不了解EEPROM 字写入(byte write)的读者必须看一下,因为这篇文章就是在那一篇的基础上来讲的。
雾盈FPGA笔记(十二)IIC协议应用之二EEPROM字写入(byte write)链接:
雾盈FPGA笔记(十一)IIC总线协议应用之一EEPROM字节写入


一、        EEPROM 随机读出(random read)

随机读出(random read)是相对于顺序读出(sequential read)来说的,这种读方式允许控制可以以随机的方式按照地址来读出IIC器件里对应地址的数据。这就好比,你拿着某一个号码的停车牌,去停车场里去取回你之前停在那里的车。
EEPROM 随机读出(random read)的工作过程 和  字写入(byte write)的工作过程,有一大部分是相同的。
我把这两个工作过程的示意图贴出来对比一下就清楚了。示意图如下:1)


       
看过示意图对比之后,我们发现随机读出(random write)和字写入(byte write) 只在后面一小部分过程不一样,一个读,一个写。
那样我们只要理解了字写入的工作过程和时序,就很容易把字写入(random write)前面部分的代码移植过来。
所以,我只把剩余几个不同的地方着重说一下。

1.        NO ACK(非应答信号):

由上面随机读出的过程示意图就可以看到,NO ACK 信号是个高电平,只能由FPGA通过SDA 数据线向EEPROM 发送。
当SCL为高电平时,SDA 开关打开输出为高电平之后,就表示发送了NO ACK 信号。
我们把NO ACK 和ACK 拉到一块 ,就能联想出来,ACK 信号是EEPROM 收到八位数据后反馈给FPGA的信号,那么 NO ACK 信号是不是就是 FPGA 读到八位数据后向EEPROM 发送的反馈信号。

2.        读数据过程

随机读出的读数据过程和字写入的写数据过程是相反的。
对比一下代码,立刻能体会出来。

写数据:

  1. if( scl == 1'b0 && cnt < 8 )
  2.                                         begin
  3.                                                 data_out <= temp[7];
  4.                                                 flag1 <= 1'b1;
  5.                                                 temp <= { temp[6:0],temp[7] };
  6.                                                 cnt <= cnt + 1'b1;
  7.                                                 state <= 4'd7;               
  8.                                         end
  9.                                 else if( scl == 1'b0 && cnt == 8 )
  10.                                          begin
  11.                                                 flag1 <= 1'b0;        
  12.                                                 cnt <= 1'b0;       
  13.                                             state <= 4'd8;      
  14.                                          end
复制代码


读数据:

  1. if( scl == 1'b1 && cnt < 8 )                // scl high and flag1=0
  2.                                         begin
  3.                                                 flag1 <= 1'b0;                                                                               
  4.                                                 temp <= { temp[6:0],sda };        // remember !!!                                                 
  5.                                                 cnt <= cnt + 1'b1;
  6.                                                 state <= 4'd10;               
  7.                                         end
  8.                                 else if( scl == 1'b1 && cnt == 8 )
  9.                                          begin
  10.                                                 flag1 <= 1'b1;        
  11.                                                 data_out <= 1'b0;
  12.                                                 data_rd <= temp;                                        
  13.                                                 cnt <= 1'b0;       
  14.                                             state <= 4'd11;                                                                               
  15.                                          end
复制代码




这两段代码中,多位数据与单位数据依靠寄存器左移进行传递的方法应该熟记下来,之前在写到这段代码时,总是卡壳,就是因为我对这种方法理解的懵懵懂懂似是而非,希望你们也能注意一下。
还有,在读数据那段,我之前写的是这样的:
代码

  1. if( scl == 1'b1 && cnt < 8 )                // scl high and flag1=0
  2.                                         begin
  3.                                                 flag1 <= 1'b0;       
  4.                                                 temp[7] <= sda  ;
  5.                                                 temp <= { temp[6:0],temp[7] };        // error!!!                                                 
  6.                                                 cnt <= cnt + 1'b1;
  7.                                                 state <= 4'd10;               
  8.                                         end
  9.                                 else if( scl == 1'b1 && cnt == 8 )
  10.                                          begin
  11.                                                 flag1 <= 1'b1;        
  12.                                                 data_out <= 1'b0;
  13.                                                 data_rd <= temp;                                        
  14.                                                 cnt <= 1'b0;       
  15.                                             state <= 4'd11;                                                                               
  16.                                          end
复制代码


后来仿真波形出来后,发现读到的数据并没有左移,经过陈老师的指点才改正过来。
问题出在temp[7]=sda,这样是左移不出来的。

而其他的步骤,几乎和字写入一毛一样了,而遇到的问题大概也就是之前字写入时碰到的问题了,我就不讲了= = 。
明天我会再发一个帖子,在一个模块里糅合写入和读出两个过程,并通过按键进行控制。
你可以给我的帖子提一些建议的,这样才能写的越来越成熟。

后面贴一下,仿真波形图。




仿真图里读出数据为高阻态,是因为仿真的时候在接收ack时把sda 屏蔽 且 没有连接eeprom 所以sda数据线读出的为高组态。


源代码:&#8195;

  1. //=====================================================================
  2. // module name:                iic_rd
  3. // function:       
  4. // create data:                from 2016-8-4 11:26:13  to   
  5. // editor:                        miao
  6. // Tool&#160;versions:         quartus 13.0
  7. //=====================================================================
  8. module        iic_rd(
  9.                            // system signal
  10.                            input                clk, //50MHZ
  11.                            input                rst_n,
  12.                            // output signal
  13.                            output reg        scl, // eeprom scl 200K
  14.                            output reg [7:0] data_rd,  // read from eeprom
  15.                            inout                sda // eeprom sda
  16. );       
  17. //=========================================================================================================
  18. //**************************     Define parameter and internal signals          *********************************
  19. //=========================================================================================================        
  20. reg clk_400k;
  21. reg [7:0] count;
  22. parameter COUNT_400K = 62;
  23. reg flag1;  //for sda        
  24. reg [3:0] state;
  25. reg [7:0] temp; // register for sda
  26. reg [7:0] cnt;  // use for data transfer
  27. reg           data_out;

  28. //=========================================================================================================
  29. //*********************************             400KHZ & scl & flag1         ***********************************
  30. //=========================================================================================================
  31. // frequency division        400KHZ , count 62 times
  32.    always @ (posedge clk or negedge rst_n)
  33. begin
  34.      if(!rst_n)
  35.          begin
  36.                     count <= 1'b0;       
  37.                         clk_400k <= 1'b0;
  38.         end
  39.      else  begin
  40.             if( count == COUNT_400K )
  41.                                 begin
  42.                                         count <= 1'b0;
  43.                                         clk_400k <= ~clk_400k;
  44.                                 end       
  45.                         else begin
  46.                                     count <= count + 1'b1;
  47.                                  end
  48.                        
  49.              end
  50. end
  51. //  400KHZ  could produce 200KHZ named scl of eeprom
  52. always @ (negedge clk_400k or negedge rst_n)
  53. begin
  54.      if(!rst_n)
  55.         begin
  56.                   scl <= 1'b1;
  57.         end
  58.      else if( state == 13)
  59.                 begin
  60.                   scl <= 1'b1;
  61.                 end
  62.          else
  63.                 begin
  64.                   scl <= ~scl;
  65.                   end
  66.          
  67. end
  68. //=========================================================================================================
  69. //*********************************                         state machine                    ***********************************
  70. //=========================================================================================================

  71. assign sda = ( flag1 == 1'b1) ? data_out : 1'bz;  



  72. always @ (posedge clk_400k or negedge rst_n)
  73. begin
  74.      if(!rst_n)
  75.         begin                                                                // initial , both scl and sda high
  76.                         state <= 4'd0;
  77.                         temp <= 8'd0;                                        // register
  78.                         data_out <= 1'b1;
  79.                         flag1 <= 1'b1;
  80.                         cnt <= 1'b0;               
  81.                
  82.                         data_rd <= 8'd0;
  83.         end
  84.      else  begin
  85.            case(state)
  86.              0:begin // send start signal
  87.                 if( scl == 1'b1 )                        //  scl high while sda low , produce  the  "start" signal
  88.                                         begin
  89.                                                 data_out <= 1'b0;
  90.                                                 flag1 <= 1'b1;
  91.                                                 temp <= 8'b1010_0000;
  92.                                                 state <= 1'b1;                                       
  93.                                         end
  94.                end
  95.              1:begin // send contrl_word        
  96.                                 if( scl == 1'b0 && cnt < 8 )        //while scl is low ,change data
  97.                                         begin
  98.                                                 data_out <= temp[7];                //cycle 0-8
  99.                                                 flag1 <= 1'b1;
  100.                                                 temp <= { temp[6:0],temp[7] };
  101.                                                 cnt <= cnt + 1'b1;
  102.                                                 state <= 1'b1;               
  103.                                         end
  104.                                 else if( scl == 1'b0 && cnt == 8 )
  105.                                          begin
  106.                                                 flag1 <= 1'b0;         // flag = 0 ,sda begin receive data
  107.                                                 state <= 4'd2;
  108.                                                 cnt <= 1'b0;
  109.                                          end
  110.                end
  111.                         2:begin // receive ack
  112.                                  if ( scl == 1'b1 )                       
  113.                                         begin
  114.                                                 if( sda == 1'b0 )                // scl high and sda low ,receive ACK . meanwhile switch to "state3"
  115.                                                 begin                                       
  116.                                                         temp <= 8'd0000_0000;        //        put 8 bit address into the register "temp"
  117.                                                         state <= 4'd3;
  118.                                                 end       
  119.                                                 else begin                          //if couldn't receive ACK ,switch to "state1" and transfer contrl_word again
  120.                                                         state <= 4'd1;
  121.                                                          end
  122.                                         end
  123.                           end
  124.                         3:begin // send high address  
  125.                                 if( scl == 1'b0 && cnt < 8 )        // scl low could change data , similar with "state1"
  126.                                         begin
  127.                                                 data_out <= temp[7];
  128.                                                 flag1 <= 1'b1;
  129.                                                 temp <= { temp[6:0],temp[7] };
  130.                                                 cnt <= cnt + 1'b1;
  131.                                                 state <= 4'd3;               
  132.                                         end
  133.                                 else if( scl == 1'b0 && cnt == 8 )
  134.                                          begin
  135.                                                 flag1 <= 1'b0;                 // sda = data_out                                               
  136.                                             state <= 4'd4;
  137.                                                 cnt <= 1'b0;
  138.                                          end
  139.                           end
  140.                         4:begin // receive ack
  141.                                  if ( scl == 1'b1 )
  142.                                         begin
  143.                                                 if( sda == 1'b0 )
  144.                                                 begin
  145.                                                         temp <= 8'd0000_0000;
  146.                                                         state <= 4'd5;
  147.                                                 end       
  148.                                                 else begin
  149.                                                         state <= 4'd3;
  150.                                                          end
  151.                                         end                               
  152.                            end
  153.                         5:begin // send low address  
  154.                                 if( scl == 1'b0 && cnt < 8 )
  155.                                         begin
  156.                                                 data_out <= temp[7];
  157.                                                 flag1 <= 1'b1;
  158.                                                 temp <= { temp[6:0],temp[7] };
  159.                                                 cnt <= cnt + 1'b1;
  160.                                                 state <= 4'd5;               
  161.                                         end
  162.                                 else if( scl == 1'b0 && cnt == 8 )
  163.                                          begin
  164.                                                 flag1 <= 1'b0;                
  165.                                                 cnt <= 1'b0;       
  166.                                             state <= 4'd6;      
  167.                                          end
  168.                          end
  169.                         6:begin // receive ack
  170.                                  if ( scl == 1'b1 )
  171.                                         begin
  172.                                                 if( sda == 1'b0 )
  173.                                                 begin
  174.                                                         temp <= 8'd0000_0000;
  175.                                                         state <= 4'd7;
  176.                                                 end
  177.                                                 else begin
  178.                                                         state <= 4'd5;
  179.                                                          end
  180.                                         end
  181.                            end
  182.                         7:begin // send start signal again  second
  183.                 if( scl == 1'b1 )                        //  scl high while sda low , produce  the  "start" signal
  184.                                         begin
  185.                                                 data_out <= 1'b0;
  186.                                                 flag1 <= 1'b1;
  187.                                                 temp <= 8'b1010_0001;  // different  first
  188.                                                 state <= 4'd8;                                       
  189.                                         end
  190.                end
  191.                     8:begin // send contrl_word again    second
  192.                                 if( scl == 1'b0 && cnt < 8 )        //while scl is low ,change data
  193.                                         begin
  194.                                                 data_out <= temp[7];                //cycle 0-8
  195.                                                 flag1 <= 1'b1;
  196.                                                 temp <= { temp[6:0],temp[7] };
  197.                                                 cnt <= cnt + 1'b1;
  198.                                                 state <= 4'd8;               
  199.                                         end
  200.                                 else if( scl == 1'b0 && cnt == 8 )
  201.                                          begin
  202.                                                 flag1 <= 1'b0;         // flag = 0 ,sda begin receive data
  203.                                                 state <= 4'd9;
  204.                                                 cnt <= 1'b0;
  205.                                          end
  206.                end
  207.                         9:begin // receive ack
  208.                                  if ( scl == 1'b1 )
  209.                                         begin
  210.                                                 if( sda == 1'b0 )
  211.                                                 begin
  212.                                                         temp <= 8'd0000_0000;
  213.                                                         state <= 4'd10;
  214.                                                 end
  215.                                                 else begin
  216.                                                         state <= 4'd8;
  217.                                                          end
  218.                                         end
  219.                            end
  220. ///***====================read state=========================*********///                          
  221.                         10:begin // read data                                         // note: if error ,add a state to make  scl  high
  222.                                 if( scl == 1'b1 && cnt < 8 )                // scl high and flag1=0
  223.                                         begin
  224.                                                 flag1 <= 1'b0;                                                                               
  225.                                                 temp <= { temp[6:0],sda };        // remember !!!                                                 
  226.                                                 cnt <= cnt + 1'b1;
  227.                                                 state <= 4'd10;               
  228.                                         end
  229.                                 else if( scl == 1'b1 && cnt == 8 )
  230.                                          begin
  231.                                                 flag1 <= 1'b1;        
  232.                                                 data_out <= 1'b0;
  233.                                                 data_rd <= temp;                                        
  234.                                                 cnt <= 1'b0;       
  235.                                             state <= 4'd11;                                                                               
  236.                                          end
  237.                          end
  238.                         11:begin // wirte noack
  239.                                  if ( scl == 1'b0 )
  240.                                         begin
  241.                                                 flag1 <= 1'b1;
  242.                                                 data_out <= 1'b1;
  243.                                                 state <= 4'd12;
  244.                                         end                               
  245.                            end
  246.                         12:begin //          order to  make sda  low to  high  
  247.                                  if( scl == 1'b0 )                        // scl low and sda low ,produce "stop" signal  
  248.                                         begin
  249.                                                 data_out <= 1'b0;
  250.                                                 flag1 <= 1'b1;                                               
  251.                                                 state <= 4'd13;                       
  252.                                         end                       
  253.                           end
  254.                         13:begin        //        "stop" flag                        
  255.                                  if( scl == 1'b1)
  256.                                   begin
  257.                                         flag1 <= 1'b1;
  258.                                         data_out <= 1'b1;
  259.                                         state <= 4'd13;
  260.                                   end
  261.                            end
  262.              default: state <= 4'd0;
  263.              endcase
  264.              end
  265. end
  266. endmodule
复制代码



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?我要注册

x
芙蓉王 发表于 2016-8-8 09:36:42 | 显示全部楼层
                              非常棒,继续追贴
zhiweiqiang33 发表于 2016-8-9 09:42:12 | 显示全部楼层
感谢分享,持续跟贴中‘
Adamancy 发表于 2016-8-9 15:13:33 | 显示全部楼层
                 感谢楼主分享
海的自由 发表于 2016-8-9 18:02:59 | 显示全部楼层
能不能分享一下整体读写包括按键的代码
 楼主| 雾盈 发表于 2016-8-10 15:06:52 | 显示全部楼层
海的自由 发表于 2016-8-9 18:02
能不能分享一下整体读写包括按键的代码

好 我整理一下就发上来
雷磊 发表于 2021-9-6 16:08:32 | 显示全部楼层
IIC协议应用之二EEPROM随机读出
您需要登录后才可以回帖 登录 | 我要注册

本版积分规则

关闭

站长推荐上一条 /1 下一条

QQ|小黑屋|手机版|Archiver|集成电路技术分享 ( 京ICP备20003123号-1 )

GMT+8, 2024-6-29 16:37 , Processed in 0.071790 second(s), 22 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表