Electrical – Connect STM32F103 to MPU9250 over I2C with HAL (ERROR)

i2cstm32stm32cubemx

my experience in programming MCU is only Arduino (also STM32F103 over Arduino) I have now started to use the STM32CUBEIDE and an ST-Link V2 to program my STM32f103.

I have tried the functions:

  • HAL_I2C_IsDeviceReady
  • HAL_I2C_Master_Transmit
  • HAL_I2C_Master_Receive
  • HAL_I2C_Mem_Read

and the 'HAL_StatusTypeDef' return value is always '1' at the first call and '2' at the following calls (of any of the above listed functions).

1 means ERROR and 2 means BUSY. 3 would mean TIMEOUT and 0 would mean OK, as far as I know.

My questions is: even if I change the I2C address the return is still 1 (ERROR) on the first call, and never 3 (TIMEOUT). Why?

According to this: https://os.mbed.com/users/EricLew/code/STM32L4xx_HAL_Driver/docs/tip/stm32l4xx__hal__i2c_8c_source.html#l02221

HAL_I2C_IsDeviceReady shouldn't even return 1, only 0 and 3…

Can somebody tell me what I am doing wrong? I setup the pins correctly in STM32Cube (PB6 and PB7):

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();
  }

}

void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(i2cHandle->Instance==I2C1)
  {
  /* USER CODE BEGIN I2C1_MspInit 0 */

  /* USER CODE END I2C1_MspInit 0 */

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**I2C1 GPIO Configuration    
    PB6     ------> I2C1_SCL
    PB7     ------> I2C1_SDA 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* I2C1 clock enable */
    __HAL_RCC_I2C1_CLK_ENABLE();
  /* USER CODE BEGIN I2C1_MspInit 1 */

  /* USER CODE END I2C1_MspInit 1 */
  }
}

And called the initialize function (just like the IDE has prepared for me in the code setup):

/* USER CODE BEGIN 0 */
HAL_StatusTypeDef ret;
unsigned char buf[2];
uint16_t val;
int16_t valt;
float temp_c;
float RoomTemp_Offset = 0;
float Temp_Sensitivity = 321;
/* USER CODE END 0 */

int main(void)
{

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */
  DWT_Delay_Init();
  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C1_Init();
  MX_SPI1_Init();
  /* USER CODE BEGIN 2 */

  ret = HAL_I2C_IsDeviceReady(&hi2c1, MPU9250_ADDR, 10, 100);
  printf("Is Ready: %d \n", ret);
  /* USER CODE END 2 */

  /* Infinite loop */

  while (1)
  {
       // Tell MPU9250 that we want to read from the temperature register
      val = read_register(0x41);
      valt = ((int16_t)val << 4) | (val >> 4);
      temp_c = ((valt - RoomTemp_Offset)/Temp_Sensitivity) + 21;
      printf("reading...\n");
      printf("%.6f \n", temp_c);
  }
}

and the read_register function is defined here:

uint16_t read_register(uint16_t register_pointer)
{
    HAL_StatusTypeDef status = HAL_OK;
    uint16_t return_value = 0;
    status = HAL_I2C_Mem_Read(&hi2c1, MPU9250_ADDR, (uint16_t)register_pointer, I2C_MEMADD_SIZE_8BIT, &return_value, 2, 100);
    printf("read HAL_RET: %d \n", status);
    /* Check the communication status */
    if(status != HAL_OK)
    {
        Error_Handler();
    }

    return return_value;
}

and the overall output of the script ower SWO:

Is Ready: 1 
read HAL_RET: 2 
reading...

read HAL_RET: 2 
reading...

read HAL_RET: 2 
reading...

read HAL_RET: 2 

Best Answer

okay, thank you brhans for your comment. I thought I had taken care of that but the clock line was pulled high to 3v3, now it works. thank you very much!

I also changed this line

valt = ((int16_t)val << 4) | (val >> 4);

to

valt = ((int16_t)buf[0] << 8) | (buf[1]);