/*****************************************************
*作 者:温子祺
*联系方式 :[email protected]
*说 明:S3C2440 I2C实现
*****************************************************/
1:I2C原理
总线的构成及信号类型 I2C总线是由数据线SDA和时钟SCL构成的串行总线,可发送和接收数据。在CPU与被控IC之间、IC与IC之间进行双向传送,最高传送速率100kbps。各种被控制电路均并联在这条总线上,但就像电话机一样只有拨通各自的号码才能工作,所以每个电路和模块都有唯一的地址,在信息的传输过程中,I2C总线上并接的每一模块电路既是主控器(或被控器),又是发送器(或接收器),这取决于它所要完成的功能。CPU发出的控制信号分为地址码和控制量两部分,地址码用来选址,即接通需要控制的电路,确定控制的种类;控制量决定该调整的类别(如对比度、亮度等)及需要调整的量。这样,各控制电路虽然挂在同一条总线上,却彼此独立,互不相关。 I2C总线在传送数据过程中共有三种类型信号, 它们分别是:开始信号、结束信号和应答信号。 开始信号:SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。 结束信号:SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据。 应答信号:接收数据的从控器在接收到8bit数据后,向发送数据的主控器发出特定的低电平脉冲,表示已收到数据。CPU向从控器发出一个信号后,等待从控器发出一个应答信号,CPU接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,判断为受控单元出现故障。 这些信号中,起始信号是必需的,结束信号和应答信号,都可以不要。
2:I2C实验代码
/*
---------------------------------------------------------------
文件名称:I2C.c
说 明:I2C协议 读写AT24C08
作 者:温子祺
创建时间:2010-08-17
测试结果:[OK]
注意事项:
(1)24C02数据速率I2C总线的数据传送速率在标准工作方式下为100kbit/s,
在快速方式下,最高传送速率可达400kbit/s。
(2)当前S3C2440各频率如下:FCLK 405MHz
HCLK 135MHz
PCLK 67.5MHz
(3)当前I2C协议在三星提供的源代码进行修改,并提升代码的容错能力
如I2C进行读写时,都有进行超时处理。
---------------------------------------------------------------
*/
#include " S3C244x.h "
#include " Global.h "
#include " IIC.h "
/*
1:rIICON IIC总线控制寄存器
2:rIICSTAT IIC总线控制状态寄存器
3:rIICADD IIC总线地址寄存器
4:rIICDS IIC总线发送接收数据移位寄存器
5:rIICLC IIC总线多主设备线路控制寄存器
*/
/*
====================================================
I2C基本函数接口
====================================================
*/
static volatile UINT8 g_ucI2CDataBuf[ 256 ]; // I2C发送数据缓冲区
static volatile UINT32 g_unI2CCurDataCount; // I2C当前数据计数
static volatile UINT32 g_unI2CCurStatus; // I2C当前状态
static volatile UINT32 g_unI2CCurDataOffset; // I2C当前发送数据偏移量
static UINT32 g_unI2CCurMode; // I2C当前模式
static UINT32 g_unIICCONSave; // 临时保存rIICCON寄存器值
static void __irq I2CISR( void ) ; // I2C中断服务函数
static BOOL I2CWriteByte(UINT32 unSlaveAddress,UINT32 ucWriteAddress,UINT8 * pucWriteByte);
static BOOL I2CReadByte (UINT32 unSlaveAddress,UINT32 ucReadAddress ,UINT8 * pucReadByte);
/* *****************************************************
*文件名称:I2CWriteByte
*输 入:unSlaveAddress 从机地址
unWriteAddress 写地址
pucWriteByte 写字节
*输 出:TRUE/FALSE
*功能说明:I2C 写单个字节
*注意事项:
主机发送起始信号后,发送一个寻址字节,收到应答后紧跟着的就是数据传输,
数据传输一般由主机产生的停止位终止。但是,如果主机仍希望在总线上通讯,
它可以产生重复起始信号和寻址另一个从机,而不是首先产生一个停止信号。
在这种传输中,可能有不同的读/写格式。
****************************************************** */
static BOOL I2CWriteByte(UINT32 unSlaveAddress,
UINT32 unWriteAddress,
UINT8 * pucWriteByte)
{
BOOL bRt = TRUE;
UINT32 unTimeouts;
g_unI2CCurMode = WRDATA; // 当前I2C模式:写
g_unI2CCurDataOffset = 0 ; // I2C数据缓冲区偏移量为0
g_ucI2CDataBuf[ 0 ] = (UINT8)unWriteAddress; // 写地址
g_ucI2CDataBuf[ 1 ] = * pucWriteByte; // 写数据
g_unI2CCurDataCount = 2 ; // 当前数据计数值(即地址+数据=2字节)
rIICDS = unSlaveAddress; // 0xa0(高四位默认是1010,低四位为xxxx)
rIICSTAT = 0xf0 ; // 主机发送启动
unTimeouts = 1000 ;
while (g_unI2CCurDataCount !=- 1 && unTimeouts -- )
{
DelayNus( 1 );
}
if ( ! unTimeouts)
{
bRt = FALSE;
goto end;
}
g_unI2CCurMode = POLLACK;
while ( 1 )
{
rIICDS = unSlaveAddress;
g_unI2CCurStatus = 0x100 ;
rIICSTAT = 0xf0 ; // 主机发送启动
rIICCON = g_unIICCONSave; // 恢复I2C运行
unTimeouts = 1000 ;
while (g_unI2CCurStatus == 0x100 && unTimeouts -- )
{
DelayNus( 1 );
}
if ( ! unTimeouts)
{
bRt = FALSE;
goto end;
}
if ( ! (g_unI2CCurStatus & 0x1 ))
{
break ; // 接收到应答(ACK)信号
}
}
end:
rIICSTAT = 0xd0 ; // 停止主机发送状态Stop MasTx condition
rIICCON = g_unIICCONSave; // 恢复I2C运行
DelayNus( 10 ); // 等待直到停止条件是有效的
return bRt;
}
/* *****************************************************
*文件名称:I2CReadByte
*输 入:unSlaveAddress 从机地址
unReadAddress 读地址
pucReadByte 读字节
*输 出:TRUE/FALSE
*功能说明:I2C 读单个字节
*注意事项:
主机发送完寻址字节后,主机立即读取从机中的数据。
当寻址字节的"R/W"位为1时,在从机产生应答信号后,
主机发送器变成主机接收器,从机接收器变成从机发送器。
之后,数据由从机发送,主机接收,每个应答由主机产生,
时钟信号CLK仍由主机产生。若主机要终止本次传输,则发送
一个非应答信号,接着主机产生停止信号
****************************************************** */
static BOOL I2CReadByte(UINT32 unSlaveAddress,
UINT32 unReadAddress,
UINT8 * pucReadByte)
{
BOOL bRt = TRUE;
UINT32 unTimeouts;
g_unI2CCurMode = SETRDADDR;
g_unI2CCurDataOffset = 0 ;
g_ucI2CDataBuf[ 0 ] = (UINT8)unReadAddress;
g_unI2CCurDataCount = 1 ;
rIICDS = unSlaveAddress;
rIICSTAT = 0xf0 ; // 主机发送启动
unTimeouts = 1000 ;
while (g_unI2CCurDataCount !=- 1 && unTimeouts -- )
{
DelayNus( 1 );
}
if ( ! unTimeouts)
{
bRt = FALSE;
goto end;
}
g_unI2CCurMode = RDDATA;
g_unI2CCurDataOffset = 0 ;
g_unI2CCurDataCount = 1 ;
rIICDS = unSlaveAddress;
rIICSTAT = 0xb0 ; // 主机接收启动
rIICCON = g_unIICCONSave; // 恢复I2C运行
unTimeouts = 1000 ;
while (g_unI2CCurDataCount !=- 1 && unTimeouts -- )
{
DelayNus( 1 );
}
if ( ! unTimeouts)
{
bRt = FALSE;
goto end;
}
* pucReadByte = g_ucI2CDataBuf[ 1 ];
end:
return bRt;
}
/* *****************************************************
*文件名称:I2CWriteNBytes
*输 入:unSlaveAddress 从机地址
unWriteAddress 写地址
pucWriteByte 写字节
unNumOfBytes 写字节数
*输 出:TRUE/FALSE
*功能说明:I2C 写多个字节
****************************************************** */
BOOL I2CWriteNBytes(UINT32 unSlaveAddress,
UINT32 unWriteAddress,
UINT8 * pucWriteBytes,
UINT32 unNumOfBytes)
{
UINT32 unSpareOfBytes = unNumOfBytes;
while (unSpareOfBytes -- )
{
if ( ! I2CWriteByte( unSlaveAddress,
unWriteAddress,
pucWriteBytes))
{
I2CMSG( " I2C[ERROR]:fail to write data fail at address %d \
success to write % d bytes \r\n " ,
unWriteAddress,(unNumOfBytes - unSpareOfBytes));
return FALSE;
}
unWriteAddress ++ ;
pucWriteBytes ++ ;
}
return TRUE;
}
/* *****************************************************
*文件名称:I2CReadNBytes
*输 入:unSlaveAddress 从机地址
unReadAddress 读地址
unNumOfBytes
*输 出:TRUE/FALSE
*功能说明:I2C 读多个字节
****************************************************** */
BOOL I2CReadNBytes(UINT32 unSlaveAddress,
UINT32 unReadAddress,
UINT8 * pucReadByte,
UINT32 unNumOfBytes)
{
UINT32 unSpareOfBytes = unNumOfBytes;
while (unSpareOfBytes -- )
{
if ( ! I2CReadByte( unSlaveAddress,
unReadAddress,
pucReadByte))
{
I2CMSG( " I2C[ERROR]:fail to read data fail at address %d \
success to read % d bytes \r\n " ,
unReadAddress,(unNumOfBytes - unSpareOfBytes));
return FALSE;
}
unReadAddress ++ ;
pucReadByte ++ ;
}
return TRUE;
}
/*
====================================================
中断服务函数
====================================================
*/
/* *****************************************************
*文件名称:I2CISR
*输 入:无
*输 出:无
*功能说明:I2C 中断服务函数
****************************************************** */
void __irq I2CISR( void )
{
UINT32 unI2CStatus;
unI2CStatus = rIICSTAT;
if (unI2CStatus & 0x8 ){} // When bus arbitration is failed.
if (unI2CStatus & 0x4 ){} // When a slave address is matched with IICADD
if (unI2CStatus & 0x2 ){} // When a slave address is 0000000b
if (unI2CStatus & 0x1 ){} // When ACK isn't received
switch (g_unI2CCurMode)
{
case POLLACK:
g_unI2CCurStatus = unI2CStatus;
break ;
case RDDATA:
if ((g_unI2CCurDataCount -- ) == 0 )
{
g_ucI2CDataBuf[g_unI2CCurDataOffset ++ ] = rIICDS;
rIICSTAT = 0x90 ; // 停止I2C接收状态
rIICCON = g_unIICCONSave; // 恢复I2C运行
DelayNus( 1 ); // 等待直到停止条件是有效的
// The pending bit will not be set after issuing stop condition.
break ;
}
g_ucI2CDataBuf[g_unI2CCurDataOffset ++ ] = rIICDS; // The last data has to be read with no ack.
if ((g_unI2CCurDataCount) == 0 )
rIICCON = 0x2f ; // Resumes IIC operation with NOACK.
else
rIICCON = g_unIICCONSave; // Resumes IIC operation with ACK
break ;
case WRDATA:
rIICDS = g_ucI2CDataBuf[g_unI2CCurDataOffset ++ ]; // g_ucI2CDataBuf[0] has dummy.
DelayNus( 10 ); // for setup time until rising edge of IICSCL
rIICCON = g_unIICCONSave; // 恢复I2C运行
if ((g_unI2CCurDataCount -- ) == 0 )
{
rIICSTAT = 0xd0 ; // Stop MasTx condition
rIICCON = g_unIICCONSave; // 恢复I2C运行
DelayNus( 10 ); // Wait until stop condtion is in effect.
// The pending bit will not be set after issuing stop condition.
}
break ;
case SETRDADDR:
if ((g_unI2CCurDataCount -- ) == 0 )
{
break ;
}
// IIC operation is stopped because of IICCON[4]
rIICDS = g_ucI2CDataBuf[g_unI2CCurDataOffset ++ ];
DelayNus( 10 ); // For setup time until rising edge of IICSCL
rIICCON = g_unIICCONSave; // 恢复I2C运行
break ;
default :
break ;
}
rSRCPND = BIT_IIC; // Clear pending bit
rINTPND = BIT_IIC;
}
/*
====================================================
测试代码
====================================================
*/
/* *****************************************************
*文件名称:I2CTest
*输 入:无
*输 出:无
*功能说明:I2C 测试代码
****************************************************** */
void I2CTest( void )
{
UINT32 i;
UINT8 buf[ 256 ];
I2CMSG( " \nIIC Test(Interrupt) using AT24C02\n " );
rGPEUP |= 0xc000 ; // Pull-up disable
rGPECON |= 0xa00000 ; // GPE15:IICSDA , GPE14:IICSCL
rCLKCON |= 1 << 16 ;
pISR_IIC = (UINT32)I2CISR;
rINTMSK &= ~ (BIT_IIC);
/*
IIC时序太重要了,要认真设置好发送时钟和接收数据时钟
当前PCLK = 405/6 = 67.5MHz
IICCLK=67.5/16= 4.22MHz
Tx Clock = 4.22/11=0.384MHz
*/
g_unIICCONSave = rIICCON = ( 1 << 7 ) | ( 0 << 6 ) | ( 1 << 5 ) | ( 0xa );
rIICADD = 0x10 ; // S3C2440 从机地址设置
rIICSTAT = 0x10 ; // I2C总线数据输出使能(Rx/Tx)
rIICLC = ( 1 << 2 ) | ( 1 ); // 滤波器使能,SDA数据延时输出
I2CMSG( " Write test data into AT24C02\n " );
for (i = 0 ;i < 256 ;i ++ )
{
buf[i] = i;
}
I2CWriteNBytes( 0xA0 , 0 ,buf, 256 );
for (i = 0 ;i < 256 ;i ++ )
buf[i] = 0 ;
I2CMSG( " Read test data from AT24C02\n " );
I2CReadNBytes( 0xA0 , 0 ,buf, 256 );
I2CMSG( " Read Data Finish\r\n " );
for (i = 0 ;i < 256 ;i ++ )
{
I2CMSG( " %d " ,buf[i]);
}
rINTMSK |= BIT_IIC;
}
3:显示结果
转载请注明出处,谢谢。