cancel
Showing results for 
Search instead for 
Did you mean: 

The I2C Protocol Being Very Problematic on STM32

AlexanderKibarov
Associate III

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:

Ekran görüntüsü 2024-09-27 004636.pngEkran görüntüsü 2024-09-27 004703.png

Ekran görüntüsü 2024-09-27 005341.png

 

Values read from STM Studio at short time intervals:

Ekran görüntüsü 2024-09-27 004756.pngEkran görüntüsü 2024-09-27 005830.png

 

Configuration settings:

Ekran görüntüsü 2024-09-27 010317.pngEkran görüntüsü 2024-09-27 010334.png

 

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

16 REPLIES 16

In your latest screen shot, is the QMC5883L connected? 

Tips and Tricks with TimerCallback https://www.youtube.com/@eebykarl
If you find my solution useful, please click the Accept as Solution so others see the solution.
AlexanderKibarov
Associate III

@Karl Yamashita @Andrew Neil @TDK @LCE 

Thank you once again for your valuable responses.

 

I am now certain that the problem is caused by the QMC sensor. In my tests, I successfully established I2C communication between Arduino-Arduino and STM32-Arduino, and the communication was flawless. As you mentioned, when I checked the resistors on the QMC, I saw that one was 2.2k and the other 0.3k. I then replaced it with a new QMC that had the correct resistors, but there was still an issue. (In fact, strangely, the device overheated and started smoking. This had happened to me before.) The connections were as follows:

* VCC-5V

* GND-GND

* SCL-SCL

* SDA-SDA

Although the overheating issue had occurred before, I still don't understand the reason behind it. As I initially mentioned, communication between Arduino-Arduino and STM32-Arduino was flawless, but sometimes the situation depicted in the image below occurred. Frankly, these are not major issues since they do not disrupt communication, and maybe these issues are due to the logic analyzer I used and its speed. Do you think such errors are normal?

 

Under normal conditions, the STM32 sends data 0x80 to the Arduino. The Arduino's address is 0x37.

 

Ekran görüntüsü 2024-09-27 231907.pngEkran görüntüsü 2024-09-27 232422.pngEkran görüntüsü 2024-09-27 232552.pngEkran görüntüsü 2024-09-27 232818.pngEkran görüntüsü 2024-09-27 235018.png


@AlexanderKibarov wrote:

the overheating issue had occurred before,


That's worrying !

Potentially could have damaged the STM32 also?

Thank you Andrew for you answer. 

According to my experience, the stm works properly. I did not see any errors regarding its operation. As I already said, while the qmc and i2c communication failed on cards such as arduino stm32, it was successful when the cards communicated with each other.

A You sure that VCC has to be 5V?

The QMC5883L is a 3.3V device.

Do You use some type of OEM Module with the QMC5883L  on it?

Has this modue a power regulator to reduce 5V to 3.3V needed by the QMC5883L?

"damaged" != "completely non-functional"

possibly, it could be "working" just enough for the other cards, but just not enough for the QMC...

Again, this is where an analogue scope on the lines would help ...

jeonwookyu
Associate

/////This is a code written in Arduino for i2c communication between stm32f1036t6 and esp8266


//#include <Wire.h>
//#include <Wire_slave.h>
#define I2C_MASTERSLAVE 1 // 1이면 마스터, 0이면 슬레이브
#define SLAVE_ADDRESS 0x08
#if I2C_MASTERSLAVE == 1 // 마스터
#include <Wire.h>
#endif

#if I2C_MASTERSLAVE == 0 // 슬레이브 모드일 때 사용
#include <Wire_slave.h>

void requestEvent();
void receiveEvent(int numBytes);
String receivedData = "";
bool stringComplete = false;
#endif
void setup(){
Wire.begin(SLAVE_ADDRESS); // join i2c bus with address #4
Serial.begin(9600);
// start serial for output
#if I2C_MASTERSLAVE == 0 // 슬레이브 모드일 때 사용
Wire.onReceive(receiveEvent); // register event
Wire.onRequest(requestEvent); // 요청 이벤트 등록
receivedData.reserve(200);
#endif
}

void loop(){
#if I2C_MASTERSLAVE == 1
Wire.beginTransmission(SLAVE_ADDRESS);

Wire.setClock(40000L); // Set speed at 40kHz
Wire.write("1234567890abcd\n");//종료문자추가
Wire.endTransmission();

Serial.println("Sent data to STM32"); // 전송한 데이터 시리얼로 출력
delay(3000); // 1초 대기
#endif
}

#if I2C_MASTERSLAVE == 0
void receiveEvent(int howMany){

 

while(Wire.available()){ // loop through all but the last

char c = (char)Wire.read(); // receive byte as a character
receivedData += c;
//Serial.print(c);
if(c=='\n'){
stringComplete = true;
}
if (stringComplete) {
Serial.println(receivedData);
// clear the string:
receivedData = "";
stringComplete = false;
    }
  }

}

void requestEvent() {
}
#endif