I2C (Inter-Integrated Circuit) 总线是由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备。是微电子通信控制领域广泛采用的一种总线标准。它是同步通信的一种特殊形式,具有接口线少,控制方式简单,器件封装形式小,通信速率较高,传输距离短等特性。
两条接口线
主机信号时序: start + address-read/write + ACK + data + ACK + … + stop
主机信号时序: start + address-read + ACK + data + ACK + … + restart + adress-write + stop
参考设计为使用串行数据线(SDA)和串行时钟线(SCL)、拥有7bit寻址空间的总线。
master | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
信号 | start | address | write | ACK | data | ACK | 重复5、6 | stop |
bit | 7 | 1 | 1 | 8 | 1 | … |
master | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
信号 | start | address | write | ACK | restart | address | read | ACK | data | ACK | 重复9、10 | last data | NACK | stop |
bit | 7 | 1 | 1 | 7 | 1 | 1 | 8 | 1 | … | 8 | 1 |
#注:主机读取从机特定地址上的数据
/* 产生start信号,发送地址数据,读/写操作 */
result = I2C_MasterStart(I2C_MASTER, I2C_SLAVE_ADDR, kI2C_Write);
/* 等待slave回复ACK信号 */
while (I2C_MASTER->S & kI2C_ReceiveNakFlag);
/* 发送数据 */
result = I2C_MasterWriteBlocking(I2C_MASTER, masterTxBuffer, I2C_DATA_LEN);
/* restart信号 */
result = I2C_MasterRepeatedStart(I2C_MASTER, I2C_SLAVE_ADDR, kI2C_Read);
/* 等待slave回复ACK信号 */
while (I2C_MASTER->S & kI2C_ReceiveNakFlag);
/* 读取数据 */
I2C_MasterReadBlocking(I2C_MASTER, masterRxBuffer, 2 * sizeof(uint8_t));
/* check stop flag */
if (status & kI2C_StopDetectFlag) {
I2C_SLAVE->S = kI2C_IntPendingFlag;
I2C_SlaveClearStatusFlags(I2C_SLAVE, kI2C_StopDetectFlag);
isStop = true;
return ;
}
/* check start flag */
if (status & kI2C_StartDetectFlag) {
isStart = true;
I2C_SLAVE->S = kI2C_IntPendingFlag;
I2C_SlaveClearStatusFlags(I2C_SLAVE, kI2C_StartDetectFlag);
if (!(status & kI2C_AddressMatchFlag)) {
return;
}
}
/* clear pending flag */
I2C_SLAVE->S = kI2C_IntPendingFlag;
/* check NAK */
if (status & kI2C_ReceiveNakFlag) {
/* nothing to do */
/* Receive mode */
I2C_SLAVE->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK);
I2C_SLAVE->D;
PRINTF("NAK\r\n");
}
/* Slave address match */
else if (status & kI2C_AddressMatchFlag) {
if (status & kI2C_TransferDirectionFlag) {
/* Slave transfer mode */
I2C_SLAVE->C1 |= I2C_C1_TX_MASK;
isTransfer = true;
} else {
/* Slave recive mode */
I2C_SLAVE->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK);
I2C_SLAVE->D;
isRecive = true;
return;
}
}
/* Transfer data */
if (status & kI2C_TransferCompleteFlag) {
/* Transmit data to master */
if (status & kI2C_TransferDirectionFlag) {
I2C_SLAVE->D = slaveRxBuffer[1];
}
else {
/* Receive data from master */
slaveRxBuffer[receive_data_len] = I2C_SLAVE->D;
receive_data_len++;
}
}
I2C从机读取数据时,读取的第一字节数据总是为0x00。在KSDK2.0代码库中,I2C主机在读取数据之前,会先读取1byte的无效数据(Do dummy read),然后读取有效数据,KSDK库函数代码如下:
status_t I2C_MasterReadBlocking(I2C_Type *base, uint8_t *rxBuff, size_t rxSize)
{
status_t result = kStatus_Success;
volatile uint8_t dummy = 0;
/* Add this to avoid build warning. */
dummy++;
/* Wait until the data register is ready for transmit. */
while (!(base->S & kI2C_TransferCompleteFlag))
{
}
/* Clear the IICIF flag. */
base->S = kI2C_IntPendingFlag;
/* Setup the I2C peripheral to receive data. */
base->C1 &= ~(I2C_C1_TX_MASK | I2C_C1_TXAK_MASK);
/* If rxSize equals 1, configure to send NAK. */
if (rxSize == 1)
{
/* Issue NACK on read. */
base->C1 |= I2C_C1_TXAK_MASK;
}
/* Do dummy read. */
dummy = base->D;
while ((rxSize--))
{
/* Wait until data transfer complete. */
while (!(base->S & kI2C_IntPendingFlag))
{
}
/* Clear the IICIF flag. */
base->S = kI2C_IntPendingFlag;
/* Single byte use case. */
if (rxSize == 0)
{
/* Read the final byte. */
result = I2C_MasterStop(base);
}
if (rxSize == 1)
{
/* Issue NACK on read. */
base->C1 |= I2C_C1_TXAK_MASK;
}
/* Read from the data register. */
*rxBuff++ = base->D;
}
return result;
}