2024-09-26 03:18 PM - edited 2024-09-26 03:27 PM
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
2024-09-26 04:15 PM
Related:
Always SCL High, SDA Low In I2C - STMicroelectronics Community
Can't solve hardware problems with software, at least not most of the time. Based on your plots and your description of the issue, it doesn't look like a software problem. SDA and SCL should be idle high after power on. If they're not, it is a hardware issue.
2024-09-26 10:49 PM
>> I’ve been dealing with an I2C protocol error for a long time ...
Then it's time to throw out the HAL I2C drivers and write your own.
I cannot imagine that there is a hardware fault in an F4 peripheral. Or have you checked chip errata sheet?
2024-09-27 01:40 AM
Let's make sure the QMC5883L is not the cause of the SCL/SDA lines staying mostly low.
First comment out your read/write routines and see if the SCL/SDA lines stay high.
If they either line go low, remove the QMC5883L and still comment out the I2C Mem read/write.
Be sure the pull-up resistors are still connected to the STM32.
Then run again to see if the SCL and SDA line stays high?
You can also connect two I2C ports together and test in loopback.
2024-09-27 05:03 AM
Thank you all very much for your valuable comments. While trying out the things you suggested, I discovered something. Indeed, when I load an empty code, the line is pulled high as it should be, but if I use HAL's MX_I2C1_Init(); function, strange signals appear as shown below. What could be the reason for this?
#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(); //This!
while (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 */
I’m receiving signals like this and similar ones, which make no sense, and moreover, the SCL line remains high as it should.
Thank you.
2024-09-27 05:10 AM
In my current test, I believe you're right. Even when I don't write any code to operate the line, the SDA line is being pulled low.
2024-09-27 05:25 AM
@AlexanderKibarov wrote:I used a logic analyzer to monitor the bus
Have you tried with an oscilloscope?
This could show up things in the analogue domain that a logic analyser's digital view may hide ...
@AlexanderKibarov wrote:The pull-up resistors are connected correctly
What value are they?
2024-09-27 07:01 AM
Doing an analog capture on SDA/SCL lines might be useful here. Even with it toggling randomly, you should see a slow rising edge and a fast falling edge as expected with an open-drain output. If they are both fast, something on there is misbehaving.
Still think the resistance test with a multimeter would be a good idea.
Could remove the external I2C slave chips to see if problem goes away. If I was stuck, that's what I would do to confirm the hardware issue.
2024-09-27 07:01 AM
Hey Andrew, Thank you for your answer
Resistor value is 2.2K. Is it enough in your opinion?
2024-09-27 07:07 AM
@AlexanderKibarov wrote:Resistor value is 2.2K. Is it enough in your opinion?
Probably.
The way to check is to look at the waveforms with an oscilloscope.
See this post:
It contains this diagram - which shows you the effect of the pullup value:
#I2CPullupValue #PullupValue