cancel
Showing results for 
Search instead for 
Did you mean: 

code stop in function HAL_I2C_IsDeviceReady

Graziele Rodrigues
Associate

Hello, I am trying to use the LORA-E5 STM32WLE5JC board with the BME688 sensor, I2C connection. I used this repository as the basis GitHub - Squieler/BME68x-STM32-HAL: BME68x STM32 HAL Library, changing what was needed. But it always hangs in that role. Can anyone help me? 

tmp1 = __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF) and tmp2 = __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) always still “reset” so brake in this part. 

 

/*
 * Library Name: 	BME68x (I2C) - STM32 HAL and BME68x API Based Library
 * Written By:		Ahmet Batuhan Günaltay (Great thanks to David Bird for IAQ calculation method and functions.)
 * Date Written:	26/05/2021 (DD/MM/YYYY)
 * Last Modified:	26/05/2021 (DD/MM/YYYY)
 * Description:		This library measures temperature, humidity, pressure and IAQ with BME680x (I2C) sensors based on STM32 HAL
 * 					and BME68x API. For more information about the IAQ calculation check: https://github.com/G6EJD/BME680-Example
 * References:
 * 	- https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bme680-ds001.pdf [Datasheet]
 *
 * Copyright (C) 2021 - Ahmet Batuhan Günaltay
 * (IAQ calculation substantial portion, the ideas and concepts is Copyright (c) David Bird 2018)
 *
	This software library is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This software library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 *  */

/* Necessary functions for BME68x API are defined here. (Functions that are hardware dependent.) */

#include "bme68x_necessary_functions.h"

// I2C handler
extern I2C_HandleTypeDef hi2c2; // I2C peripheral for the device.

// BME68x device address:
uint8_t dev_addr = BME68X_I2C_ADDR_LOW; // High is 0x77 and low is 0x76
uint8_t chip_id = BME68X_CHIP_ID; // is 0x61

// BME68x Variables
struct bme68x_dev bme;
struct bme68x_data * BME68x_DATA;
int8_t rslt;
struct bme68x_conf conf;
struct bme68x_heatr_conf heatr_conf;
uint32_t del_period;
uint8_t n_fields;

// IAQ Calculation Variables
float humidity_score, gas_score;
float gas_reference = 250000;
float hum_reference = 40;
int8_t getgasreference_count = 0;
float gas_lower_limit = 5000;   // Bad air quality limit
float gas_upper_limit = 50000;  // Good air quality limit

/* Complete init. function. */
int8_t bme68x_start(struct bme68x_data *dataPtr) {

	// Init.
	bme68x_interface_init(&bme, BME68X_I2C_INTF);

	// Init. for data variable
	BME68x_DATA = dataPtr;

	// Configuration
	/* Check if rslt == BME68X_OK, report or handle if otherwise */
	conf.filter = BME68X_FILTER_OFF;
	conf.odr = BME68X_ODR_NONE;
	conf.os_hum = BME68X_OS_16X;
	conf.os_pres = BME68X_OS_1X;
	conf.os_temp = BME68X_OS_2X;
	bme68x_set_conf(&conf, &bme);

	// Heat conf.
	/* Check if rslt == BME68X_OK, report or handle if otherwise */
	heatr_conf.enable = BME68X_ENABLE;
	heatr_conf.heatr_temp_prof = 320;
	heatr_conf.heatr_dur_prof = 150;
	heatr_conf.profile_len = 1;
	rslt = bme68x_set_heatr_conf(BME68X_SEQUENTIAL_MODE, &heatr_conf, &bme);

	//Gather gas reference for the IAQ calculation
	bme68x_GetGasReference();

	return rslt;
}

/* Force mode measurement. */
int8_t bme68x_single_measure(struct bme68x_data *dataPtr) {

	bme68x_set_op_mode(BME68X_FORCED_MODE, &bme);

	/* Calculate delay period in microseconds */
	del_period = bme68x_get_meas_dur(BME68X_FORCED_MODE, &conf, &bme)
			+ (heatr_conf.heatr_dur * 1000);
	bme.delay_us(del_period, bme.intf_ptr);

	/* Check if rslt == BME68X_OK, report or handle if otherwise */
	rslt = bme68x_get_data(BME68X_FORCED_MODE, dataPtr, &n_fields, &bme);

	return rslt;
}

/* Necessary functions. */
// I2C write function.
BME68X_INTF_RET_TYPE bme68x_i2c_write(uint8_t reg_addr, const uint8_t *reg_data,
		uint32_t len, void *intf_ptr) {
	uint8_t dev_addr = *(uint8_t*) intf_ptr;

	if (HAL_I2C_Mem_Write(&hi2c2, (uint16_t) (dev_addr << 1), reg_addr, 1,
			(uint8_t*) reg_data, len, 15) == HAL_OK)
		return 0;

	return 1;
}

// I2C read function.
BME68X_INTF_RET_TYPE bme68x_i2c_read(uint8_t reg_addr, uint8_t *reg_data,
		uint32_t len, void *intf_ptr) {
	uint8_t dev_addr = *(uint8_t*) intf_ptr;

	if (HAL_I2C_Mem_Read(&hi2c2, (uint16_t) ((dev_addr << 1) | 0x1), reg_addr,
			1, reg_data, len, 15) == HAL_OK)
		return 0;

	return 1;
}

// BME68x delay function
void bme68x_delay_us(uint32_t period, void *intf_ptr) {
	HAL_Delay(period / 1000);
}

// BME68x interface function
int8_t bme68x_interface_init(struct bme68x_dev *bme, uint8_t intf) {
	int8_t rslt = BME68X_OK;

	if (bme != NULL) {

		// Check for the device on the I2C line
		if (HAL_I2C_IsDeviceReady(&hi2c2, (uint16_t) (dev_addr << 1), 1, 1) //stop here
				== HAL_OK) {
			// Device found at the I2C line.
			rslt = 0;
		} else {
			rslt = -2; // Communication error.
			return rslt;
		}

		/* Bus configuration : I2C */
		if (intf == BME68X_I2C_INTF) {
			bme->read = bme68x_i2c_read;
			bme->write = bme68x_i2c_write;
			bme->intf = BME68X_I2C_INTF;
		} else {
			return -2;
		}

		bme->delay_us = bme68x_delay_us;
		bme->intf_ptr = &dev_addr;
		bme->amb_temp = 30; /* The ambient temperature in deg C is used for defining the heater temperature */
	} else {
		rslt = BME68X_E_NULL_PTR;
	}

	return rslt;
}
}

HAL_StatusTypeDef HAL_I2C_IsDeviceReady(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Trials,
                                        uint32_t Timeout)
{
  uint32_t tickstart;

  __IO uint32_t I2C_Trials = 0UL;

  FlagStatus tmp1;
  FlagStatus tmp2;

  if (hi2c->State == HAL_I2C_STATE_READY)
  {
    if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) == SET)
    {
      return HAL_BUSY;
    }

    /* Process Locked */
    __HAL_LOCK(hi2c);

    hi2c->State = HAL_I2C_STATE_BUSY;
    hi2c->ErrorCode = HAL_I2C_ERROR_NONE;

    do
    {
      /* Generate Start */
      hi2c->Instance->CR2 = I2C_GENERATE_START(hi2c->Init.AddressingMode, DevAddress);

      /* No need to Check TC flag, with AUTOEND mode the stop is automatically generated */
      /* Wait until STOPF flag is set or a NACK flag is set*/
      tickstart = HAL_GetTick();

      tmp1 = __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF);
      tmp2 = __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF);

      while ((tmp1 == RESET) && (tmp2 == RESET))
      {
        if (Timeout != HAL_MAX_DELAY)
        {
          if (((HAL_GetTick() - tickstart) > Timeout) || (Timeout == 0U))
          {
            /* Update I2C state */
            hi2c->State = HAL_I2C_STATE_READY;

            /* Update I2C error code */
            hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT;

            /* Process Unlocked */
            __HAL_UNLOCK(hi2c);

            return HAL_ERROR;
          }
        }

        tmp1 = __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF);
        tmp2 = __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF);
      }

      /* Check if the NACKF flag has not been set */
      if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == RESET)
      {
        /* Wait until STOPF flag is reset */
        if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_STOPF, RESET, Timeout, tickstart) != HAL_OK)
        {
          return HAL_ERROR;
        }

        /* Clear STOP Flag */
        __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF);

        /* Device is ready */
        hi2c->State = HAL_I2C_STATE_READY;

        /* Process Unlocked */
        __HAL_UNLOCK(hi2c);

        return HAL_OK;
      }
      else
      {
        /* Wait until STOPF flag is reset */
        if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_STOPF, RESET, Timeout, tickstart) != HAL_OK)
        {
          return HAL_ERROR;
        }

        /* Clear NACK Flag */
        __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF);

        /* Clear STOP Flag, auto generated with autoend*/
        __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF);
      }

      /* Check if the maximum allowed number of trials has been reached */
      if (I2C_Trials == Trials)
      {
        /* Generate Stop */
        hi2c->Instance->CR2 |= I2C_CR2_STOP;

        /* Wait until STOPF flag is reset */
        if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_STOPF, RESET, Timeout, tickstart) != HAL_OK)
        {
          return HAL_ERROR;
        }

        /* Clear STOP Flag */
        __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF);
      }

      /* Increment Trials */
      I2C_Trials++;
    } while (I2C_Trials < Trials);

    /* Update I2C state */
    hi2c->State = HAL_I2C_STATE_READY;

    /* Update I2C error code */
    hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT;

    /* Process Unlocked */
    __HAL_UNLOCK(hi2c);

    return HAL_ERROR;
  }
  else
  {
    return HAL_BUSY;
  }
}

 

 

2 REPLIES 2
Pavel A.
Evangelist III

If HAL_I2C_IsDeviceReady hangs for long time, your "HAL" timer is not ticking. Check why.

 

Graziele Rodrigues
Associate

yes, it is scoring, if it beats the time it calls error function handler.