/***************************************************************************** * * Filename: * --------- * soft_i2c.c * * * Description: * ------------ * Use GPIO simulate I2C interface. * * Author: * ------- * jimmy.li ****************************************************************************/ #define uint32 #define uint16 #define uint8 #define int32 #define int16 #define int8 /* GPIO setting */ #define SDA_GPIO #define SCL_GPIO /* set GPIO function as general output/input */ #define SET_SDA_FN_0 #define SET_SCL_FN_0 #define SET_SDA_OUTPUT #define SET_SDA_INPUT #define SET_SCL_OUTPUT /* read SDA status */ #define GET_SDA_VALUE /* pull SDA/SCL high or low */ #define SEND_SDA_VALUE(x) #define PULL_SDA_LOW #define PULL_SDA_HIGH #define PULL_SCL_LOW #define PULL_SCL_HIGH /* delay */ #define I2C_DUMMY_DELAY \ do{\ uint16 i2c_dummy_cnt; \ ; i2c_dummy_cnt!=; i2c_dummy_cnt--); \ }) /************************************************************************* * FUNCTION * I2C_Init * * DESCRIPTION * Prepare to control I2C bus, set SCL, SDA normal GPIO mode. * * PARAMETERS * None. * * RETURNS * None * *************************************************************************/ void I2C_Init(void) { /* set SCL, SDA normal GPIO mode */ SET_SDA_FN_0; SET_SCL_FN_0; } /************************************************************************* * FUNCTION * I2C_Release * * DESCRIPTION * Release I2C bus. * * PARAMETERS * None. * * RETURNS * None * *************************************************************************/ void I2C_Release(void) { /* set SCL, SDA high */ PULL_SCL_HIGH; PULL_SDA_HIGH; } /************************************************************************* * FUNCTION * I2C_Start * * DESCRIPTION * Initiate a START condition. * A High to Low transition on the SDA line while SCL is High defines a START condition. * * SCL --- --- * |___ * SDA --- * |___ ___ * * PARAMETERS * None. * * RETURNS * None * *************************************************************************/ void I2C_Start(void) { SET_SCL_OUTPUT; SET_SDA_OUTPUT; PULL_SCL_HIGH; PULL_SDA_HIGH; I2C_DUMMY_DELAY; PULL_SDA_LOW; I2C_DUMMY_DELAY; PULL_SCL_LOW; I2C_DUMMY_DELAY; } /************************************************************************* * FUNCTION * I2C_Stop * * DESCRIPTION * Generate a Stop condition. * A Low to High transition on the SDA line while SCL is High defines a START condition. * * SCL --- --- * ___| * SDA --- * ___ ___| * * PARAMETERS * None. * * RETURNS * None * *************************************************************************/ void I2C_Stop(void) { SET_SCL_OUTPUT; SET_SDA_OUTPUT; PULL_SCL_LOW; PULL_SDA_LOW; I2C_DUMMY_DELAY; PULL_SCL_HIGH; I2C_DUMMY_DELAY; PULL_SDA_HIGH; I2C_DUMMY_DELAY; } /************************************************************************* * FUNCTION * I2C_TxByte * * DESCRIPTION * Send a byte to I2C bus. * * PARAMETERS * @uint8 data data to be send. * * RETURNS * ack received from I2C slave device. * *************************************************************************/ uint8 I2C_TxByte(uint8 data) { int8 i, ack; SET_SCL_OUTPUT; SET_SDA_OUTPUT; // send 8bits data, MSB first ; --i>=; ){ if((data>>i)& 0x01) PULL_SDA_HIGH; else PULL_SDA_LOW; I2C_DUMMY_DELAY; PULL_SCL_HIGH; I2C_DUMMY_DELAY; PULL_SCL_LOW; I2C_DUMMY_DELAY; } // receive ack SET_SDA_INPUT; PULL_SCL_HIGH; I2C_DUMMY_DELAY; ack = GET_SDA_VALUE; // read ack when HIGH period of the SCL PULL_SCL_LOW; SET_SDA_OUTPUT; return ack; } /************************************************************************* * FUNCTION * I2C_RxByte * * DESCRIPTION * Receive a byte from I2C bus. * * PARAMETERS * @uint8 *data store received data. * @uint8 ack ack send to I2C slave device after receive a byte. * ACK -- 0 * NACK -- 1 * RETURNS * None. * *************************************************************************/ void I2C_RxByte(uint8 *data, uint8 ack) { int16 i; uint32 dataCache; dataCache = ; SET_SDA_INPUT; // receive 8bits data ; --i>=; ){ dataCache <<= ; PULL_SCL_HIGH; I2C_DUMMY_DELAY; dataCache |= GET_SDA_VALUE; PULL_SCL_LOW; I2C_DUMMY_DELAY; } SET_SDA_OUTPUT; // send ack if(ack) PULL_SDA_HIGH; else PULL_SDA_LOW; I2C_DUMMY_DELAY; PULL_SCL_HIGH; I2C_DUMMY_DELAY; PULL_SCL_LOW; *data = (uint8)dataCache; }
I2C总线协议标准版本是v2.1,于2000年推出。I2C的主要特性如下:
1、只需两根线:串行数据线(SDA), 串行时钟线(SCL)。
2、SDA 和SCL 都是双向线路都通过一个电流源或上拉电阻连接到正的电源电压, 当总线空闲时这两条线路都是高电平,连接到总线的器件输出级必须是漏极开路或集电极开路才能执行线与的功能。
3、每一个连接到I2C总线上的设备都要求是可被软件寻址的,也就是在I2C总线上每一个设备都必须有一个独一无二的地址(7bits)。同一时刻,总线上只能存在一个主/从(Master/Slave)关系,而且只有主设备(Master)才能发起Read和Write。
4、I2C总线是面向8位的串行双向传输总线,其标准模式(Standard-mode)下,速率可达100kbit/s,在其快速模式(Fast-mode)下,速率可达400kbit/s,而在高速模式(High-speed mode)下,速率可高达3.4Mbit/s。
Transmitter
I2C总线上发送数据的设备
Receiver
I2C总线上接收数据的设备
Master
发起传输、产生时钟信号,并且终止传输的设备
Slave
被master寻址的设备
I2C数据的有效性:
SDA线上的数据在时钟High阶段必须稳定,只有在时钟Low时SDA数据线上的数据才能发生高/低电平变化。
START
当SCL在高电平时,SDA由高转变为低电平。(SCL=High, SDA : High ->Low)
STOP
当SCL在高电平时,SDA由低转变为高电平。 (SCL=High, SDA: Low -> High)
I2C总线上的数据传输
SDA线上传输的每一个字节都必须是8-bits长,但每一次所传输的字节数不限,每传输完一个字节,必须跟随一个ack位(ack 方向与数据传输方向相反 ),I2C上传输的数据都是高位优先传输(MSB)的。
I2C 的应答信号
1, ACK (应答) --- 是一个低电平信号
2, NACK(应答非) --- 是一个高电平信号