295 lines
8.4 KiB
C
295 lines
8.4 KiB
C
#include "BME280.h"
|
|
#include "hardware/LED.h"
|
|
#include "util/time.h"
|
|
#include "util/Config.h"
|
|
|
|
void bme280_cs(bool val) {
|
|
if (!val) {
|
|
// Pull CS line low to enable bus
|
|
USR_IO_PORT &= ~(_BV(bme280_cs_usrio_pin));
|
|
} else {
|
|
// Set CS line to high to disable bus
|
|
USR_IO_PORT |= _BV(bme280_cs_usrio_pin);
|
|
}
|
|
}
|
|
|
|
uint8_t bme280_exchange(uint8_t tx) {
|
|
SPDR = tx;
|
|
while(!(SPSR & (1<<SPIF)));
|
|
return SPDR;
|
|
}
|
|
|
|
void bme280_deselect(void) {
|
|
bme280_cs(true);
|
|
}
|
|
|
|
void bme280_select(void) {
|
|
bme280_cs(false);
|
|
}
|
|
|
|
void bme280_exchange_multi(const uint8_t *buf, size_t len) {
|
|
do {
|
|
SPDR = *buf++; while(!(SPSR & (1<<SPIF)));
|
|
SPDR = *buf++; while(!(SPSR & (1<<SPIF)));
|
|
} while (len -= 2);
|
|
}
|
|
|
|
void bme280_receive_multi(uint8_t *buf, size_t len) {
|
|
do {
|
|
SPDR = 0xFF; loop_until_bit_is_set(SPSR,SPIF); *buf++ = SPDR;
|
|
SPDR = 0xFF; loop_until_bit_is_set(SPSR,SPIF); *buf++ = SPDR;
|
|
} while (len -= 2);
|
|
}
|
|
|
|
void bme280_write8(uint8_t reg_addr, uint8_t value) {
|
|
bme280_select();
|
|
bme280_exchange(reg_addr & ~0x80); // Write mode
|
|
bme280_exchange(value);
|
|
bme280_deselect();
|
|
}
|
|
|
|
uint8_t bme280_read8(uint8_t reg_addr) {
|
|
bme280_select();
|
|
bme280_exchange(reg_addr | 0x80); // Read mode
|
|
uint8_t value = bme280_exchange(0x00);
|
|
bme280_deselect();
|
|
return value;
|
|
}
|
|
|
|
uint16_t bme280_read16(uint8_t reg_addr) {
|
|
bme280_select();
|
|
bme280_exchange(reg_addr | 0x80);
|
|
uint16_t value = (bme280_exchange(0x00) << 8) | bme280_exchange(0x00);
|
|
bme280_deselect();
|
|
return value;
|
|
}
|
|
|
|
uint16_t bme280_read16_le(uint8_t reg_addr) {
|
|
uint16_t value = bme280_read16(reg_addr);
|
|
return (value >> 8) | (value << 8);
|
|
}
|
|
|
|
int16_t bme280_read16_s(uint8_t reg_addr) {
|
|
return (int16_t)bme280_read16(reg_addr);
|
|
}
|
|
|
|
int16_t bme280_read16_s_le(uint8_t reg_addr) {
|
|
return (int16_t)bme280_read16_le(reg_addr);
|
|
}
|
|
|
|
uint32_t bme280_read24(uint8_t reg_addr) {
|
|
uint32_t value;
|
|
|
|
bme280_select();
|
|
bme280_exchange(reg_addr | 0x80); // Bit 7 high for read mode
|
|
|
|
value = bme280_exchange(0x00);
|
|
value = value << 8;
|
|
value |= bme280_exchange(0x00);
|
|
value = value << 8;
|
|
value |= bme280_exchange(0x00);
|
|
|
|
bme280_deselect();
|
|
return value;
|
|
}
|
|
|
|
bool bme280_reading_calibration(void) {
|
|
uint8_t const status = bme280_read8(BME280_REGISTER_STATUS);
|
|
return (status & (1 << 0)) != 0;
|
|
}
|
|
|
|
void bme280_read_coefficients(void) {
|
|
bme280_calibration.dig_T1 = bme280_read16_le(BME280_REGISTER_DIG_T1);
|
|
bme280_calibration.dig_T2 = bme280_read16_s_le(BME280_REGISTER_DIG_T2);
|
|
bme280_calibration.dig_T3 = bme280_read16_s_le(BME280_REGISTER_DIG_T3);
|
|
|
|
bme280_calibration.dig_P1 = bme280_read16_le(BME280_REGISTER_DIG_P1);
|
|
bme280_calibration.dig_P2 = bme280_read16_s_le(BME280_REGISTER_DIG_P2);
|
|
bme280_calibration.dig_P3 = bme280_read16_s_le(BME280_REGISTER_DIG_P3);
|
|
bme280_calibration.dig_P4 = bme280_read16_s_le(BME280_REGISTER_DIG_P4);
|
|
bme280_calibration.dig_P5 = bme280_read16_s_le(BME280_REGISTER_DIG_P5);
|
|
bme280_calibration.dig_P6 = bme280_read16_s_le(BME280_REGISTER_DIG_P6);
|
|
bme280_calibration.dig_P7 = bme280_read16_s_le(BME280_REGISTER_DIG_P7);
|
|
bme280_calibration.dig_P8 = bme280_read16_s_le(BME280_REGISTER_DIG_P8);
|
|
bme280_calibration.dig_P9 = bme280_read16_s_le(BME280_REGISTER_DIG_P9);
|
|
|
|
bme280_calibration.dig_H1 = bme280_read8(BME280_REGISTER_DIG_H1);
|
|
bme280_calibration.dig_H2 = bme280_read16_s_le(BME280_REGISTER_DIG_H2);
|
|
bme280_calibration.dig_H3 = bme280_read8(BME280_REGISTER_DIG_H3);
|
|
|
|
bme280_calibration.dig_H4 = ((int8_t)bme280_read8(BME280_REGISTER_DIG_H4) << 4) |
|
|
(bme280_read8(BME280_REGISTER_DIG_H4 + 1) & 0xF);
|
|
|
|
bme280_calibration.dig_H5 = ((int8_t)bme280_read8(BME280_REGISTER_DIG_H5 + 1) << 4) |
|
|
(bme280_read8(BME280_REGISTER_DIG_H5) >> 4);
|
|
|
|
bme280_calibration.dig_H6 = bme280_read8(BME280_REGISTER_DIG_H6);
|
|
}
|
|
|
|
|
|
void bme280_set_sampling(void) {
|
|
uint8_t humidity_control_reg_values = BME280_SAMPLING_X16;
|
|
uint8_t config_reg_values = BME280_STANDBY_MS_0_5 << 5 | BME280_FILTER_OFF << 2;
|
|
uint8_t control_reg_values = BME280_SAMPLING_X16 << 5 | BME280_SAMPLING_X16 << 2 | BME280_MODE_NORMAL;
|
|
|
|
bme280_write8(BME280_REGISTER_CONTROLHUMID, humidity_control_reg_values);
|
|
bme280_write8(BME280_REGISTER_CONFIG, config_reg_values);
|
|
bme280_write8(BME280_REGISTER_CONTROL, control_reg_values);
|
|
|
|
}
|
|
|
|
bool bme280_read_temperature(void) {
|
|
int32_t var1, var2;
|
|
int32_t adc_temp = bme280_read24(BME280_REGISTER_TEMPDATA);
|
|
if (adc_temp == 0x800000) {
|
|
bme280_temperature = BME280_TEMP_UNDEFINED;
|
|
return false;
|
|
} else {
|
|
adc_temp >>= 4;
|
|
|
|
var1 = ((((adc_temp >> 3) - ((int32_t)bme280_calibration.dig_T1 << 1))) *
|
|
((int32_t)bme280_calibration.dig_T2)) >>
|
|
11;
|
|
|
|
var2 = (((((adc_temp >> 4) - ((int32_t)bme280_calibration.dig_T1)) *
|
|
((adc_temp >> 4) - ((int32_t)bme280_calibration.dig_T1))) >>
|
|
12) *
|
|
((int32_t)bme280_calibration.dig_T3)) >>
|
|
14;
|
|
|
|
bme280_temperature_fine = var1 + var2 + bme280_temperature_fine_adjust;
|
|
|
|
float temperature = (bme280_temperature_fine * 5 + 128) >> 8;
|
|
bme280_temperature = temperature / 100;
|
|
|
|
return true;
|
|
}
|
|
|
|
}
|
|
|
|
bool bme280_read_pressure(void) {
|
|
int64_t var1, var2, p;
|
|
|
|
bme280_read_temperature();
|
|
int32_t adc_P = bme280_read24(BME280_REGISTER_PRESSUREDATA);
|
|
|
|
if (adc_P == 0x800000) {
|
|
bme280_pressure = BME280_PRESSURE_UNDEFINED;
|
|
return false;
|
|
}
|
|
|
|
adc_P >>= 4;
|
|
|
|
var1 = ((int64_t)bme280_temperature_fine) - 128000;
|
|
var2 = var1 * var1 * (int64_t)bme280_calibration.dig_P6;
|
|
var2 = var2 + ((var1 * (int64_t)bme280_calibration.dig_P5) << 17);
|
|
var2 = var2 + (((int64_t)bme280_calibration.dig_P4) << 35);
|
|
var1 = ((var1 * var1 * (int64_t)bme280_calibration.dig_P3) >> 8) +
|
|
((var1 * (int64_t)bme280_calibration.dig_P2) << 12);
|
|
var1 =
|
|
(((((int64_t)1) << 47) + var1)) * ((int64_t)bme280_calibration.dig_P1) >> 33;
|
|
|
|
if (var1 == 0) {
|
|
return false;
|
|
}
|
|
|
|
p = 1048576 - adc_P;
|
|
p = (((p << 31) - var2) * 3125) / var1;
|
|
var1 = (((int64_t)bme280_calibration.dig_P9) * (p >> 13) * (p >> 13)) >> 25;
|
|
var2 = (((int64_t)bme280_calibration.dig_P8) * p) >> 19;
|
|
|
|
p = ((p + var1 + var2) >> 8) + (((int64_t)bme280_calibration.dig_P7) << 4);
|
|
|
|
bme280_pressure = (float)p / 25600;
|
|
return true;
|
|
}
|
|
|
|
bool bme280_read_humidity(void) {
|
|
int32_t v_x1_u32r;
|
|
|
|
bme280_read_temperature();
|
|
|
|
int32_t adc_H = bme280_read16(BME280_REGISTER_HUMIDDATA);
|
|
|
|
if (adc_H == 0x800000) {
|
|
bme280_humidity = BME280_PRESSURE_UNDEFINED;
|
|
return false;
|
|
}
|
|
|
|
v_x1_u32r = (bme280_temperature_fine - ((int32_t)76800));
|
|
|
|
v_x1_u32r = (((((adc_H << 14) - (((int32_t)bme280_calibration.dig_H4) << 20) -
|
|
(((int32_t)bme280_calibration.dig_H5) * v_x1_u32r)) +
|
|
((int32_t)16384)) >>
|
|
15) *
|
|
(((((((v_x1_u32r * ((int32_t)bme280_calibration.dig_H6)) >> 10) *
|
|
(((v_x1_u32r * ((int32_t)bme280_calibration.dig_H3)) >> 11) +
|
|
((int32_t)32768))) >>
|
|
10) +
|
|
((int32_t)2097152)) *
|
|
((int32_t)bme280_calibration.dig_H2) +
|
|
8192) >>
|
|
14));
|
|
|
|
v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) *
|
|
((int32_t)bme280_calibration.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;
|
|
float h = (v_x1_u32r >> 12);
|
|
bme280_humidity = h / 1024.0;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool bme280_init(uint8_t cs_usrio_pin) {
|
|
bme280_installed = false;
|
|
bme280_ready = false;
|
|
bme280_cs_usrio_pin = cs_usrio_pin;
|
|
|
|
bme280_temperature_fine_adjust = BME280_TEMPERATURE_ADJUSTMENT;
|
|
|
|
USR_IO_DDR |= bme280_cs_usrio_pin;
|
|
|
|
SPI_DDR |= _BV(SPI_MOSI) | _BV(SPI_CLK);
|
|
SPI_DDR &= ~(_BV(SPI_MISO));
|
|
SPCR = (1<<SPE) | (1<<MSTR) | (1<<SPR0);
|
|
|
|
bme280_deselect();
|
|
uint8_t sensor_id = bme280_read8(BME280_REGISTER_CHIPID);
|
|
if (sensor_id == 0x60) {
|
|
bme280_installed = true;
|
|
|
|
// Soft-reset chip to clear settings
|
|
bme280_write8(BME280_REGISTER_SOFTRESET, 0xB6);
|
|
delay_ms(10);
|
|
|
|
// Wait for chip to read calibration data
|
|
while (bme280_reading_calibration()) {
|
|
delay_ms(10);
|
|
}
|
|
|
|
// Load calibration coefficients
|
|
bme280_read_coefficients();
|
|
|
|
// Set sampling configuration
|
|
bme280_set_sampling();
|
|
delay_ms(100);
|
|
|
|
bme280_ready = true;
|
|
return true;
|
|
} else {
|
|
bme280_installed = false;
|
|
bme280_ready = false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool bme280_poll(void) {
|
|
if (bme280_read_temperature() && bme280_read_pressure() && bme280_read_humidity()) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
} |