20502|32

77

帖子

0

TA的资源

一粒金砂(初级)

楼主
 

请教I2C超时处理 [复制链接]

目前在调试I2C接口的LED驱动器,每隔16ms进行一次I2C写操作,原先采用V2.0.3驱动库中的查询方式,在无外界干扰时运行正常,一旦有干扰程序陷入I2C死循环中;
看到先前的帖子:
主题:STM32 I2C 封装库(查询方式+29楼中断方式+32楼DMA方式)
https://bbs.eeworld.com.cn/icview-108420-4-1.html
综合考虑决定改用中断方式,但直接采用库中函数:
I2C_Comm_MasterWrite();

发现即使在无干扰情况下仍会死机,比原先的查询方式运行效果还差。
不知何故?
此帖出自stm32/stm8论坛

最新回复

                                 看看  详情 回复 发表于 2010-7-16 15:49
点赞 关注
 

回复
举报

74

帖子

0

TA的资源

一粒金砂(初级)

沙发
 
下载帖子中中断方式的代码,发现错误中断处理中只对两种情况进行处理,查阅I2C_SR1的寄存器说明增加了超时错误处理,但调试没发现进入该中断。
还请论坛里的高手指教!
void i2c1_err_isr()
{
    if (I2C_GetFlagStatus(I2C1, I2C_FLAG_AF))
    {
        if (check_begin)
            I2C_GenerateSTART(I2C1, ENABLE);
        else if (I2C1->SR2 & 0x01)
        {
            I2C_GenerateSTOP(I2C1, ENABLE);
            i2c_comm_state = COMM_EXIT;
            PV_flag_1 = 0;
        }
      
        I2C_ClearFlag(I2C1, I2C_FLAG_AF);
    }

    if (I2C_GetFlagStatus(I2C1, I2C_FLAG_BERR))
    {
        if (I2C1->SR2 & 0x01)
        {
            I2C_GenerateSTOP(I2C1, ENABLE);
            i2c_comm_state = COMM_EXIT;
            PV_flag_1 = 0;
        }
      
        I2C_ClearFlag(I2C1, I2C_FLAG_BERR);
    }

    /*以下超时错误处理代码为自行添加*/
    if (I2C_GetFlagStatus(I2C1, I2C_FLAG_TIMEOUT))
    {
        //主模式下设置该位,硬件发出停止条件
        I2C1->SR1 |= 0x4000;
        I2C_ClearFlag(I2C1, I2C_FLAG_TIMEOUT);
    }   
}
此帖出自stm32/stm8论坛
 
 

回复

74

帖子

0

TA的资源

一粒金砂(初级)

板凳
 
" 发现即使在无干扰情况下仍会死机 "

程序死在哪里,此时I2C的SR1和SR2的值有什么异常么。
另外,lz能够从死的时候的I2C总线上的波形上看到什么异常么。
此帖出自stm32/stm8论坛
 
 

回复

68

帖子

0

TA的资源

一粒金砂(初级)

4
 
由于电路板密度较大,且STM32为BGA封装,I2C接口LED驱动芯片为TQFN,无法测到I2C总线波形;只是仿真运行时有干扰程序会停在I2C函数中各处的WHLIE语句处
SR1、SR2倒是没观测过,我仿真看下。
此帖出自stm32/stm8论坛
 
 
 

回复

74

帖子

0

TA的资源

一粒金砂(初级)

5
 
另外询问超时时间多少合适?
顺便看了下“STM32 I2C 封装库(查询方式+29楼中断方式+32楼DMA方式)”帖子中查询方式,定义的超时时间大都为(i2c_10clk_us*one_us_unit)*100,以快速模式400KHz的速率算,该值为2.5ms,而我的应用要求是16ms进行一次STM32对I2C器件的写操作,这样的超时时间太长了。
超时时间取值范围多少?如何保证16ms一次的I2C操作的可靠性?
此帖出自stm32/stm8论坛
 
 
 

回复

66

帖子

0

TA的资源

一粒金砂(初级)

6
 
发生超时一般I2C通信已经出错了。这时返回的错误代码报告给应用层,作应用相关的出错处理。你要做怎样的出错处理,时间持续多长,整个就看用户了。

另外,那个帖子中定义的的超时(i2c_10clk_us*one_us_unit)*100,我记得就是100us,跟当前I2C时钟无关。400Khz还是100Khz,已经包含在i2c_10clk_us这个变量中了,就是10个时钟脉冲占据的时间。(因为正常i2c通信,每字节的收发只需要9个时钟)

还有,我记得帖子里已经没有单纯的while()了,好像都有超时标志在while()的判断条件里了吧。
此帖出自stm32/stm8论坛
 
 
 

回复

75

帖子

0

TA的资源

一粒金砂(初级)

7
 


仿真运行发现I2C读写出现异常时PV_flag_1 = 3,造成I2C_Comm_MasterWrite直接返回,而状态寄存器SR1、SR2全为0
I2C_Comm_MasterWrite故障.jpg
顺便问下,详细看了下说明文档,还是不明白PV互斥操作是什么意思?有什么用处?
此帖出自stm32/stm8论坛
 
 
 

回复

75

帖子

0

TA的资源

一粒金砂(初级)

8
 
                                 PV互斥操作在这里是防止函数的重入。
此帖出自stm32/stm8论坛
 
 
 

回复

76

帖子

0

TA的资源

一粒金砂(初级)

9
 
哇哇哇。。。

PV_flag_1==3表示外设I2C1,正在被它的函数I2C_Comm_MasterWrite/Read()使用,还未结束当前通信,直到本次通信结束,就是stop出现在总线上,给标志PV_flag_1才会被重新回到0。

这个PV_Flag就是相当于O.S中的信用量,用于保证互斥操作。

SR1,SR2全为0,好像是本次通信正常结束了。PV_flag_1似乎在通信结束时没有把它归零?
此帖出自stm32/stm8论坛
 
 
 

回复

99

帖子

0

TA的资源

一粒金砂(初级)

10
 
多谢版主和lut1lut指点。
互斥操作明白了。
PV_flag在中断服务程序void i2c1_evt_isr()中成功发送后归零,这是帖子提供的库中的源码,我并未修改。既然SR1、SR2为0,那么PV_flag怎么没被清零,而是一直等于3呢?
此帖出自stm32/stm8论坛
 
 
 

回复

87

帖子

0

TA的资源

一粒金砂(初级)

11
 


LZ可不可以调试一下,缩小范围:

在这个PV_flag_1==3的I2C_Comm_MasterWrite()之前,调用的哪个函数,使得这个PV标志没有归零,以及那个函数的调用参数。并且这个错误是不是每次运行都这样,都死在这同一个地方。
此帖出自stm32/stm8论坛
 
 
 

回复

65

帖子

0

TA的资源

一粒金砂(初级)

12
 
帖子中改进的查询方式仍有纯while,我现在用查询方式调试,有干扰(电机)时就会造成程序停在这样的while处,于是干脆取消这个处理,判断超时后直接
return DDR_MATCH_ERR;不知这样处理有何不妥?
纯while处.jpg
另外关于超时时间,恕我愚笨,呵呵,在I2C_Comm_Init函数中有如下初始化代码:
/********** SysTick for timeout configuration *****/
  RCC_GetClocksFreq(&rcc_clocks);
  hclk = rcc_clocks.HCLK_Frequency;
  NVIC_SystemHandlerPriorityConfig(SystemHandler_SysTick, 0, 0);
  SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);
  one_us_unit = hclk/1000000;
  i2c_10clk_us = 1000000*10/I2C_Speed;
我系统时钟为72MHz,那么one_us_unit  = 72,时间为1us
我I2C速率设为400KHz,那么i2c_10clk_us = 25
那么#define BUS_BUSY_TIMEOUT (i2c_10clk_us*one_us_unit)*100的值计算出来换算成时间不是2500us(2.5ms)吗?
还请lut1lut指正!谢谢!
此帖出自stm32/stm8论坛
 
 
 

回复

68

帖子

0

TA的资源

一粒金砂(初级)

13
 


另外有个疑问,利用查询超时方式,假如某次I2C通讯出现错误,比如下图中的“总线忙”,此时观测SR1和SR2,分别为0x401和0x3,指示:
AF应答失败;
起始条件已发送;
主模式;
总线忙;

虽然程序不会死机(不影响其他模块运行),但I2C会一直处于“总线忙”故障状态。
如何使I2C从上一次异常中恢复?
查询超时方式某次出错.jpg
此帖出自stm32/stm8论坛
 
 
 

回复

70

帖子

0

TA的资源

一粒金砂(初级)

14
 


哇哇哇。。。
第一:关于延迟,是我看错了,恕我眼拙哈
LZ说的是对的,在你这个应用里就是2.5ms。
反正“i2c_10clk_us*one_us_unit”就是要延迟10个I2C时钟脉冲这么长的时间,需要给以72MHz频率free running的systick的reload值。
"i2c_10clk_us*one_us_unit*100"么就是1000个I2C时钟脉冲的时间啦。
我这里的"*100"都是随便写的,"*120","*200"都可以。因为我没有LZ具体应用中什么16ms间隔之类的要求。如果有具体的应用要求,适当修改这个超时的值。
此帖出自stm32/stm8论坛
 
 
 

回复

71

帖子

0

TA的资源

一粒金砂(初级)

15
 
                                 这类程序俺在行,搜搜俺的I2C思想,何有超时之忧???
此帖出自stm32/stm8论坛
 
 
 

回复

68

帖子

0

TA的资源

一粒金砂(初级)

16
 


第二:那个查询方式中还"残存"的那个while()
I2C_GenerateStop(I2Cx, ENABLE);
while((I2C10>CR1&0x200)==0x200);
第一句,通过软件写bit9@CR1,在总线上发出STOP信号;第二句,等待bit9@CR1被硬件清零。

为什么要加上第二句呢。有客户报告说STOP位在产生了STOP信号后不会被清零。
原因在于:按理说,软件置位了STOP位,一旦STOP信号出现在了总线上,该位应该被硬件自动清零。但是如果这两个事件之间,有一个写CR1的操作,而这个写操作是用读-修改-写的方式。那么读的时候,把还未清零的STOP也读了进来,随后又写了回去。这样STOP位就又被置位了。
总而言之,就是如果软件置位STOP位后有对CR1的写操作,最后要等到STOP位被清零后。

这里,后面是对SR的查询和设置(if(I2C_GetFlagStatus(I2Cx, I2C_FLAG_AF))...),并且直接返回错误代码,不要这个while()应该应该也可以。但是LZ的代码死在这里,说明STOP位确实没有清掉咯?按照LZ那样直接退出,那个STOP位还在,下次通信时会有问题的,除非手动把它清零。

另外多说一句,怎么会走到这里,是因为干扰使得不满足slave地址匹配的条件么。即I2C——CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSIMITTER_MODE_SELECTED)?然后在超时处理后,又由于干扰STOP位都不能清零?

我现在对干扰下的STM32 I2C不正常工作的情况很感兴趣呀,LZ多提供点反馈才好。
此帖出自stm32/stm8论坛
 
 
 

回复

85

帖子

0

TA的资源

一粒金砂(初级)

17
 
hotpower大虾,能不能在这里扼要说下你的I2C思想啊。

这里加上overtime超时,是因为固件库里的无数的while(),如果出现错误,不满足while里严格的条件就死在那里了,因此加上超时,并返回错误原因哪。
此帖出自stm32/stm8论坛
 
 
 

回复

81

帖子

0

TA的资源

一粒金砂(初级)

18
 
一般来说,查询SR发现有BUSY置位,那么I2C总线上的两个信号线CLK和DATA肯定不是都处于高电平的idle状态。那么这个时候,请参看SWRST@CR1。另外,如果正常通信被意外打断,可能某根信号线被外部的slave拉住没有释放,这种情况可以模拟几个CLK时钟,来让外部释放。

你这个通信之前之前查询是否BUSY是对的,但是此时AF和SB和MSL还处于置位,这个状态有点搞也,应该是上次通信错误退出后没有妥当善后吧。
此帖出自stm32/stm8论坛
 
 
 

回复

70

帖子

0

TA的资源

一粒金砂(初级)

19
 
hotpower哪?

打一枪就换地方了索?
此帖出自stm32/stm8论坛
 
 
 

回复

84

帖子

0

TA的资源

一粒金砂(初级)

20
 


致16楼:“我现在对干扰下的STM32 I2C不正常工作的情况很感兴趣呀,LZ多提供点反馈才好。”
呵呵,非常感谢lut1lut的无私帮助!我的系统是这样子的,STM32控制六个电机和2路LED,LED驱动芯片是12C接口的,和电机公用5V电源。经测试发现在各电机运动时造成5V电源不稳(输出能力不足),因此影响到LED驱动芯片。
由于该LED驱动芯片非Memory器件,因此没有lut1lut大侠库中I2C_Comm_MasterWrite函数后面的Check处理,此前的代码基本一致,只是修改了延时方式,不做check处理这样会有影响吗?
lut1lut在18楼提到“应该是上次通信错误退出后没有妥当善后吧”,具体怎样善后呢?不都在I2C_Comm_MasterWrite这个函数中针对各种事件进行处理吗?
此帖出自stm32/stm8论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网 11

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表