ccxzjz 发表于 2021-11-9 09:03

关于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;
}


cehuafan 发表于 2021-11-10 22:06

不太喜欢硬件iic。      

wengh2016 发表于 2021-11-10 22:06

推荐模拟iic吧。         

qiufengsd 发表于 2021-11-10 22:07

F415硬件I2C有坑吗?   

kmzuaz 发表于 2021-11-10 22:07

F415硬件I2C读写速度怎么样?   

plsbackup 发表于 2021-11-10 22:07

就是读取超时了吧。         

mnynt121 发表于 2021-11-10 22:07

硬件I2C不好调试。            

aspoke 发表于 2021-11-10 22:07

为什么不使用IO模拟呢?         

232321122 发表于 2021-11-10 22:07

这个是官网的代码吗?      

ghuca 发表于 2021-11-10 22:08

可能读写速度太快了。         

soodesyt 发表于 2021-11-10 22:08

芯片没有响应吗?      

yangxiaor520 发表于 2021-11-11 07:44

这算是bug吗?

ccxzjz 发表于 2021-11-12 15:20

改用模拟的了,硬件确实繁琐

muyichuan2012 发表于 2021-11-12 15:34

本帖最后由 muyichuan2012 于 2021-11-12 15:39 编辑

官方代码都是测试通过的,不会有问题的。
不过,官方的代码一般不会去考虑 “一旦有一次传输不正常(比如人为断开i2c的线再接回去)”这种应用情形,所以需要使用者根据自己的应用去调整,毕竟官方提供的仅仅是demo。



vt2017 发表于 2021-11-14 10:50

“传输不正常”有很多种情况,硬件I2C是有提供一部分的错误处理的,比如应答失败、欠载/过载、仲裁丢失等,但你提到的人为断开I2C线再接回去不是硬件I2C所能处理的错误。遇到此类的错误很可能会导致I2C内部的状态标志出现异常,你可以做下面几个尝试:
1、设定函数的超时时间,如果长时间无法通讯就退出函数,并返回相应的你自己定义的标志位
2、根据你自己定义的标志位来选择是否要复位硬件I2C
3、调用I2C_DeInit函数,将时钟复位,清除所有的I2C状态
4、重新初始化I2C配置

骑着蜗牛狂奔O 发表于 2021-11-14 17:50

SCL SDA总线任意一根拉低就会出现此标志,在收到Stop时,硬件会自动清除,出现这种情况一般是你整个通信流程未完成,此时软件复位I2C就行,不用芯片复位

6552918 发表于 2021-11-15 09:41

需要人为判断异常处理,原厂例程一般不会考虑这些,只有产品及的代码才会处理异常
页: [1]
查看完整版本: 关于F415硬件I2C