I2C Working Inconsistently
I am trying to read data from an MPU6050 sensor using I2C with the STM32F413ZH board. However, I am encountering errors, likely because the levels of the SCL and SDA initialization and termination bits are incorrect. This causes the system to sometimes work correctly and other times result in errors. When the HAL_I2C_IsDeviceReady function returns an error value, I tried to deinitialize and reinitialize the I2C unit, but it did not work. Upon investigating the error, I found that it returns HAL_BUSY and enters the I2C_WaitOnFlagUntilTimeout function, where the I2C error code indicates a timeout issue. Specifically, in these sections:
if (hi2c->State == HAL_I2C_STATE_READY)
{
/* Wait until BUSY flag is reset */
if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart) != HAL_OK)
{
return HAL_BUSY;
}
while (__HAL_I2C_GET_FLAG(hi2c, Flag) == Status)
{
/* Check for the Timeout */
if (Timeout != HAL_MAX_DELAY)
{
if (((HAL_GetTick() - Tickstart) > Timeout) || (Timeout == 0U))
{
if ((__HAL_I2C_GET_FLAG(hi2c, Flag) == Status))
{
hi2c->PreviousState = I2C_STATE_NONE;
hi2c->State = HAL_I2C_STATE_READY;
hi2c->Mode = HAL_I2C_MODE_NONE;
hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT;
/* Process Unlocked */
__HAL_UNLOCK(hi2c);
return HAL_ERROR;
}
}
}
}
Later, as described in section 30.4.5 of RM0285, I attempted to release the SCL and SDA lines by setting the I2C_CR1_PE bit to 0 for 3 time cycles and then back to 1, but that also did not work. Here is that code:
void I2C_Software_Reset(I2C_HandleTypeDef *hi2c)
{
hi2c->Instance->CR1 &= ~I2C_CR1_PE;
while (hi2c->Instance->CR1 & I2C_CR1_PE);
hi2c->Instance->CR1 |= I2C_CR1_PE;
}
I haven't fully understood the exact problem. Could you please help?
Here is the complete code:
#include "main.h"
I2C_HandleTypeDef hi2c1;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
HAL_StatusTypeDef hal_status_one;
uint8_t data_mpu[1] = {0x00};
void I2C_Software_Reset(I2C_HandleTypeDef *hi2c)
{
hi2c->Instance->CR1 &= ~I2C_CR1_PE;
while (hi2c->Instance->CR1 & I2C_CR1_PE);
hi2c->Instance->CR1 |= I2C_CR1_PE;
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_I2C1_Init();
uint8_t data_data[1] = {0x00};
HAL_I2C_Mem_Write(&hi2c1, (0x68 << 1), 0x6B, 1, data_data, 1, 100);
while (1)
{
if(!HAL_I2C_IsDeviceReady(&hi2c1, (0x68 << 1), 4, 100)) {
hal_status_one = HAL_I2C_Mem_Read(&hi2c1, (0x68 << 1), 0x3C, 1, data_mpu, 1, 100);
}
else {
I2C_Software_Reset(&hi2c1);
}
}
}
static void MX_I2C1_Init(void)
{
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000;
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
HAL_GPIO_WritePin(GPIOB, LD1_Pin|LD3_Pin|LD2_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(USB_PowerSwitchOn_GPIO_Port, USB_PowerSwitchOn_Pin, GPIO_PIN_RESET);
GPIO_InitStruct.Pin = USER_Btn_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(USER_Btn_GPIO_Port, &GPIO_InitStruct);
GPIO_InitStruct.Pin = LD1_Pin|LD3_Pin|LD2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = USB_PowerSwitchOn_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(USB_PowerSwitchOn_GPIO_Port, &GPIO_InitStruct);
GPIO_InitStruct.Pin = USB_OverCurrent_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(USB_OverCurrent_GPIO_Port, &GPIO_InitStruct);
}
