The I2C Protocol Being Very Problematic on STM32
Hello Sir,
I’ve been dealing with an I2C protocol error for a long time, but unfortunately, neither the solutions online nor the suggestions here have been successful. I've changed sensors multiple times and tried different methods, but the problem remains the same. I’m using the STM32F413ZH board, and in my current tests, I’m using the QMC5883L model for I2C. The pull-up resistors are connected correctly. I even tried soldering the connections to improve them. I also attempted to supply power externally and change the cables, but the issue still wasn’t resolved.
I used a logic analyzer to monitor the bus, and either the signal gets stuck as shown below, or it works chaotically in a meaningless way. For example, SCL often stays high, while SDA changes continuously, or SDA stops entirely at certain points and then continues later. I've seen many variations like this, but it rarely works correctly. I mostly get error codes like 32, 36, and 544.(So it comes as 32 + 512, and in the HAL definitions, 512 is defined as an error of incorrect initialization. To be honest, I have no idea why I’m receiving 512.) I’ve tried the solution involving 9 clock toggles, as many people suggested, but that didn’t help either. I suspected the issue was with the STM32, so I tried it with an Arduino, but although it worked, it stopped after 30-40 seconds. Whatever I do, I’ve never been able to achieve stable operation.
There have been rare instances where the STM32 managed to make a single read, but it would then break again as I described. However, this happened very infrequently. At this point, I’m really starting to think that STM32 engineers have failed in handling this issue effectively.
I will now provide a few examples from the logic analyzer, the current code I'm testing, the values read, and the products I'm using.
I would like to thank in advance everyone who takes the time out of their valuable schedule to assist me with this issue.
Signals captured within very short time intervals:



Values read from STM Studio at short time intervals:


Configuration settings:


Code:
#include "main.h"
#define qmc_address (0x0D << 1)
I2C_HandleTypeDef hi2c1;
UART_HandleTypeDef huart3;
PCD_HandleTypeDef hpcd_USB_OTG_FS;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART3_UART_Init(void);
static void MX_USB_OTG_FS_PCD_Init(void);
static void MX_I2C1_Init(void);
uint8_t read_register[6];
uint8_t write_register[2] = {0x01, 0x1D};
void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c){
GenerateNineClockPulses();
}
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART3_UART_Init();
MX_USB_OTG_FS_PCD_Init();
MX_I2C1_Init();
GenerateNineClockPulses();
HAL_I2C_Mem_Write(&hi2c1, qmc_address, 0x0B, 1, &write_register[0], 1, 50);
HAL_Delay(1);
HAL_I2C_Mem_Write(&hi2c1, qmc_address, 0x09, 1, &write_register[1], 1, 50);
HAL_Delay(1);
while (1)
{
HAL_I2C_Mem_Read(&hi2c1, qmc_address, 0x00, 1, &read_register[0], 1, 50);
HAL_Delay(1);
HAL_I2C_Mem_Read(&hi2c1, qmc_address, 0x01, 1, &read_register[1], 1, 50);
HAL_Delay(1);
HAL_I2C_Mem_Read(&hi2c1, qmc_address, 0x02, 1, &read_register[2], 1, 50);
HAL_Delay(1);
HAL_I2C_Mem_Read(&hi2c1, qmc_address, 0x03, 1, &read_register[3], 1, 50);
HAL_Delay(1);
HAL_I2C_Mem_Read(&hi2c1, qmc_address, 0x04, 1, &read_register[4], 1, 50);
HAL_Delay(1);
HAL_I2C_Mem_Read(&hi2c1, qmc_address, 0x05, 1, &read_register[5], 1, 50);
HAL_Delay(1);
}
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 384;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
RCC_OscInitStruct.PLL.PLLQ = 8;
RCC_OscInitStruct.PLL.PLLR = 2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
{
Error_Handler();
}
}
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_USART3_UART_Init(void)
{
huart3.Instance = USART3;
huart3.Init.BaudRate = 115200;
huart3.Init.WordLength = UART_WORDLENGTH_8B;
huart3.Init.StopBits = UART_STOPBITS_1;
huart3.Init.Parity = UART_PARITY_NONE;
huart3.Init.Mode = UART_MODE_TX_RX;
huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart3.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart3) != HAL_OK)
{
Error_Handler();
}
}
static void MX_USB_OTG_FS_PCD_Init(void)
{
hpcd_USB_OTG_FS.Instance = USB_OTG_FS;
hpcd_USB_OTG_FS.Init.dev_endpoints = 6;
hpcd_USB_OTG_FS.Init.speed = PCD_SPEED_FULL;
hpcd_USB_OTG_FS.Init.dma_enable = DISABLE;
hpcd_USB_OTG_FS.Init.phy_itface = PCD_PHY_EMBEDDED;
hpcd_USB_OTG_FS.Init.Sof_enable = ENABLE;
hpcd_USB_OTG_FS.Init.low_power_enable = DISABLE;
hpcd_USB_OTG_FS.Init.lpm_enable = DISABLE;
hpcd_USB_OTG_FS.Init.battery_charging_enable = ENABLE;
hpcd_USB_OTG_FS.Init.vbus_sensing_enable = ENABLE;
hpcd_USB_OTG_FS.Init.use_dedicated_ep1 = DISABLE;
if (HAL_PCD_Init(&hpcd_USB_OTG_FS) != 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_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOG_CLK_ENABLE();
__HAL_RCC_GPIOA_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);
}
void GenerateNineClockPulses(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
HAL_I2C_DeInit(&hi2c1);
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);
for (int i = 0; i < 9; i++) {
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);
HAL_Delay(1);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);
HAL_Delay(1);
}
HAL_I2C_Init(&hi2c1);
}
void Error_Handler(void)
{
__disable_irq();
while (1)
{
}
}
#ifdef USE_FULL_ASSERT
void assert_failed(uint8_t *file, uint32_t line)
{
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
}
#endif /* USE_FULL_ASSERT */
Board: STM32F413ZH
Sensor: QMC5883L or MPU6050
