查看: 1948|回复: 0

总结在学习关于IIC的时序遇到的问题。

[复制链接]

该用户从未签到

发表于 2016-2-29 13:03:28 | 显示全部楼层 |阅读模式
分享到:
一、IIC的时序很简单,主要有:
        (1)起始信号S:是在SCL信号为高电平期间,信号SDA由1变为0,代表着数据开始要传输,注意:SCL信号和SDA信号在空闲的时候为高电平。
        (2)停止信号P:是在SCL信号为高电平期间,信号SDA由0变为1,代表着数据传输完成;
        (3)数据传输:在 I2C 总线上传送的每一位数据都有一个时钟脉SCL冲相对应。在对数据传送时,在 SCL 高电平期间,SDA 上的电平必项保持稳定,低电平为数据 0,高电平为数据 1。只有在 SCL 为低电平期间,才允讲 SDA 上的电平改变状态。
        重点:(4)应答信号ACK与非应答信号NACK:I2C 总线上的所有数据都是以 8 位字节传送的,发送器(FPGA)每发送一个字节,就在时钟脉冲 9 期间释放数据线(也就是将SDA信号的传输方向改变为输入),由接收器(EEPROM)反馈一个应答信号ACK,为低电平时是有效应答位,表示接收器已经成功地接收了该字节,接收器(EEPROM)在第 9 个时钟脉冲之前的低电平期间将 SDA 线拉低,并且确保在第9个时钟脉的高电平期间为稳定的低电平。
               应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。 如果接收器(EEPROM)是主控器,则在它收到最后一个字节后,发送一个 NACK 信号,以通知被控发送器(FPGA)结束数据发送,并释放 SDA 线,以便接收器(FPGA)发送一个停止信号。
        下面是关于IIC 的时序图,采用的是24LC04B的EEPROM芯片。

                                                                                           图一
        二、关于IIC的几种读写
          自己主要是采用的是:单字节写,随机读
        图二是关于读写的方式:


                                                                           图二
                                三、在写代码时所遇到的问题:
                                       1、自己看了特权的关于IIC的代码与黑金资料的IIC的代码,马上就遇到第一个问题:关于IIC的传输的速率问题:在网络上和datasheet上都给 了两种传输速率,标准速率100kb/s和快速速率400kb/s。还以为IIC只是有这两种速率而已,但是看了黑金的资料后,发现IIC的速率不仅仅有 这两种,原来100kb/s是最高的传输速率,只要比这个小就可以,比如200kb/s。只是刚才说的这两种速率是通用的规定。所以明白了IIC的速率也 是可以自己设定的,不止标准速率100kb/s和快速速率400kb/s这两种。
                                     2、端口的信号:
                                            (1)output scl,是采用对SCL信号进行分段写成的,如
                                   reg [9:0] cnt;
                                reg [2:0] cnt_clk;
                                always@(posedge clk or negedge rst_n)
                                if(!rst_n)begin
                                cnt <= 10'd0;
                                end
                                else if( cnt == 10'd499)begin
                                cnt <= 10'd0;
                                  end
                                  else begin
                                cnt <= cnt + 1'b1;
                                end
                                always@(posedge clk or negedge rst_n)
                                if(!rst_n)begin
                                cnt_clk <= 3'd0;
                                end
                                else begin
                                case(cnt)
                                10'd124:cnt_clk <= 3'd1;
                                10'd249:cnt_clk <= 3'd2;
                                10'd374:cnt_clk <= 3'd3;
                                10'd499:cnt_clk <= 3'd0;
                                default:cnt_clk <= 3'd5;
                                endcase
                                end
                                always@(posedge clk or negedge rst_n)
                                if(!rst_n)begin
                                scl_r <= 1'b0;
                                end
                                else if(cnt_clk == 3'd0)begin
                                scl_r <= 1'b1;
                                end
                                else if(cnt_clk == 3'd2)begin
                                scl_r <= 1'b0;
                                end
                                assign scl = scl_r;
                                `define SCL_POS   (cnt_clk == 3'd0)
                                `define SCL_HIG   (cnt_clk == 3'd1)
                                `define SCL_NEG   (cnt_clk == 3'd2)
                                `define SCL_LOW   (cnt_clk == 3'd3)
                                         (2)inout sda,由于SDA是双向端口,则使用assign sda = sda_link ? sda_r : 1'bz;来实现数据的传输,其中sda_link 是控制SDA是作为输出(sda_link 为1,输出的是sda_r 的数据)还是输入(sda_link 为0,)。
                                        (3)input [1:0]  key;作为控制IIC的写与读的控制信号。自己也在这栽了跟头,由于参考的是特权的代码,自己稍微做了改动,将前后两次的按键值取反相与,为了使检测有 按键所按下,输出的信号其实是检验下降沿的一个高脉冲,但是在后面的状态机仍使用该输出的信号,但此时的输出信号以为低电平,所以会返回到初始状态。
                                        (4)output [3:0];作为检验读取信号是否正确的方法。
                                         3、关于ACK信号:
                                             (1)信号的方向:代码写完之后一直发现怎么就是不返回ACK信号呢,一直觉得自己代码没有错,从chipscope所看到的信号就是为低,怎么判断  就是不为低呢,后来经同学指点,才发现,自己在写关于ACK的状态时,没有将sda信号作为判断条件,而是将sda_r作为判断条件,所以总是返回到初始 状态。下面就是关于ACK的状态机,红色就是所错误的地方。
                               ACK1: begin
                                            sda_link <= 1'b0;
                                            if(`SCL_HIG)begin
                                                if(sda== 1'b0)begin //之间将sda写成了sda_r,造成一直返回                                                                                          到IDLE状态
                                                 state <= RAM_ADDRESS;
                                                  temp_data <= ADDRESS;
                                            end
                                              else begin
                                                    state <= IDLE;
                                                   end
                                                end
                                             else begin
                                                  state <= ACK1;
                                                  end
                                            end
               (2)ACK谁给的问题:(特权的代码中没有,给忽略了)
                 在进行写的操作很简单,明白ACK信号都是由EEPROM给FPGA,只要在每发送8位的字节后,在高电平期间,若EEPROM将sda信号拉低,说明就有应答信号。
               在进行读操作的时候,在进行读取 数据之前,还有一个ACK信号,别忘记了,自己就把这个ACK信号忘记了,之后读取完数据之后会有个NACK信号,那么这个信号是FPGA给EEPROM的。(很容易理解错误,以为都是EEPROM所给的呢)
                4、SCL的时钟
                    一定要记住:数据的改变只能在SCL信号的低电平期间,在SCL高电平器件保持平稳。如在SCL高电平期间有数据改变很容易被认为是起始信号或是停止信号。
             5、代码问题
                  自己主要采用的特权的IIC时序代码,让我更 容易理解;而黑金资料中的IIC时序代码,自己将时序图在纸上画出来才明白怎么一回事,这个看个人理解吧。
回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

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

手机版|小黑屋|与非网

GMT+8, 2024-4-19 05:30 , Processed in 0.113547 second(s), 17 queries , MemCache On.

ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

苏公网安备 32059002001037号

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.