07-26-2019 07:51 PM - edited 07-26-2019 07:56 PM
Hi. I am planning to use BME680 in my project but have some questions. I already downloaded sample code for BSEC and bme680 api and looked through it. But I dont understand why I must use BSEC. Is it important to use BSEC and also *.lib file for my platform or I can use only functions from bme680.c? When I compile my project in Keil MDK5 it gives a lot of errors L6406E: No space in execution regions with .ANY selector matching .....because I use in this project E-Ink display and nrf24l01.
Also I have problem in communicating with sensor. I already filled bus_write and bus_read functions:
int8_t bus_write(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data_ptr, uint16_t data_len)
{
uint16_t i;
int8_t rslt = 0; /* Return 0 for Success, non-zero for failure */
/*
* Data on the bus should be like
* |------------+---------------------|
* | I2C action | Data |
* |------------+---------------------|
* | Start | - |
* | Write | (reg_addr) |
* | Write | (reg_data[0]) |
* | Write | (....) |
* | Write | (reg_data[len - 1]) |
* | Stop | - |
* |------------+---------------------|
*/
I2C_AcknowledgeConfig(I2C_PORT,ENABLE); // Enable I2C acknowledgment
I2C_GenerateSTART(I2C_PORT,ENABLE);
while (!I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_MODE_SELECT)){}; // Wait for EV5
UART1_Transmit_string("\r\nStart sent");
I2C_Send7bitAddress(I2C_PORT,dev_addr,I2C_Direction_Transmitter); // Send slave address
UART1_Transmit_string("\r\nDev_addr sent");
while (!I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)){}; // Wait for EV6
I2C_SendData(I2C_PORT,reg_addr); // Send register address
UART1_Transmit_string("\r\nReg_addr sent");
while (!I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_BYTE_TRANSMITTED)){}; // Wait for EV8
for(i=0; i < data_len; i++)
{
I2C_SendData(I2C_PORT, reg_data_ptr[i]); // Send all bytes
while (!I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_BYTE_TRANSMITTED)){}; // Wait for EV8
}
I2C_GenerateSTOP(I2C_PORT,ENABLE);
return rslt;
}
int8_t bus_read(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data_ptr, uint16_t data_len)
{
uint16_t i =0;
uint8_t status = 0;
I2C_AcknowledgeConfig(I2C_PORT,ENABLE); // Enable I2C acknowledgment
I2C_GenerateSTART(I2C_PORT,ENABLE);
while (!I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_MODE_SELECT)); // Wait for EV5
I2C_Send7bitAddress(I2C_PORT,dev_addr,I2C_Direction_Transmitter); // Send slave address 0x76
while (!I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); // Wait for EV6
I2C_SendData(I2C_PORT,reg_addr); // Send register address
while (!I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_BYTE_TRANSMITTED)); // Wait for EV8
I2C_GenerateSTOP(I2C_PORT,ENABLE); // Send STOP condition
delay_ms_sys(1);
I2C_GenerateSTART(I2C_PORT,ENABLE); // Send repeated START condition (aka Re-START)
while (!I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_MODE_SELECT)); // Wait for EV5
I2C_Send7bitAddress(I2C_PORT,dev_addr,I2C_Direction_Receiver); // Send slave address for READ
while (!I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); // Wait for EV6
while (!I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_BYTE_RECEIVED)); // Wait for EV7 (Byte received from slave)
status = I2C_CheckEvent(I2C_PORT, I2C_EVENT_MASTER_BYTE_RECEIVED);
//status = I2C_CheckEvent(I2C_PORT, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED);
for(i=0; i < data_len; i++)
{
reg_data_ptr[i] = I2C_ReceiveData(I2C_PORT); // Receive high byte
while (!I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_BYTE_RECEIVED)); // Wait for EV7 (Byte received from slave)
}
I2C_GenerateSTOP(I2C_PORT,ENABLE); // Send STOP condition
/* Return 0 for Success, non-zero for failure */
if(status == 1)return 0;
else return status;
}
but sensor did not answering(I checked it with logic analyzer). It stops after slave address sent(0x76).
Solved! Go to Solution.
07-29-2019 08:10 AM
Hi,
You cloud use BME680 only by using BME680 API.
Please configure as the following file :
https://github.com/BoschSensortec/BME680_driver/blob/master/README.md
07-29-2019 01:50 PM
@Ruslan wrote:
But I dont understand why I must use BSEC. Is it important to use BSEC and also *.lib file for my platform or I can use only functions from bme680.c?
BME680's gas sensor alone (using only its sensor API) will output a raw Gag Resistance signal (in Ω). Using the BSEC library will process all raw sensors signals into relevant virtuals sensors such as our IAQ index (and more). By not using BSEC you will have to make your own use/interpretation of the raw resistance signal.
@Ruslan wrote:
When I compile my project in Keil MDK5 it gives a lot of errors L6406E: No space in execution regions with .ANY selector matching .....because I use in this project E-Ink display and nrf24l01.
This seems indeed like memory limitations from your microcontroller. This could happen based on how many external components the same MCU is processing/handling, also RTOS envrionments can be consuming significant memory too. To figure out if this could be solved with your current MCU, one could have a look at the linker map file, or find the linker script and see if things could still be tweaked to fit all your components.
@Ruslan wrote:
Also I have problem in communicating with sensor. I already filled bus_write and bus_read functions:
[...]
but sensor did not answering(I checked it with logic analyzer). It stops after slave address sent(0x76).
Would you be able to share more details about the sensor's schematic/connections, your sensor API configuration/settings, ideally even snippet of your logic analyzer?
07-31-2019 01:18 PM - edited 07-31-2019 01:20 PM
Thanks for answers. About using BSEC I already understood for what purpose it was made. For first time I will try to work only with BME api. But sensor still not working. On the same bus I have SHT20, I attached it to check if I2C bus is working. And it working but BME does not. I cant attach screensot from logic analyzer window now, but it is clearly seen that MCU sends start condition, then address 0x76(SDO pin connected to GND) but ther is no ACK from BME. Later I will attach screenshot. For the first time I desoldered BME from chinese module (CJMCU-680) and soldered it to my pcb. Sensor did not answered. I decided that I killed sensor during soldering. Then I took the same new module and connected it with my pcb with short wires but result is the same, no answer from bme. For pullup I used 4,7 k resistors.
Some code:
//================================ BUS WRITE ===========================================//
/*!
* @brief Write operation in I2C
*
* param[in] dev_addr I2C device address
* param[in] reg_addr register address
* param[in] reg_data_ptr pointer to the data to be written
* param[in] data_len number of bytes to be written
*
* @return result of the bus communication function
*/
int8_t bus_write(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data_ptr, uint16_t data_len)
{
uint16_t i;
int8_t rslt = 0; /* Return 0 for Success, non-zero for failure */
/*
* Data on the bus should be like
* |------------+---------------------|
* | I2C action | Data |
* |------------+---------------------|
* | Start | - |
* | Write | (reg_addr) |
* | Write | (reg_data[0]) |
* | Write | (....) |
* | Write | (reg_data[len - 1]) |
* | Stop | - |
* |------------+---------------------|
*/
I2C_AcknowledgeConfig(I2C1,ENABLE); // Enable I2C acknowledgment
I2C_GenerateSTART(I2C1,ENABLE);
while (!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT)){}; // Wait for EV5
UART1_Transmit_string("\r\nStart sent");
I2C_Send7bitAddress(I2C1,dev_addr,I2C_Direction_Transmitter); // Send slave address (dev_addr| 0x01)
while (!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)){}; // Wait for EV6
UART1_Transmit_string("\r\nDev_addr sent");
I2C_SendData(I2C1,reg_addr); // Send register address
while (!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED)){}; // Wait for EV8
UART1_Transmit_string("\r\nReg_addr sent");
for(i=0; i < data_len; i++)
{
I2C_SendData(I2C1, reg_data_ptr[i]); // Send all bytes
while (!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED)){}; // Wait for EV8
}
UART1_Transmit_string("\r\nAll data sent");
I2C_GenerateSTOP(I2C1,ENABLE);
UART1_Transmit_string("\r\nStop sent");
return rslt;
}
//================================ BUS READ ===========================================//
/*!
* @brief Read operation in I2C
*
* param[in] dev_addr I2C device address
* param[in] reg_addr register address
* param[out] reg_data_ptr pointer to the memory to be used to store the read data
* param[in] data_len number of bytes to be read
*
* @return result of the bus communication function
*/
int8_t bus_read(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data_ptr, uint16_t data_len)
{
uint16_t i;
uint8_t status = 0;
/*
* Data on the bus should be like
* |------------+---------------------|
* | I2C action | Data |
* |------------+---------------------|
* | Start | - |
* | Write | (reg_addr) |
* | Stop | - |
* | Start | - |
* | Read | (reg_data[0]) |
* | Read | (....) |
* | Read | (reg_data[len - 1]) |
* | Stop | - |
* |------------+---------------------|
*/
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); // While the bus is busy
I2C_AcknowledgeConfig(I2C1,ENABLE); // Enable I2C acknowledgment
I2C_GenerateSTART(I2C1,ENABLE);
while (!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT)){}; // Wait for EV5
I2C_Send7bitAddress(I2C1,dev_addr,I2C_Direction_Transmitter); // Send slave address for write
while (!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)){}; // Wait for EV6
I2C_SendData(I2C1,reg_addr); // Send register address
while (!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED)){}; // Wait for EV8
I2C_GenerateSTART(I2C1,ENABLE); // Send repeated START condition (aka Re-START)
while (!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT)){}; // Wait for EV5
I2C_Send7bitAddress(I2C1,dev_addr,I2C_Direction_Receiver); // Send slave address for READ
while (!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)){}; // Wait for EV6
status = I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED);
for(i=0; i < data_len; i++)
{
if(i == data_len - 1) { I2C_AcknowledgeConfig(I2C1,DISABLE); }// Disable I2C acknowledgment if it is last byte to recieve
reg_data_ptr[i] = I2C_ReceiveData(I2C1); // Receive high byte
while (!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED)){}; // Wait for EV7 (Byte received from slave)
}
I2C_GenerateSTOP(I2C1,ENABLE); // Send STOP condition
/* Return 0 for Success, non-zero for failure */
if(status == 1)return 0;
else return status;
}
//===========================================================================================//
// Init I2C with Clock_Speed (in Hz)
void I2C_Port_Init(uint32_t Clock_Speed)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
// Init I2C
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE); // Enable I2C clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
I2C_DeInit(I2C1); // I2C reset to initial state
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; // I2C mode is I2C
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; // I2C fast mode duty cycle
I2C_InitStructure.I2C_OwnAddress1 = 0x00; // This device address (7-bit or 10-bit)
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; // Acknowledgment enable
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; // choose 7-bit address for acknowledgment
I2C_InitStructure.I2C_ClockSpeed = Clock_Speed;
I2C_Cmd(I2C1,ENABLE); // Enable I2C
I2C_Init(I2C1,&I2C_InitStructure); // Configure I2C
I2C_AcknowledgeConfig(I2C1, ENABLE);
while (I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY)); // Wait until I2C free
}
Using:
int main(void)
{
uint8_t set_required_settings;
uint16_t meas_period;
struct bme680_field_data data;
int8_t rslt = BME680_OK;
bme680_port_init();
BME680_On; // power on
I2C_Port_Init(100000); // init I2C
UART1_Transmit_string("\r\nI2C Init OK");
// Sensor settings
//Fixed I2C configuration
gas_sensor.dev_id = BME680_I2C_ADDR_PRIMARY; // 0x76
gas_sensor.intf = BME680_I2C_INTF;
gas_sensor.read = bus_read;
gas_sensor.write = bus_write;
gas_sensor.delay_ms = delay_ms_sys; // SysTickTimer
// amb_temp can be set to 25 prior to configuring the gas sensor
//or by performing a few temperature readings without operating the gas sensor.
gas_sensor.amb_temp = 25;
rslt = bme680_init(&gas_sensor);
if (rslt == BME680_OK)
{
sprintf(uart_buf,"\nBME680 Init OK -> result %i", rslt);
UART1_Transmit_string(uart_buf);
}
// Set the temperature, pressure and humidity settings
gas_sensor.tph_sett.os_hum = BME680_OS_2X;
gas_sensor.tph_sett.os_pres = BME680_OS_4X;
gas_sensor.tph_sett.os_temp = BME680_OS_8X;
gas_sensor.tph_sett.filter = BME680_FILTER_SIZE_3;
// Set the remaining gas sensor settings and link the heating profile
gas_sensor.gas_sett.run_gas = BME680_ENABLE_GAS_MEAS;
// Create a ramp heat waveform in 3 steps
gas_sensor.gas_sett.heatr_temp = 320; // degree Celsius
gas_sensor.gas_sett.heatr_dur = 150; // milliseconds
// Select the power mode
// Must be set before writing the sensor configuration
gas_sensor.power_mode = BME680_FORCED_MODE;
// Set the required sensor settings needed
set_required_settings = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_FILTER_SEL | BME680_GAS_SENSOR_SEL;
// Set the desired sensor configuration
rslt = bme680_set_sensor_settings(set_required_settings, &gas_sensor);
if (rslt == BME680_OK)
{
sprintf(uart_buf,"\nBME680 set sensor settings OK ->result %i", rslt);
UART1_Transmit_string(uart_buf);
}
// Set the power mode
rslt = bme680_set_sensor_mode(&gas_sensor);
if (rslt == BME680_OK)
{
sprintf(uart_buf,"\nBME680 set sensor mode OK ->result %i", rslt);
UART1_Transmit_string(uart_buf);
}
// Get the profile duration of the sensor
bme680_get_profile_dur(&meas_period, &gas_sensor);
while (1)
{
delay_ms_sys(meas_period); // Delay till the measurement is ready
rslt = bme680_get_sensor_data(&data, &gas_sensor);
sprintf(uart_buf,"T: %.2f degC, P: %.2f hPa, H %.2f %%rH ", data.temperature / 100.0f, data.pressure / 100.0f, data.humidity / 1000.0f );
UART1_Transmit_string(uart_buf);
if(data.status & BME680_GASM_VALID_MSK) // Avoid using measurements from an unstable heating setup
{
sprintf(uart_buf,", G: %d ohms", data.gas_resistance);
UART1_Transmit_string(uart_buf);
}
UART1_Transmit_string("\r\n");
// Trigger the next measurement if you would like to read data out continuously
if (gas_sensor.power_mode == BME680_FORCED_MODE) {
rslt = bme680_set_sensor_mode(&gas_sensor);
}
07-31-2019 10:24 PM - edited 07-31-2019 10:26 PM