STM32之I2C_FLAG_BUSY置位解决办法
来源:互联网 发布:淘宝招募分销商 编辑:程序博客网 时间:2024/06/01 08:19
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();<span style="white-space:pre"></span>//########## look here ############# /* Release the I2C Periheral Clock Reset */ DISCOVERY_I2Cx_RELEASE_RESET(); <span style="white-space:pre"></span>//########## 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();<span style="white-space:pre"></span>//######## look here ######### __I2C3_RELEASE_RESET();<span style="white-space:pre"></span>//######## 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通信出错,该IP核有可能也会将BUSY置位,且不自动复位,此步骤也可作为除错的参考。
0 0
- STM32之I2C_FLAG_BUSY置位解决办法
- STM32之位绑定
- STM32之位绑定
- STM32之位绑定
- stm32之位带操作
- STM32之SPI_CR1寄存器的SSM, SSI位理解
- stm32 复位标志位
- STM32 位段
- STM32位带应用
- STM32 位带应用
- STM32 位带应用
- STM32位带
- stm32 位带操作
- stm32的位操作
- STM32位带操作
- STM32位操作
- STM32位带操作
- stm32 位操作
- 第十一周项目一:函数版型号图(1)
- iOS坐标操作
- 第11周 项目1 函数版星号图(1)(4)
- Go语言知识积累——特点简介与windows开发环境搭建
- windows下配置git
- STM32之I2C_FLAG_BUSY置位解决办法
- 资源链接正则表达式30分钟入门教程
- Android中shape的使用
- iOS7 最佳实践:一个天气应用案例(上)
- Apache Maven 入门篇(下)
- hdu1839Delay Constrained Maximum Capacity Path(二分 + spfa)
- 第十一周项目函数版星号图1
- 每个程序员都应读的书
- 使用FindFirstFile,FindNextFile遍历一个文件夹