Strange Barometer behaviour

I’m using Python3 in Shipshape to access the Weather module’s Temperature and Barometer values but I can’t understand the Barometer’s pressure values. How do I convert the values to hPa ?
Also the chart below shows that the pressure values I’m retrieving are inversely proportional to the temperature values retrieved ! During the period show in the chart the Atmospheric Pressure was constant at 1031 hPa on my weather station, which has been calibrated with the local values. I would therefore not have expected to see any variation in the pressure value from the Weather module, let alone varying with temperature. Has any one else played with the Weather module and received sensible values ? Or have I got a faulty module ?

Same thing here - just plotted this against values I’d been taking today to try and see if I could work out a callibration. Something not quite right, I’d guess in the dock firmware. I’m using the Shipshape firmware (but talking to the dock directly via USB/Serial, so it’s not a python thing).

Edited to add: The temperature around the sensor is nowhere near 25 C - more like 21 C. And if the pressure number is just millibar * 100 it’s obviously way high also.

Ah, it’s not just me then, thanks for commenting.

I saw the same problem with temperature as you but I’ve now added a constant correction factor (i.e. T/1.18) which works well over the range 4C to 22C compared to two different bulb thermometers (I have not gone beyond this range yet). I’d estimate +/- 1 degree accuracy.

I think this is a firmware change… I’ve not had a chance to investigate, but in the original firmware, the output was in Pascals (or some hPA - I forget). It was pretty obvious and worked reliably.

I had some code working reliable with it, but when I demo’d the code yesterday it wasn’t working. I suspect that the 1.0 firmware has changed something (or maybe the HW just had stage fright!).

I’ve had a chance to quickly go through the various available firmwares. The readings are plausible up to and including 1.0, but broken from 1.1 through 1.12.

MD5 (flotilla-dock-010.hex) = 595f053a665249768f47af81406bcaf1  readings OK
MD5 (flotilla-dock-100.hex) = f5154802f96c1a9408988bd468328310  readings OK
MD5 (flotilla-dock-110.hex) = 3df935122e1785daca974f68852faed7  readings bad
MD5 (flotilla-dock-111.hex) = 7727152e0432eac90ab1615a9b584e3f  readings bad
MD5 (flotilla-dock-112.hex) = 121b4821a4881bbe8a0b7ce6040b5d3f  readings bad

Doing some research, it seems with these kind of sensors one has to read some factory-set, sensor-specific calibration data and apply it (via quite convoluted calculations) to the raw readings. This presumably was being done in the dock firmware up to 1.0 but from 1.1 the firmware is just sending the raw readings. The calculation for pressure involves the temperature reading so this could explain the apparent inverse relationship between the raw values. Since we can’t get at the calibration values it would need to be fixed in the firmware.

I based this on https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BMP180-DS000-121.pdf - of course bearing in mind I don’t know what sensor Flotilla uses but I assume at least a similarity to this.

@o172
Great research !
Let’s hope one of the Pimoroni crew pick this up.

Steve

yes, we’re very much on the case. and for info, the IC in the Barometer module is the BMP280.

1 Like

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;
}
1 Like

Great stuff - this is looking much more plausible at a quick check: the temperature is within half a degree of another device (whose accuracy is unknown) and the pressure number is virtually constant with temperate changes from touching the sensor.

I can see why it’s not a favourite!

Good news! I’ve tidied up this firmware release and added it into the pre-release GitHub repository as v1.13.

You can find it here: https://github.com/pimoroni/flotilla-pre/tree/master/firmware

@gadgetoid
Please can you explain how I can apply V1.13 RC1 firmware or should I wait until the update_firmware script has been updated ?

@rc10b the update script in pre should now point to the v1.13 firmware. If you already have flotilla-pre cloned to your Pi, open terminal, find your way into the flotilla-pre folder and type git pull to grab the most recent files, then skip to the update steps below.

If not, clone the repository like so:

git clone https://github.com/pimoroni/flotilla-pre

Then:

cd flotilla/raspi/firmware
sudo ./update_firmware

Great that works, thanks, I’m now getting sensible pressure readings.

Two minor issues, in case any other newbies are following this thread:
a) Should be:

cd flotilla/raspi/firmware

to run update_firmware

b) The update_firmware script still refers to v1.12 but I guess this will be remedied if/when 1.13 becomes a final release.

Thanks again,
Steve

Good spot. I’ve bumped the firmware version number in the update script.

Glad to hear you’re also getting sane readings. Thanks for feeding back!