This is my least favourite module in terms of getting the convoluted calculations right. I made some changes to try and fix the temperature data, which appear to have broken basically everything.
I have a hunch what the problem might be, so I've applied a "fix" and humbly submit Firmware 1.13 for testing: http://get.pimoroni.com/flotilla-dock-113.hex
For anyone interested, or good at bug hunting, this is basically the code as it stands now. It's full of type traps, where things could be cast to the wrong signedness.
#define WEATHER_ADDRESS 0x77
#define WEATHER_TEMP_THRESHOLD_DELTA 5
#define WEATHER_PRESSURE_THRESHOLD_DELTA 50
#define BMP280_REGISTER_CHIPID 0xD0
#define BMP280_REGISTER_VERSION 0xD1
#define BMP280_REGISTER_SOFTRESET 0xE0
#define BMP280_REGISTER_STATUS 0xF3 // bit 3 set to 1 when conversion is running
#define BMP280_REGISTER_CONTROL 0xF4
#define BMP280_REGISTER_CONFIG 0xF5
#define BMP280_REGISTER_TEMPDATA 0xFA // Temp MSB ( 3 bytes ) 0xFA, 0xFB, 0xFC
#define BMP280_REGISTER_PRESSUREDATA 0xF7 // Pressure MSB ( 3 bytes ) 0xF7, 0xF8, oxF9
#define BMP280_REGISTER_READTEMPCMD 0x2E
#define BMP280_REGISTER_READPRESSURECMD 0x34
#define BMP280_REGISTER_DIG_T1 0x88 // Unsigned Short
#define BMP280_REGISTER_DIG_T2 0x8A // Signed Short
#define BMP280_REGISTER_DIG_T3 0x8C // Signed Short
#define BMP280_REGISTER_DIG_P1 0x8E // Unsigned Short
#define BMP280_REGISTER_DIG_P2 0x90 // Signed Short
#define BMP280_REGISTER_DIG_P3 0x92 // Signed Short
#define BMP280_REGISTER_DIG_P4 0x94 // Signed Short
#define BMP280_REGISTER_DIG_P5 0x96 // Signed Short
#define BMP280_REGISTER_DIG_P6 0x98 // Signed Short
#define BMP280_REGISTER_DIG_P7 0x9A // Signed Short
#define BMP280_REGISTER_DIG_P8 0x9C // Signed Short
#define BMP280_REGISTER_DIG_P9 0x9E // Signed Short
static int32_t bmp280_read_config(unsigned char reg){
if( reg == BMP280_REGISTER_DIG_T1 || reg == BMP280_REGISTER_DIG_P1 ){
return (uint16_t)i2c_read_word_lsb_first(WEATHER_ADDRESS,reg);
}
else
{
return (int16_t)i2c_read_word_lsb_first(WEATHER_ADDRESS,reg);
}
}
// 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
static int32_t bmp280_compensate_T_int32(long signed int adc_T)
{
int32_t var1, var2;
int32_t t1 = bmp280_read_config(BMP280_REGISTER_DIG_T1);
var1 = ((((adc_T>>3) - (t1 <<1))) *
(bmp280_read_config(BMP280_REGISTER_DIG_T2))) >> 11;
var2 = (((((adc_T>>4) - (t1)) *
((adc_T>>4) - (t1))) >> 12) *
(bmp280_read_config(BMP280_REGISTER_DIG_T3))) >> 14;
return var1 + var2;
}
// Returns pressure in Pa as unsigned 32 bit integer. Output value of “96386” equals 96386 Pa = 963.86 hPa
static uint32_t bmp280_compensate_P_int32(long signed int adc_P, long signed int t_fine)
{
int64_t var1, var2, p;
var1 = ((int64_t)t_fine) - 128000;
var2 = var1 * var1 * (int64_t)bmp280_read_config(BMP280_REGISTER_DIG_P6);
var2 = var2 + ((var1*(int64_t)bmp280_read_config(BMP280_REGISTER_DIG_P5))<<17);
var2 = var2 + (((int64_t)bmp280_read_config(BMP280_REGISTER_DIG_P4))<<35);
var1 = ((var1 * var1 * (int64_t)bmp280_read_config(BMP280_REGISTER_DIG_P3))>>8) +
((var1 * (int64_t)bmp280_read_config(BMP280_REGISTER_DIG_P2))<<12);
var1 = (((((int64_t)1)<<47)+var1))*((int64_t)bmp280_read_config(BMP280_REGISTER_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)bmp280_read_config(BMP280_REGISTER_DIG_P9)) * (p>>13) * (p>>13)) >> 25;
var2 = (((int64_t)bmp280_read_config(BMP280_REGISTER_DIG_P8)) * p) >> 19;
p = ((p + var1 + var2) >> 8) + (((int64_t)bmp280_read_config(BMP280_REGISTER_DIG_P7))<<4);
return p/256;
}
static int32_t read_int32(unsigned char reg)
{
int32_t v = i2c_read_word(WEATHER_ADDRESS, reg);
return (v<<4) + (i2c_read_byte(WEATHER_ADDRESS, reg+2) >> 4);
}
static bool is_connected(void) {
return i2c_slave_present(WEATHER_ADDRESS);
}
static void init(channel_t *channel) {
i2c_write_byte(WEATHER_ADDRESS, BMP280_REGISTER_CONTROL, 0b01001001);
}
static bool tick(channel_t *channel) {
if((i2c_read_byte(WEATHER_ADDRESS, BMP280_REGISTER_STATUS) & 0b00001000) == 0){
int32_t temp = bmp280_compensate_T_int32(read_int32(BMP280_REGISTER_TEMPDATA));
uint32_t pressure = bmp280_compensate_P_int32(read_int32(BMP280_REGISTER_PRESSUREDATA),temp);
int32_t last_temp = *(int32_t *)(&channel->data[0]);
uint32_t last_pressure = *(uint32_t *)(&channel->data[2]);
temp = (temp * 5 + 128) >> 8;
if( abs(temp - last_temp) > WEATHER_TEMP_THRESHOLD_DELTA || abs(pressure - last_pressure) > WEATHER_PRESSURE_THRESHOLD_DELTA){
serial_printf_P(PSTR("u %d/%s %ld,%lu\r\n"), channel->id, channel->module_type->name, (int32_t)temp, (uint32_t)pressure);
*(int32_t *)(&channel->data[0]) = temp;
*(uint32_t *)(&channel->data[2]) = pressure;
return true;
}
// Force next conversion
i2c_write_byte(WEATHER_ADDRESS, BMP280_REGISTER_CONTROL, 0b01001001);
}
return false;
}