关于F415硬件I2C
本帖最后由 ccxzjz 于 2021-11-9 09:37 编辑AT32F415使用I2C与另一个芯片通信,主要实现读寄存器和写寄存器功能,代码参考的是下面这个例子
刚开始读取数据通信是正常,但是一旦有一次传输不正常(比如人为断开i2c的线再接回去),后面一直读取失败,一直陷入到这个,只有复位芯片i2c才能读取成功。请教大家,怎么处理,完整代码如下
static I2C_StatusType I2C_WaitOnFlagUntilTimeout(I2C_Type *I2Cx, uint32_t Flag, FlagStatus Status, uint32_t EventCheck, uint32_t Timeout)
{
/* delay 10 us = ms * 100 */
Timeout *= 100;
while (I2C_GetFlagStatus(I2Cx, Flag) == Status)
{
if (EventCheck & I2C_EVT_CHECK_ACKFAIL)
{
if (I2C_GetFlagStatus(I2Cx, I2C_FLAG_ACKFAIL) == SET)
{
I2C_GenerateSTOP(I2Cx, ENABLE);
I2C_ClearFlag(I2Cx, I2C_FLAG_ACKFAIL);
return I2C_ERROR;
}
}
if (EventCheck & I2C_EVT_CHECK_STOP)
{
if (I2C_GetFlagStatus(I2Cx, I2C_FLAG_STOPF) == SET)
{
I2C_ClearSTOPFlag(I2Cx);
return I2C_ERROR;
}
}
I2C_Delay(10);
if ((Timeout--) == 0)
{
return I2C_TIMEOUT;
}
}
return I2C_OK;
}
I2C_StatusType hw_i2c_read_reg(I2C_Type *I2Cx, uint8_t slave_addr, uint8_t reg, uint8_t *rd_value, uint32_t Timeout)
{
/* Wait until BUSY flag is reset */
if (I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_BUSYF, SET, I2C_EVT_CHECK_NONE, I2C_TIMEOUT_BUSY_FLAG) != I2C_OK)
{
return I2C_ERROR_STEP_1;
}
/* Disable Pos */
I2C_NACKPositionConfig(I2Cx, I2C_NACKPosition_Current);
/* Enable Acknowledge */
I2C_AcknowledgeConfig(I2Cx, ENABLE);
/* Send START condition */
I2C_GenerateSTART(I2Cx, ENABLE);
/* Wait until SB flag is set */
if (I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_STARTF, RESET, I2C_EVT_CHECK_NONE, Timeout) != I2C_OK)
{
/* Send STOP Condition */
I2C_GenerateSTOP(I2Cx, ENABLE);
return I2C_ERROR_STEP_2;
}
/* Send slave address for write */
I2C_Send7bitAddress(I2Cx, slave_addr, I2C_Direction_Transmit);
/* Wait until ADDR flag is set */
if (I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_ADDRF, RESET, I2C_EVT_CHECK_NONE, Timeout) != I2C_OK)
{
/* Send STOP Condition */
I2C_GenerateSTOP(I2Cx, ENABLE);
return I2C_ERROR_STEP_3;
}
/* Clear ADDR flag */
I2C_ClearADDRFlag(I2Cx);
/* Wait until TDE flag is set */
if (I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_TDE, RESET, I2C_EVT_CHECK_NONE, Timeout) != I2C_OK)
{
/* Send STOP Condition*/
I2C_GenerateSTOP(I2Cx, ENABLE);
return I2C_ERROR_STEP_4;
}
/* Send Memory Address */
I2C_SendData(I2Cx, reg);
/* Wait until TDE flag is set */
if (I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_TDE, RESET, I2C_EVT_CHECK_ACKFAIL, Timeout) != I2C_OK)
{
/* Send STOP Condition */
I2C_GenerateSTOP(I2Cx, ENABLE);
return I2C_ERROR_STEP_5;
}
/* Send START condition */
I2C_GenerateSTART(I2Cx, ENABLE);
/* Wait until SB flag is set */
if (I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_STARTF, RESET, I2C_EVT_CHECK_NONE, Timeout) != I2C_OK)
{
/* Send STOP Condition */
I2C_GenerateSTOP(I2Cx, ENABLE);
return I2C_ERROR_STEP_6;
}
/* Send slave address for read */
I2C_Send7bitAddress(I2Cx, slave_addr, I2C_Direction_Receive);
/* Wait until ADDR flag is set */
if (I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_ADDRF, RESET, I2C_EVT_CHECK_ACKFAIL, Timeout) != I2C_OK)
{
/* Send STOP Condition */
I2C_GenerateSTOP(I2Cx, ENABLE);
return I2C_ERROR_STEP_7;
}
/* Disable Acknowledge */
I2C_AcknowledgeConfig(I2Cx, DISABLE);
/* Clear ADDR flag */
I2C_ClearADDRFlag(I2Cx);
/* Send STOP Condition */
I2C_GenerateSTOP(I2Cx, ENABLE);
/* Wait until RXNE flag is set */
if (I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_RDNE, RESET, I2C_EVT_CHECK_NONE, Timeout) != I2C_OK)
{
/* Send STOP Condition */
I2C_GenerateSTOP(I2Cx, ENABLE);
return I2C_ERROR_STEP_8;
}
/* Read data from DR */
(*rd_value) = I2C_ReceiveData(I2Cx);
return I2C_OK;
}
不太喜欢硬件iic。 推荐模拟iic吧。 F415硬件I2C有坑吗? F415硬件I2C读写速度怎么样? 就是读取超时了吧。 硬件I2C不好调试。 为什么不使用IO模拟呢? 这个是官网的代码吗? 可能读写速度太快了。 芯片没有响应吗? 这算是bug吗? 改用模拟的了,硬件确实繁琐 本帖最后由 muyichuan2012 于 2021-11-12 15:39 编辑
官方代码都是测试通过的,不会有问题的。
不过,官方的代码一般不会去考虑 “一旦有一次传输不正常(比如人为断开i2c的线再接回去)”这种应用情形,所以需要使用者根据自己的应用去调整,毕竟官方提供的仅仅是demo。
“传输不正常”有很多种情况,硬件I2C是有提供一部分的错误处理的,比如应答失败、欠载/过载、仲裁丢失等,但你提到的人为断开I2C线再接回去不是硬件I2C所能处理的错误。遇到此类的错误很可能会导致I2C内部的状态标志出现异常,你可以做下面几个尝试:
1、设定函数的超时时间,如果长时间无法通讯就退出函数,并返回相应的你自己定义的标志位
2、根据你自己定义的标志位来选择是否要复位硬件I2C
3、调用I2C_DeInit函数,将时钟复位,清除所有的I2C状态
4、重新初始化I2C配置 SCL SDA总线任意一根拉低就会出现此标志,在收到Stop时,硬件会自动清除,出现这种情况一般是你整个通信流程未完成,此时软件复位I2C就行,不用芯片复位 需要人为判断异常处理,原厂例程一般不会考虑这些,只有产品及的代码才会处理异常
页:
[1]