diff --git a/Include/bme280.h b/Include/bme280.h new file mode 100644 --- /dev/null +++ b/Include/bme280.h @@ -0,0 +1,85 @@ +#ifndef _BME280_H_ +#define _BME280_H_ + +#include +#include +#include "stm32f0xx_hal.h" + +#define BME280_I2C_ADDR 0b11101100 + +#define PIN_BME280_SDA GPIO_PIN_7 +#define PIN_BME280_SCL GPIO_PIN_6 +#define PORT_BME280 GPIOB + + +//Register names +#define BME280_DIG_T1_LSB_REG 0x88 +#define BME280_DIG_T1_MSB_REG 0x89 +#define BME280_DIG_T2_LSB_REG 0x8A +#define BME280_DIG_T2_MSB_REG 0x8B +#define BME280_DIG_T3_LSB_REG 0x8C +#define BME280_DIG_T3_MSB_REG 0x8D +#define BME280_DIG_P1_LSB_REG 0x8E +#define BME280_DIG_P1_MSB_REG 0x8F +#define BME280_DIG_P2_LSB_REG 0x90 +#define BME280_DIG_P2_MSB_REG 0x91 +#define BME280_DIG_P3_LSB_REG 0x92 +#define BME280_DIG_P3_MSB_REG 0x93 +#define BME280_DIG_P4_LSB_REG 0x94 +#define BME280_DIG_P4_MSB_REG 0x95 +#define BME280_DIG_P5_LSB_REG 0x96 +#define BME280_DIG_P5_MSB_REG 0x97 +#define BME280_DIG_P6_LSB_REG 0x98 +#define BME280_DIG_P6_MSB_REG 0x99 +#define BME280_DIG_P7_LSB_REG 0x9A +#define BME280_DIG_P7_MSB_REG 0x9B +#define BME280_DIG_P8_LSB_REG 0x9C +#define BME280_DIG_P8_MSB_REG 0x9D +#define BME280_DIG_P9_LSB_REG 0x9E +#define BME280_DIG_P9_MSB_REG 0x9F +#define BME280_DIG_H1_REG 0xA1 +#define BME280_CHIP_ID_REG 0xD0 //Chip ID +#define BME280_RST_REG 0xE0 //Softreset Reg +#define BME280_DIG_H2_LSB_REG 0xE1 +#define BME280_DIG_H2_MSB_REG 0xE2 +#define BME280_DIG_H3_REG 0xE3 +#define BME280_DIG_H4_MSB_REG 0xE4 +#define BME280_DIG_H4_LSB_REG 0xE5 +#define BME280_DIG_H5_MSB_REG 0xE6 +#define BME280_DIG_H6_REG 0xE7 +#define BME280_CTRL_HUMIDITY_REG 0xF2 //Ctrl Humidity Reg +#define BME280_STAT_REG 0xF3 //Status Reg +#define BME280_CTRL_MEAS_REG 0xF4 //Ctrl Measure Reg +#define BME280_CONFIG_REG 0xF5 //Configuration Reg +#define BME280_PRESSURE_MSB_REG 0xF7 //Pressure MSB +#define BME280_PRESSURE_LSB_REG 0xF8 //Pressure LSB +#define BME280_PRESSURE_XLSB_REG 0xF9 //Pressure XLSB +#define BME280_TEMPERATURE_MSB_REG 0xFA //Temperature MSB +#define BME280_TEMPERATURE_LSB_REG 0xFB //Temperature LSB +#define BME280_TEMPERATURE_XLSB_REG 0xFC //Temperature XLSB +#define BME280_HUMIDITY_MSB_REG 0xFD //Humidity MSB +#define BME280_HUMIDITY_LSB_REG 0xFE //Humidity LSB + +bool bme280_init(void); +void bme280_update(void); +void bme280_update_pressure(void); +void bme280_update_temperature(void); +void bme280_update_humidity(void); +int32_t bme280_get_pressure(void); +int32_t bme280_get_temperature(void); +int32_t bme280_get_humidity(void); +int32_t bme280_read_pressure_raw(void); +int32_t bme280_read_temperature_raw(void); +int32_t bme280_read_humidity_raw(void); +int32_t bme280_read_pressure_raw(void); +int32_t bme280_read_temperature_raw(void); +int32_t bme280_read_humidity_raw(void); +uint8_t bme280_read_byte(uint8_t register_address); +void bme280_read(uint8_t register_address, uint8_t* data, uint8_t length); +void bme280_write(uint8_t register_address, uint8_t data); +int32_t bme280_convert_temperature(int32_t adc_T); +uint32_t bme280_convert_pressure(int32_t adc_P); +uint32_t bme280_convert_humidity(int32_t adc_H); +I2C_HandleTypeDef* bme280_get_i2c_handle(void); + +#endif /* _BME280_H_ */ diff --git a/Libraries/aprs/aprs.c b/Libraries/aprs/aprs.c --- a/Libraries/aprs/aprs.c +++ b/Libraries/aprs/aprs.c @@ -24,7 +24,8 @@ #include #include "config.h" -#include "pressure.h" +//#include "pressure.h" +#include "bme280.h" #include "aprs.h" #include "gps.h" //#include "gps.h" @@ -80,11 +81,15 @@ void aprs_send(void) ax25_send_string(tmpBuffer); // Pressure - snprintf(tmpBuffer, 128, "%d,", pressure_getpressure()); + snprintf(tmpBuffer, 128, "%d,", bme280_get_pressure()); ax25_send_string(tmpBuffer); // Temperature - snprintf(tmpBuffer, 128, "%d,", pressure_gettemp()); + snprintf(tmpBuffer, 128, "%d,", bme280_get_temperature()); + ax25_send_string(tmpBuffer); + + // Humidity + snprintf(tmpBuffer, 128, "%d,", bme280_get_humidity()); ax25_send_string(tmpBuffer); // HDOP diff --git a/Source/bme280.c b/Source/bme280.c new file mode 100644 --- /dev/null +++ b/Source/bme280.c @@ -0,0 +1,220 @@ +#include "bme280.h" +#include "stm32f0xx_hal.h" +#include "config.h" + +static uint16_t dig_T1; +static int16_t dig_T2; +static int16_t dig_T3; + +static uint16_t dig_P1; +static int16_t dig_P2; +static int16_t dig_P3; +static int16_t dig_P4; +static int16_t dig_P5; +static int16_t dig_P6; +static int16_t dig_P7; +static int16_t dig_P8; +static int16_t dig_P9; + +static uint8_t dig_H1; +static int16_t dig_H2; +static uint8_t dig_H3; +static int16_t dig_H4; +static int16_t dig_H5; +static uint8_t dig_H6; + +static int16_t pressure; +static int16_t temperature; +static int16_t humidity; + +static I2C_HandleTypeDef hi2c1; + + +// Initialize the BME280 PTU on I2C +bool bme280_init(void) +{ + GPIO_InitTypeDef GPIO_InitStruct; + + // I2C Pins + GPIO_InitStruct.Pin = PIN_BME280_SCL|PIN_BME280_SDA; + GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; + GPIO_InitStruct.Pull = GPIO_PULLUP; + GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF1_I2C1; + HAL_GPIO_Init(PORT_BME280, &GPIO_InitStruct); + + // Initialize I2C peripheral + __I2C1_CLK_ENABLE(); + hi2c1.Instance = I2C1; + hi2c1.Init.Timing = 0x00108EFB; + hi2c1.Init.OwnAddress1 = 0x0; + hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; + hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLED; + hi2c1.Init.OwnAddress2 = 0; + hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK; + hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLED; + hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLED; + volatile HAL_StatusTypeDef res = HAL_I2C_Init(&hi2c1); + + // Configure Analog filter + res = HAL_I2CEx_AnalogFilter_Config(&hi2c1, I2C_ANALOGFILTER_ENABLED); + + // Enable I2C interrupt + HAL_NVIC_SetPriority(I2C1_IRQn, 7, 4); + HAL_NVIC_EnableIRQ(I2C1_IRQn); + + + volatile uint8_t result = bme280_read_byte(BME280_CHIP_ID_REG); + + + if (result != 0x60) + { + return false; + } + + bme280_write(BME280_CTRL_MEAS_REG, 0x00); + bme280_write(BME280_CONFIG_REG, 0b01100000); // 4hz sampling rate + bme280_write(BME280_CTRL_HUMIDITY_REG, 0x01); //0b00000001, oversample*1 + bme280_write(BME280_CTRL_MEAS_REG, 0x27); //0b00100111 + + + //calibrate + + dig_T1 = ((uint16_t)((bme280_read_byte(BME280_DIG_T1_MSB_REG) << 8) + bme280_read_byte(BME280_DIG_T1_LSB_REG))); + dig_T2 = ((int16_t)((bme280_read_byte(BME280_DIG_T2_MSB_REG) << 8) + bme280_read_byte(BME280_DIG_T2_LSB_REG))); + dig_T3 = ((int16_t)((bme280_read_byte(BME280_DIG_T3_MSB_REG) << 8) + bme280_read_byte(BME280_DIG_T3_LSB_REG))); + + dig_P1 = ((uint16_t)((bme280_read_byte(BME280_DIG_P1_MSB_REG) << 8) + bme280_read_byte(BME280_DIG_P1_LSB_REG))); + dig_P2 = ((int16_t)((bme280_read_byte(BME280_DIG_P2_MSB_REG) << 8) + bme280_read_byte(BME280_DIG_P2_LSB_REG))); + dig_P3 = ((int16_t)((bme280_read_byte(BME280_DIG_P3_MSB_REG) << 8) + bme280_read_byte(BME280_DIG_P3_LSB_REG))); + dig_P4 = ((int16_t)((bme280_read_byte(BME280_DIG_P4_MSB_REG) << 8) + bme280_read_byte(BME280_DIG_P4_LSB_REG))); + dig_P5 = ((int16_t)((bme280_read_byte(BME280_DIG_P5_MSB_REG) << 8) + bme280_read_byte(BME280_DIG_P5_LSB_REG))); + dig_P6 = ((int16_t)((bme280_read_byte(BME280_DIG_P6_MSB_REG) << 8) + bme280_read_byte(BME280_DIG_P6_LSB_REG))); + dig_P7 = ((int16_t)((bme280_read_byte(BME280_DIG_P7_MSB_REG) << 8) + bme280_read_byte(BME280_DIG_P7_LSB_REG))); + dig_P8 = ((int16_t)((bme280_read_byte(BME280_DIG_P8_MSB_REG) << 8) + bme280_read_byte(BME280_DIG_P8_LSB_REG))); + dig_P9 = ((int16_t)((bme280_read_byte(BME280_DIG_P9_MSB_REG) << 8) + bme280_read_byte(BME280_DIG_P9_LSB_REG))); + + dig_H1 = ((uint8_t)(bme280_read_byte(BME280_DIG_H1_REG))); + dig_H2 = ((int16_t)((bme280_read_byte(BME280_DIG_H2_MSB_REG) << 8) + bme280_read_byte(BME280_DIG_H2_LSB_REG))); + dig_H3 = ((uint8_t)(bme280_read_byte(BME280_DIG_H3_REG))); + dig_H4 = ((int16_t)((bme280_read_byte(BME280_DIG_H4_MSB_REG) << 4) + (bme280_read_byte(BME280_DIG_H4_LSB_REG) & 0x0F))); + dig_H5 = ((int16_t)((bme280_read_byte(BME280_DIG_H5_MSB_REG) << 4) + ((bme280_read_byte(BME280_DIG_H4_LSB_REG) >> 4) & 0x0F))); + dig_H6 = ((uint8_t)bme280_read_byte(BME280_DIG_H6_REG)); + + return true; +} + + +// Acquire new readings from sensor and update values in RAM +void bme280_update(void) +{ + uint8_t result[8]; + bme280_read(BME280_PRESSURE_MSB_REG, result, 8); + + pressure = bme280_convert_pressure(result[0] << 12 | result[1] << 4 | (result[2] & 0xf0) << 0) / 256 / 10; // convert to mBar/hPa + temperature = bme280_convert_temperature(result[3] << 12 | result[4] << 4 | (result[5] & 0xf0) << 0); // 0.01C + humidity = bme280_convert_humidity(result[6] << 8 | result[7] << 0) / 1024; // 0.01% RH +} + + +// returns pressure in mb with 0.1mb resolution +int32_t bme280_get_pressure(void) +{ + return pressure; +} + +// returns temperature in DegC with 0.01 DegC resolution +int32_t bme280_get_temperature(void) +{ + + return temperature; +} + +// returns humidity in %RH with 0.01% resolution +int32_t bme280_get_humidity(void) +{ + + return humidity; +} + + + + +void bme280_read(uint8_t register_address, uint8_t* data, uint8_t length) +{ + HAL_I2C_Mem_Read(&hi2c1, BME280_I2C_ADDR, register_address, 1, data, length, 500); +} + +uint8_t bme280_read_byte(uint8_t register_address) +{ + uint8_t result; + bme280_read(register_address, &result, 1); + return result; +} + +void bme280_write(uint8_t register_address, uint8_t data) +{ + //register_address &= 0x7F; + uint8_t data_arr[1]; + data_arr[0] = data; + HAL_I2C_Mem_Write(&hi2c1, BME280_I2C_ADDR, register_address, 1, data_arr, 1, 500); +} + +// Returns temperature in DegC, resolution is 0.01 DegC. Output value of “5123” equals 51.23 DegC. +// t_fine carries fine temperature as global value +int32_t t_fine; +int32_t bme280_convert_temperature(int32_t adc_T) +{ + int32_t var1, var2, T; + var1 = ((((adc_T>>3) - ((int32_t)dig_T1<<1))) * ((int32_t)dig_T2)) >> 11; + var2 = (((((adc_T>>4) - ((int32_t)dig_T1)) * ((adc_T>>4) - ((int32_t)dig_T1))) >> 12) * + ((int32_t)dig_T3)) >> 14; + t_fine = var1 + var2; + T = (t_fine * 5 + 128) >> 8; + return T; +} + + +// Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24 integer bits and 8 fractional bits). +// Output value of “24674867” represents 24674867/256 = 96386.2 Pa = 963.862 hPa +uint32_t bme280_convert_pressure(int32_t adc_P) +{ + int64_t var1, var2, p; + var1 = ((int64_t)t_fine) - 128000; + var2 = var1 * var1 * (int64_t)dig_P6; + var2 = var2 + ((var1*(int64_t)dig_P5)<<17); + var2 = var2 + (((int64_t)dig_P4)<<35); + var1 = ((var1 * var1 * (int64_t)dig_P3)>>8) + ((var1 * (int64_t)dig_P2)<<12); + var1 = (((((int64_t)1)<<47)+var1))*((int64_t)dig_P1)>>33; + if (var1 == 0) + { + return 0; // avoid exception caused by division by zero + } + p = 1048576-adc_P; + p = (((p<<31)-var2)*3125)/var1; + var1 = (((int64_t)dig_P9) * (p>>13) * (p>>13)) >> 25; + var2 = (((int64_t)dig_P8) * p) >> 19; + p = ((p + var1 + var2) >> 8) + (((int64_t)dig_P7)<<4); + return (uint32_t)p; +} + +// Returns humidity in %RH as unsigned 32 bit integer in Q22.10 format (22 integer and 10 fractional bits). +// Output value of “47445” represents 47445/1024 = 46.333 %RH +uint32_t bme280_convert_humidity(int32_t adc_H) +{ + int32_t v_x1_u32r; + v_x1_u32r = (t_fine - ((int32_t)76800)); + v_x1_u32r = (((((adc_H << 14) - (((int32_t)dig_H4) << 20) - (((int32_t)dig_H5) * v_x1_u32r)) + + ((int32_t)16384)) >> 15) * (((((((v_x1_u32r * ((int32_t)dig_H6)) >> 10) * (((v_x1_u32r * + ((int32_t)dig_H3)) >> 11) + ((int32_t)32768))) >> 10) + ((int32_t)2097152)) * + ((int32_t)dig_H2) + 8192) >> 14)); + v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * ((int32_t)dig_H1)) >> 4)); + v_x1_u32r = (v_x1_u32r < 0 ? 0 : v_x1_u32r); + v_x1_u32r = (v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r); + return (uint32_t)(v_x1_u32r>>12); +} + +I2C_HandleTypeDef* bme280_get_i2c_handle(void) +{ + return &hi2c1; +} diff --git a/Source/main.c b/Source/main.c --- a/Source/main.c +++ b/Source/main.c @@ -24,7 +24,8 @@ #include "config.h" #include "error.h" -#include "pressure.h" +//#include "pressure.h" +#include "bme280.h" #include "gps.h" #include "system/gpio.h" @@ -48,8 +49,8 @@ int main(void) si446x_init(); si446x_init(); gps_poweron(); - pressure_init(); - +// pressure_init(); + bme280_init(); // Software timers uint32_t last_transmission = HAL_GetTick(); uint32_t last_led = HAL_GetTick(); @@ -60,7 +61,8 @@ int main(void) if(HAL_GetTick() - last_transmission > 700) { gps_update_data(); // Will always return at 1hz rate (default measurement rate) - pressure_read(); + //pressure_read(); + bme280_update(); while(afsk_busy()); // ensure previous message finished aprs_send(); diff --git a/Source/system/interrupts.c b/Source/system/interrupts.c --- a/Source/system/interrupts.c +++ b/Source/system/interrupts.c @@ -8,7 +8,7 @@ #include "stm32f0xx.h" #include "system/gpio.h" #include "aprs/afsk.h" -#include "pressure.h" +#include "bme280.h" #include "system/adc.h" // Systick @@ -33,10 +33,10 @@ void TIM1_BRK_UP_TRG_COM_IRQHandler(void // Handle I2C interrupts void I2C1_IRQHandler(void) { - if (pressure_get_i2c_handle()->Instance->ISR & (I2C_FLAG_BERR | I2C_FLAG_ARLO | I2C_FLAG_OVR)) { - HAL_I2C_ER_IRQHandler(pressure_get_i2c_handle()); + if (bme280_get_i2c_handle()->Instance->ISR & (I2C_FLAG_BERR | I2C_FLAG_ARLO | I2C_FLAG_OVR)) { + HAL_I2C_ER_IRQHandler(bme280_get_i2c_handle()); } else { - HAL_I2C_EV_IRQHandler(pressure_get_i2c_handle()); + HAL_I2C_EV_IRQHandler(bme280_get_i2c_handle()); } }