这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 综合技术 » 基础知识 » OLED显示屏的I2C锁死,大家有碰到过?如何解决?

共8条 1/1 1 跳转至

OLED显示屏的I2C锁死,大家有碰到过?如何解决?

工程师
2021-08-09 21:43:25     打赏

 近日在做项目的时候,遇到了一个问题让我百思不得其解。为了尽可能复现问题,我说的尽量详细一些,并附上一些尝试。


        IIC协议是一种很常用的通信协议,一般分为硬件IIC和软件IIC两种实现方式。在实际使用过程中可能会出现IIC锁死[1]的问题。其具体表现为:SCL始终为高,SDA始终为低。但这种现象往往出现在硬件IIC,软件IIC并不会出现。但我在使用过程中却意外发现了,软件IIC也会出现IIC死锁的现象。

我使用的板子是STM32F103RCT6。资源配置如下:

         NVIC分组为2bits抢占2bits响应
        串口:①USART1用于红外,串口波特率为9600,使用DMA接受数据。②USART2用于语音芯片,波特率9600,使用DMA发送数据。③USART3用于陀螺仪模块,波特率为57600,陀螺仪的采样率为50Hz,采用中断处理数据,抢占2,响应0。④UART4、UART5用于两个激光测距模块,波特率为115200,采样率100Hz,采用中断处理数据,抢占2响应2.
       定时器:①TIM4,CH1-CH4均用于PWM输出驱动电机。②TIM2、TIM3采用了编码器模式,用于采集电机编码器的值 ③TIM6为抢占0响应1的10ms中断,用于处理当前电机的编码器的值通过PID运算得出PWM输出值作用于TIM4   ④TIM7为抢占1响应0的中断,用于刷新处理陀螺仪的数据。
       主函数:①硬件初始化,初始化OLED以及上述定时器串口。OLED采用软件IIC,运用延时函数delay_us处理IIC时序。 ②死循环里是:

  1. LED1 = ~LED1;

  2.                

  3.                 OLED_ShowNum(0,18,flag_water_cd,8,12);

  4.                 OLED_FloatShow(0,36,speed_L,12);        

  5.                 OLED_FloatShow(0,52,speed_R,12);

  6.                 OLED_Refresh_Gram();

复制代码

       即跑马灯和OLED数据更新。由于OLED刷新需要一定时间,虽然没有delay但可以看到灯是在闪的。

       问题描述:当系统运行一段时间后,会出现OLED数据不更新,灯不再闪烁,SCL为高,SDA为低的现象。可以判定为是IIC死锁的问题。但经过查阅资料,IIC死锁只会在硬件IIC出现,软件IIC不出现。

        一些尝试:
        ①注释掉UART4, UART5初始化后运行五分钟,测试三次均未出现死锁问题。 ②注释掉定时器6的初始化,运行五分钟,三次测试均不出现死锁。  ③不注释任何代码,系统运行7s后IIC死锁,灯不再闪烁,OLED不更新。 ④注释掉UART4,UART5后,修改与陀螺仪的波特率为115200,运行数十秒后死锁。⑤注释掉陀螺仪的初始化代码,运行约3min后出现死锁问题。

        猜测:高波特率的中断会打断IIC时序使主机不能收到IIC的Ack信号。

        想过的解决方案:
        ①采用输入捕获和定时器对SCL进行检测,当长时间为高电平时再给SCL一个脉冲。实测可以解决但在此系统不能实装。因为TIM6要进行PID运算,如果有比他优先级更高的中断会导致PID更新不稳定,电机转动不顺畅。②目前临时办法是不使用OLED,或者不使用激光测距模块。不知道论坛的大神有没有遇到过类似的问题,希望能有所指点。






关键词: 显示屏     OLED     I2C     IIC    

工程师
2021-08-09 22:05:13     打赏
2楼

外界干扰或者电源波动或者是其它中断冲突什么之类的,都会影响IIC的应答
但问题并不是像描述那样复杂,看半天都不知道在说什么
while((SDA==1)&&(k<1000))
                {
                k++;
                Delay();
                }
检测1000次,不应答就退出,觉得不够就1万次
可以重新写入
也可以设定一个IIC写入完成标志位,通过检测标志位来处理


工程师
2021-08-09 22:11:46     打赏
3楼

IIC从设备锁住后,你判断总线异常或者ACK异常后,复位一下IIC总线:不管之前处于什么状态,先给一个STOP信号,然后将SDA和SCL都拉低,延时10ms(这个时间根据芯片调整)以上,然后在正常初始化。


工程师
2021-08-09 22:16:30     打赏
4楼

换行的时候老是按成了发送了。
上面是我们之前的处理方式,大部分都有用。但是你最好还是模拟一下,在IIC锁住时,强行这样测试一下,看看是否有效。
如果不行,测试一下你链接里的那个方案,发一整BYTE数据看看。
不过,这个是锁住后的处理,还是要测试一下,IIC最大延时能到多少,修改一下中断,保证时间小于这个延时,才是解决根本。


工程师
2021-08-09 22:23:52     打赏
5楼

拉低SDA,然后SCL输出数百个方波,估计可解这类问题。实在不行,就断电控制、重启!


工程师
2021-08-12 23:48:24     打赏
6楼

解决起来还是非常复杂的


工程师
2021-08-15 23:44:02     打赏
7楼

楼上说的满正确的


工程师
2021-08-17 23:58:48     打赏
8楼

解决方法还是蛮多的


共8条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]