iic可以开启时钟拉伸功能,这种功能可以让主机决定什么时候继续发送时钟,此功能作用时会将从机SCL拉低。
针对主机多读或者多写的情况(比如主机收10个字节,从机发送5个字节),hal库并未作处理,会导致从机一直拉低SCL。Hal库原来的程序是这样:
代码语言:javascript复制static void
I2C_SlaveTransmit_BTF(I2C_HandleTypeDef *hi2c)
{
if
(hi2c->XferCount != 0U)
{
/* Write data to DR */
hi2c->Instance->DR = *hi2c->pBuffPtr;
/* Increment Buffer pointer */
hi2c->pBuffPtr ;
/* Update counter */
hi2c->XferCount--;
}
}
static void
I2C_SlaveReceive_BTF(I2C_HandleTypeDef *hi2c)
{
if
(hi2c->XferCount != 0U)
{
/* Read data from DR */
*hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR;
/* Increment Buffer pointer */
hi2c->pBuffPtr ;
/* Update counter */
hi2c->XferCount--;
}
}
这个是原来的库函数,多读或者多写后,会触发btf中断进入这个函数,同时hi2c->XferCount为0(原计划的数据量读写已经完成),导致btf中断函数什么也没做,SCL持续拉低.
可以做如下修改解决此问题
代码语言:javascript复制static void I2C_SlaveTransmit_BTF(I2C_HandleTypeDef *hi2c)
{
if (hi2c->XferCount != 0U)
{
/* Write data to DR */
hi2c->Instance->DR = *hi2c->pBuffPtr;
/* Increment Buffer pointer */
hi2c->pBuffPtr ;
/* Update counter */
hi2c->XferCount--;
}
else
{
hi2c->Instance->CR1&= ~(1<<0);
hi2c->Instance->CR1|= (1<<0);
}
}
static void I2C_SlaveReceive_BTF(I2C_HandleTypeDef *hi2c)
{
if (hi2c->XferCount != 0U)
{
/* Read data from DR */
*hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR;
/* Increment Buffer pointer */
hi2c->pBuffPtr ;
/* Update counter */
hi2c->XferCount--;
}
else
{
hi2c->Instance->CR1&= ~(1<<0);
hi2c->Instance->CR1|= (1<<0);
}
}
这样清除btf标志位,结束此次通信。