全部博文(321)
分类: 嵌入式
2014-05-14 23:17:43
三、IIC----EEPROM(每次在读写之前都要初始化!!!!!!!!!!!!!!!!!!!!!!!非常重要,否则会出现连续读第二次就读不出来)电可擦除的可编程存储芯片。
在项目中是用数组,不用指针,因为当前读的时候,指针是指向我们之前写的位置,而我们并不知道之前写的地址写到哪,所以不知道指针在哪。故用数组指定地址。
E2PROM地址:1010 p2p1p0 r/w(r=1,w=0)我们是2408 8k是位,1k字节,p2p1p0代表页码或者的E2PROM的地址,如果多个E2PROM,则区别到底哪一个E2PROM,2401代码最多能挂8个E2PROM,即P2P1P0全部用来做地址线,而我们现在8K的只有P2代码地址线P1P0代码页码,所以最多能挂两个(0 1)若是16K的只能挂一个P2,P1,P0不接。此时的P1P0代表大页的地址。所以我们写为1010 0 00 0 1010 0 01 0 1010 0 10 0
1010 0 11 0;p1p0为大页的标签,有四大页,每个大页有16个小页,每个小页16个字节
最后一位是读写方向位,1读,0写。
补充:
1、是一种通讯协议,类似串口。数据的传输都会有一个同步时钟。
2、上升沿是用来写,下降沿用来读。
3、总共有10位表示地址,前两位2位表示页码,大页,后8位表示页内地址。
4、E2PROM都是以八位的为一帧来传输,后面接着低电平的ACK信号,在第九个时钟周期。
5、若是写的话,其实我们写的东西先放在缓存中,当收到停止条件的时候,则进入写周期,从BUFFER里面写入E2PROM。所以若我们写的时候,收到停止条件就马上结束的话,有可能写不进去。但是我们的写周期时间的多大呢。。??我们采用不停的呼叫(发送启动条件和设备地址),若有应答ACK的话,则说明写完,若没写完,则不会应答。
6、时钟线为低的话,数据线可以切换,代表数据的传输,若SCL为高,切换数据则是起始或停止条件。
7、写:
解释:字节写:
1、设备地址接着启动信号。设备地址:1010 A2没用(因为此时就只有一块E2PROM,当两块E2PROM时,0 - 1来区别哪一块),A1A0为页码,最后一位是读或写。0,为写。应答信号:ACK,对应数据线为低电平
2、内存地址:八位。再接应答信号:ACK
3、传输数据:八位数据,再产生ACK。
4、最后停止信号。数据线为高电平
5、再进入写周期。写周期期间,所有输入都是无效的,E2PROM不会反应。
6、
解释:页写:
1、设备地址接着启动信号。设备地址:1010 A2没用(因为此时就只有一块E2PROM,当两块E2PROM时,0 - 1来区别哪一块),A1A0为页码,最后一位是读或写。0,为写。应答信号:ACK,对应数据线为低电平
2、内存地址,ACK。
3、发送数据,ACK。。。。发送数据。。。ACK
4、注:虽然与上字节写看似差不多,其实不是:区别:每发完一帧数据,即产生ACK信号后,要先进入写周期,即发个停止信号进入写周期,写完后再继续发生数据,不停的查询ACK,如何才能产生ACK,方法:通过发送一个启动信号和设备地址。
5、记住,发送最后一个数据与读不一样,他是有产生ACK信号的。
6、页写,若写了大于16个字节(因为一小页为16个字节,16*16=256,一个大页等于16个小页),则出现卷耀,即覆盖0地址的地方。即写不能跨页(小页)。只能在内部的小页卷耀。
8、读:
字节读:与写操作一样,就一位读写方向位不同。
最大区别在这:在cpu收到数据后,是发送NOACK,即把SDA拉为高电平。
读,一般都是指定地址读,不用当前地址读。读可以跨页,整个大页。
随即读:
1、先产生启动信号,设备地址,写伪写,产生ACK。
2、内存地址,ACK
3、再启动,发送设备地址,读的。
4、发送数据,产生ACK,当收到ACK信号时,就知道还要接着读,紧接着就再发送数据,直到当最后一个要读出来的时候,不用发送ACK信号,其实那就是NOACK信号,硬件决定。就是直接收到一个高电平,紧接着就有个停止信号。
5、连续读:即当前地址读+随即读。。
9、谁发出同步信号,谁就是主设备。
10、数据都是MSB发送的。。就是高位先发送。没发八位,都要有个应答信号,有接收方发送。
11、CPU呼叫从设备,就把数据(地址)发在SDA线上,所有挂在线上的设备都要跟自己的地址比较。如果收到的地址就是自己的地址,则要回答ACK信号。
12、这边的移位寄存器是双缓冲,先放在IICDS上,在一位位移位到shift register上,再一位位移到SDA线上。
13、四种模式:主传输,主接收,从传输,从接收。
14、SCL时钟线保持低电平,则挂起,**。
15、当发送器收到ACK时钟脉冲时应该通过拉高SDA线来释放SDA线。
16、在SCL为低电平的时候才切换电平。发送:S3C2440A 应该等待中断来确定当前数据发送的完成。在CPU收到中断请求后,需要再次写一个新数据到 IICDS 寄存器中。 接收:S3C2440A 应该等待中断来确定当前数据接收的完成。在CPU收到中断请求后,需要从 IICDS 寄存器中读取数据。
17、IIC 总线中断发生在:1)当完成了 1 字节发送或接收操作;2)当广播呼叫或从地址匹配发生时;3 )如果总线仲裁失败。 为了在 SCL 上升沿之前调整 SDA的建立时间,必须在清除 IIC 中断挂起位前写 IICDS 。
18、EEPROM接口, Rx 模式中为了产生停止条件在读取最后数据之前会禁止产生应答。
19、每次产生ACK后,要进入写,所以一般查询中断挂起位,而不查询ACK,因为ACK不能保证已经写完了,而采用查询中断,则保证已经已经写完,如果两个都查询的话,就万无一失了。
1.串行数据线(SDA)和专用串行时钟线(SCL)
2.释放时,空闲,SDA和SCL为高电平,即待机。当SCL为低的时候,SDA改变数据,当SCL为高的时候,若是改变SDA则是启动或停止。(启动:高-->低,停止:低--->高)
3.起始条件和结束条件都为主设备产生,这边cpu是主设备,E2PROM为从设备,因为E2PROM不会产生时钟。
4.由IICSDA,IICSCL,可以确定GPE==(((U32)2<<30)|(2<<28));口,U32是为了消除警告
5.在读出去,和写进来之前,scl线都保持为低,直到读写完毕才释放
6.总线仲裁:(预防两个主机竞争),当主机产生从地址时,检测SDA线地址位,SDA线更趋向获得低电平的,从第一个地址到最后一个地址位,若都一样,则失败。
ICCON;先清除挂起enable ACK,prescaler IICCLK=PCLK/512=100KHZ(3.3v),enable interrupt,其中100KHZ,是从2401第一页,所以只能用50M/512最接近
6.因为E2PROM不能产生时钟,所以只能是从机,故rIICSTAT=(3<<6)|(1<<4)只能设置为主发送模式
7.IIC_READ
{设备地址=内存地址=设备地址=数据
1.rIICSTAT = 0XF0;先进行伪写,
2.rIICDS = devaddr,0XA0,写设备地址,从地址,其中IICDS为发送/接受移位寄存器
3等待while(rIICSTAT&0x1);//0为收到ack,1未收到ack
while(!(rIICCON & 0X10)); //wait until interrupt pending第五位,0,无中断挂起,
5写内存地址。注意:写(地址或者数据)要延时(for(i=0; i<100; i++);//差不多750ns
6.rIICSTAT = 0XB0; //真正的读状态rIICDS = devaddr|1;
7. 写----设备地址//slave address可不用| 1,硬件 自己会转化,但是为更清除的表达意思, 或上1.
8.读,应答,中间有ack信号产生,就有中断,所以要清除中断,而且要延时,要等待 while,上面不完整,具体见代码iic
9.在Rx模式中,读取最后一个数据的时候,要先disable ack,和清除挂起,因为最后一 个数据硬件自己知道,所以最后数据发送的时候要把ACK信号拉高。Disable。
rIICCON &= ~((1<<7)|(1<<4)); //ack disable before reading last data, clear pending
10.读取数据从rIICDS,最好用数组, 用指针的话很容易指针最后不知道指到哪里去, 所以用数组比较不会出错。
11.再发停止信号 rIICSTAT = 0X90;
rIICCON &= ~(1<<4);
for(j=0; j<10000; j++);加个大延时,这些延时没有固定,都是硬件自己决 定。自己测试
}
8.IIC_WRITE
{
1.写设备地址rIICSTAT = 0XF0; //(1)若(1)(2)对调,则会出现第一个数据丢失。
rIICDS = devaddr; //slave address(2)
while(!(rIICCON & 0X10)); //wait until interrupt pending
2.内存地址rIICDS = wordaddr; //memory address
3.写的都要延时,同上,延时===》清除挂起===》等待while
4.页写,字节写=====页写:16个字节,超过则覆盖;
5.字节写,超过256,则覆盖,最好用字节写,比较不会出现错。
4.停止
5.清除挂起,(注意:要有个延时(很重要)for(i=0; i<10000; i++))这句话一定不能少。!!!
6.while(1)//呼叫
{
起始信号
写设备地址
清除挂起
注意:判断有没有ack
判断是否由中断挂起 (这两个就一个都不能少,因为产生中断挂起的情况有 很多种,不能判断是否写完)
break;
}
7.写周期写完
8.发送停止信号
9.停止 rIICCON &= ~(1<<4); //clear pending
for(j=0; j<10000;j++);
}