对于S3C2440 IIC的主发送/接收模式来说,主要涉及三个寄存器 IICCON,IICSTAT,IICDS。
从上图可以看出,IIC的时钟来源是 PCLK,数据从SDA线移入然后保存在IICDS寄存器中。
在S3C2440中,当数据发送完或者接收完数据后会产生中断。
IIC 主发送模式流程图:
IIC 主接收模式流程图:
在文档中的比较需要注意的是,对于EEProm来说,读取数据时最后一个一定不要发送ACK。
此程序是参照赵春江的程序来写的,他的博客:
示例代码:
#ifndef IIC_H
#define IIC_H
#include "2440addr.h"
#include "config.h"
void IIC_Init(void);
void wr2402(unsigned char devAddr,unsigned char addr,unsigned char *data, int len);
void rd2402(unsigned char devAddr,unsigned char addr,unsigned char *data, int len);
__irq void IIC_ISR(void);
void delay(int time);
#endif
#include "IIC.h"
void IIC_Init(void)
{
/* 将IO口配置为SDA和SCL */
rGPECON &= ~(0xf<<28);
rGPECON |= (2<<28) | (2<<30);
/* 禁止上拉 */
rGPEUP |= (1<<14) | (1<<13);
/* 使能应答信号,设置IIC时钟为fPCLK的512分频,使能中断 */
rIICCON = (1<<7) | (1<<6) | (1<<5);
pISR_IIC = (unsigned int)IIC_ISR;
/* 使能串行输出 */
rIICSTAT |= (1<<4);
/* 使能中断 */
rINTMSK &= ~(1<<27);
rSRCPND = (1<<27);
rINTPND = (1<<27);
}
volatile int flag;
void wr2402(unsigned char devAddr,unsigned char addr, unsigned char *data, int len)
{
int i;
/* 发送从设备地址(寻址) */
flag = 1;
rIICDS = devAddr;
rIICCON &= ~(1<<4); //清除中断,注意,这句话要放在写IICDS后面
rIICSTAT = 0xf0; //设置为主发送模式
while(flag==1) //等待从设备应答
delay(100);
/* 发送所写的内存地址 */
flag = 1;
rIICDS = addr;
rIICCON &= ~(1<<4);
while(flag == 1)
delay(100);
/* 发送所需要写入的数据 */
for(i=0; i<len; i++)
{
flag = 1;
rIICDS = data[i];
rIICCON &= ~(1<<4);
while(flag == 1)
delay(100);
}
/* 发送停止信号 */
rIICSTAT = 0xd0;
/* 恢复操作 */
rIICCON = 0xe0;
delay(100);
}
void rd2402(unsigned char devAddr,unsigned char addr,unsigned char *data, int len)
{
int i;
/* 发送从设备地址 */
flag = 1;
rIICDS = devAddr;
rIICCON &= ~(1<<4);
rIICSTAT = 0xf0;
while(flag == 1)
delay(100);
/* 发送所需要读的内存地址 */
flag = 1;
rIICDS = addr;
rIICCON &= ~(1<<4);
while(flag == 1)
delay(100);
/* 设置主设备接收模式 */
flag = 1;
rIICDS = devAddr;
rIICCON &= ~(1<<4);
rIICSTAT = 0xB0;
while(flag == 1)
delay(100);
/* 读取的是设备地址 */
flag = 1;
i = rIICDS;
rIICCON &= ~(1<<4);
while(flag==1)
delay(100);
/* 读数据 */
for(i=0; i<len; i++)
{
flag = 1;
/* 最后一个数据不发送ACK */
if (i==len-1)
{
rIICCON &= ~(1<<7);
}
data[i] = rIICDS;
rIICCON &= ~(1<<4);
while(flag==1)
delay(100);
}
rIICSTAT = 0x90;
rIICCON = 0xe0;
delay(100);
}
__irq void IIC_ISR(void)
{
flag = 0;
rSRCPND = (1<<27);
rINTPND = (1<<27);
}
void delay(int time)
{
int i,j;
for(i=0; i<time;i++)
for(j=0;j<1000;j++)
;
}
#include "2440addr.h"
#include "config.h"
#include "IIC.h"
unsigned char data[16];
void Main(void)
{
int i;
IIC_Init();
for(i=0; i<16; i++)
data[i] = i;
wr2402(0xa0,0,data,8);
wr2402(0xa0,8,data+8,8); //这里使用的是AT24C02,每页只有8B,所以每次最多只能写8B,多了会回滚
for(i=0; i<16; i++)
data[i] = 0;
rd2402(0xa0,0,data,16); //读可以不受页大小的影响
while(1);
}