分享

【记录】关于IIC的学习以及调试

 ID被吃 2016-03-29

这几天一直在学习关于IIC的时序,总结一下学习中遇到的问题。

一、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 <=>

end

else if( cnt == 10'd499)begin

cnt <=>

end

else begin

cnt <= cnt="" +="">

end

always@(posedge clk or negedge rst_n)

if(!rst_n)begin

cnt_clk <=>

end

else begin

case(cnt)

10'd124:cnt_clk <=>

10'd249:cnt_clk <=>

10'd374:cnt_clk <=>

10'd499:cnt_clk <=>

default:cnt_clk <=>

endcase

end

always@(posedge clk or negedge rst_n)

if(!rst_n)begin

scl_r <=>

end

else if(cnt_clk == 3'd0)begin

scl_r <=>

end

else if(cnt_clk == 3'd2)begin

scl_r <=>

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 <=>

if(`SCL_HIG)begin

if(sda== 1'b0)begin //之间将sda写成了sda_r,造成一直返回到IDLE状态

state <=>

temp_data <=>

end

else begin

state <=>

end

end

else begin

state <=>

end

end

(2)ACK谁给的问题:

在进行写的操作很简单,明白ACK信号都是由EEPROM给FPGA,只要在每发送8位的字节后,在高电平期间,若EEPROM将sda信号拉低,说明就有应答信号。

在进行读操作的时候,在进行读取 数据之前,还有一个ACK信号,别忘记了,自己就把这个ACK信号忘记了,之后读取完数据之后会有个NACK信号,那么这个信号是FPGA给EEPROM的。(很容易理解错误,以为都是EEPROM所给的呢)

4、SCL的时钟

一定要记住:数据的改变只能在SCL信号的低电平期间,在SCL高电平器件保持平稳。如在SCL高电平期间有数据改变很容易被认为是起始信号或是停止信号。

5、代码问题

自己主要采用的特权的IIC时序代码,让我更 容易理解;而黑金资料中的IIC时序代码,自己将时序图在纸上画出来才明白怎么一回事,这个看个人理解吧。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多