From 596539f0cdb7cf5e84237bea75aacec43ac6f5f7 Mon Sep 17 00:00:00 2001 From: Mark Qvist Date: Fri, 23 Oct 2020 13:53:34 +0200 Subject: [PATCH] Added BME280 driver --- Makefile | 2 +- device.h | 12 ++ hardware/BME280.c | 295 ++++++++++++++++++++++++++++++++++++++++++++++ hardware/BME280.h | 113 ++++++++++++++++++ hardware/GPS.c | 16 +-- main.c | 30 +++++ util/Config.c | 5 + util/Config.h | 6 + 8 files changed, 463 insertions(+), 16 deletions(-) create mode 100644 hardware/BME280.c create mode 100644 hardware/BME280.h diff --git a/Makefile b/Makefile index 78a128b..02f887d 100755 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ TARGET = images/OpenModem OPT = s FORMAT = ihex -SRC = main.c util/Config.c hardware/Serial.c hardware/AFSK.c hardware/VREF.c hardware/LED.c hardware/UserIO.c hardware/SD.c hardware/sdcard/diskio.c hardware/sdcard/ff.c hardware/sdcard/ffsystem.c hardware/sdcard/ffunicode.c hardware/Bluetooth.c hardware/GPS.c hardware/Crypto.c hardware/crypto/AES.c hardware/crypto/HMAC_MD5.c hardware/crypto/MD5.c hardware/crypto/MD5_sbox.c util/CRC-CCIT.c protocol/AX25.c protocol/KISS.c +SRC = main.c util/Config.c hardware/Serial.c hardware/AFSK.c hardware/VREF.c hardware/LED.c hardware/UserIO.c hardware/SD.c hardware/sdcard/diskio.c hardware/sdcard/ff.c hardware/sdcard/ffsystem.c hardware/sdcard/ffunicode.c hardware/Bluetooth.c hardware/BME280.c hardware/GPS.c hardware/Crypto.c hardware/crypto/AES.c hardware/crypto/HMAC_MD5.c hardware/crypto/MD5.c hardware/crypto/MD5_sbox.c util/CRC-CCIT.c protocol/AX25.c protocol/KISS.c # TODO: Try hardware/crypto/MD5_asm.S # List Assembler source files here. diff --git a/device.h b/device.h index f15efa7..62fe0c1 100755 --- a/device.h +++ b/device.h @@ -56,6 +56,14 @@ // Packet settings #define CONFIG_PASSALL false +// User jobs +#define CONFIG_USER_JOBS_ENABLED true + +// External sensor support +#define CONFIG_SENSORS_ENABLED true +#define CONFIG_SENSORS_INTERVAL_MS 1000 +#define CONFIG_BME280_ENABLED true + // Port settings #if TARGET_CPU == m1284p #define ADC_PORT PORTA @@ -118,4 +126,8 @@ #define PATH_AES_128_KEY "OpenModem/aes128.key" #define PATH_CRYPTO_DISABLE "OpenModem/aes128.disable" +// User-scriptable forward function declarations +void user_init(void); +void user_jobs(void); + #endif \ No newline at end of file diff --git a/hardware/BME280.c b/hardware/BME280.c new file mode 100644 index 0000000..11b6d19 --- /dev/null +++ b/hardware/BME280.c @@ -0,0 +1,295 @@ +#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<> 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< +#include +#include +#include +#include "device.h" +#include "util/time.h" + +#define BME280_TEMPERATURE_ADJUSTMENT 0 + +#define BME280_TEMP_UNDEFINED -274 +#define BME280_PRESSURE_UNDEFINED -1 +#define BME280_HUMIDITY_UNDEFINED -1 + +#define BME280_REGISTER_DIG_T1 0x88 +#define BME280_REGISTER_DIG_T2 0x8A +#define BME280_REGISTER_DIG_T3 0x8C +#define BME280_REGISTER_DIG_P1 0x8E +#define BME280_REGISTER_DIG_P2 0x90 +#define BME280_REGISTER_DIG_P3 0x92 +#define BME280_REGISTER_DIG_P4 0x94 +#define BME280_REGISTER_DIG_P5 0x96 +#define BME280_REGISTER_DIG_P6 0x98 +#define BME280_REGISTER_DIG_P7 0x9A +#define BME280_REGISTER_DIG_P8 0x9C +#define BME280_REGISTER_DIG_P9 0x9E +#define BME280_REGISTER_DIG_H1 0xA1 +#define BME280_REGISTER_DIG_H2 0xE1 +#define BME280_REGISTER_DIG_H3 0xE3 +#define BME280_REGISTER_DIG_H4 0xE4 +#define BME280_REGISTER_DIG_H5 0xE5 +#define BME280_REGISTER_DIG_H6 0xE7 +#define BME280_REGISTER_CHIPID 0xD0 +#define BME280_REGISTER_VERSION 0xD1 +#define BME280_REGISTER_SOFTRESET 0xE0 +#define BME280_REGISTER_CAL26 0xE1 // R calibration stored in 0xE1-0xF0 +#define BME280_REGISTER_CONTROLHUMID 0xF2 +#define BME280_REGISTER_STATUS 0XF3 +#define BME280_REGISTER_CONTROL 0xF4 +#define BME280_REGISTER_CONFIG 0xF5 +#define BME280_REGISTER_PRESSUREDATA 0xF7 +#define BME280_REGISTER_TEMPDATA 0xFA +#define BME280_REGISTER_HUMIDDATA 0xFD + +#define BME280_SAMPLING_NONE 0b000 +#define BME280_SAMPLING_X1 0b001 +#define BME280_SAMPLING_X2 0b010 +#define BME280_SAMPLING_X4 0b011 +#define BME280_SAMPLING_X8 0b100 +#define BME280_SAMPLING_X16 0b101 + +#define BME280_MODE_SLEEP 0b00 +#define BME280_MODE_FORCED 0b01 +#define BME280_MODE_NORMAL 0b11 + +#define BME280_FILTER_OFF 0b000 +#define BME280_FILTER_X2 0b001 +#define BME280_FILTER_X4 0b010 +#define BME280_FILTER_X8 0b011 +#define BME280_FILTER_X16 0b100 + +#define BME280_STANDBY_MS_0_5 0b000 +#define BME280_STANDBY_MS_10 0b110 +#define BME280_STANDBY_MS_20 0b111 +#define BME280_STANDBY_MS_62_5 0b001 +#define BME280_STANDBY_MS_125 0b010 +#define BME280_STANDBY_MS_250 0b011 +#define BME280_STANDBY_MS_500 0b100 +#define BME280_STANDBY_MS_1000 0b101 + + +typedef struct { + uint16_t dig_T1; // temperature compensation value + int16_t dig_T2; // temperature compensation value + int16_t dig_T3; // temperature compensation value + + uint16_t dig_P1; // pressure compensation value + int16_t dig_P2; // pressure compensation value + int16_t dig_P3; // pressure compensation value + int16_t dig_P4; // pressure compensation value + int16_t dig_P5; // pressure compensation value + int16_t dig_P6; // pressure compensation value + int16_t dig_P7; // pressure compensation value + int16_t dig_P8; // pressure compensation value + int16_t dig_P9; // pressure compensation value + + uint8_t dig_H1; // humidity compensation value + int16_t dig_H2; // humidity compensation value + uint8_t dig_H3; // humidity compensation value + int16_t dig_H4; // humidity compensation value + int16_t dig_H5; // humidity compensation value + int8_t dig_H6; // humidity compensation value +} bme280_calib_data; + +bool bme280_init(uint8_t cs_usrio_pin); +bool bme280_poll(void); + +bool bme280_installed; +bool bme280_ready; +uint8_t bme280_cs_usrio_pin; + +int32_t bme280_temperature_fine_adjust; +int32_t bme280_temperature_fine; + +float bme280_temperature; +float bme280_pressure; +float bme280_humidity; + +bme280_calib_data bme280_calibration; + +#endif \ No newline at end of file diff --git a/hardware/GPS.c b/hardware/GPS.c index e85953c..e1ca5b3 100644 --- a/hardware/GPS.c +++ b/hardware/GPS.c @@ -274,21 +274,7 @@ void gps_nmea_parse(uint8_t sentence_length) { gps_t_year = (nmea_date % 100); gps_update_rtc(); } - - // TODO: Remove this - // printf("GPS fix\r\n"); - // printf("GPS satellites: %d\r\n", gps_sats); - // printf("GPS latitude: %d\" %d' %.2fs %c\r\n", gps_lat_degrees, gps_lat_minutes, gps_lat_seconds, gps_lat_sign); - // printf("GPS longtitude: %d\" %d' %.2fs %c\r\n", gps_lon_degrees, gps_lon_minutes, gps_lon_seconds, gps_lon_sign); - // printf("GPS coords: %.6f,%.6f\r\n", gps_lat, gps_lon); - // printf("GPS speed %.2f Km/h\r\n", gps_speed_kmh); - // printf("GPS speed %.2f knots\r\n", gps_speed_knots); - // printf("GPS bearing %.2f\r\n", gps_bearing); - // printf("GPS height above MSL: %.2f\r\n", gps_height_above_msl); - // printf("GPS altitude: %.2f\r\n", gps_altitude); - // printf("GPS geoid height: %.2f\r\n", gps_geoid_height); - // printf("GPS HDOP: %.2f\r\n", gps_hdop); - // printf("GPS time %d/%d/%d %d:%d:%d UTC\r\n", gps_t_year, gps_t_month, gps_t_day, gps_t_hour, gps_t_minute, gps_t_second); + } else { gps_speed_knots = 0; gps_speed_kmh = 0; diff --git a/main.c b/main.c index 08147b4..dcf406a 100755 --- a/main.c +++ b/main.c @@ -16,6 +16,7 @@ #include "hardware/SD.h" #include "hardware/Crypto.h" #include "hardware/Bluetooth.h" +#include "hardware/BME280.h" #include "hardware/GPS.h" #include "protocol/AX25.h" #include "protocol/KISS.h" @@ -92,7 +93,33 @@ void init(void) { gps_init(&serial); usrio_init(); + if (config_sensors_enabled) { + if (config_sensor_bme280_enabled) bme280_init(config_sensor_bme280_cs_pin); + } + system_check(); + + if (config_user_jobs_enabled) user_init(); +} + +mtime_t sensor_poll_time = 0; +void sensor_jobs(void) { + if (rtc_milliseconds() > sensor_poll_time+config_sensor_interval_ms) { + if (config_sensor_bme280_enabled && bme280_ready) { + bme280_poll(); + } + + sensor_poll_time = rtc_milliseconds(); + } +} + +void user_init(void) { + // Place user-specified initialisation code here +} + + +void user_jobs(void) { + // Place user-specified tasks and jobs here } @@ -105,6 +132,9 @@ int main (void) { kiss_csma(); sd_jobs(); gps_poll(); + + if (config_sensors_enabled) sensor_jobs(); + if (config_user_jobs_enabled) user_jobs(); } return(0); diff --git a/util/Config.c b/util/Config.c index b6e3cb0..6bf241b 100644 --- a/util/Config.c +++ b/util/Config.c @@ -30,7 +30,12 @@ void config_init(void) { } void config_init_ephemeral(void) { + config_user_jobs_enabled = CONFIG_USER_JOBS_ENABLED; config_gps_nmea_output = CONFIG_GPS_NMEA_NONE; + config_sensors_enabled = CONFIG_SENSORS_ENABLED; + config_sensor_interval_ms = CONFIG_SENSORS_INTERVAL_MS; + config_sensor_bme280_enabled = CONFIG_BME280_ENABLED; + config_sensor_bme280_cs_pin = USR_IO_1; } void config_apply(void) { diff --git a/util/Config.h b/util/Config.h index 8833c51..69732bd 100644 --- a/util/Config.h +++ b/util/Config.h @@ -74,8 +74,14 @@ uint8_t config_gps_nmea_output; uint8_t config_bluetooth_mode; uint8_t config_serial_baudrate; +bool config_user_jobs_enabled; bool config_output_diagnostics; +bool config_sensors_enabled; +int32_t config_sensor_interval_ms; +bool config_sensor_bme280_enabled; +uint8_t config_sensor_bme280_cs_pin; + void config_init(void); void config_init_ephemeral(void); void config_apply(void);