stm32硬件i2c缺陷解决方法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了stm32硬件i2c缺陷解决方法相关的知识,希望对你有一定的参考价值。

参考技术A stm32硬件i2c缺陷解决方法? 登录

goldage_
关注
STM32’s I2C 硬件BUG引发的血案 转载
2016-12-06 14:18:37
 1点赞

goldage_ 

码龄4年

关注
2010-4-8 1: 45 下面的函数中有一个BUG, 也就是SR2不能用WHILE来轮询,而应直接读出.如下面代码段, 因此,在这里说的这是STM32的BUG其实是我的代码的错误:
I2C2->DR = inerAddress[1];
while( (I2C2->SR1&Q_I2C_SR1_BIT_BTF)==0 );
I2C2->SR2; // 正解

2010-4-1 1:44,一直都不相信STM32 的I2C接口会存在问题,因为工作经验无数次告诉我,嵌入式系统设计中的99.999%的问题不会是由于MCU本身的设计问题所引起,绝大部分都是硬件工程师或软件工程师的某个设计缺陷所造成的. 这次的设计经历也不例外.

由于终于可以抽多点时间用于设计STM32的I2C的软件接口, 因此, 决定重构之前用于主从STM32通讯所用的I2C模块(基于I2C中断+状态机收发)。I2C的中断发送模块很快就重构完毕并且强化了错误处理和I2C总线hang的自恢复功能代码模块(I2C BUS Hang:也就是SDA 和SCL都被某Slave DEVICE拉低,大部分发生在主机接收从机传过来的数据包的最后一个字节的数据时,没有发送P(停止位)所造成的,这时Slave device (EEPROM)因为接收不到P,从而会DEAD LOOP地发送数据给主机,在主机方向看,I2C总线就相当于一直处于BUSY的状态,也就是网上问得最多的关于I2C的问题-I2C总线TMD的怎么会突然间死掉了、BUSY了、HANG的原因。)。

本以为I2C中断读模块也会很顺利地完成,但是却被卡住了一整天,只要加一个断点,在大部份代码处加无所谓,读FUN每次都正确执行,但只要全速运行,就只能运行一次,然后就过不去了,而且过不去的地方并不固定。由于DUBEG得有点集中不了精力,于是就做好问题的Brainstrom的笔记,放了下,晚上出差到深圳,到客户处做系统需求的讨论会,主要是上位机部分的。然后第二天晚上又赶回来,在车上的半梦半觉中让潜意思去思考。回到家后,选择在我的生物钟的最佳的时侯,晚上10点。开始重新在问题的Brainstorm处接着DUBGE。WORK PLAN如下:
(1)把程序恢复到测试I2C写的测试用例状态,PASS。

(2)一小段代码就DEBUG一次的步步为营方法,按之前的思路把代码加入到读的模块(忽略防守代码,只加入必需的功能代码)。都OK后,全速运行,XXX,又卡住了。细过了一片读模块。PASS。于是进入计划中的(3)

(3)全速运行,然后在可能卡住的地方加上断点,而不是之前的先加断点,然后运行的方式(这种方式,已确认PASS):
加了几处后,发现程序是在下面代码处卡住的:


但是奇怪了,每次我只要在箭头指向的语句后加上断点,每次都能PASS。于是知道要到 I2C_CheckEvent 函数中就能找到问题的原因了,于是做下面的几步,目的是把包含I2C_CheckEvent Fun的链接库中的stm32f10x_i2c.o排除掉,而把stm32f10x_i2c.c加入到项目中,使得DEBUG时能进入到 I2C_CheckEvent Fun 中去.

STM32库函数void USART_SendData的缺陷和解决方法

void USART_SendData()函数在快速发送时存在问题 有丢数据的可能

转自https://blog.csdn.net/qq_27114397/article/details/50601548

 

STM32库函数void USART_SendData的缺陷和解决方法
使用USART_SendData()函数非连续发送单个字符是没有问题的;当连续发送字符时(两个字符间没有延时),就会发现发送缓冲区有溢出现象。若发送的数据量很小时,此时串口发送的只是最后一个字符,当发送数据量大时,就会导致发送的数据莫名其妙的丢失。

如:

for(TxCounter = 0;TxCounter < RxCounter; TxCounter++)

USART_SendData(USART1, RxBuffer[TxCounter]);

原因

此API函数不完善,函数体内部没有一个判断一个字符是否发送完毕的语句,而是把数据直接放入发送缓冲区,当连续发送数据时,由于发送移位寄存器的速度限制(与通信波特率有关),导致发送缓冲区的数据溢出,老的数据还未及时发送出去,新的数据又把发送缓冲区的老数据覆盖了。

解决方法(目前总结的两种方案)

方案1. 加入延时函数(下下策),不需要修改USART_SendData()函数

for(TxCounter = 0;TxCounter < RxCounter; TxCounter++)
{

USART_SendData(USART1, RxBuffer[TxCounter]);

DelayMS(2); //加入一个小的延时
}

方案2. 修改USART_SendData()函数,在其内部加入发送缓冲区的USART_FLAG_TXE状态检测语句,确保一个字符完全发送出去,才进行下一个字符的发送。

实现方法:每发送一个字符都检测状态寄存器,确保数据已经发送完毕。具体操作步骤如下所示。

修改前的函数定义体

void USART_SendData(USART_TypeDef* USARTx, u16 Data)

{

assert_param(IS_USART_ALL_PERIPH(USARTx));

assert_param(IS_USART_DATA(Data));

USARTx->DR = (Data & (u16)0x01FF);

}

修改后的函数定义体

void USART_SendData(USART_TypeDef* USARTx, u16 Data)

{

assert_param(IS_USART_ALL_PERIPH(USARTx));

assert_param(IS_USART_DATA(Data));

USARTx->DR = (Data & (u16)0x01FF);

while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET){} //等待发送缓冲区空才能发送下一个字符

}

方案3. 不修改原来的库函数,在每一个字符发送后检测状态位。

USART_SendData(USART1, RxBuffer[TxCounter]);

while(USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET){} //等待发送缓冲区空才能发送下一个字符

ST这么做的原因是:使用发送中断功能。

 

以上是关于stm32硬件i2c缺陷解决方法的主要内容,如果未能解决你的问题,请参考以下文章

STM32库函数void USART_SendData的缺陷和解决方法

STM32F10x_模拟I2C读写_硬件I2C读写

关于STM32的I2C硬件DMA实现

STM32F103VET6基于STM32CubeMX 配置硬件I2C驱动ssd1306 OLED屏幕

STM32 硬件I2C 死循环 自动退出

stm32F407的硬件I2C稳定吗