Skip to main content
Associate
August 10, 2023
Question

code stop in function HAL_I2C_IsDeviceReady

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

 

 

    This topic has been closed for replies.

    2 replies

    Pavel A.
    August 10, 2023

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

     

    Associate
    August 11, 2023

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