STM32 I2C总线锁死原因及解决方法

本文介绍STM32 I2C总线锁死原因及解决方法。

在使用STM32 I2C总线操作外设时,有时会遇到I2C总线锁死(I2C总线为Busy状态)的问题,即便复位MCU也无法解决,本文介绍其锁死的原因和解决方法,并给出相应的参考代码。

1.故障现象

在I2C总线锁死时,使用示波器测量发现,SCL为高电平,SDA为低电平。

1)MCU操作I2C总线(读/写)时复位MCU(通过复位按键操作)比较容易再现。

2)MCU操作I2C总线(读/写)时,强制将SDA拉低(用金属摄子夹到地,并持续一段时间)会再现。

3)设想,MCU操作I2C总线过程中,SDA受外界干扰(毛刺)被拉低,也可能导致I2C总线锁死。

2.原因

1)I2C总线被设计成多主机可共享总线,这会导致总线竞争,主设备判断当前总线被占用是根据SDA线为低来判断的。当主设备检测到总线被占用,则指示总线忙,并无法操作总线。

2)主设备操作从设备(读/写)时,复位主设备,如果恰好从设备处于ACK状态(SDA拉低)或回复主设备数据位0,那么在复位完成,主设备重新接管总线时,会错误的认为总线忙,因为此时从设备并未复位,SDA仍然被拉低。从设备等待主设备拉低SCL取走ACK或者数据位0,而主设备等待从设备释放SDA。主设备和从设备互相等待,进入死锁状态。值的注意的时,对于故障现象2),STM32 I2C内部似乎有超时机制,如果SDA被拉低持续一段时间,则无法恢复。

3.解决方法

1)硬件复位

直接硬件复位外部从设备,比如通过MOS管软开关从设备电源,或通过外部设备硬件复位脚(从设备有才行)复位。

2)软件复位

情况1:

出现I2C总线锁死时正好外设回复数据位0,则需经历小于9个SCL时钟,从设备会释放SDA。

情况2:

出现I2C总线锁死时正好外设ACK,则经历9个SCL时钟,从设备会释放SDA。

综合情况1,2可知,通过软件复位解决时,当检测到总线锁死(BUSY状态),可以生成9个SCL时钟,并不断检测SDA引脚电平状态,若SDA被释放(为高)则退出,主机重新初始化I2C总线。Software Rest如下图。

3)某些I2C缓冲器提供I2C总线错误恢复功能。

4.参考代码

参考代码如下(这里以STM32F4xx平台为例,其它平台类似):

DrvI2C1.h:

#ifndef __DRV_I2C1_H
#define __DRV_I2C1_H


#ifdef __cplusplus
 extern "C" {
#endif 
     

#include "datatype.h"
#include "stm32f4xx_hal.h"


#define I2C1_SCL_GPIO_PORT     (GPIOB)
#define I2C1_SCL_PIN           (GPIO_PIN_6)

#define I2C1_SDA_GPIO_PORT     (GPIOB)
#define I2C1_SDA_PIN           (GPIO_PIN_7)


extern I2C_HandleTypeDef hi2c1;


extern int32_t I2C1_Init(void);
     
     
#ifdef __cplusplus
}
#endif




#endif

DrvI2C1.c:

#include "DrvI2C1.h"


I2C_HandleTypeDef hi2c1;


static void I2C1_MspInit(I2C_HandleTypeDef* i2cHandle);
static void I2C1_MspDeInit(I2C_HandleTypeDef* i2cHandle);
static BOOL I2C1_Unlock(void);
static void I2C1_SetPortODOutput(void);


int32_t I2C1_Init(void)
{
    if (!I2C1_Unlock())
    {
        DbgPrint("I2C1 unlock failed!\r\n");
    }

    if (HAL_I2C_RegisterCallback(&hi2c1, HAL_I2C_MSPINIT_CB_ID, I2C1_MspInit) != HAL_OK)
    {
        Error_Handler();
    }

    hi2c1.Instance = I2C1;
    hi2c1.Init.ClockSpeed = 200000;
    hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
    hi2c1.Init.OwnAddress1 = 0;
    hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
    hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
    hi2c1.Init.OwnAddress2 = 0;
    hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
    if (HAL_I2C_Init(&hi2c1) != HAL_OK)
    {
        Error_Handler();
    }

    if (HAL_I2C_RegisterCallback(&hi2c1, HAL_I2C_MSPDEINIT_CB_ID, I2C1_MspDeInit) != HAL_OK)
    {
        Error_Handler();
    }

    return 0;
}


static void I2C1_MspInit(I2C_HandleTypeDef* i2cHandle)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    __HAL_RCC_GPIOB_CLK_ENABLE();

    /**I2C1 GPIO Configuration
    PB6     ------> I2C1_SCL
    PB7     ------> I2C1_SDA
    */
    GPIO_InitStruct.Pin = I2C1_SCL_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
    HAL_GPIO_Init(I2C1_SCL_GPIO_PORT, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = I2C1_SDA_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
    HAL_GPIO_Init(I2C1_SDA_GPIO_PORT, &GPIO_InitStruct);

    /* I2C1 clock enable */
    __HAL_RCC_I2C1_CLK_ENABLE();
}


static void I2C1_MspDeInit(I2C_HandleTypeDef* i2cHandle)
{
    /* Peripheral clock disable */
    __HAL_RCC_I2C1_CLK_DISABLE();

    /**I2C1 GPIO Configuration
    PB6     ------> I2C1_SCL
    PB7     ------> I2C1_SDA
    */
    HAL_GPIO_DeInit(I2C1_SCL_GPIO_PORT, I2C1_SCL_PIN);

    HAL_GPIO_DeInit(I2C1_SDA_GPIO_PORT, I2C1_SDA_PIN);
}


static BOOL I2C1_Unlock(void)
{
    uint8_t i = 0;

    I2C1_SetPortODOutput();

    HAL_GPIO_WritePin(I2C1_SCL_GPIO_PORT, I2C1_SCL_PIN, GPIO_PIN_SET);  //Release bus
    HAL_GPIO_WritePin(I2C1_SDA_GPIO_PORT, I2C1_SDA_PIN, GPIO_PIN_SET);

    if (HAL_GPIO_ReadPin(I2C1_SDA_GPIO_PORT, I2C1_SDA_PIN) == GPIO_PIN_RESET)
    {
        for (i = 0; i < 9; i++)
        {
            HAL_GPIO_WritePin(I2C1_SCL_GPIO_PORT, I2C1_SCL_PIN, GPIO_PIN_RESET);
            DelayUS(5);  //
            HAL_GPIO_WritePin(I2C1_SCL_GPIO_PORT, I2C1_SCL_PIN, GPIO_PIN_SET);
            DelayUS(5);  //
            if (HAL_GPIO_ReadPin(I2C1_SDA_GPIO_PORT, I2C1_SDA_PIN) == GPIO_PIN_SET)
            {
                break;
            }
        }

        if (i >= 9)
        {
            return FALSE;
        }
    }

    return TRUE;
}


static void I2C1_SetPortODOutput(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    __HAL_RCC_GPIOB_CLK_ENABLE();

    GPIO_InitStruct.Pin = I2C1_SCL_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
    HAL_GPIO_Init(I2C1_SCL_GPIO_PORT, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = I2C1_SDA_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
    HAL_GPIO_Init(I2C1_SDA_GPIO_PORT, &GPIO_InitStruct);
}

注意:

1)上电即对I2C总线作检测,并执行解锁操作,见初始化的开头部分。

2)“HAL_I2C_Init()”函数内部包含对I2C总线的复位操作,因此,“I2C1_Unlock()”函数里未对I2C总线作复位操作。若HAL库里未对I2C总线作复位操作,则需添加如下代码:

static void I2C1_Reset(void)
{
    /*Reset I2C*/
    I2C1->CR1 |= I2C_CR1_SWRST;
    I2C1->CR1 &= ~I2C_CR1_SWRST;
}

3)在操作I2C外设出错时,若需要添加解锁操作,可按如下进行:

if (HAL_I2C_Master_Transmit(&hi2c1, SlaveAddr, &Value, 1, 1000) != HAL_OK)
{
    HAL_I2C_DeInit(&hi2c1);
    I2C1_Init();
}

先取消初始化I2C,再对I2C进行初始化(包含解锁操作)。

总结,本文介绍了STM32 I2C总线锁死原因及解决方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/729530.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

融资融券有哪些优势和风险,融资融券利息怎么算,利率最低是?4.0

融资融券的优势 1. 提高资金利用率&#xff1a;获得额外的资金或股票交易&#xff0c;提高资金利用率&#xff0c;扩大投资规模。 2. 降低投资风险&#xff1a;通过融资融券买入多只股票分散风险&#xff0c;降低单一股票持仓风险。 3. 增加投资收益&#xff1a;提供更多的交…

CVPR2024|UniPAD:一种自动驾驶的统一的预训练范式

本文章仅用于学术分享 论文标题丨 UniPAD: A Universal Pre-training Paradigm for Autonomous Driving 论文地址丨 https://arxiv.org/abs/2310.08370 代码地址 | https://github.com/Nightmare-n/UniPAD 关注「AI前沿速递」公众号&#xff0c;获取更多前沿资讯 01总览 这…

Android下QVideoFrame转QImage不成功记录

1.由于QVideoFrame::image() const : unsupported pixel format Format_ABGR32 &#xff0c;在转换时需要做个特殊处理如下,增加了android手机下的特殊格式处理: if(frame.pixelFormat() QVideoFrame::Format_ABGR32) 此部分代码 QImage imageFromVideoFrame(QVideoFrame &…

uniapp 打包 H5 实现在 uniapp 打包 APP 的 webview 通信

一、前言 遇到 uniapp 打包的 APP 在 webview 内嵌入 uniapp 打包的 H5 页面的需求&#xff0c;并实现通信。本篇主要总结了如何实现并总结遇到的问题&#xff0c;希望可以帮助大家减少负担。 实现需求主要有三个地方需要处理&#xff1a; index.html 的打包配置导入 uni.we…

STM32 CAN总线通讯

使用STM32的CAN通讯&#xff0c;利用回环模式&#xff0c;按键控制发送CAN数据&#xff0c;中断接收CAN数据并通过串口助手打印出来。 7.2、配置引脚信息 由于每次新建工程都需要配置信息&#xff0c;比较麻烦&#xff0c;好在STM32CubeIDE提供了导入.ioc文件的功能&#xff…

eclipse中svn从分支合并到主干及冲突解决

1、将分支先commit&#xff0c;然后再update&#xff0c;然后再clean一下&#xff0c;将项目多余的target都清理掉。 2、将branches切换到trunk 3、工程上右键-》Team-》合并&#xff08;或Merge&#xff09; 4、默认选项&#xff0c;点击Next 5、有未提交的改动&#xff0c;…

Python轻松设置Excel单元格数字显示格式

Excel作为强大的数据处理与分析工具&#xff0c;不仅能够存储大量数据&#xff0c;还支持复杂的数据处理与可视化功能。而如何恰当地展示Excel表格中的数据是Excel文件制作的关键之一。这便涉及到Excel单元格数字格式的设置。数字格式不仅关乎数据的美学呈现&#xff0c;如货币…

钒能新材料综合回收利用,钒溶液净化富集工艺之离子交换法

钒电池储能产业作为典型的绿色低碳优势产业&#xff0c;是新型储能领域重要发展方向。钒电池储能具备大规模、长周期等优势&#xff0c;是储能领域的重要组成部分&#xff0c;将成为拓展电能利用、应对可再生能源随机波动、支撑可再生能源高占比电力系统的最佳技术途径之一。 …

【R语言】地理探测器模拟及分析(Geographical detector)

地理探测器模拟及分析 1. 写在前面2. R语言实现2.1 数据导入2.2 确定数据离散化的最优方法与最优分类2.3 分异及因子探测器&#xff08;factor detector&#xff09;2.4 生态探测器&#xff08;ecological detector&#xff09;2.5 交互因子探测器&#xff08;interaction dete…

处理机调度算法即cpu scheduling

i Arrival Time 到达时间Burst Time服务时间 response time开始时间-到达时间 FCFS 按照进程顺序 finsh 按照进程顺序 从0开始依次加上服务时间 周转时间即 finsh时间-到达时间&#xff08;注意不是开始时间&#xff09; waiting time等待时间开始时间-到达时间 带权周转时…

VsCode-PlatformIO 开发环境搭建

在VScode中搜索PlatformIO&#xff0c;然后点击install 安装即可 安装后重新打开vscode&#xff0c;会出现如下界面。

Photoshop揭秘:图像处理领域的领军软件

Photoshop 是一款由 Adobe 企业开发的图像处理软件&#xff0c;也被大家简称为 PS。在广告设计、摄影后期、数字绘画、网页设计等各个领域都得到了广泛的应用&#xff0c;是目前业界最受欢迎的图像处理软件之一。作为一款图像处理软件&#xff0c;Photoshop 为设计者提供了许多…

接到一家公司做团购活动类型的策划海报项目,使用AI给他们设计了相关的海报

在这个充满挑战和机遇的时代&#xff0c;我有幸接到一家公司的委托&#xff0c;为他们策划一场团购活动。这不仅是对我的专业能力的认可&#xff0c;也是对我创新思维的考验。 这家公司是一家知名的电子产品销售商&#xff0c;他们希望通过团购活动来提升产品的销售量和品牌的…

基于国产飞腾2000制作的paddleocr hubserving服务docker镜像文件

目录导航 paddleocr hubserving国产化飞腾、鲲鹏armv8 api服务镜像制作 一、编译paddle 二、准备Dockerfile文件 三、制作paddleocr hubserving服务镜像 四、paddleocr hubserving镜像导出和导入 paddleocr hubserving国产化飞腾、鲲鹏armv8 api服务镜像制作 一、编译padd…

爆火的AI姓名头像号篇篇10w+, 流量主赚麻了...

最近二师兄在刷公众号时&#xff0c;看到一个非常有趣的账号。简单又“暴li”。 几乎篇篇10w。点击去一看&#xff0c;内容也是非常极简&#xff0c;利用姓氏生成头像。一个字都不多。 几乎每篇文末都有广告&#xff0c;一篇10w按照800来算&#xff0c; 一个月大概 ~~一七得七、…

重生奇迹MU整理装备注意事项

想成为奇迹MU的顶尖玩家&#xff0c;整理装备是必不可少的一项技能。在这篇文章中&#xff0c;我们将为您分享一些整理装备的注意事项与技巧&#xff0c;帮助您在游戏中更好地管理装备&#xff0c;提升你的实力。 整理装备&#xff0c;须知几点 整理装备是每位玩家必须完成的…

异步编程中的性能优化技巧

异步编程中的性能优化技巧 在上一篇文章中&#xff0c;我们详细介绍了Python中的异步编程及其基础知识和实战应用。今天&#xff0c;我们将深入探讨异步编程中的性能优化技巧&#xff0c;帮助你进一步提升异步代码的效率。 异步编程中的性能优化技巧结语 异步编程中的常见性能问…

电子设计新宠SmartEDA:揭秘其爆红背后的神秘力量

SmartEDA账号免费领取https://www.ismarteda.com 在当下这个电子科技迅猛发展的时代&#xff0c;电子设计领域的创新层出不穷。其中&#xff0c;SmartEDA作为一颗璀璨的新星&#xff0c;凭借其卓越的性能和便捷的操作体验&#xff0c;迅速在电子设计领域崭露头角&#xff0c;成…

【MAUI】resource xml/file_paths (aka com.xxx.xxx:xml/ file _paths) not found.

APP2260:resource xml/file_paths (aka com.zettlercn.wms:xml/ file _paths) not found. This error is likely caused by an issue with the AndroidManifest.xml file or an Android manifest generation attribute in a source code file MAUI从6.0升级到8.0,调试发现资源…

kylinos 国产操作系统离线安装firefox 麒麟操作系统安装新版本firefox

1. 火狐地址&#xff1a; 下载 Firefox 浏览器&#xff0c;这里有简体中文及其他 90 多种语言版本供您选择 2. 选择&#xff1a; 3. 下载完之后&#xff0c;上传到离线机器 4. 解压缩&#xff1a; tar -xvjf firefox-127.0.1.tar.bz2 5. 去点击解压后的文件夹&#xff0c;找…