STM32之I2C_FLAG_BUSY置位解决办法

发布者:明石轩最新更新时间:2019-04-08 来源: eefocus关键字:STM32  I2C  FLAG  BUSY置位 手机看文章 扫描二维码
随时随地手机看文章

stm32f429-disco上的触摸屏IC是STMPE811,使用I2C通信,该ic的使用还不算难,里面包括8通道12bit AD,8个GPIO口,加128set FIFO以及几个寄存器。


问题是出在STM32 的I2C IP核上,网上大家也吐槽了不少,最主要的就是各种当机,当当当当,哈哈。


我第一次出现当机的地方是在


if(__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) == SET)

    {

      return HAL_BUSY;

    }


返回的BUSY值是一直置H的,这就奇怪了,用的是官方的STM32CubeMX生成的初始化代码,刚初始完就BUSY,太坑了吧。


查看datasheet,有两点可以参考



这渣渣IP核的BUSY位是判断sda,scl两线的stop位,没检测到就置H;而不是判断I2C的状态及超时,置位BUSY,坑!


解决的办法是有的:



可以通过CR1位的rst位,手动将其清零。


网上不少童鞋也是通过该位清BUSY


hi2c->Instance->CR1 |= 0x8000;

hi2c->Instance->CR1 &= ~0x8000;


要注意的是,此复位操作要放置于,所有I2C寄存器配置之前!!!以上是方法一


方法二:


查看了例程,例程的I2C是这样初始化的


I2Cx_MspInit(&I2cHandle);

HAL_I2C_Init(&I2cHandle);


其中

static void I2Cx_MspInit(I2C_HandleTypeDef *hi2c)

{

  GPIO_InitTypeDef  GPIO_InitStruct;  

 

  if (hi2c->Instance == DISCOVERY_I2Cx)

  {

    /* Configure the GPIOs ---------------------------------------------------*/ 

    /* Enable GPIO clock */

    DISCOVERY_I2Cx_SDA_GPIO_CLK_ENABLE();

    DISCOVERY_I2Cx_SCL_GPIO_CLK_ENABLE();

      

    /* Configure I2C Tx as alternate function  */

    GPIO_InitStruct.Pin       = DISCOVERY_I2Cx_SCL_PIN;

    GPIO_InitStruct.Mode      = GPIO_MODE_AF_OD;

    GPIO_InitStruct.Pull      = GPIO_NOPULL;

    GPIO_InitStruct.Speed     = GPIO_SPEED_FAST;

    GPIO_InitStruct.Alternate = DISCOVERY_I2Cx_SCL_SDA_AF;

    HAL_GPIO_Init(DISCOVERY_I2Cx_SCL_GPIO_PORT, &GPIO_InitStruct);

      

    /* Configure I2C Rx as alternate function  */

    GPIO_InitStruct.Pin = DISCOVERY_I2Cx_SDA_PIN;

    HAL_GPIO_Init(DISCOVERY_I2Cx_SDA_GPIO_PORT, &GPIO_InitStruct);

    

    

    /* Configure the Discovery I2Cx peripheral -------------------------------*/ 

    /* Enable I2C3 clock */

    DISCOVERY_I2Cx_CLOCK_ENABLE();

    

    /* Force the I2C Periheral Clock Reset */  

    DISCOVERY_I2Cx_FORCE_RESET();//########## look here #############

      

    /* Release the I2C Periheral Clock Reset */  

    DISCOVERY_I2Cx_RELEASE_RESET(); //########## look here #############

   }

}

STM自己也受不鸟这I2C,手动复位了,那么解决办法就变得很明显了,在我们自己的i2c初始化函数中加入:

void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)

{

    GPIO_InitTypeDef GPIO_InitStruct;

    if(hi2c->Instance==I2C3)

    {

        __I2C3_CLK_ENABLE();

        

        /**I2C3 GPIO Configuration    

        PC9     ------> I2C3_SDA

        PA8     ------> I2C3_SCL 

        */

        GPIO_InitStruct.Pin = GPIO_PIN_9;

        GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;

        GPIO_InitStruct.Pull = GPIO_NOPULL;

        GPIO_InitStruct.Speed = GPIO_SPEED_FAST;

        GPIO_InitStruct.Alternate = GPIO_AF4_I2C3;

        HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

        

        GPIO_InitStruct.Pin = GPIO_PIN_8;

        GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;

        GPIO_InitStruct.Pull = GPIO_NOPULL;

        GPIO_InitStruct.Speed = GPIO_SPEED_FAST;

        GPIO_InitStruct.Alternate = GPIO_AF4_I2C3;

        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

        

        __I2C3_FORCE_RESET();//######## look here #########

        __I2C3_RELEASE_RESET();//######## look here #########

        

        

        HAL_NVIC_SetPriority(I2C3_EV_IRQn, 13, 0);

        HAL_NVIC_EnableIRQ(I2C3_EV_IRQn);

        HAL_NVIC_SetPriority(I2C3_ER_IRQn, 13, 0);

        HAL_NVIC_EnableIRQ(I2C3_ER_IRQn);

    }

}

说实话,i2c3_force_reset()是STM32的RCC(时钟与复位)模块的功能函数,并不是I2C模块的函数,即不是操作I2C的CR1位,而是通过总复位模块对I2C来了一次复位操作




总结一下i2c的初始化方式:


1.配置GPIO口 HAL_I2C_MspInit();


2.复位一下(CR1位复位)或(RCC对i2c模块复位)


3.配置i2c寄存器 MX_I2C3_Init();






至此,初始化后的I2C就不会将BUSY位置位了。

后期,假如I2C通信出错,该IP核有可能也会将BUSY置位,且不自动复位,此步骤也可作为除错的参考。


关键字:STM32  I2C  FLAG  BUSY置位 引用地址:STM32之I2C_FLAG_BUSY置位解决办法

上一篇:STM32 I2C 死锁问题
下一篇:STM32 IIC 详解 之 stm32 IIC 从机模式(中断方式收发数据)

推荐阅读最新更新时间:2024-03-16 16:26

STM32入门系列-STM32外设地址映射
片上外设区分为四条总线,根据外设速度的不同,不同总线挂载着不同的外设,APB1挂载低速外设,APB2和AHB挂载高速外设。相应总线的最低地址我们称为该总线的基地址,总线基地址也是挂载在该总线上的首个外设的地址。APB1总线的地址最低,因此片上外设就从这这个地址开始,也称外设基地址。 总线基地址 从存储器映射那张图的Block2可以看到,分为4大块,每块都有一个起始地址,这个起始地址就是基地址,然后到下一块起始地址的时候就会和前一块地址出现偏差,这个差值就是偏移量,即相对基地址的偏移量。如下图所示。 从上图可以看到APB1总线基地址是0x4000 0000,相对外设基地址的偏移量是0,所以此总线也是外设Block2的基
[单片机]
<font color='red'>STM32</font>入门系列-<font color='red'>STM32</font>外设地址映射
关于STM32中RTC的校准方法
实现RTC 校准的核心之一是库文件Stm321f0x_bkp.c中的void BKP_SetRTCCalibrationValue (uint8_t CalibrationValue) 函数。谈到RTC校准的相关参考文档包括AN2604.pdf,AN2821.pdf和AN2821.zip。这三个文档都可以从STM32官方网站下载。 按照AN2604.pdf描述的原理,RTC 的校准值应在0-127之间。可实现的校准误差对应为0-121ppm。相当于每30天跑快的秒数为0-314s。 这里应注意的一个关键问题是,RTC只能对跑快进行校准,不能对跑慢进行校准。如果手表晶振的标称频率是32768Hz,设其可能的误差范围是±2Hz
[单片机]
stm32 奇怪的赋值问题 出错了
1、在51单片机里 ,下面这两种操作方法都是一样的,没有什么问题! (1) 、OUT1_R1 是单片机的一个IO口 , dat是传进来的一个数据 if ( (dat & 0x80) == 0) OUT1_R1 = 0; // 0是不亮,1是亮 else OUT1_R1 = 1; (2)、 OUT1_R1 = (dat&0x8000); // stm32里,这样操作不行,因为stm32里没有bit ; 在51里会自动把(dat&0x8000)强制转化为bit 。 2、但是在编译 stm32的keil 里编译上面的两个程序,就发生了不同。 在STM32里, (1) 是可以正常的往IO里输入数据的,但是(
[单片机]
STM32 UART4,UART5配置方式
昨天偶然用到STM32 UART4,UART5两个串口,我开始觉得配置很简单,就简单的配置了,但是怎么都调试部通,我试了1,2串口都没有问题,但是就是4,5不行,我查了一些资料,我相信自己的配置没有错,就是一直调试不通,只能用示波器看了,一看才知道是硬件引脚连错了,电路图上画的就是错的,芯片引脚写的都是错的,我无语了,以后仔细看芯片手册................ 配置如下: /* * 函数名:UART4_Config * 描述 :UART4 GPIO 配置,工作模式配置。115200 8-N-1 * 输入 :无 * 输出 : 无 * 调用 :外部调用 */ void UART4_Config(void)
[单片机]
STM32—— DMA介绍
1.1 DMA结构框图 DMA 控制器独立于内核,属于一个单独的外设,结构比较简单,从编程的角度来看,我们只需掌握结构框图中的三部分内容即可。 如图:(大家也可以查看《STM32F10x中文参考手册》-10 DMA控制器(DMA)章节 内容) (1)标号1:DMA请求 如果外设要想通过 DMA 来传输数据,必须先给 DMA 控制器发送 DMA请求, DMA收到请求信号之后,控制器会给外设一个应答信号,当外设应答后且 DMA 控制器收到应答信号之后,就会启动 DMA 的传输,直到传输完毕。 根据前面介绍我们知道,DMA含有DMA1和DMA2两个控制器,其中DMA1含有7个通道,DMA2含有5个通道,不同的 DMA 控制器
[单片机]
<font color='red'>STM32</font>—— DMA介绍
stm32——串口1和串口2初始化
void USART1_Initialise(u32 bound) { //GPIO端口设置 GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE); //USART1_TX PA.9 GPIO_InitStructur
[单片机]
stm32专题三十七:自动分配变量到指定 SRAM 空间
当有多个内存块时,MDK 优先使用空间更大的内存。 使用 sct 文件来进行内存管理: 编程要点: 1 取消勾选Use Memory Layout from Target Dialog,然后直接点击 edit 来编辑工程的 sct 文件: sct 文件的默认配置如下所示: 看一下此时的 map 文件。可以看到,HEAP 和 STACK 都位于IRAM1 区域。 接下来,我们将64 KB的内存空间分成两块,如下所示(直接复制,然后修改): 我们将 64 KB 的内部SRAM,人为的分成了 20 + 28 KB,按照 MDK 优先使用大容量的空间进行存储,我们预计结果会是保存在ERAM1中,map文件证实
[单片机]
<font color='red'>stm32</font>专题三十七:自动分配变量到指定 SRAM 空间
STM32速成笔记(3)—按键检测
一、按键 检测 原理 按键检测原理比较简单,按键按下和不按下,其连接引脚的电平是不一样的,按键检测正是通过检测按键引脚的电平变化来实现的。比如按键未按下时引脚电平为高电平,按键按下后为低电平。我们在检测按键时只需要检测按键引脚是否变为低电平来确定按键是否按下。 二、 硬件 连接 按键的硬件连接决定了我们在配置按键IO时IO的状态。以我们使用的普中核心板为例,上面有三个按键 普中核心板按键硬件电路图 其中K1一端接VCC,另一端接单片机。K2和K3一端接地,另一端接单片机。硬件电路不同,导致他们在进行按键检测时IO的配置不同。 针对K1这种按键电路,按键按下时, 单片机 的引脚接到VCC,因此在未按下的情况下该引脚的默认电平
[单片机]
<font color='red'>STM32</font>速成笔记(3)—按键检测
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved