在 HAL_I2C_Mem_Read 中观察到
STM32 I2C Hal 驱动程序中存在问题,但其他读取命令中可能存在相同问题。
我观察到有时 I2C 主机无法确认并发送停止条件的问题,之后 SDA 卡在低电平并且 HAL_BUSY 在连续的 I2C 读取时返回。我可以重现此问题,同时强调 I2C 读取(读取加速度传感器的 7 个值)并结合运行 httpd 并每 5 秒在浏览器中刷新一次网页。
我注意到当我遇到只剩下 2 个剩余字节的情况时会出现问题
- /* Two bytes */
- else if (hi2c->XferSize == 2U)
问题是在这种情况下没有禁用 ACK (CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK); )
通常,当读取多个数据时,MCU 会从 hi2c->Instance->DR 中一次读取 1 个字节,最终得到剩余 3 个字节的情况(此时行为是正确的)。但是,如果设置了“I2C_FLAG_BTF”,MCU 将读出一个额外的字节。如果在那之后,只剩下 2 个字节,则 ACK 永远不会被禁用。
作为解决方案,下面的内容对我有用:(检查“//NEW”评论)
- {
- /* Wait until RXNE flag is set */
- if (I2C_WaitOnRXNEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK)
- {
- return HAL_ERROR;
- }
- /* Read data from DR */
- *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR;
- /* Increment Buffer pointer */
- hi2c->pBuffPtr++;
- /* Update counter */
- hi2c->XferSize--;
- hi2c->XferCount--;
- if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == SET)
- {
- if(hi2c->XferSize == 3U) {
- //NEW -> clear ACK (must be done before reading DR). After this read, only 2 bytes are remaining.
- CLEAR_BIT(hi2c->Instance->CR1, I2C_CR1_ACK);
- }
- /* Read data from DR */
- *hi2c->pBuffPtr = (uint8_t)hi2c->Instance->DR;
- /* Increment Buffer pointer */
- hi2c->pBuffPtr++;
- /* Update counter */
- hi2c->XferSize--;
- hi2c->XferCount--;
- }
- }
- }
但是,我根本不喜欢这种“I2C_FLAG_BTF”检查,没有必要,因为它并没有真正加快进程,而且(正如您注意到的那样)只会产生更多的错误和更复杂的代码。我认为这个函数可以在没有 IF 情况下完美运行,但我可能是错的。也许它是出于其他原因添加的?
“HAL_I2C_Master_Receive”函数中可能存在同样的问题,但我没有验证过。代码看起来都一样。
我什至怀疑这段代码 (HAL_I2C_Mem_Read) 是否 100% 正确,因为我不确定“I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BTF, RESET, Timeout, tickstart)”(当只剩下 2 个字节时)是否能有效保证正好接收到最后 2 个字节。在我看来,当接收到最后 3 个字节中的第 2 个字节时,也可能会出现这种情况。但我在这方面可能是错的,而且更难解释。
0