Slave状态介绍: 1) 收到 RE-START 信号或者 STOP 信号,发生 I2C 中断,STATUS 寄存器的值=0xA0 2) 收到 SLA+R 信号并返回 ACK,发生 I2C 中断,STATUS 寄存器的值=0xA8 3) 作为 Master 仲裁失败 HW 会自动转为 Slave,之后收到 SLA+R 信号,发生 I2C 中断, STATUS 寄存器的值=0xB0 4) 发送数据并收到 ACK,发生 I2C 中断,STATUS 寄存器的值=0xB8 5) 发送数据并收到 NACK,发生 I2C 中断,STATUS 寄存器的值=0xC0 6) 从接发送最后一个数据,但是居然收到的是 ACK,发生 I2C 中断,STATUS 寄存器的值 =0xC8 7) 从接收到 SLA+W 并返回 ACK,发生 I2C 中断,STATUS 寄存器的值=0x60 8) 作为 Master 仲裁失败 HW 会自动转为 Slave,之后收到 SLA+W 信号,发生 I2C 中断, STATUS 寄存器的值=0x68 9) 收到数据并返回 ACK,发生 I2C 中断,STATUS 寄存器的值=0x80 10) 收到数据并返回 NACK,发生 I2C 中断,STATUS 寄存器的值=0x88 11) 广播模式收到 SLA+W 并返回 ACK,发生 I2C 中断,STATUS 寄存器的值=0x70 12) 广播模式仲裁失败,发生 I2C中断,STATUS寄存器的值=0x78 13) 广播模式收到数据并返回 ACK,发生 I2C 中断,STATUS 寄存器的值=0x90 知道所有的状态之后,配置好I2C,然后在中断里面查看STATUS寄存器,处理状态就可以了。超时中断是用户设定时间内没有发生状态改变,就会发生超时中断,这个可以防止软件被hold住。 下面是一个读/写EEPROM的例子。照样是先选择用到的IP的时钟源,使能各个IP的时钟,然后配置多功能引脚,然后是I2C IP功能初始化。另外是I2C 的中断处理函数。中断处理函数中根据 STATUS寄存器的值,进行状态处理。只要调用函数I2C_SET_CONTROL_REG(I2C0, I2C_SI);清除状态改变标志,I2CIP就会自动开始下一个状态。
void I2C0_IRQHandler(void)
{
uint32_t u32Status;
/* 清除中断标志 */
I2C0->INTSTS |= I2C_INTSTS_INTSTS_Msk;
/*取得STATUS寄存器的值*/
u32Status = I2C_GET_STATUS(I2C0);
/*检查中断标志*/
if (I2C_GET_TIMEOUT_FLAG(I2C0)) {/*发生超时中断*/
/* 清除超时中断标志 */
I2C_ClearTimeoutFlag(I2C0); } else {/*状态改变中断*/
if (s_I2C0HandlerFn != NULL) s_I2C0HandlerFn(u32Status);
}
}
/* I2C 接收回调函数
*/ void I2C_MasterRx(uint32_t u32Status)
{
if (u32Status == 0x08) { /* START 被发送,准备SLA+W */
I2C_SET_DATA(I2C0, (g_u8DeviceAddr << 1)); /* 写 SLA+W 到数据寄存器 I2CDAT */
I2C_SET_CONTROL_REG(I2C0, I2C_SI); /*清除状态改变标志,I2C IP开始发送SLA+W*/
} else if (u32Status == 0x18) { /* SLA+W 已经发送并且收到ACK */
I2C_SET_DATA(I2C0, g_au8TxData[g_u8DataLen++]);/*将要发送的数据写到I2CDAT寄存器*/
I2C_SET_CONTROL_REG(I2C0, I2C_SI); /* 清除状态改变标志, I2C IP开始发送数据 */
} else if (u32Status == 0x20) { /* SLA+W 已经被发送并且收到NACK */
I2C_SET_CONTROL_REG(I2C0, I2C_STA | I2C_STO | I2C_SI); /*发送STOP并重新发送START信号*/
} else if (u32Status == 0x28) { /* DATA 已经被发送并且收到ACK */ if (g_u8DataLen != 2) {
I2C_SET_DATA(I2C0, g_au8TxData[g_u8DataLen++]);/*继续写数据到I2CDAT寄存器*/
I2C_SET_CONTROL_REG(I2C0, I2C_SI); /*清除状态改变标志,I2C IP开始发送数据*/ } else {
I2C_SET_CONTROL_REG(I2C0, I2C_STA|I2C_SI);/*清除状态改变标志并再次发送START信号*/ }
} else if (u32Status == 0x10) { /* Repeat START 已经被发送,准备SLA+R */
I2C_SET_DATA(I2C0, (g_u8DeviceAddr << 1) | 0x01); /* 写 SLA+R 到I2CDAT寄存器 */
I2C_SET_CONTROL_REG(I2C0, I2C_SI); /*清除状态改变标志,I2C IP开始发送SLA+R*/
} else if (u32Status == 0x40) { /* SLA+R 已经发送并且收到ACK信号 */
|