打印
[STM32F1]

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

[复制链接]
302|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
dspmana|  楼主 | 2024-5-24 22:19 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
按照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控制器。所以解除复位是用户来做的,硬件不会自动清除该位。

使用特权

评论回复
沙发
OKAKAKO| | 2024-5-25 21:19 | 只看该作者
把I2C端口配置成GPIO-OUTPUT,并强制拉高,是必需的

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

35

主题

2417

帖子

2

粉丝