Conecte STM32F103 a MPU9250 a través de I2C con HAL (ERROR)

Mi experiencia en la programación de MCU es solo Arduino (también STM32F103 sobre Arduino). Ahora comencé a usar el STM32CUBEIDE y un ST-Link V2 para programar mi STM32f103.

He probado las funciones:

  • HAL_I2C_IsDeviceReady
  • HAL_I2C_Master_Transmit
  • HAL_I2C_Master_Receive
  • HAL_I2C_Mem_Read

y el valor de retorno de 'HAL_StatusTypeDef' es siempre '1' en la primera llamada y '2' en las siguientes llamadas (de cualquiera de las funciones enumeradas anteriormente).

1 significa ERROR y 2 significa OCUPADO. 3 significaría TIMEOUT y 0 significaría OK, hasta donde yo sé.

Mi pregunta es: incluso si cambio la dirección I2C, el retorno sigue siendo 1 (ERROR) en la primera llamada, y nunca 3 (TIMEOUT). ¿Por qué?

Según esto: https://os.mbed.com/users/EricLew/code/STM32L4xx_HAL_Driver/docs/tip/stm32l4xx__hal__i2c_8c_source.html#l02221

HAL_I2C_IsDeviceReadyni siquiera debería devolver 1, solo 0 y 3 ...

¿Alguien puede decirme qué estoy haciendo mal? Configuré los pines correctamente en STM32Cube (PB6 y 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 */
  }
}

Y llamé a la función de inicialización (al igual que el IDE me preparó en la configuración del código):

/* 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);
  }
}

y la read_registerfunción se define aquí:

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

y el resultado general del 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 
¿Estás seguro de que tu hardware está conectado correctamente? ¿Qué pullups estás usando?

Respuestas (1)

ok, gracias brhans por tu comentario. Pensé que me había encargado de eso, pero la línea del reloj se elevó a 3v3, ahora funciona. ¡muchas gracias!

También cambié esta línea.

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

a

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