I2C总线以及GPIO模拟I2C

·I2C总线的一些特征:

1、 只要求两条总线,一条串行数据线(SDA),一条串行时钟线(SCL)

2、 两个连接到总线的器件都可以通过唯一的地址和一直存在的简单的主机/从机系统软件设定的地址;主机可以作为主机发送器或主机接收器

3、 它是一个真正的多主机总线,如果两个或更多个主机同时初始化数据传输,可以通过冲突检测和总裁防止数据被破坏

4、 串行的8位双向数据传输位速率在标准模式下可达100kbit/s,快速模式下可达400kbit/s,高速模式下可达3.4Mbit/s

5、 片上的滤波器可以滤去总线数据线上的毛刺波,保证数据完整

6、 连接到相同总线上的IC数量只收到总线的最大电容400pF限制

·I2C总线术语定义:

1、 发送器:发送数据到总线的器件。

2、 接收器:从总线接收数据的器件。

3、 主机:初始化发送、产生时钟信号和终止发送的器件。

4、 从机:被主机寻址的器件。

5、 多主机:同时有多于一个主机尝试控制总线,但不破坏报文。

6、 仲裁:是一个在有多个主机同时尝试控制总线,但只允许其中一个控制总线并使报文不被破坏的过程。

7、 同步:两个或多个器件同步时钟信号的过程。

/* */

·主机发出的总线时钟信号只有在以下的情况下才能被改变:慢速的从机器件控制时钟线并延长时钟信号(时钟线被拉低延长),或者在发生仲裁时被另一个主机改变。

·I2C总线支持任何IC生产过程(NMOS、CMOS、双极性)。

·两线——串行数据(SDA)和串行时钟(SCL)线在连接到总线的器件间传递信息。

·每个器件都有一个唯一的地址识别,而且都可以作为一个发送器或接收器。

·除了发送器和接收器外,器件在执行数据传输时也可以被看作是主机或从机。

·主机是初始化总线的数据传输并产生允许传输的时钟信号的器件。任何被寻址的器件都认为是从机。

·在I2C总线上产生时钟信号通常是主机器件的责任;在总线上传输数据时,每个主机产生自己的时钟信号。

·SDA和SCL都是双向线路,都通过一个电流源或上拉电阻连接到正的电源电压。当总线空闲时,这两条线路都是高电平。

·连接到总线的器件输出级必须是漏极开路或集电极开路才能执行线与功能。(????)

·SDA线上的数据必须在时钟的高电平周期保持稳定。数据线的高或低电平状态只有在SCL线的时钟信号是低电平时才能改变:

I2C总线以及GPIO模拟I2C

·起始条件:在SCL线是高电平时,SDA线从高电平向低电平切换。

·停止条件:当SCL线是高电平时,SDA线由低电平向高电平切换。

I2C总线以及GPIO模拟I2C

·起始和停止条件一般由主机产生。总线在起始条件后被认为处于忙的状态。在停止条件的某段时间后,总线被认为再次处于空闲状态。

传输数据:

·字节格式:发送到SDA线上的每个字节必须为8位。每次传输可以发送的字节数量不受限制。每个字节后必须跟一个响应位。

·如果从机要完成一些其他功能后(例如一个内部中断服务程序)才能接收或发送下一个完整的数据字节,可以使时钟线SCL保持低电平迫使主机进入等待状态。当从机准备好接收下一个数据字节并释放时钟线SCL后,数据传输继续。

·数据传输必须带响应。相关的响应时钟脉冲由主机产生。在响应的时钟脉冲期间,发送器释放SDA线(高)。

·在响应的时钟脉冲期间,接收器必须将SDA线拉低,使它在这个时钟脉冲的高电平期间保持稳定的低电平。

·当从机不能响应从机地址时(例如它正在执行一些实时函数不能接收或发送),从机必须是数据线保持高电平。主机然后产生一个停止条件终止传输或者产生重复起始条件开始新的传输。

·如果从机-接收器响应了从机地址但是在传输了一段时间后不能接收更多数据字节,主机必须再一次终止传输。这种情况用从机在第一个字节后没有产生响应来表示。从机使数据线保持高电平,主机产生一个停止或重复起始条件。

·如果传输中有主机接收器,它必须通过在从机不产生时钟的组后一个字节不产生一个响应,向从机-发送器通知数据结束,从机-发送器必须释放数据线,允许主机产生一个停止或重复起始条件。

【IO模拟IIC源码】

 #include "base.h"
#include "simI2C.h" #define MAX_PORT_INDEX 4
#define MIN_PORT_INDEX 0
#define MAX_PIN_INDEX 31
#define MIN_PIN_INDEX 0
#define I2C_INTVAL 15 // ~=30KHz #define DIR_MODE_IN 0
#define DIR_MODE_OUT 1 #define CLK_DELAY_RETRY 10000 #define log /*
set the io dir
*/
static int i2c_SetIODir(int iPin, int iMode)
{
int port, subno; port = (iPin >> ) & 0xff;
subno = (iPin & 0xff);
if(port < MIN_PORT_INDEX || port > MAX_PORT_INDEX)
return I2C_ERR_INVALID_PARAM;
if(subno < MIN_PIN_INDEX|| subno > MAX_PIN_INDEX)
return I2C_ERR_INVALID_PARAM; gpio_set_pin_type(port, subno, iMode);
return I2C_OK;
} /*
set the io level
*/
static int i2c_SetIO(int iPin, int iLevel)
{
int port, subno; port = (iPin >> ) & 0xff;
subno = (iPin & 0xff);
if(port < MIN_PORT_INDEX || port > MAX_PORT_INDEX)
return I2C_ERR_INVALID_PARAM;
if(subno < MIN_PIN_INDEX|| subno > MAX_PIN_INDEX)
return I2C_ERR_INVALID_PARAM; gpio_set_pin_val(port, subno, iLevel);
return I2C_OK;
} /*
get the io level
*/
static int i2c_GetIO(int iPin)
{
int port, subno; port = (iPin >> ) & 0xff;
subno = (iPin & 0xff);
if(port < MIN_PORT_INDEX || port > MAX_PORT_INDEX)
return I2C_ERR_INVALID_PARAM;
if(subno < MIN_PIN_INDEX|| subno > MAX_PIN_INDEX)
return I2C_ERR_INVALID_PARAM; return gpio_get_pin_val(port, subno);
} static void i2c_Intval(void)
{
DelayUs(I2C_INTVAL);
} static void i2c_start (T_SimI2CHdl *pHdl)
{
int m;
int clk; pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_OUT);
pHdl->pfSetDIR(pHdl->iSDA, DIR_MODE_OUT);
pHdl->pfSetIO(pHdl->iSDA, );
do {
pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_IN);
pHdl->pfSetIO(pHdl->iSCL, );
if(pHdl->pfGetIO(pHdl->iSCL) == )
continue ;
else
break;
}while(); pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_OUT);
pHdl->pfSetIO(pHdl->iSCL, );
// TODO:
pHdl->pfSetIO(pHdl->iSDA, );
i2c_Intval();
pHdl->pfSetIO(pHdl->iSDA, );
i2c_Intval();
pHdl->pfSetIO(pHdl->iSCL, );
i2c_Intval();
} static void i2c_stop (T_SimI2CHdl *pHdl)
{
int m;
int clk; pHdl->pfSetDIR(pHdl->iSDA, DIR_MODE_OUT);
//pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_OUT);
pHdl->pfSetIO(pHdl->iSDA, );
do {
pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_IN);
pHdl->pfSetIO(pHdl->iSCL, );
if(pHdl->pfGetIO(pHdl->iSCL) == )
continue ;
else
break;
}while(); pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_OUT);
pHdl->pfSetIO(pHdl->iSCL, );
i2c_Intval();
pHdl->pfSetIO(pHdl->iSDA, );
i2c_Intval();
//log("out");
} static void i2c_ack (T_SimI2CHdl *pHdl)
{
int m;
int clk; pHdl->pfSetDIR(pHdl->iSDA, DIR_MODE_OUT);
//pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_OUT);
i2c_Intval();
// i2c_Intval();
pHdl->pfSetIO(pHdl->iSDA, );
// i2c_Intval();
do {
pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_IN);
pHdl->pfSetIO(pHdl->iSCL, );
if(pHdl->pfGetIO(pHdl->iSCL) == )
continue ;
else
break;
}while(); pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_OUT);
pHdl->pfSetIO(pHdl->iSCL, );
i2c_Intval();
pHdl->pfSetIO(pHdl->iSCL, );
i2c_Intval();
//log("out");
} static void i2c_nack (T_SimI2CHdl *pHdl)
{
int m;
int clk; pHdl->pfSetDIR(pHdl->iSDA, DIR_MODE_OUT);
//pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_OUT);
i2c_Intval();
// i2c_Intval();
pHdl->pfSetIO(pHdl->iSDA, );
do {
pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_IN);
pHdl->pfSetIO(pHdl->iSCL, );
if(pHdl->pfGetIO(pHdl->iSCL) == )
continue ;
else
break;
}while(); pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_OUT);
pHdl->pfSetIO(pHdl->iSCL, );
i2c_Intval();
pHdl->pfSetIO(pHdl->iSCL, );
i2c_Intval();
//log("out"); } /*
the receiver acknowlage the ack?
1 yes, 0 no
*/
static int i2c_isack (T_SimI2CHdl *pHdl)
{
int val = ;
int m;
int clk; // pHdl->pfSetIO(pHdl->iSDA, 0); //Joshua _a
pHdl->pfSetDIR(pHdl->iSDA, DIR_MODE_IN);
// i2c_Intval();
//pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_OUT);
do {
pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_IN);
pHdl->pfSetIO(pHdl->iSCL, );
if(pHdl->pfGetIO(pHdl->iSCL) == )
continue ;
else
break;
}while(); pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_OUT);
pHdl->pfSetIO(pHdl->iSCL, );
i2c_Intval();
val = pHdl->pfGetIO(pHdl->iSDA);
pHdl->pfSetIO(pHdl->iSCL, );
i2c_Intval(); return val==? : ;
} static int i2c_ReadByte(T_SimI2CHdl *pHdl, char *ch)
{
int i;
int temp = ;
int m;
int clk; //pHdl->pfSetIO(pHdl->iSDA, 1); //Joshua _a
pHdl->pfSetDIR(pHdl->iSDA, DIR_MODE_IN);
//pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_OUT);
//pHdl->pfSetIO(pHdl->iSDA, 1);
i2c_Intval(); for (i=; i<; i++)
{
temp <<= ;
do {
pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_IN);
pHdl->pfSetIO(pHdl->iSCL, );
if(pHdl->pfGetIO(pHdl->iSCL) == )
continue ;
else
break;
}while(); pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_OUT);
pHdl->pfSetIO(pHdl->iSCL, );
i2c_Intval();
temp |= pHdl->pfGetIO(pHdl->iSDA);
pHdl->pfSetIO(pHdl->iSCL, );
i2c_Intval();
}
*ch = (char)(temp&0xff);
//log("ReadByte = %02X", temp);
return ;
} static int i2c_WriteByte(T_SimI2CHdl *pHdl, char ch)
{
int i;
char temp = ch;
int m;
int clk; pHdl->pfSetDIR(pHdl->iSDA, DIR_MODE_OUT);
//pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_OUT); for (i=; i<; i++)
{
if ((temp << i) & 0x80)
{
pHdl->pfSetIO(pHdl->iSDA, );
}
else
{
pHdl->pfSetIO(pHdl->iSDA, );
}
do {
pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_IN);
pHdl->pfSetIO(pHdl->iSCL, );
if(pHdl->pfGetIO(pHdl->iSCL) == )
continue ;
else
break;
}while(); pHdl->pfSetDIR(pHdl->iSCL, DIR_MODE_OUT);
pHdl->pfSetIO(pHdl->iSCL, );
i2c_Intval();
pHdl->pfSetIO(pHdl->iSCL, );
if (i >= )
pHdl->pfSetDIR(pHdl->iSDA, DIR_MODE_IN);
i2c_Intval();
}
} /*********************************************************
Name :
imI2CInit
Descritpion :
initialize the I2C handle
input: output:
pHdl - the handle pointer;
return:
= 0 - success
< 0 - failed
Joshua Guo. @ 2012-06-27
**********************************************************/
int SimI2CInit(T_SimI2CHdl *pHdl, int iSDA, int iSCL)
{
int sda_port, sda_subno;
int scl_port, scl_subno; sda_port = (iSDA >> ) & 0xff;
sda_subno = (iSDA & 0xff);
scl_port = (iSCL >> ) & 0xff;
scl_subno = (iSCL & 0xff); if(pHdl == NULL
|| sda_port < MIN_PORT_INDEX || sda_port > MAX_PORT_INDEX
|| sda_subno < MIN_PIN_INDEX || sda_subno > MAX_PIN_INDEX
|| scl_port < MIN_PORT_INDEX || scl_port > MAX_PORT_INDEX
|| scl_subno < MIN_PIN_INDEX || scl_subno > MAX_PIN_INDEX)
return I2C_ERR_INVALID_PARAM; pHdl->iSDA = iSDA;
pHdl->iSCL = iSCL;
pHdl->iRetry = ;
pHdl->pfGetIO = i2c_GetIO;
pHdl->pfSetIO = i2c_SetIO;
pHdl->pfSetDIR = i2c_SetIODir; return ;
} int SimI2CSetRetry(T_SimI2CHdl *pHdl, int iRetry)
{
if (pHdl == NULL || iRetry < )
{
return I2C_ERR_INVALID_PARAM;
}
pHdl->iRetry = iRetry;
return ;
} /*
read data from the simulator I2C bus return:
< 0 read failed, return the error No.
>=0 data length Joshua Guo. @ 2012-06-27
*/
//int SimI2CReadDataFromAddr(T_SimI2CHdl *pHdl, char slave, char addr, char *buf, int iLen)
int SimI2CReadDataFromAddr(T_SimI2CHdl *pHdl,
unsigned char slave, unsigned char addr, unsigned char *buf, unsigned char iLen)
{
int i;
int iRetry1 = ;
int iRetry2 = ;
// if (pHdl == NULL || buf == NULL || iLen < 0)
if (pHdl == NULL || buf == NULL)
{
log("I2C_ERR_INVALID_PARAM");
return I2C_ERR_INVALID_PARAM;
}
if (iLen == )
{
log("iLen = 0");
return ;
}
/*
* Read Data From the Device
* +---+-------+---+------------+---+---+---+-------+---+
* | S | SLA+W | A | MemAddress | A | P | S | SLA+R | A | ...
* +---+-------+---+------------+---+---+---+-------+---+
* +-------+----+-------+----+-----+-------+-----+---+
* | Data1 | mA | Data2 | mA | ... | DATAn | /mA | P |
* +-------+----+-------+----+-----+-------+-----+---+
* S - Start Condition
* P - Stop Condition
* SLA+W - Slave Address plus Wirte Bit
* SLA+R - Slave Address plus Read Bit
* MemAddress - Targe memory address within device
* mA - Host Acknowledge Bit
* A - Slave Acknowledge Bit
*/
/*
i2c_nack(pHdl);
i2c_ack(pHdl);
i2c_stop(pHdl);
*/
retry1:
//start
i2c_start(pHdl);
//slave with the R/W as 0
i2c_WriteByte(pHdl, slave);
if (i2c_isack(pHdl) == ) //not acknowlage the ACK
{
i2c_stop(pHdl);
if(iRetry1++ >= pHdl->iRetry)
{
log("I2C_ERR_READ_FAILED 1");
return I2C_ERR_READ_FAILED;
}
goto retry1;
} //addr byte
i2c_WriteByte(pHdl, addr);
if (i2c_isack(pHdl) == ) //not acknowlage the ACK
{
i2c_stop(pHdl);
log("I2C_ERR_READ_FAILED 2");
return I2C_ERR_READ_FAILED;
}
retry2:
//start
i2c_start(pHdl);
//slave byte with R/W as 1
i2c_WriteByte(pHdl, (slave|0x01));
if (i2c_isack(pHdl) == ) //not acknowlage the ACK
{
i2c_stop(pHdl);
if(iRetry2++ >= pHdl->iRetry)
{
log("I2C_ERR_READ_FAILED 3");
return I2C_ERR_READ_FAILED;
}
goto retry2;
} //real read
for(i=; i<iLen; i++)
{
i2c_ReadByte(pHdl, buf+i);
if (i == (iLen-)) //the last byte will acknowlage the NACK
{
//log("if");
i2c_nack(pHdl);
}
else
{
//log("else");
i2c_ack(pHdl);
}
} //log("stop");
//stop
i2c_stop(pHdl);
//logHex(buf, iLen, "Read<%d> = ", iLen);
return iLen;
} /*
Write data to the simulator I2C bus return:
< 0 write failed, return the error No.
>=0 data length Joshua Guo. @ 2012-06-27
*/
//int SimI2CWriteDataToAddr(T_SimI2CHdl *pHdl, char slave, char addr, char *buf, int iLen)
int SimI2CWriteDataToAddr(T_SimI2CHdl *pHdl,
unsigned char slave, unsigned char addr, unsigned char *buf, unsigned char iLen)
{
int i;
int iRetry = ;
//if (pHdl == NULL || buf == NULL || iLen < 0)
if (pHdl == NULL || buf == NULL)
{
log("I2C_ERR_INVALID_PARAM");
return I2C_ERR_INVALID_PARAM;
}
if (iLen == )
{
log("iLen = 0");
return ;
} /*
* Write Data to the Device
* +---+-------+---+------------+---+------+---+---+
* | S | SLA+W | A | MemAddress | A | Data | A | P |
* +---+-------+---+------------+---+------+---+---+
* S - Start Condition
* SLA+W - Slave Address plus write bit
* MemAddress - Targe memory address within device
* Data - Data to be written
* A - Slave Acknowledge Bit
* P - Stop Condition
*/
retry:
//start
i2c_start(pHdl);
//slave
i2c_WriteByte(pHdl, slave);
if (i2c_isack(pHdl) == )
{
i2c_stop(pHdl);
if(iRetry++ >= pHdl->iRetry)
{
log("I2C_ERR_WRITE_FAILED 1");
return I2C_ERR_WRITE_FAILED;
}
goto retry;
} //addr
i2c_WriteByte(pHdl, addr);
if (i2c_isack(pHdl) == ) //not acknowlage the ACK
{
i2c_stop(pHdl);
log("I2C_ERR_WRITE_FAILED 2");
return I2C_ERR_WRITE_FAILED;
} for (i=; i<iLen; i++)
{
i2c_WriteByte(pHdl, buf[i]);
if (i2c_isack(pHdl) == ) //not acknowlage the ACK
{
i2c_stop(pHdl);
log("I2C_ERR_WRITE_FAILED 3");
return I2C_ERR_WRITE_FAILED;
}
}
i2c_stop(pHdl);
//log("return iLen = %d", iLen);
return iLen;
} // TODO: test
上一篇:array_count_values函数


下一篇:ASP.net:截取固定长度字符串显示在页面,多余部分显示为省略号