Added BME280 driver

This commit is contained in:
Mark Qvist 2020-10-23 13:53:34 +02:00
parent 6c9e0f1fb4
commit 596539f0cd
8 changed files with 463 additions and 16 deletions

View File

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

View File

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

295
hardware/BME280.c Normal file
View File

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

113
hardware/BME280.h Normal file
View File

@ -0,0 +1,113 @@
#ifndef bme280_H
#define bme280_H
#include <avr/io.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
#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

View File

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

30
main.c
View File

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

View File

@ -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) {

View File

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