IIC(Inter-Integrated Circuit,I2C)总线是一种由PHILIPS公司开发的两线式串行总线,用于连接微处理器及其外围设备,它的最主要优点是简单和有效。它只需要数据线SDA和时钟线SCL,就能够实现CPU与被控IC之间、IC与IC之间进行双向传送。
s3c2440内部有一个IIC总线接口,因此为我们连接带有IIC通信模块的外围设备提供了便利。它具有四种操作模式:主设备发送模式、主设备接收模式、从设备发送模式和从设备接收模式。
在这里我们只把s3c2440当做IIC总线的主设备来使用,因此只介绍前两种操作模式。在主设备发送模式下,它的工作流程为:首先配置IIC模式,然后把从设备地址写入接收发送数据移位寄存器IICDS中,再把0xF0写入控制状态寄存器IICSTAT中,这时等待从设备发送应答信号,如果想要继续发送数据,那么在接收到应答信号后,再把待发送的数据写入寄存器IICDS中,清除中断标志后,再次等待应答信号;如果不想再发送数据了,那么把0x90写入寄存器IICSTAT中,清除中断标志并等待停止条件后,即完成了一次主设备的发送。
在主设备接收模式下,它的工作流程为:首先配置IIC模式,然后把从设备地址写入接收发送数据移位寄存器IICDS中,再把0xB0写入控制状态寄存器IICSTAT中,这时等待从设备发送应答信号,如果想要接收数据,那么在应答信号后,读取寄存器IICDS,清除中断标志;如果不想接收数据了,那么就向寄存器IICSTAT写入0x90,清除中断标志并等待停止条件后,即完成了一次主设备的接收。
在完成上述两个模式时,主要用到了控制寄存器IICCON、控制状态寄存器IICSTAT和发送接收数据移位寄存器IICDS。由于我们只把s3c2440当做主设备来用,并且系统的IIC总线上只有这么一个主设备,因此用来设置从设备地址的地址寄存器IICADD,和用于仲裁总线的多主设备线路控制寄存器IICLC都无需配置。寄存器IICCON的第6位和低4位用于设置IIC的时钟频率,因为IIC的时钟线SCL都是由主设备提供的。
s3c2440的IIC时钟源为PCLK,当系统的PCLK为50MHz,而从设备最高需要100kHz时,可以将IICCON的第6位置1,IICCON的低4位全为0即可。寄存器IICCON的第7位用于设置是否发出应答信号,第5位用于是否使能发送和接收中断,第4位用于中断的标志,当接收或发送数据后一定要对该位进行清零,以清除中断标志。寄存器IICSTAT的高2位用于设置是哪种操作模式,当向第5位写0或写1时,则表示结束IIC或开始IIC通讯,第4位用于是否使能接收/发送数据。
由于通讯是双方的事情,在了解了主设备的操作模式后,还要清楚从设备的运行机制,两者要达到完美地结合,才能实现彼此的通讯。在这里,从设备是EEPROM——AT24C02A,要想让s3c2440能够正确地对AT24C02A读写,就必须让s3c2440的时序完全按照AT24C02A的时序。AT24C02A的写操作有两种模式:字节写和页写。字节写是先接收带有写命令的设备地址信息,如果符合就应答,再接收设备内存地址信息,发出应答后,再接收要写入的数据,这样就完成了字节写过程。页写与字节写的区别就是,页写可以一次写多个数据,而字节写只能一次写一个数据。但由于AT24C02A的一页才8个字节,所以页写也最多写8个数据,而且只能在该页内写,不会发生一次页写同时写两页的情况。AT24C02A的读操作有三种模式:当前地址读、随机读和序列读。当前地址读是只能读取当前地址内的数据,它的时序是先接收带有读命令的设备地址信息,如果符合就应答,然后发送当前地址内的数据,在没有接收从主设备发来的应答信号的情况下终止该次操作。随机读的时序是,连续接收带有写命令的设备地址信息和设备内存地址信息,然后主设备重新开启IIC通信,AT24C02A再次接收到带有读命令的设备地址信息,在发出应答信号以后,发送该内存地址的数据,在没有接收到任何应答信号的情况下结束该次通信。当前地址读和随机读一次都只能读取一个数据,而序列读一次可以读取若干个数据,它的时序就是在当前地址读或随机读发出数据后,接收到了应答信号,那么AT24C02A会把下一个内存地址中的数据送出,除非AT24C02A接收不到任何应答信号,否则它会一直把下一个内存地址中的数据送出。序列读没有一页8个字节的限制。
下面是写入和读取
#include "iic.h"
void init_iic(void)
{
unsigned int a;
rGPEUP|=0xC000;
a=rGPECON;
a&=0x0fffffff;
a|=0xa0000000;
rIICADD=0x10;
rIICCON = (1<<7)|(0<<6)|(1<<5)|(0xf);
rIICSTAT = 0x10;
}
void iic_sendbyte(char salveaddr,char dataaddr,char data)
{
int i;
//rIICCON&=0xEF;
//发送芯片从地址,地址最0位为0
rIICDS=salveaddr;
rIICSTAT=0xf0;
for(i=0;i<200;i++);
//i=rIICSTAT;
//发送芯片数据地址
rIICDS=dataaddr;
rIICCON&= ~0x10;
for(i=0;i<20;i++);
//发送数据
rIICDS=data;
rIICCON&= ~0x10;
for(i=0;i<20;i++);
/*
//连续写入数据
for(i=0;i<sizeofdate;i++)
{
rIICDS =dataaddr;
rIICCON &= ~0x10;
for(i=0;i<20;i++);
}
*/
//结束发送
rIICSTAT = 0xd0;
rIICCON=0xAF;
for(i=0;i<20;i++);
}
void iic_recvbyte(char salveaddr,char dataaddr,char *data)
{
int i;
//发送芯片从地址,地址第0位为1
rIICDS = salveaddr;
rIICSTAT = 0xf0;
for(i=0;i<20;i++);
//
rIICDS=dataaddr;
rIICCON&= ~0x10; //清中断标志,引发数据传送
for(i=0;i<20;i++);
rIICDS=0xa1;
rIICSTAT = 0xB0;//设置位接收模式
rIICCON&= ~0x10;
for(i=0;i<20;i++);
//读取数据
*data = rIICDS;
/*
//在之前读取地址的基础上连续读,
for(i=0;i<sizeofdate;i++)
{
if(i==sizeofdate-1) //如果是最后一个数据
rIICCON &= ~0x80; //不再响应
*data = rIICDS;
rIICCON &= ~0x10;
for(i=0;i<20;i++);
}
*/
//读取结束
rIICSTAT = 0x90;
rIICCON=0x0xe0;
}
|