Bosch Sensortec Community

    cancel
    Showing results for 
    Search instead for 
    Did you mean: 
    SOLVED

    BME680 with STM32F103C8

    Member

    BME680 with STM32F103C8

    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).

     

    7 REPLIES 7
    Community Moderator

    Re: BME680 with STM32F103C8

    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

     

     

    Highlighted
    Community Moderator

    Re: BME680 with STM32F103C8


    @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?

    Member

    Re: BME680 with STM32F103C8

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

     

    Member

    Re: BME680 with STM32F103C8

    Screenshot of communication wih BME680

    Icon--AD-black-48x48Icon--address-consumer-data-black-48x48Icon--appointment-black-48x48Icon--back-left-black-48x48Icon--calendar-black-48x48Icon--center-alignedIcon--Checkbox-checkIcon--clock-black-48x48Icon--close-black-48x48Icon--compare-black-48x48Icon--confirmation-black-48x48Icon--dealer-details-black-48x48Icon--delete-black-48x48Icon--delivery-black-48x48Icon--down-black-48x48Icon--download-black-48x48Ic-OverlayAlertIcon--externallink-black-48x48Icon-Filledforward-right_adjustedIcon--grid-view-black-48x48IC_gd_Check-Circle170821_Icons_Community170823_Bosch_Icons170823_Bosch_Icons170821_Icons_CommunityIC-logout170821_Icons_Community170825_Bosch_Icons170821_Icons_CommunityIC-shopping-cart2170821_Icons_CommunityIC-upIC_UserIcon--imageIcon--info-i-black-48x48Icon--left-alignedIcon--Less-minimize-black-48x48Icon-FilledIcon--List-Check-grennIcon--List-Check-blackIcon--List-Cross-blackIcon--list-view-mobile-black-48x48Icon--list-view-black-48x48Icon--More-Maximize-black-48x48Icon--my-product-black-48x48Icon--newsletter-black-48x48Icon--payment-black-48x48Icon--print-black-48x48Icon--promotion-black-48x48Icon--registration-black-48x48Icon--Reset-black-48x48Icon--right-alignedshare-circle1Icon--share-black-48x48Icon--shopping-bag-black-48x48Icon-shopping-cartIcon--start-play-black-48x48Icon--store-locator-black-48x48Ic-OverlayAlertIcon--summary-black-48x48tumblrIcon-FilledvineIc-OverlayAlertwhishlist