/* * bme680.c * * Created on: Feb 11, 2020 * Author: KamilB */ #include "bme680.h" void BME680_write8(uint8_t reg, uint8_t val){ HAL_GPIO_WritePin(NSS_PORT, NSS_PIN, GPIO_PIN_RESET); reg = reg & ~0x80; uint8_t tx_buf[] = {reg, val}; HAL_SPI_Transmit(&hspi2, tx_buf, 2, HAL_MAX_DELAY); HAL_GPIO_WritePin(NSS_PORT, NSS_PIN, GPIO_PIN_SET); } int8_t BME680_read8(uint8_t reg){ HAL_GPIO_WritePin(NSS_PORT, NSS_PIN, GPIO_PIN_RESET); reg = reg|0x80; uint8_t answer; HAL_SPI_Transmit(&hspi2, ®, 1, HAL_MAX_DELAY); HAL_SPI_Receive(&hspi2, &answer, 1, HAL_MAX_DELAY); HAL_GPIO_WritePin(NSS_PORT, NSS_PIN, GPIO_PIN_SET); return answer; } uint8_t BME680_sread8(uint8_t reg){ HAL_GPIO_WritePin(NSS_PORT, NSS_PIN, GPIO_PIN_RESET); reg = reg|0x80; uint8_t answer; HAL_SPI_TransmitReceive(&hspi2, ®, &answer, 1, HAL_MAX_DELAY); HAL_GPIO_WritePin(NSS_PORT, NSS_PIN, GPIO_PIN_SET); return answer; } int8_t BME680_begin(){ int8_t rslt=0; for(int i=0;i<15;i++){ data_buff[i] = 0; } amb_temp = 15; rslt = BME680_soft_reset(); if(rslt==1){ rslt =BME680_read8(ID_REG); if(rslt==BME680_ID){ rslt =BME680_calib_data(); return rslt; } else{ return 0; } }else{ return 0; } } int8_t BME680_calib_data(){ uint8_t coeff_array[BME680_COEFF_SIZE]={0}; uint8_t temp_var = 0; for(int i=0;i> BME680_HUM_REG_SHIFT_VAL)); par_h3 = (int8_t) coeff_array[BME680_H3_REG]; par_h4 = (int8_t) coeff_array[BME680_H4_REG]; par_h5 = (int8_t) coeff_array[BME680_H5_REG]; par_h6 = (uint8_t) coeff_array[BME680_H6_REG]; par_h7 = (int8_t) coeff_array[BME680_H7_REG]; par_gh1 = (int8_t) coeff_array[BME680_GH1_REG]; par_gh2 = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_GH2_MSB_REG], coeff_array[BME680_GH2_LSB_REG])); par_gh3 = (int8_t) coeff_array[BME680_GH3_REG]; temp_var= BME680_read8(BME680_ADDR_RES_HEAT_RANGE_ADDR); res_heat_range = ((temp_var&BME680_RHRANGE_MSK)/16); temp_var = BME680_read8(BME680_ADDR_RES_HEAT_VAL_ADDR); res_heat_val = (int8_t)temp_var; temp_var = BME680_read8(BME680_ADDR_RANGE_SW_ERR_ADDR); range_sw_err = ((int8_t)temp_var & (int8_t)BME680_RSERROR_MSK) / 16; return 1; } uint8_t BME680_sample(){ /* par_g[0] = BME680_read8(0xED); par_g[1] = BME680_read8(0xEC); par_g[1] <<= 8; par_g[1] += BME680_read8(0xEB); par_g[2] = BME680_read8(0xEE); res_heat_range = BME680_read8(0x02); res_heat_range <<=2; res_heat_range >>=6; res_heat_val = (int8_t)BME680_read8(0x00); double var[5]; var[0] = ((double)par_g[0]/16.0)+49.0; var[1] = (((double)par_g[1]/32768.0)*0.0005)+0.00235; var[2] = (double)par_g[2]/1024.0; var[3] = var[0]*(1.0+(var[1]*(double)300)); var[4] = var[3] + (var[2]*18.0); uint8_t res_heat_x = (uint8_t)(3.4*((var[4]*(4.0/(4.0+(double)res_heat_range))*(1.0/(1.0+((double)res_heat_val*0.002))))-25)); BME680_write8(GAS_WAIT0_REG, 0x87); BME680_write8(RES_HEAT0_REG, res_heat_x); BME680_write8(CTRL_GAS1_REG, 0x10); BME680_write8(CTRL_GAS0_REG, 0x00); BME680_write8(CTRL_HUM_REG, 0x01); BME680_write8(CONFIG_REG, 0x08); BME680_write8(CTRL_MEAS_REG, 0x55); res_heat_x = BME680_read8(GAS_WAIT0_REG); return res_heat_x; */ } uint8_t BME680_readgas(){ uint8_t valid = BME680_read8(GAS_R_LSB_REG); return valid; } int8_t BME680_soft_reset(){ BME680_write8(RESET_REG, SOFT_RESET_MODE); HAL_Delay(BME680_RESET_PERIOD); return 1; } void BME680_set_gas_heater(uint16_t temp, uint16_t dur){ heater_temp = temp; heater_dur = dur; if(temp==0||dur==0){ heater_ctrl = BME680_DISABLE_HEATER; run_gas = BME680_DISABLE_GAS_MEAS; _gas_enabled = false; }else{ heater_ctrl = BME680_ENABLE_HEATER; run_gas = BME680_ENABLE_GAS_MEAS; _gas_enabled = true; } } bool BME680_set_temperature_oversampling(uint8_t oversample){ if(oversample>BME680_OS_16X) return false; os_temp = oversample; if(oversample == BME680_OS_NONE){ _temp_enabled = false; }else{ _temp_enabled = true; } return true; } bool BME680_set_humidity_oversampling(uint8_t oversample){ if(oversample>BME680_OS_16X) return false; os_hum = oversample; if(oversample==BME680_OS_NONE){ _hum_enabled = false; }else{ _hum_enabled = true; } return true; } bool BME680_set_pressure_oversampling(uint8_t oversample){ if(oversample>BME680_OS_16X) return false; os_press = oversample; if(oversample == BME680_OS_NONE){ _press_enabled = false; }else{ _press_enabled = true; } return true; } bool BME680_set_IIR_filter_size(uint8_t filtersize){ if(filtersize>BME680_FILTER_SIZE_127) return false; filter= filtersize; if(filtersize==BME680_FILTER_SIZE_0){ _filter_enabled = false; }else{ _filter_enabled = true; } return true; } unsigned long BME680_begin_reading(){ uint8_t set_required_settings = 0; int8_t rslt; power_mode = BME680_FORCED_MODE; if(_temp_enabled) set_required_settings |= BME680_OST_SEL; if(_hum_enabled) set_required_settings |= BME680_OSH_SEL; if(_press_enabled) set_required_settings |= BME680_OSP_SEL; if(_filter_enabled) set_required_settings |= BME680_FILTER_SEL; if(_gas_enabled) set_required_settings |= BME680_GAS_SENSOR_SEL; rslt = BME680_set_sensor_settings(set_required_settings); if(rslt!=1) return 0; rslt = BME680_set_sensor_mode(); if(rslt!=1)return 0; uint16_t meas_period; BME680_get_profile_dur(&meas_period); return (unsigned long) meas_period; } int8_t BME680_set_sensor_settings(uint16_t desired_settings){ int8_t rslt; uint8_t reg_addr, data=0, count=0, reg_array[BME680_REG_BUFFER_LENGTH] = {0}, data_array[BME680_REG_BUFFER_LENGTH]={0}, intended_power_mode = power_mode; if(desired_settings&BME680_GAS_MEAS_SEL){ rslt = BME680_set_gas_config(); } power_mode = BME680_SLEEP_MODE; if(rslt==1){ rslt = BME680_set_sensor_mode(); } if(desired_settings&BME680_FILTER_SEL){ rslt = BME680_boundary_check(&filter, BME680_FILTER_SIZE_0, BME680_FILTER_SIZE_127); if(rslt==1){ reg_addr = BME680_CONF_ODR_FILT_ADDR; data = BME680_read8(reg_addr); if(desired_settings&BME680_FILTER_SEL){ data =BME680_SET_BITS(data, BME680_FILTER, filter); } reg_array[count] = reg_addr; data_array[count] = data; count++; } } if(desired_settings &BME680_HCNTRL_SEL){ rslt = BME680_boundary_check(&heater_ctrl, BME680_ENABLE_HEATER, BME680_DISABLE_HEATER); if(rslt==1){ reg_addr = BME680_CONF_HEAT_CTRL_ADDR; data = BME680_read8(reg_addr); data = BME680_SET_BITS_POS_0(data, BME680_HCTRL, heater_ctrl); reg_array[count] = reg_addr; data_array[count] = data; count++; } } if(desired_settings &(BME680_OST_SEL|BME680_OSP_SEL)){ rslt = BME680_boundary_check(&os_temp, BME680_OS_NONE, BME680_OS_16X); if(rslt==1){ reg_addr = BME680_CONF_T_P_MODE_ADDR; data = BME680_read8(reg_addr); if(desired_settings & BME680_OST_SEL){ data = BME680_SET_BITS(data, BME680_OST, os_temp); } if(desired_settings&BME680_OSP_SEL){ data = BME680_SET_BITS(data, BME680_OSP, os_press); } reg_array[count] = reg_addr; data_array[count] = data; count++; } } if(desired_settings &BME680_OSH_SEL){ rslt = BME680_boundary_check(&os_hum, BME680_OS_NONE, BME680_OS_16X); if(rslt==1){ reg_addr = BME680_CONF_OS_H_ADDR; data = BME680_read8(reg_addr); data = BME680_SET_BITS_POS_0(data, BME680_OSH, os_hum); reg_array[count] = reg_addr; data_array[count] = data; count++; } } if(desired_settings &(BME680_RUN_GAS_SEL|BME680_NBCONV_SEL)){ rslt = BME680_boundary_check(&run_gas, BME680_RUN_GAS_DISABLE, BME680_RUN_GAS_ENABLE); if(rslt==1){ rslt = BME680_boundary_check(&nb_conv, BME680_NBCONV_MIN, BME680_NBCONV_MAX); if(rslt==1){ reg_addr = BME680_CONF_ODR_RUN_GAS_NBC_ADDR; data = BME680_read8(reg_addr); if(desired_settings&BME680_RUN_GAS_SEL){ data = BME680_SET_BITS(data, BME680_RUN_GAS, run_gas); } if(desired_settings & BME680_NBCONV_SEL){ data = BME680_SET_BITS_POS_0(data, BME680_NBCONV, nb_conv); } reg_array[count] = reg_addr; data_array[count] = data; count++; } } } if(rslt==1){ for(int i=0; i400) temp = 400; var[0] = (((int32_t)amb_temp*par_gh3)/1000)*256; var[1] = (par_gh1+784)*(((((par_gh2+154009)*temp*5)/100)+3276800)/10); var[2] = var[0] +(var[1]/2); var[3] = (var[2]/(res_heat_range+4)); var[4] = (131*res_heat_val)+65536; heater_res_x100 = (int32_t)(((var[3]/var[4])-250)*34); heater_res = (uint8_t)((heater_res_x100+50)/100); return heater_res; } uint8_t BME680_calc_heater_dur(uint16_t dur){ uint8_t durval, factor=0; if(dur>=0xFC0){ durval = 0xFF; }else{ while(dur>0x3F){ dur = dur / 4; factor += 1; } durval = (uint8_t)(dur+(factor*64)); } return durval; } int8_t BME680_set_sensor_mode(){ uint8_t tmp_pow_mode, pow_mode=0, reg_addr=BME680_CONF_T_P_MODE_ADDR; do{ tmp_pow_mode = BME680_read8(BME680_CONF_T_P_MODE_ADDR); pow_mode = (tmp_pow_mode&BME680_MODE_MSK); if(pow_mode!=BME680_SLEEP_MODE){ tmp_pow_mode = tmp_pow_mode &(~BME680_MODE_MSK); BME680_write8(reg_addr, tmp_pow_mode); HAL_Delay(BME680_POLL_PERIOD_MS); } }while(pow_mode!=BME680_SLEEP_MODE); if(power_mode !=BME680_SLEEP_MODE){ tmp_pow_mode = (tmp_pow_mode & ~BME680_MODE_MSK)|(power_mode&BME680_MODE_MSK); BME680_write8(reg_addr, tmp_pow_mode); } return 1; } int8_t BME680_boundary_check(uint8_t *value, uint8_t min, uint8_t max){ if(value!=NULL){ if(*valuemax){ *value = max; } }else{ return 0; } return 1; } void BME680_get_profile_dur(uint16_t *duration){ uint32_t tph_dur, meas_cycles; uint8_t os_to_meas_cycles[6] = {0, 1, 2, 4, 8, 16}; meas_cycles = os_to_meas_cycles[os_temp]; meas_cycles += os_to_meas_cycles[os_press]; meas_cycles += os_to_meas_cycles[os_hum]; tph_dur = meas_cycles * UINT32_C(1963); tph_dur += UINT32_C(477 * 4); /* TPH switching duration */ tph_dur += UINT32_C(477 * 5); /* Gas measurement duration */ tph_dur += UINT32_C(500); /* Get it to the closest whole number.*/ tph_dur /= UINT32_C(1000); /* Convert to ms */ tph_dur += UINT32_C(1); *duration = (uint16_t)tph_dur; if(run_gas){ *duration += heater_dur; } } bool BME680_end_reading(){ unsigned long meas_end = BME680_begin_reading(); if(meas_end==0){ return false; } HAL_Delay(meas_end); if(BME680_read_field_data()==1){ return true; }else{ return false; } } uint32_t BME680_read_gas_data(){ uint8_t gas_range; uint16_t adc_gas_res; int64_t var1; uint64_t var2; int64_t var3; uint32_t calc_gas_res; uint32_t lookupTable1[16] = { UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2126008810), UINT32_C(2147483647), UINT32_C(2130303777), UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2143188679), UINT32_C(2136746228), UINT32_C(2147483647), UINT32_C(2126008810), UINT32_C(2147483647), UINT32_C(2147483647) }; /**Look up table 2 for the possible gas range values */ uint32_t lookupTable2[16] = { UINT32_C(4096000000), UINT32_C(2048000000), UINT32_C(1024000000), UINT32_C(512000000), UINT32_C(255744255), UINT32_C(127110228), UINT32_C(64000000), UINT32_C(32258064), UINT32_C(16016016), UINT32_C(8000000), UINT32_C(4000000), UINT32_C(2000000), UINT32_C(1000000), UINT32_C(500000), UINT32_C(250000), UINT32_C(125000) }; adc_gas_res = (uint16_t)((uint32_t)data_buff[13]*4|(((uint32_t)data_buff[14])/64)); gas_range = data_buff[14]& BME680_GAS_RANGE_MSK; var1 = (int64_t)((1340+(5*(int64_t)range_sw_err))*((int64_t)lookupTable1[gas_range]))>>16; var2 = (((int64_t)((int64_t)adc_gas_res<<15)-(int64_t)(16777216))+var1); var3 = (((int64_t)lookupTable2[gas_range]*(int64_t)var1)>>9); if(status&BME680_HEAT_STAB_MSK){ calc_gas_res = (uint32_t)((var3+((int64_t)var2>>1))/(int64_t)var2); }else{ calc_gas_res = 0; } return calc_gas_res; } int8_t BME680_read_field_data(){ uint8_t tries = 10; do{ for(int i=0; i