cancel
Showing results for 
Search instead for 
Did you mean: 

HAL_I2C_Transmit returns HAL_BUSY.

akoluacik
Senior

I am trying to write a code so that I measure temperature and humidity via HTU21D sensor. It uses I2C interface. In the datasheet:

The HTU21D(F) sensor requires a voltage supply between 1.5V and 3.6V. After power up, the device needs at most 15ms while SCK is high for reaching idle state (sleep mode), i.e to be ready accepting commands from the MCU. No command should be sent before that time. Soft reset is recommended at start.

According to this information, I formed the following function:

void HTU21D_SensorInit(void)
{
	uint8_t pData[] = {0xFE}; // SOFT_RESET
	if(HAL_I2C_Mem_Write(&hi2c2, (DEVICE_ADDRESS << 1), WRITE_REGISTER, 1, pData, 1, HAL_MAX_DELAY) != HAL_OK)
	{
		Error_Handler();
	}
//	HAL_UART_Transmit(&huart1, (uint8_t*)"Sensor initialized!\r\n", 21, 100); for debugging
	HAL_Delay(15);
}

And I invoke this function in main after MX_I2C2 is called.

This function works find and doesn't go into Error_Handler. In while(1) part of the main function, I invoke the following function:

void HTU21D_MeasureTemp(void)
{
	uint8_t pData[] = {0xE3};
    HAL_UART_Transmit(&huart1, (uint8_t *)output, strlen(output), 100);
	HAL_StatusTypeDef res = HAL_I2C_Master_Transmit(&hi2c2, (DEVICE_ADDRESS << 1), pData, 1, HAL_MAX_DELAY);
	sprintf(output, "Res:%d\r\n", res);
	HAL_UART_Transmit(&huart1, (uint8_t*)output, strlen(output), 100);
	uint8_t temp[2];
	uint16_t raw_temp;
	HAL_UART_Transmit(&huart1, (uint8_t*)"Before if\r\n", 9, 100);
	HAL_UART_Transmit(&huart1, (uint8_t *)output, strlen(output), 100);
	if (res == HAL_OK)
	{
		HAL_I2C_Master_Receive(&hi2c2, ((DEVICE_ADDRESS << 1) | 0x01), temp, 2, HAL_MAX_DELAY);
		raw_temp = ((temp[0] << 8) | temp[1]);
		sprintf(output, "raw temp:%d\r\n", raw_temp);
		HAL_UART_Transmit(&huart1, (uint8_t*)output, strlen(output), 100);
		g_temp = -46.85 + 175.72 * raw_temp / 65536;
		HAL_UART_Transmit(&huart1, (uint8_t*)"In if after calc\r\n", 15, 100);
	}
	else
	{
		uint32_t error = HAL_I2C_GetError(&hi2c2);
		sprintf(output, "Error code:%lu\r\n", error);
		HAL_UART_Transmit(&huart1, (uint8_t*)output, 20, 100);
		Error_Handler();
	}
}

Where device address is (0x40). For reading, purpose, I shift it to left by 1 bit apply or operation with 0x01, this is described in datasheet.

However, this code returns HAL_BUSY, and HAL_I2C_GetError returns 0x32, which is Timeout afaik.

More interesting thing is that, if I do not call HTU21D_Init function, I get temperature value twice. I mean, the loop iterates only twice, then get stuck in somewhere else. What is wrong with my code?

Note that I am using proteus. This results were not taken from real life.

My whole code is below(excluding the parts Cubemx created):

#include "main.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
 
#define		TEMP_MEASUREMENT	0xE3
#define		HUMI_MEASUREMENT	0xE5
#define		WRITE_REGISTER		0xE6
#define		READ_REGISTER		0xE7
#define		DEVICE_ADDRESS      0x40
I2C_HandleTypeDef hi2c2; 
UART_HandleTypeDef huart1;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C2_Init(void);
static void MX_USART1_UART_Init(void);
 
void HTU21D_SensorInit(void);
void HTU21D_MeasureTemp(void);
 
float temp;
float humidity;
float g_temp;
float g_humidity;
char output[50];
 
int main(void)
{
 
  HAL_Init();
 
  SystemClock_Config();
  MX_GPIO_Init();
  MX_I2C2_Init();
  MX_USART1_UART_Init();
  HTU21D_SensorInit();
  while (1)
  {
	HTU21D_MeasureTemp();
	sprintf(output, "temp:%.2f\r\n", g_temp);
	HAL_UART_Transmit(&huart1, (uint8_t*)output, strlen(output), 100);
	HAL_Delay(10);
  }
}
 
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_SCALE2);
 
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  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_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
}
 
static void MX_I2C2_Init(void)
{
  hi2c2.Instance = I2C2;
  hi2c2.Init.ClockSpeed = 100000;
  hi2c2.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c2.Init.OwnAddress1 = 0;
  hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c2.Init.OwnAddress2 = 0;
  hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(&hi2c2) != HAL_OK)
  {
    Error_Handler();
  }
}
 
static void MX_USART1_UART_Init(void)
{
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
}
static void MX_GPIO_Init(void)
{
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
 
}
void HTU21D_SensorInit(void)
{
	uint8_t pData[] = {0xFE}; // SOFT_RESET
	if(HAL_I2C_Mem_Write(&hi2c2, (DEVICE_ADDRESS << 1), WRITE_REGISTER, 1, pData, 1, HAL_MAX_DELAY) != HAL_OK)
	{
		Error_Handler();
	}
	HAL_UART_Transmit(&huart1, (uint8_t*)"Sensor initialized!\r\n", 21, 100);
	HAL_Delay(15);
}
 
void HTU21D_MeasureTemp(void)
{
	uint8_t pData[] = {TEMP_MEASUREMENT};
    HAL_UART_Transmit(&huart1, (uint8_t *)output, strlen(output), 100);
	HAL_StatusTypeDef res = HAL_I2C_Master_Transmit(&hi2c2, (DEVICE_ADDRESS << 1), pData, 1, HAL_MAX_DELAY);
	sprintf(output, "Res:%d\r\n", res);
	HAL_UART_Transmit(&huart1, (uint8_t*)output, strlen(output), 100);
	uint8_t temp[2];
	uint16_t raw_temp;
	HAL_UART_Transmit(&huart1, (uint8_t*)"Before if\r\n", 9, 100);
	HAL_UART_Transmit(&huart1, (uint8_t *)output, strlen(output), 100);
	if (res == HAL_OK)
	{
		HAL_I2C_Master_Receive(&hi2c2, ((DEVICE_ADDRESS << 1) | 0x01), temp, 2, HAL_MAX_DELAY);
		raw_temp = ((temp[0] << 8) | temp[1]);
		sprintf(output, "raw temp:%d\r\n", raw_temp);
		HAL_UART_Transmit(&huart1, (uint8_t*)output, strlen(output), 100);
		g_temp = -46.85 + 175.72 * raw_temp / 65536;
		HAL_UART_Transmit(&huart1, (uint8_t*)"In if after calc\r\n", 15, 100);
	}
	else
	{
		uint32_t error = HAL_I2C_GetError(&hi2c2);
		sprintf(output, "Error code:%lu\r\n", error);
		HAL_UART_Transmit(&huart1, (uint8_t*)output, 20, 100);
		Error_Handler();
	}
}
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  HAL_UART_Transmit(&huart1, (uint8_t*)"Error Handler\r\n", 15, 100);
  while (1)
  {
  }
}

15 REPLIES 15

Well, this is already not HAL_BUSY.

What does HAL_I2C_GetError() return?

It returns 0, which is HAL_I2C_ERROR_NONE.

Can you try to trace thru HAL_I2C_Master_Transmit, to understand where it fails?

Try to use an Oscilloscope to see the SDA and SCL behavior.

Foued

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.

Yeah I did that. The function call at line 244 returns HAL_ERROR, so the goes into else block.

Karl Yamashita
Lead III

in HAL_I2C_Master_Transmit put break points on each of the return HAL_ERROR. This way you can narrow down to which part of the transmit function is returning the error.

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.