1. 硬件原理
I2C总线是PHLIPS公司推出的一种串行总线,是具备多主机系统所需的包括总线裁决和高低速器件同步功能的高性能串行总线。 I2C总线只有两根双向信号线。一根是数据线SDA,另一根是时钟线SCL。
I2C总线通过上拉电阻接正电源。当总线空闲时,两根线均为高电平。连到总线上的任一器件输出的低电平,都将使总线的信号变低,即各器件的SDA及SCL都是线“与”关系。
每个接到I2C总线上的器件都有唯一的地址。主机与其它器件间的数据传送可以是由主机发送数据到其它器件,这时主机即为发送器。由总线上接收数据的器件则为接收器。
1.1. 数据位的有效性规定
I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。
1.2. 起始和终止信号
SCL线为高电平期间,SDA线由高电平向低电平的变化表示起始信号;SCL线为高电平期间,SDA线由低电平向高电平的变化表示终止信号。
起始和终止信号都是由主机发出的,在起始信号产生后,总线就处于被占用的状态;在终止信号产生后,总线就处于空闲状态。接收器件收到一个完整的数据字节后,有可能需要完成一些其它工作,如处理内部中断服务等,可能无法立刻接收下一个字节,这时接收器件可以将SCL线拉成低电平,从而使主机处于等待状态。直到接收器件准备好接收下一个字节时,再释放SCL线使之为高电平,从而使数据传送可以继续进行。
1.3. 数据传送
a、主机向从机发送数据,数据传送方向在整个传送过程中不变:
b、主机在第一个字节后,立即从从机读数据
c、在传送过程中,当需要改变传送方向时,起始信号和从机地址都被重复产生一次,但两次读/写方向位正好反相。
2. 芯片手册
2.1. ATMEL公司的AT24C系列
AT24C01:128字节(128×8位);
AT24C02:256字节(256×8位);
AT24C04:512字节(512×8位)AT24C08:1K字节(1K×8位);
AT24C16:2K字节(2K×8位);
AT24C系列E2PROM芯片地址的固定部分为1010,A2、A1、A0引脚接高、低电平后得到确定的3位编码。形成的7位编码即为该器件的地址码。
2.2. 写入
单片机进行写操作时,首先发送该器件的7位地址码和写方向位“0”(共8位,即一个字节),发送完后释放SDA线并在SCL线上产生第9个时钟信号。被选中的存储器器件在确认是自己的地址后,在SDA线上产生一个应答信号作为相应,单片机收到应答后就可以传送数据了。
传送数据时,单片机首先发送一个字节的被写入器件的存储区的首地址,收到存储器器件的应答后,单片机就逐个发送各数据字节,但每发送一个字节后都要等待应答。
AT24C系列器件片内地址在接收到每一个数据字节地址后自动加1,在芯片的“一次装载字节数”(不同芯片字节数不同)限度内,只需输入首地址。装载字节数超过芯片的“一次装载字节数”时,数据地址将“上卷”,前面的数据将被覆盖
当要写入的数据传送完后,单片机应发出终止信号以结束写入操作。写入n个字节的数据格式 :
2.3. 读出
单片机先发送该器件的7位地址码和写方向位“0”(“伪写”),发送完后释放SDA线并在SCL线上产生第9个时钟信号。被选中的存储器器件在确认是自己的地址后,在SDA线上产生一个应答信号作为回应。
然后,再发一个字节的要读出器件的存储区的首地址,收到应答后,单片机要重复一次起始信号并发出器件地址和读方向位(“1”),收到器件应答后就可以读出数据字节,每读出一个字节,单片机都要回复应答信号。当最后一个字节数据读完后,单片机应返回以“非应答”(高电平),并发出终止信号以结束读出操作。
3. mini2440电路图
由原理图可以看出,2440只有两根引脚和EEPROM连接。
4. S3C2440寄存器
IICCON 控制寄存器,控制是否发生ACK信号,设置发送器时钟,开启IIC中断。
IICSTAT 控制/状态寄存器,选择工作模式(从机接收、从机发生、主机接收、主机发送),发出S信号、P信号,使能接收/发送功能,并标识各种状态。
IICADDR 从机地址
IICDS 发送/接收寄存器,数据移位。
IICLC 行控制寄存器
iic.h
/*******************************************************************
* Copyright (C),2011-2012, XXX.
* FileName: iic.h
* Author:HuangYinqing
* Version:1.0
* Date::2012-04-22
* Description:IIC读写EEPROM.
* Function List:
* History:
******************************************************************/
#ifndef __IIC_H__
#define __IIC_H__
#define DBG_IIC_LEVEL 1
#define DEV_ADDR 0xa0
/*函数声明*/
void IICInit(void);
void IICTest(void);
#endif //__IIC_H__
iic.c
/*******************************************************************
* Copyright (C),2011-2012, XXX.
* FileName: iic.c
* Author:HuangYinqing
* Version:1.0
* Date::2012-04-22
* Description:IIC驱动(中断方式).
* Function List:
* History:
******************************************************************/
#include "common.h"
#include "core.h"
#include "iic.h"
unsigned char pucIICBuffer[32][8]; //IIC数据通讯缓存数组
unsigned char g_bIICFlag = 0; //应答标志
/********************************************************************
函数功能:IIC中断函数。
入口参数:无。
返 回:无。
备 注:无。
********************************************************************/
static void __irq IICIntHandler(void)
{
rSRCPND = BIT_IIC; //Clear pending bit
rINTPND = BIT_IIC;
g_bIICFlag = 1;
}
/********************************************************************
函数功能:IIC初始化。
入口参数:无。
返 回:无。
备 注:无。
********************************************************************/
void IICInit(void)
{
rGPECON &= 0x0fffffff;
rGPECON |= 0xa0000000; //GPE15:IICSDA , GPE14:IICSCL
rGPEUP |= 3<<14; //Pull-up disable
//Enable ACK, Prescaler IICCLK=PCLK/16, Enable interrupt,
//Transmit clock value Tx clock=IICCLK/16,
//If PCLK 50.7MHz, IICCLK = 3.17MHz, Tx Clock = 0.198MHz
rIICCON = (1<<7) | (0<<6) | (1<<5) | (0xf);
rIICSTAT = 0x10; //IIC bus data output enable(Rx/Tx)
#if 0
rIICADD = 0x10; //2440 slave address = [7:1]
rIICLC = (1<<2) | (1); // Filter enable, 15 clocks SDA output delay added by junon
#endif
pISR_IIC = ( unsigned int )IICIntHandler;
rINTMSK &= ~(BIT_IIC);
}
/********************************************************************
函数功能:AT24c02a写函数。
入口参数:
ulMemAddr:设备内存地址
pucBuffer:IIC数据缓存数组
ulCount:要写入的数据个数。
返 回:无。
备 注:当ulCount==1时是字节写,最多写一页8字节。
********************************************************************/
void Wr24c02a ( unsigned long ulMemAddr, unsigned char *pucBuffer, unsigned long ulCount )
{
int i;
g_bIICFlag = 0; //应答标志
if ( ulCount > 8 )
{
DbgPrintX( DBG_IIC_LEVEL, "\rAT24c02a write number must blow 8 byte!\n");
return;
}
rIICDS = DEV_ADDR;
rIICCON &= ~0x10; //清中断标志
rIICSTAT = 0xf0; //主设备发送模式
while( !g_bIICFlag ) //等待从设备应答,
udelay(10); //一旦进入IIC中断,即可跳出该死循环
g_bIICFlag = 0;
rIICDS = ulMemAddr; //写入从设备内存地址
rIICCON &= ~0x10;
while( !g_bIICFlag )
udelay(10);
for ( i=0; i
{
g_bIICFlag = 0;
rIICDS = *( pucBuffer + i );
rIICCON &= ~0x10;
while( !g_bIICFlag )
udelay(10);
}
rIICSTAT = 0xd0; //发出stop命令,结束该次通讯
rIICCON = 0xaf; //为下次IIC通讯做准备
mdelay(10); //等待
}
/********************************************************************
函数功能:AT24c02a读函数。
入口参数:
ulMemAddr:设备内存地址
pucBuffer:IIC数据缓存数组
ulCount:要读取的数据个数。
返 回:无。
备 注:当ulCount==1时是字节写,无最多读限制。
********************************************************************/
void Rd24c02a ( unsigned long ulMemAddr, unsigned char *pucBuffer, unsigned long ulCount )
{
int i;
unsigned char temp;
/*发送设备地址(写操作)*/
g_bIICFlag =0;
rIICDS = DEV_ADDR;
rIICCON &= ~0x10; //清中断标志
rIICSTAT = 0xf0; //主设备发送模式
while ( !g_bIICFlag )
udelay(10);
/*发送内存地址*/
g_bIICFlag = 0;
rIICDS = ulMemAddr;
rIICCON &= ~0x10;
while ( !g_bIICFlag )
udelay(10);
/*发送设备地址(读操作)*/
g_bIICFlag = 0;
rIICDS = DEV_ADDR;
rIICCON &= ~0x10;
rIICSTAT = 0xb0; //主设备接收模式
while ( !g_bIICFlag )
udelay(10);
/*读到第一个数据是地址,丢弃*/
g_bIICFlag = 0;
temp = rIICDS; //读取从设备地址
rIICCON &= ~0x10;
while(!g_bIICFlag)
udelay(10);
/*连续读数据*/
for ( i=0; i
{
g_bIICFlag = 0;
if( i==ulCount-1 ) //如果是最后一个数据
rIICCON &= ~0x80; //不再响应
*(pucBuffer+i) = rIICDS;
rIICCON &= ~0x10;
while ( !g_bIICFlag )
udelay(10);
}
rIICSTAT = 0x90; //结束该次通讯
rIICCON = 0xaf;
mdelay(10);
}
/********************************************************************
函数功能:IIC测试函数。
入口参数:无。
返 回:无。
备 注:无。
********************************************************************/
void IICTest(void)
{
int i, j;
DbgPrintX( DBG_IIC_LEVEL, "\nIIC Test(Interrupt) using AT24C02\n");
/*写操作*/
DbgPrintX( DBG_IIC_LEVEL, "Write test data into AT24C02\n");
memset ( pucIICBuffer, 0x49, 256);
for(i=0 ;i<32; i++)
Wr24c02a (0+8*i, pucIICBuffer[i], 8);
memset ( pucIICBuffer, 0, 256);
/*读操作*/
DbgPrintX( DBG_IIC_LEVEL, "Read test data from AT24C02\n");
// for(i=0 ;i<32; i++)
Rd24c02a (0, (unsigned char *)pucIICBuffer, 256);
for(i=0;i<32;i++)
{
for(j=0; j<8; j++)
DbgPrintX( DBG_IIC_LEVEL, "%2x ", pucIICBuffer[i][j] );
DbgPrintX( DBG_IIC_LEVEL, "\n");
}
rINTMSK |= BIT_IIC;
}
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』