TODOPIC

Otros Microcontroladores / Dispositivos programables => Microcontroladores ARM => Mensaje iniciado por: Zener en 21 de Agosto de 2018, 22:23:20

Título: Problemas con I2C en STM32F407G
Publicado por: Zener en 21 de Agosto de 2018, 22:23:20
Hola a todos.

 Estoy tratando de programar el bus I2C de una placa STM32F407G para comunicarse con un sensor de presión y temperatura BMP180. Inicialmente utilizo el soft Cube MX para configurar los puertos a usar para el I2C, luego importo el proyecto en AC6 Eclipse para realizar el programa.
 El sensor que utilizo consta con un registro de memoria el cual debo leer para obtener sus datos. El problema es que los datos que lee no son correctos. Si por ejemplo genero cambio en la temperatura, la lectura debería cambiar, pero no ocurre. Otras veces directamente el valor leído es 0. No logro identificar si se trata de un problema de programación o de un problema en la manera de leer el registro.

 En la hoja de datos del sensor se cuenta con un algoritmo a seguir para su correcto funcionamiento el cual adjunto a continuación. Dado que no me funciona, reduje el programa a algo muy simple solo para asegurarme el funcionamiento correcto del I2C en donde solo se debe realizar lo siguiente:

Primera parte:

-Escribir 0x2E en el registro 0xF4
-Esperar 5ms
-Leer el registro 0xF6 (MSB) y 0xF7 (LSB)
-Almacenar parte baja yparte alta en la variable UT

Segunda Parte

-Escribir 0x34 en el registro 0xF4
-Esperar 5ms
-Leer el registro 0xF6 (MSB) y 0xF7 (LSB)
-Almacenar parte baja y parte alta en la variable UP


----------------------------------------------------------------------------------
El código del programa principal (main) en Eclipse es el siguiente:

Código: [Seleccionar]
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f4xx_hal.h"



/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;


/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);


int main(void)
{

  /* MCU Configuration----------------------------------------------------------*/
  HAL_Init();


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


  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_I2C1_Init();
//----------------------------
  uint8_t valor1[10];
  uint8_t valor2[10];
  uint8_t dato1[1];
  uint8_t dato2[1];

 dato1[0]=0x2E;
 dato2[0]=0x34;


  while (1)
  {

   HAL_I2C_Mem_Write(&hi2c1, 0XEE, 0XF4, 16, dato1,1, 50);
   HAL_Delay(5);
   HAL_I2C_Mem_Read(&hi2c1, 0XEF, 0XF6, 16, valor1,2, 50);
   UT=valor1[0]<<8|valor1[1];

   HAL_I2C_Mem_Write(&hi2c1, 0XEE, 0XF4, 16, dato2,1, 50);
   HAL_Delay(5);
   HAL_I2C_Mem_Read(&hi2c1, 0XEF, 0XF6, 16, valor2,2, 50);
   UP = (valor2[0] << 8 | valor2[1] ) >> (8);
  }

}

/** System Clock Configuration
*/
void SystemClock_Config(void)
{

  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;

    /**Configure the main internal regulator output voltage
    */
  __HAL_RCC_PWR_CLK_ENABLE();

  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

    /**Initializes the CPU, AHB and APB busses clocks
    */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = 16;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 8;
  RCC_OscInitStruct.PLL.PLLN = 50;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV4;
  RCC_OscInitStruct.PLL.PLLQ = 7;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

    /**Initializes the CPU, AHB and APB busses clocks
    */
  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_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

    /**Configure the Systick interrupt time
    */
  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

    /**Configure the Systick
    */
  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

/* I2C1 init function */
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(__FILE__, __LINE__);
  }

}

/** Configure pins as
        * Analog
        * Input
        * Output
        * EVENT_OUT
        * EXTI
*/
static void MX_GPIO_Init(void)
{

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @param  None
  * @retval None
  */
void _Error_Handler(char * file, int line)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  while(1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef USE_FULL_ASSERT

/**
   * @brief Reports the name of the source file and the source line number
   * where the assert_param error has occurred.
   * @param file: pointer to the source file name
   * @param line: assert_param error line source number
   * @retval None
   */
void assert_failed(uint8_t* file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
    ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */

}

#endif

/**
  * @}
  */

/**
  * @}
*/

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
//---------------------------------------------------------------------------------------------

Por otra parte, quisiera saber si estoy usando correctamente las funciones HAL_I2C_Mem_Write y HAL_I2C_Mem_Read, en especial el segundo parámetro (dirección del sensor) y el quinto (puntero para el buffer de datos)

Adjunto a demás una captura de imagen de Cube Mx donde se muestran los puertos PB6 y PB7 configurados para el I2C1 de la placa y también la hoja de datos del sensor donde figura su dirección. Espero puedan ayudarme. Gracias.


Saludos.

Título: Re:Problemas con I2C en STM32F407G
Publicado por: Carl47D en 01 de Septiembre de 2018, 17:38:25
Que tal Zener,

Citar
Por otra parte, quisiera saber si estoy usando correctamente las funciones HAL_I2C_Mem_Write y HAL_I2C_Mem_Read, en especial el segundo parámetro (dirección del sensor) y el quinto (puntero para el buffer de datos)

Como referencia pongo los prototipos de ambas funciones:
Código: C
  1. HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize,
  2.  uint8_t *pData, uint16_t Size, uint32_t Timeout);

Código: C
  1. HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize,
  2.  uint8_t *pData, uint16_t Size, uint32_t Timeout);

La dirección del sensor que espera HAL_I2C_Mem_Write es la de escritura del sensor, que en este caso es 0xEE, y HAL_I2C_Mem_Read espera la dirección de lectura del sensor, en este caso es 0xEF.

El puntero al buffer de datos (uint8_t *pData) es la dirección de la variable la cual quieres escribirle al sensor en el caso de HAL_I2C_Mem_Write o a donde quieres almacenar los datos leídos del sensor en caso de HAL_I2C_Mem_Read.

Con respecto al algoritmo creo que hacen falta pasos, parece que tu código debería ser mas parecido a esto.
Código: C
  1. uint8_t temp[2] = {0};
  2. uint8_t pressure[3] = {0};
  3.  
  4. uint16_t UT = 0;
  5. uint16_t UP = 0;
  6. uint8_t oversampling_setting = 0;
  7.  
  8. uint8_t dato1 = 0x2E;
  9. uint8_t dato2 = 0x34 + (oversampling_setting << 6);
  10.  
  11.   while (1)
  12.   {
  13.            HAL_I2C_Mem_Write(&hi2c1, 0xEE, 0xF4, 1, &dato1, 1, 50);
  14.            HAL_Delay(5);
  15.            HAL_I2C_Mem_Read(&hi2c1, 0xEF, 0xF6, 2, temp, sizeof(temp), 50);
  16.            UT= (temp[0] << 8) | temp[1];
  17.  
  18.            HAL_I2C_Mem_Write(&hi2c1, 0xEE, 0xF4, 1, &dato2, 1, 50);
  19.            HAL_Delay(5);
  20.            HAL_I2C_Mem_Read(&hi2c1, 0xEF, 0xF6, 3, pressure, sizeof(pressure), 50);
  21.            UP = ((pressure[0] << 16) | (pressure[1] << 8) | pressure[2]) >> (8 - oversampling_setting);
  22.            
  23.            /* resto del algoritmo */
  24.   }

No tengo el sensor BMP180, pero prueba y nos cuentas como te fue.

Saludos
Título: Re:Problemas con I2C en STM32F407G
Publicado por: planeta9999 en 01 de Septiembre de 2018, 21:01:49

Prueba a usar una librería ya existente y probada para ese sensor, buscando por Google salen unas cuantas, algunas para los STM32, por ejemplo esta. Solo tienes que cambiar la definición de los puertos, y te funcionará de inmediato.

https://github.com/LonelyWolf/stm32/tree/master/bmp180

Tal vez te falta lo relativo a la calibración, o estás haciendo mal alguno de los cálculos. Leyendo algún fuente comprobado, también te puedes dar cuenta donde está fallando el tuyo.
Título: Re:Problemas con I2C en STM32F407G
Publicado por: Zener en 04 de Septiembre de 2018, 15:43:12
Hola a todos

    Al fin pude solucionarlo. El problema estaba en el parámetro  "MemAddSize", este parámetro  debe estar en "1". Como los datos a leer tiene una parte alta MSB y parte baja LSB, suponía que el parámetro debía ser 2 por tratarse de 2 bytes. Pero ese es un error de mi parte, ya que el valor debe ser el del espacio de memoria a leer y no el de todos los espacios de memoria a leer. En este caso, el espacio de memoria es de 8 bits.
    Una vez corregido eso pude leer la EEPROM y los valores de temperatura y presión barométrica sin problemas.
    El código corregido es el siguiente:

Código: [Seleccionar]

uint8_t temp[2] = {0};
uint8_t pressure[3] = {0};
uint8_t datos[22] = {0};
 
uint16_t UT = 0;
uint16_t UP = 0;
uint8_t oversampling_setting = 0;
 
uint8_t dato1 = 0x2E;
uint8_t dato2 = 0x34 + (oversampling_setting << 6);
 
  while (1)
  {
           HAL_I2C_Mem_Read(&hi2c1, 0xEF, 0xAA, 1, datos, sizeof(datos), 50);                //Leer datos de calibración
           HAL_I2C_Mem_Write(&hi2c1, 0xEE, 0xF4, 1, &dato1, 1, 50);
           HAL_Delay(5);
           HAL_I2C_Mem_Read(&hi2c1, 0xEF, 0xF6, 1, temp, sizeof(temp), 50);                     //Leer temperatura
           UT= (temp[0] << 8) | temp[1];
 
           HAL_I2C_Mem_Write(&hi2c1, 0xEE, 0xF4, 1, &dato2, 1, 50);
           HAL_Delay(5);
           HAL_I2C_Mem_Read(&hi2c1, 0xEF, 0xF6, 1, pressure, sizeof(pressure), 50);           //Leer presión

           UP = ((pressure[0] << 16) | (pressure[1] << 8) | pressure[2]) >> (8 - oversampling_setting);
           
           /* resto del algoritmo */
  }

Utilice el código propuesto por Carl47D con algunas modificaciones. Por otra parte, ya tenía conocimiento de las  librerías que me indicaste planeta9999, el problema es que no utilizan las librerías HAL y yo estoy usando librerías HAL. Gracias igualmente por tu aporte.

Saludos.