解决STM32 I2C接口死锁在BUSY状态的方法讨论

2023-05-16

解决STM32 I2C接口死锁在BUSY状态的方法讨论

 

关于STM32的I2C接口死锁在BUSY状态无法恢复的现象,网上已有很多讨论,看早几年比较老的贴子,有人提到复位MCU也无法恢复、只有断电才行的状况,那可是相当严重的问题。类似复位也无法恢复的情况是存在的,技术支持矢口否认问题存在,并不是正确面对问题的态度。比如我用这款F439芯片的SDRAM控制器,在错误操作后进入HardFault状态,复位无法恢复,JTAG也无法联机,只能断电重来,官方的Erratasheet里也提到了。

如果I2C接口无法可靠工作,那么所做的设计将存在严重隐患,不可能要求用户用断电的方法恢复系统。如果像某些网友提到弃用硬件I2C,转为GPIO模拟I2C时序,那么首先I2C时钟频率不易确定,因为STM32的时钟频率可以动态调节;此外不用硬件I2C,无法用中断、DMA等高级模式,会严重降低ARM内核效率。所以务须确认和解决这个问题。

 

一.问题存在

我用STM32F439IGT,为了确定问题存在,让I2C控制器作Master,先人为产生I2C总线故障。产生I2C总线故障的方法简单而粗暴:在I2C总线工作过程中,用镊子把SCL和SDA两个信号短路一下,很容易进入BUSY死锁状态。长时间短路也可能产生超时。HAL_I2C_Init()、HAL_I2C_Master_Transmit()、HAL_I2C_Master_Receive()等函数返回值分别为HAL_BUSY(0x02)、HAL_TIMEOUT(0x03)。

试着用MCU复位,是可以恢复的,说明硬件没死穴。又测试不用MCU复位,而是在程序中依次调用STM32Cube_FW_F4_V1.5.0固件库提供的如下两个初始化函数:HAL_I2C_DeInit(&hi2c1)、HAL_I2C_Init(&hi2c1),并不能保证一定恢复正常。

BUSY死锁时,用万用表测试I2C信号电压,SCL、SDA均为低电平。如果调用函数:HAL_I2C_DeInit(&hi2c1),会函数释放IO口回到GPIO的默认状态(Input),此时再测SCL、SDA电压,均为高电平。这说明总线是被MCU这边的Master拉低的,而不是被Slave拉低的。当然也存在Slave刚好输出低电平拉低SDA的可能。

 

二.出错代码位置跟踪

单步运行,可以看到进入stm32f4xx_hal_i2c.c程序中I2C读写函数不远处(如图阴影所在行),读BUSY位,总会得到SET的结果,无法继续执行后续程序而返回。

 

三.参考文献

读了网上很多解决方案,其中比较有启发意义的有这几篇:

1. 百度文库,这个好像是ST官方客服提供的,关于死锁的可能机理和解决方案做了说明:
http://wenku.baidu.com/link?url=KB9p-TYrQcmVu1azHG66BXAcG6Pe6Bm2kWF_9ERSU35EOA8obiTVTDrZ6fZ3IOjfVAb71RCvJIiAODo4p4Sr0fUPDy0kQyyqWWJgxjfYHzO

2. STM社区,这个提到了初始化I2C引脚前应该先置为OUT及高电平。这在上电初始化时无虞,因为MCU复位后IO口为输入,并由外部上拉电阻拉为高电平。但在做故障恢复时很重要,因为此时IO口可能正被Master或Slave拉成低电平。 http://www.stmcu.org/module/forum/thread-518463-1-1.html

3. 这个解决方案和上面思想两个相仿,但是写了太多代码,又有放置位置的要求,看起来头大。仅作参考:http://bbs.ednchina.com/BLOG_ARTICLE_2154168.HTM

4. 最重要的说明,在ST官方提供的STM32F4xx用户指南:RM0090 Reference manualRev9,第845页,关于I2C_CR1,SWRST位的Note,提到解决BUSY死锁问题:


意思是说SWRST位可以在出错或死锁时,用于复位I2C控制器,例如众所周知的BUSY位问题。我没有看其它老STM型号的手册,至少STM32F4xx有SWRST位,STM32L0xx用户指南提到可以用PE位复位。

 

四.问题的解决方案

按照ST手册的提示,经过各种尝试,本着尽量少改动代码、尽量不改动固件库里只读文件的原则,我的解决方案如下所述。假设主程序里有如下的代码,返回值ret不等于0表示出错,按stm32f4xx_hal_def.h头文件中的错误代码定义,返回值为0x02是HAL_BUSY,0x03是HAL_TIMEOUT,这两个返回值都可能得到。下面程序里红色的两行是错误处理必须的:

 

4.1 主程序改动,加错误处理代码2行:

unsigned char ret = Sensor_ReadData(uint8* buf);   // I2C读写函数

    if (ret != 0)  {                   //I2C故障处理

      HAL_I2C_DeInit(&hi2c1);        //释放IO口为GPIO,复位句柄状态标志

      HAL_I2C_Init(&hi2c1);          //这句重新初始化I2C控制器

    }

    else  {

      // 。。。。I2C无错误时的正常程序

    }

 

 

4.2 子程序的改动,加7行代码:

上面HAL_I2C_Init(&hi2c1)函数会调用HAL_I2C_MspInit(hi2c)函数,这个函数在stm32f4xx_hal_msp.c文件中实现,主要是初始化IO口以及外设,由STM32CubeMX工具生成或用户自行编写,非只读文件。以下节选该函数第一段,其中I2C端口用哪个pin,是由用户自己设定的,我这里用的PB6、PB7。红、绿底色的几行是为了处理BUSY死锁问题专门插入的。

 

void HAL_I2C_MspInit(I2C_HandleTypeDef *hi2c)

{

  GPIO_InitTypeDef GPIO_InitStruct;

  if(hi2c->Instance==I2C1)

  {

    __I2C1_CLK_ENABLE();

    // PB6    ---->  I2C1_SCL

    // PB7    ---->  I2C1_SDA

    // strong pull-uphigh to recover from locking in BUSY state

    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;      //此行原有

    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;   //GPIO配置为输出

    GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;         //强上拉

HAL_GPIO_Init(GPIOB,&GPIO_InitStruct);

 

    HAL_GPIO_WritePin(GPIOB, 6, GPIO_PIN_SET);       //拉高SCL

    HAL_GPIO_WritePin(GPIOB, 7, GPIO_PIN_SET);       //拉高SDA

 

   hi2c->Instance->CR1= I2C_CR1_SWRST;          //复位I2C控制器

   hi2c->Instance->CR1= 0;              //解除复位(不会自动清除)

// 以下是原有代码

GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;

GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;

    GPIO_InitStruct.Pull = GPIO_PULLUP;

    GPIO_InitStruct.Speed = GPIO_SPEED_FAST;

    GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;

    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  }

//。。。

}

 

上面程序中,把I2C端口配置成GPIO-OUTPUT,并强制拉高,是必需的。注意到手册里关于SWRST位说明的第一句:“When set, the I2C isunder reset state. Before resetting this bit,make sure the I2C lines are released and the bus isfree.” 意思就是置位SWRST,会使I2C控制器保持在复位状态。解除复位前,确保I2C总线已经释放到空闲状态,即SCL、SDA均为高电平,再恢复I2C控制器。所以解除复位是用户来做的,硬件不会自动清除该位。

 

五.结论

我用这款STM32F439IGT单片机,I2C部分没有出现断电才能解除BUSY死锁的严重问题,看来STM已经意识到这个硬BUG,并在后期产品里逐步进行了改进。

在没有硬件死穴的情况下,我这里仅增加10行程序,就可以用软件恢复故障。多次尝试,触发I2C故障时,一次就可以恢复,无需加延时等语句,也未改动现有固件库代码。

 

                                        Circuitlife

                                      2015年6月3日

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

解决STM32 I2C接口死锁在BUSY状态的方法讨论 的相关文章

  • ESP8266 固件擦除

    折腾了两天 真是醉了 首先确认安装 python python2是否安装 python2 version sudo apt isntall python pip 安装pip和他的许多其他依赖 pip 9 0 1 from usr lib p
  • 第二次实验报告:使用Packet Tracer分析应用层协议

    姓名 xff1a 刘钰学号 xff1a 201821121036班级 xff1a 计算1812 1 实验目的 熟练使用Packet Tracer工具 分析抓到的应用层协议数据包 xff0c 深入理解应用层协议 xff0c 包括语法 语义 时
  • C++的类与C语言结构体比较

    C 43 43 的类与C语言结构体比较 C 43 43 的类与C语言结构体比较 一 结构体 xff0c 类的介绍二 结构体和类的具体区别1 C语言对结构体数组初始化 必须要在定义时初始化 xff1a 2 C 43 43 的类的初始化 构造函
  • CPP-网络/通信:经典HTTP协议详解

    2008 11 03 09 11 by Hundre 266688 阅读 23 评论 收藏 编辑 转自 xff1a http blog csdn net gueter archive 2007 03 08 1524447 aspx Auth
  • 串口编程3:使用串口读取GPS信息

    关于GPS的使用 xff0c 参考 本文主要参考的博客 xff0c 在此表示感谢 xff01 xff01 xff01 主函数 主函数gps main c xff0c 这里便涉及到了串口的打开 xff0c 读操作 xff0c 以及调用了串口设
  • 基于单片机语音智能导盲仪仿真设计-毕设课设资料

    资料下载地址 1110 xff08 百度网盘 xff09 xff1a 点击下载 包含超声波传感器检测障碍物 xff0c 温度传感器检测当前温度 可以通过按键设置距离报警范围 xff0c 报警装置通过声光报警 包含的电路有电源电路 显示电路
  • 宏定义详解

    宏定义有无参数宏定义和带参数宏定义两种 无参数的宏定义的一般形式为 define 标识符 字符序列 其中 define之后的标识符称为宏定义名 简称宏名 xff0c 要求宏名与字符序列之间用空格符分隔 这种宏定义要求编译预处理程序将源程序中
  • 一个无线鼠标的HID Report Desc

    HID设备是USB规范定义的设备类型之一 xff0c 其分类号为0x03 关于USB设备类型定义 xff0c 可参见本站 xff1a USB设备类型定义 USB中文网 HID设备除了用于专门的输入输出设备外 xff0c 有时也与其它的设备类
  • 虚拟机的三种网络连接方式

    1 NAT模式 xff1a 用于共享主机的IP地址 安装完VMware后在本地网络连接里会虚拟出两块网卡 xff08 VMnet1 xff0c VMnet8 xff09 如果选择的是NAT模式 xff0c 则会使用VMnet8这块网卡来和虚
  • 全局变量不能放在头文件当中

    看网上各种说法说 变量的声明和变量的定义 xff0c 但是还是没有讲清楚什么是声明什么是定义 xff0c 如果说定义要分配内存 xff0c 声明不分配 xff0c 这个谁都知道 刚我在VS2012中测试 xff1b 按理说 int i xf
  • 使用strcat连接字符串

    include lt iostream gt using namespace std int main int argc char argv char str1 61 34 hello 34 char str2 61 34 china 34
  • 单片机学习笔记————51单片机实现常用的自定义串口通讯协议

    proteus虚拟串口的实现 xff1a https mp csdn net console editor html 107251649 一 使用proteus绘制简单的电路图 xff0c 用于后续仿真 二 编写程序 64 Project
  • Uart串口收发回环验证

    Uart串口收发回环验证 接受模块发送模块波特率设置模块顶层模块TBModelsim仿真结果板级验证总结 本次所做的项目比较复杂 xff08 对我本人来讲 xff09 xff0c 设计一个Uart IP核 xff0c 在其基础 xff0c
  • C++ vector的用法(整理)

    vector 是向量类型 xff0c 它可以容纳许多类型的数据 xff0c 如若干个整数 xff0c 所以称其为容器 vector 是C 43 43 STL的一个重要成员 xff0c 使用它时需要包含头文件 xff1a include lt
  • 示波器的使用

    示波器的使用 在家电维修的过程中使用示波器已十分普遍 通过示波器可以直观地观察被测电路的波形 xff0c 包括形状 幅度 频率 xff08 周期 xff09 相位 xff0c 还可以对两个波形进行比较 xff0c 从而迅速 准确地找到故障原
  • 谈谈嵌入式系统的可靠性和安全性

    这里谈的安全性 xff0c 跟通用计算机所说的网络安全性不是一个概念 xff0c 网络安全性指的是数据不被人为破坏和窃取 xff0c 计算机不被恶意控制 而这里谈的安全性 xff0c 指的是设备安全 xff0c 例如自动化生产线不夹断工人手
  • 裸奔和rtos下开发的差异分析

    嵌入式设备网络化 u盘化 功能复杂化的趋势 xff0c 使越来越多的 过去可以用裸奔实现的嵌入式产品 xff0c 产生了应用操作系统的需求 而人力成本的持续上升 芯片成本的连续下降 xff0c 以及cpu性能的迅速提高 xff0c 又为大面
  • “全员编程,广泛嵌入”(六)—— 物联网时代(四)

    物联网操作系统是个伪命题 xff0c 很多人炒物联网概念 xff0c 炒物联网操作系统 xff0c 其实 xff0c 物联网操作系统 xff0c 与其说是一个技术概念 xff0c 还不如说是一个商业概念 这也无可厚非 xff0c 你不炒 x
  • 高通Qualcomm处理器的手机或设备进EDL 9008模式的办法

    适用于变砖的设备 由于我们有很多基于 Qualcomm 的设备 xff0c 其中一些设备可能会古怪地猜测如何进入 EDL 模式 xff0c 或者如何正确进入 例如 xff0c 对于 Alcatel xff0c 您必须先按住两个音量键 xff
  • 远程桌面能解决物联网和智能硬件的什么问题

    前几篇 xff0c 讲了许多远程桌面的功能和应用 xff0c 但还是有不少网友不明白 xff0c 在QQ上跟我讨论 xff0c 在物联网和智能硬件方面 xff0c 究竟能解决什么问题 智能硬件发展这么多年 xff0c 总是雷声大雨点小 xf

随机推荐

  • 物联网技术上面临的基本问题和操作系统设计

    时下 xff0c 在操作系统界 xff0c 有一个热得发紫的名词 物联网操作系统 xff0c 但物联网和操作系统究竟是什么关系 xff0c 物联网将面临什么问题 xff0c 操作系统又能为其解决什么问题呢 xff1f 操作系统和其他电子产品
  • Duktape:一个新的小巧的超精简可嵌入式JavaScript引擎

    原文链接 xff1a http ourjs com detail duktape E4 B8 80 E4 B8 AA E6 96 B0 E7 9A 84 E5 B0 8F E5 B7 A7 E7 9A 84 E8 B6 85 E7 B2 B
  • 解析物联网三大实时协议

    解析物联网三大实时协议 2015 08 25 国家物联网标识管理公共服务平台 实时通信技术作为一项根本性前提 xff0c 在物联网应用程序的开发工作中扮演着核心角色 想象一下 xff0c 如果我们能够利用手机与家居环境内的各种小装置进行通信
  • stm32低功耗定时器lptimer在djyos下的应用

    djyos的tickless模式配合低功耗模块可以支持传感器之类功耗要求极端苛刻的应用 xff0c djyos的系统时基如果能用stm32的lptimer来提供 xff0c 堪称妙绝 xff0c APP就可以做到完全不用操心功耗 xff0c
  • 一起学djyos-罗侍田-专题视频课程

    一起学djyos 2195人已学习 课程介绍 djyos是国内原创的开源操作系统 xff0c 采用类BSD许可证 经历13年的时间考验 xff0c 可靠性高 xff0c 实时性高 xff0c 功能强大 xff0c 广泛用于电力系统 自动控制
  • C#中十进制与十六进制之间的转换

    一 十进制转换为十六进制 int a 61 654 string A 61 a ToString 34 X6 34 上面Tostring 34 X6 34 是将整型a转化成16进制数 xff1b 其中 xff1a xff08 1 xff09
  • RS485波形记录与分析

    异步串行数据的一般格式是 xff1a 起始位 43 数据位 43 停止位 xff0c 其中起始位1 位 xff0c 数据位可以是5 6 7 8位 xff0c 停止位可以是1 1 5 2位 对于正逻辑的TTL电平 xff0c a 起始位是一个
  • 电脑作为服务器+数据库环境构建以及VS中C#远程连接数据库

    一 将作为服务器的电脑连接网络 xff08 以下简称 服务器 xff09 xff0c 查询服务器的ip地址 方法 xff1a cmd命令ipconfig中IPv4地址就是服务器的ip地址 二 测试服务器和用户电脑 xff08 就是另一台电脑
  • t和printf的缓冲机制

    众所周知 xff0c cout和buffer都是有缓冲的 网上很多把cout和printf混用出错归结为一个有缓冲 xff0c 一个无缓冲 xff0c 事实会在下面说明 cout和printf的输出是先从右往左读入缓冲区 xff0c 再从t
  • 天神降临,大家过来膜拜吧! FLASH AS 3.0 A星(A*, A star) 寻路算法--史上最快,极限优化挑战!

    天神降临 xff0c 大家过来膜拜吧 oh yeah 转载请声明出处 xff0c 例子代码可以免费随意使用 xff0c 但请保留或注明作者信息 这里的算法说是终极优化 我挑战了一下 http eidiot net 2007 04 17 a
  • redis master和slave主备切换,可能导致数据丢失,如何解决?

    1 两种数据丢失的情况 2 解决异步复制和脑裂导致的数据丢失 1 两种数据丢失的情况 主备切换的过程 xff0c 可能会导致数据丢失 xff08 1 xff09 异步复制导致的数据丢失 因为master gt slave的复制是异步的 xf
  • C:基于可以自动扩展缓冲区的stringbuffer,实现内存格式化输出(bufprintf)

    最近做一个C语言的嵌入式项目 xff0c 需要分段向指定内存调用vsnprintf输出不定长度的格式化输出 xff0c 因为是分段输出 xff0c 而且长度不定 xff0c 所以一开始就不能分配固定长度内存 xff0c 每次输出都要从输出到
  • Gitblit服务器搭建及Git使用

    使用Gitblit搭建属于公司或自己的Git服务器 xff0c 方便公司或自己程序代码及文档版本管理 环境 xff1a 1 Win10 64位操作系统 2 Git 2 24 1 2 64 bit xff08 git工具 xff09 3 To
  • C语言中int到float的强制类型转换

    最近在看一本名为的书 由于我所看过的计算机理论方面的书较少 xff0c 加上自己大学期间一直也不用功 xff0c 所以对于计算机的工作原理以及程序的工作方式我始终只知甚少 xff0c 印象也十分模糊 不过 xff0c 应该说我碰到了一本好书
  • 非常实用的一键开关机电路

    按键电路在我们的电路设计中非常常见 xff0c 其中有一种比较特殊 xff0c 就是一键开关机电路 xff0c 顾名思义 xff0c 就是只用一个按键实现开机关机以及其他功能 xff0c 其实大家都接触过 xff0c 我们手机中的开机键就是
  • 一个很精妙的高精度电压基准电路

    先上图 xff0c 图里面的431也可以是别的基准源 xff08 比如LT1004之类的 xff09 甚至可以是一个简单的稳压二极管 需要说明的时 xff0c 此电路并非本人原创 xff0c 也不知道作者是谁 xff0c 偶然看到后 xff
  • AD拼板技巧

    随着整个电子产业的不断发展 xff0c 电子行业的很多产品都已经有完善的上下游配套企业 从一个成熟产品的方案设计 xff0c 外观设计 xff0c 加工制造 xff0c 装配测试 xff0c 包装 xff0c 批发商渠道等等 xff0c 这
  • 单片机RS485通信接口、控制线、原理图及程序实例

    RS232 标准是诞生于 RS485 之前的 xff0c 但是 RS232 有几处不足的地方 xff1a 接口的信号电平值较高 xff0c 达到十几 V xff0c 使用不当容易损坏接口芯片 xff0c 电平标准也与TTL 电平不兼容 传输
  • AD圆形铺铜技巧

    1 在铺铜时按shift 43 空格是可以画圆弧 xff0c 但那只能画一个很小的圆 xff0c 可以用 34 34 34 34 xff08 逗号 xff0c 句号键 xff09 来调整圆的半径 选择铺铜命令 gt 设置参数 gt 进入铺铜
  • 解决STM32 I2C接口死锁在BUSY状态的方法讨论

    解决STM32 I2C接口死锁在BUSY状态的方法讨论 关于STM32的I2C接口死锁在BUSY状态无法恢复的现象 xff0c 网上已有很多讨论 xff0c 看早几年比较老的贴子 xff0c 有人提到复位MCU也无法恢复 只有断电才行的状况