找回密码
立即注册
搜索
热搜: 活动 交友 discuz
发新帖

143

积分

0

好友

12

主题
发表于 2023-9-22 11:44:06 | 查看: 460| 回复: 3 IP:广东省珠海市 电信
gd32l233cct6芯片在硬件i2c读写过程中会偶尔出现write函数在TI标志位超时跳出,read函数在RBNE标志位超时跳出,TIMEOUT时间测试200ms+,在这两个标志位超时异常跳出导致i2c通信时序缺少stop位,bsy标志位一直位1,I2C再也无法继续通信,一定要通过复位i2c外设才能解决。硬件i2c驱动代码如下

  1. int gd32_i2c_write(unsigned char bus, unsigned short addr, unsigned char *data, unsigned int data_len)
  2. {
  3.     drv_i2c_mgr_t *i2c_mgr = NULL;
  4.     unsigned int timeout = DRV_I2C_TIME_OUT;
  5.     unsigned int idx;

  6.     if (bus >= DRV_I2C_BUS_MAX)
  7.     {
  8.         return -1;
  9.     }

  10.     i2c_mgr = &s_st_i2c_mgr[bus];
  11.     if (0 == i2c_mgr->is_init)
  12.     {
  13.         return -1;
  14.     }

  15.     /* wait until I2C bus is idle */
  16.     timeout = DRV_I2C_TIME_OUT;
  17.     i2c_master_addressing(i2c_mgr->periph, addr<<1, I2C_MASTER_TRANSMIT);
  18.     i2c_address_config(i2c_mgr->periph, DRV_I2C_OWN_ADDRESS7, I2C_ADDFORMAT_7BITS);
  19.     /* len not include addr byte */
  20.     i2c_transfer_byte_number_config(i2c_mgr->periph, data_len);
  21.     while(i2c_flag_get(i2c_mgr->periph, I2C_FLAG_I2CBSY))
  22.     {
  23.         if ((timeout--) == 0)
  24.         {
  25.             return -1;
  26.         }
  27.     }

  28.     /* send a start condition to I2C bus */
  29.     timeout = DRV_I2C_TIME_OUT;
  30.     i2c_start_on_bus(i2c_mgr->periph);

  31.     /* wait until the transmit data buffer is empty */
  32.     I2C_STAT(i2c_mgr->periph) |= I2C_STAT_TBE;
  33.     while(!i2c_flag_get(i2c_mgr->periph, I2C_FLAG_TBE))
  34.     {
  35.         if ((timeout--) == 0)
  36.         {
  37.             return -1;
  38.         }
  39.     }

  40.     for(idx = 0; idx < data_len; idx++)
  41.     {
  42.         /* data transmission */
  43.         timeout = DRV_I2C_TIME_OUT;
  44.         i2c_data_transmit(i2c_mgr->periph, data[idx]);
  45.         while(!i2c_flag_get(i2c_mgr->periph, I2C_FLAG_TI))
  46.         {
  47.             if ((timeout--) == 0)
  48.             {
  49.                 LOG_DIRECT_ERR("ti\r\n");
  50.                 return -1;
  51.             }
  52.         }
  53.     }
  54.     timeout = DRV_I2C_TIME_OUT;
  55.     while(!i2c_flag_get(i2c_mgr->periph, I2C_FLAG_TC))
  56.     {
  57.         if ((timeout--) == 0)
  58.         {
  59.             return -1;
  60.         }
  61.     }

  62.     /* send a stop condition to I2C bus */
  63.     i2c_stop_on_bus(i2c_mgr->periph);
  64.     /* wait until stop condition generate */
  65.     while(!i2c_flag_get(i2c_mgr->periph, I2C_FLAG_STPDET))
  66.     {
  67.         if ((timeout--) == 0)
  68.         {
  69.             return -1;
  70.         }
  71.     }

  72.     /* clear the STPDET bit */
  73.     i2c_flag_clear(i2c_mgr->periph, I2C_FLAG_STPDET);

  74.     return 0;
  75. }

  76. int gd32_i2c_read(unsigned char bus, unsigned short addr, unsigned char *data, unsigned int data_len)
  77. {
  78.     drv_i2c_mgr_t *i2c_mgr = NULL;
  79.     unsigned int timeout = DRV_I2C_TIME_OUT;
  80.     unsigned int idx;

  81.     if (bus >= DRV_I2C_BUS_MAX)
  82.     {
  83.         return -1;
  84.     }

  85.     i2c_mgr = &s_st_i2c_mgr[bus];
  86.     if (0 == i2c_mgr->is_init)
  87.     {
  88.         /* I2C init fail ,value invalid */
  89.         return -1;
  90.     }

  91.     /* wait until I2C bus is idle */
  92.     i2c_master_addressing(i2c_mgr->periph, addr<<1, I2C_MASTER_RECEIVE);
  93.     i2c_address_config(i2c_mgr->periph, addr<<1, I2C_ADDFORMAT_7BITS);
  94.     i2c_transfer_byte_number_config(i2c_mgr->periph, data_len);

  95.     timeout = DRV_I2C_TIME_OUT;
  96.     while(i2c_flag_get(i2c_mgr->periph, I2C_FLAG_I2CBSY))
  97.     {
  98.         if ((timeout--) == 0)
  99.         {
  100.             return -1;
  101.         }
  102.     }

  103.     /* send a start condition to I2C bus */
  104.     i2c_start_on_bus(i2c_mgr->periph);

  105.     for(idx = 0; idx < data_len; idx++)
  106.     {
  107.         /* wait until the RBNE bit is set */
  108.         timeout = DRV_I2C_TIME_OUT;
  109.         while(!i2c_flag_get(i2c_mgr->periph, I2C_FLAG_RBNE))
  110.         {
  111.             if ((timeout--) == 0)
  112.             {
  113.                 LOG_DIRECT_ERR("rbne\r\n");
  114.                 return -1;
  115.             }
  116.         }
  117.         /* read a data from I2C_DATA */
  118.         data[idx] = i2c_data_receive(i2c_mgr->periph);
  119.     }

  120.     while(!i2c_flag_get(i2c_mgr->periph, I2C_FLAG_TC))
  121.     {
  122.         timeout = DRV_I2C_TIME_OUT;
  123.         if ((timeout--) == 0)
  124.         {
  125.             return -1;
  126.         }
  127.     }
  128.     /* send a stop condition to I2C bus */
  129.     i2c_stop_on_bus(i2c_mgr->periph);
  130.     /* wait until stop condition generate */
  131.     while(!i2c_flag_get(i2c_mgr->periph, I2C_FLAG_STPDET))
  132.     {
  133.         timeout = DRV_I2C_TIME_OUT;
  134.         if ((timeout--) == 0)
  135.         {
  136.             return -1;
  137.         }
  138.     }

  139.     /* clear the STPDET bit */
  140.     i2c_flag_clear(i2c_mgr->periph, I2C_FLAG_STPDET);   

  141.     return 0;
  142. }
复制代码


发表于 2023-9-22 11:46:27 IP:广东省珠海市 电信
你的硬件I2C驱动代码看起来是正确的,但是可能需要注意以下几点:

* 检查您的I2C总线上是否有干扰或噪声,可能导致信号质量下降或丢失。
* 检查您的I2C设备是否支持您的I2C时钟速度,如果太快,可能会导致设备无法响应或应答错误。
* 检查您的I2C设备是否有正确的上拉电阻,如果太大或太小,可能会影响信号电平或电流。
* 检查您的I2C设备是否有正确的电源电压,如果太低或太高,可能会导致设备工作不稳定或损坏。

你也可以尝试以下几个方法来解决I2C超时问题:

* 在每次I2C操作之后,调用i2c\_reset函数来复位I2C外设,清除所有的标志位和寄存器。
* 在每次I2C操作之前,调用i2c\_bus\_busy\_wait函数来等待I2C总线空闲,避免在总线忙的时候发送命令。
* 在每次I2C操作之后,调用i2c\_stop\_on\_bus函数来发送一个停止条件到I2C总线,释放总线控制权,避免总线锁死。

还可以尝试使用i2cdetect命令来检测您的I2C设备是否存在,如果没有检测到,可能说明您的I2C设备有问题或者地址不正确。

发表于 2023-9-22 11:49:44 IP:广东省珠海市 电信
补充一下:排查问题发现是在TBE标志位等待,异常情况的波形TBE标志位等待延时了20us左右,导致会在TI标志位等待超时跳出。手动在这个地方加了一个20us的延时函数测试验证问题就是出在这里,在TBE后TI前的地方加了一个us级延时函数,i2c必定异常。各位大佬有没有遇到过类似情况的,帮忙看看,谢谢!
发表于 2023-9-22 11:51:49 IP:广东省珠海市 电信

这个问题很可能是硬件层面的问题。

下面是几个可能的原因和解决方案:

  1. I2C总线上的电源噪声:由于I2C总线和其他外设共用同一个电源,可能会产生电源噪声,导致I2C通信出现故障。解决方案是在I2C总线上添加电源滤波器,或使用单独的电源。
  2. I2C总线上的信号线噪声:类似于电源噪声,信号线噪声也可能导致I2C通信故障。解决方案是在I2C总线上添加信号线滤波器,或使用更短、更优质的信号线。
  3. I2C总线时钟频率过高:如果I2C总线时钟频率过高,可能会导致I2C读写操作失败。解决方案是降低I2C总线的时钟频率,或使用更高质量的时钟源。
  4. I2C总线上的负载过重:如果I2C总线上的负载过重,可能会导致I2C读写操作失败。解决方案是减少I2C总线上的负载,或增强I2C总线的驱动能力。
  5. I2C总线上的电容负载:如果I2C总线上存在电容负载,可能会导致I2C通信出现故障。解决方案是在I2C总线上添加合适的电容,以降低总线噪声。

上面的解决方案都需要在硬件层面进行调试和验证,需要根据实际情况进行选择和实施。同时,代码中的延时函数可能会影响I2C总线的时序,建议使用更精确的时钟同步方法。

*滑块验证:
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|国产电子社区 ( 沪ICP备2023018578号-1|

苏公网安备 32011102010465号


)|网站地图

GMT+8, 2024-7-27 18:16 , Processed in 0.062672 second(s), 23 queries , MemCached On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表