PDA

View Full Version : BME280 sensor.



HenrikOlsson
- 27th September 2020, 14:49
Has anyone been able to interface the BME280 temp, humidity and pressure sensor to PBP?
I've been messing with it for two days. Getting temperature to read correctly (at least I think it is) took a couple of hours but the compensation formulas for the pressure, let alone humidity is about as convoluted as they get and I'm really struggling. They do provide code in the datasheet but no real explaination or formulas.

Take a look at the fixed point version of the compensation code in the datasheet and tell me if you can figure out what it's doing :-) Like I said, I managed to get temperature working (at least it seems to be, don't know what happens when temp goes negative...) but just look at the code for pressure and humidity, they're using bloody 64bit signed variables, leftshift 47 times, rightshift 33 times...jeeez :-)

Of course there is Arduino code available but it pretty much copies the datasheet.

Anyone already done it? Anyone interested?

/Henrik.

EDIT:Link to datasheet (https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bme280-ds002.pdf)

towlerg
- 27th September 2020, 16:50
Yer, the compensation is horrible. Sorry don't have PICBASIC code but do have working code from the dark side.

richard
- 28th September 2020, 01:14
i posted this some time ago and the topic seems to have disappeared , i can't remember who's post it was and the context
but the calcs work but for the ones that need 64bit vars


' DEVICE CONFIGURATION

#CONFIG
CONFIG OSC = IRCIO
CONFIG FCMEN = OFF
CONFIG IESO = OFF
CONFIG PWRTEN = OFF
CONFIG BOREN = OFF
CONFIG BORV = 20
CONFIG WDTEN = OFF
CONFIG WDPS = 512
CONFIG WINEN = OFF
CONFIG PWMPIN = OFF
CONFIG LPOL = HIGH ; PWM0, 2, 4 and 6 are active-high
CONFIG HPOL = HIGH ; PWM1, 3, 5 and 7 are active-high
CONFIG T1OSCMX = ON ; Low-power Timer1 operation when microcontroller is in Sleep mode
CONFIG MCLRE = OFF
CONFIG STVREN = ON ; Stack full/underflow will cause Reset
CONFIG LVP = OFF ; Low-voltage ICSP disabled
CONFIG DEBUG = OFF ; Background debugger disabled; RB6 and RB7 configured as general purpose I/O pins
CONFIG CP0 = OFF ; Block 0 (000200-000FFFh) not code-protected
CONFIG CP1 = OFF ; Block 1 (001000-001FFF) not code-protected
CONFIG CP2 = OFF ; Block 2 (002000-002FFFh) not code-protected
CONFIG CP3 = OFF ; Block 3 (003000-003FFFh) not code-protected
CONFIG CPB = OFF ; Boot Block (000000-0001FFh) not code-protected
CONFIG CPD = OFF ; Data EEPROM not code-protected
CONFIG WRT0 = OFF ; Block 0 (000200-000FFFh) not write-protected
CONFIG WRT1 = OFF ; Block 1 (001000-001FFF) not write-protected
CONFIG WRT2 = OFF ; Block 2 (002000-002FFFh) not write-protected
CONFIG WRT3 = OFF ; Block 3 (003000-003FFFh) not write-protected
CONFIG WRTC = OFF ; Configuration registers (300000-3000FFh) not write-protected
CONFIG WRTB = OFF ; Boot Block (000000-0001FFh) not write-protected
CONFIG WRTD = OFF ; Data EEPROM not write-protected
CONFIG EBTR0 = OFF ; Block 0 (000200-000FFFh) not protected from table reads executed in other blocks
CONFIG EBTR1 = OFF ; Block 1 (001000-001FFF) not protected from table reads executed in other blocks
CONFIG EBTR2 = OFF ; Block 2 (002000-002FFFh) not protected from table reads executed in other blocks
CONFIG EBTR3 = OFF ; Block 3 (003000-003FFFh) not protected from table reads executed in other blocks
CONFIG EBTRB = OFF ; Boot Block (000000-0001FFh) not protected from table reads executed in other blocks
#ENDCONFIG

' DEFINEs
DEFINE OSC 8 ' Internal 8MHz


' Pin ALIASES
LED1 VAR PORTB.0 ' Orange Lights
GRNLED VAR PORTB.4 '
ClockPin VAR PORTA.6 ' IIC BME280
DataPin VAR PORTA.7 ' IIC BME280


' CONSTANTS

' --- BME280 Registers---
BMEADDR CON $EC ' Chip Address
ID CON $D0 ' Chip ID (0x60)
ctrl_hum CON $F2 ' Humidity Control Register
stat CON $F3 ' Status Register
ctrl_meas CON $F4 ' Temperature/Pressure Control Register
config CON $F5 ' Cofiguration
cal_st_addr CON $88 ' Calibration Start Address


' VARIABLES
FLAG VAR BYTE
IIC_RX VAR BYTE[8] ' IIC Received Data BME280
i var byte
T1 VAR LONG
T2 VAR LONG
T3 VAR LONG
adc_T VAR LONG
var1 VAR LONG
var2 VAR LONG
T VAR LONG
adc_Tr3 VAR LONG
' T1l1 VAR LONG
' T2r11 VAR LONG
' adc_Tr4 VAR LONG
' T1r12 VAR LONG
' T3r14 VAR LONG
t_fine VAR LONG
' TT VAR LONG


' INITIALIZE REGISTERS
OSCCON = %01110000 ' Set internal osc to 8MHZ
ANSEL0 = %00000000 ' Set to Digital PortA
' -HW RS232 Setup-


TXSTA = $20 ' Enable transmit, BRGH = 0
SPBRG = 51 ' 9600 Baud @ 8MHz, 0.16%
SPBRGH = 0
BAUDCON.3 = 1 ' Enable 16 bit baudrate generator




' -HW Timer Setup-
TMR0H = 0 ' HighByte of preload value
TMR0L = 0 ' LowByte of preload value (the order is important!)
INTCON.2 = 0 ' Clear the flag bit
T0CON = %10000111 ' Setup and Enable TMR0 (8.388s)


TRISA = %00000000 ' Set ports as outputs (2-4 I/P)
TRISB = %00000000
TRISC = %00000000 ' Set ports as outputs

CLEAR
' PROGRAM Start

PORTA = 0 ' Clear PORTA
PORTB = 0
PORTC = 0

IIC_RX = 0
Init:
GOSUB P500 ' Let everything settle
GOSUB VER_BME ' Is the BME280 Connected. Verify


MAIN:
GOSUB GETTEMPBME ' Get the temperature reading from BME280
GOSUB P1

GOTO MAIN
' Go back to mainloop
END


GETTEMPBME:
'I2CREAD DataPin, ClockPin, BMEADDR, stat ,[IIC_RX] ' Check to see if busy Converting Measurements, or writing data
'If IIC_RX[0] != 0 THEN ' If not, it should read as 0
' GOSUB P100
' GOSUB GETTEMPBME
'ENDIF

' DO
' IF FLAG.0 = 1 THEN GOSUB P100 ' If flag is set the BME280 was not ready (Try again)
' TOGGLE LED1
' I2CREAD DataPin, ClockPin, BMEADDR, stat ,[IIC_RX] ' Check to see if busy Converting Measurements, or writing data
' FLAG.0 = 1
' LOOP WHILE IIC_RX[0] != 0 '
' FLAG.0 = 0 ' Clear Flag

' I2CREAD DataPin, ClockPin, BMEADDR, $F7 ,[STR IIC_RX\8] ' Read Temp/Hum/Press registers
arraywrite IIC_RX,[ $55 ,$2F ,$D0 ,$82 ,$D7 ,$90 ,$85 ,$A6 ]
for i=0 to 6
HSEROUT[hex2 IIC_RX[i],","]
next
HSEROUT[hex2 IIC_RX[i],13,10]
' GOSUB P1


adc_T.Byte0 = IIC_RX[5] ' Store Raw Temerature data
adc_T.Byte1 = IIC_RX[4]
adc_T.Byte2 = IIC_RX[3]
' GOSUB P1



adc_T=adc_T >> 4
var1 = ((((adc_T >> 3) - (T1 << 1))) * (T2)) >> 11
var2 = (((((adc_T >> 4) - (T1)) *((adc_T >> 4) - (T1))) >>12) *(T3)) >>14
t_fine = var1 + var2
T = ((t_fine * 5) + 128)>>8
HSEROUT["T " ,#T/100,".",#T//100,13,10]






RETURN

VER_BME:
' I2CREAD DataPin, ClockPin, BMEADDR, ID ,[IIC_RX] ' Read the BME's ID
' IF IIC_RX[0] != $60 THEN ERROR2 ' Cannot Connect to the BME280

' ' -Read Calibration Data for Temperature-
' I2CREAD DataPin, ClockPin, BMEADDR, cal_st_addr ,[STR IIC_RX\6] '
arraywrite IIC_RX,[$6C ,$6E ,$77 ,$66 ,$32 ,$00]
for i=0 to 4
HSEROUT[hex2 IIC_RX[i],","] ' Display -> 6C 6E 77 66 32 00 0D 0A
next
HSEROUT[hex2 IIC_RX[i],13,10]

T1.Byte0 = IIC_RX[0] ' Calibration data into Unsigned Word
T1.Byte1 = IIC_RX[1]
T2.Byte0 = IIC_RX[2] ' Calibration data into Signed Long
T2.Byte1 = IIC_RX[3]
T3.Byte0 = IIC_RX[4] ' Calibration data into Signed Long
T3.Byte1 = IIC_RX[5]


' -Initialise the Sensor-
' I2CWRITE DataPin, ClockPin, BMEADDR, config ,[%10101000] ' Config Setting (1000ms Standby, IIR Filter @ 4)
' I2CWRITE DataPin, ClockPin, BMEADDR, ctrl_hum ,[%00000010] ' Humidity Setting (x2 Oversampling)
' I2CWRITE DataPin, ClockPin, BMEADDR, ctrl_meas ,[%01001011] ' Temp/Pres Settings (x2 Oversampling, Normal Mode)

' GOSUB P250
RETURN

ERROR1:
DO
TOGGLE LED1 ' Flash the Orange LED every 1/2 second
GOSUB P500
LOOP

ERROR2: ' BME280 Connection Error
LED1 = 1
GOSUB P250
LED1 = 0
GOSUB P250
LED1 = 1
GOSUB P250
LED1 = 0
GOSUB P1
GOTO ERROR2

P100:
PAUSE 100 ' Just a pause..
RETURN

P250:
PAUSE 250 ' Just a pause..
RETURN

P500:
PAUSE 500 ' Just a pause..
RETURN

P1:
PAUSE 1000 ' Just a pause..
RETURN

Ioannis
- 28th September 2020, 12:28
I wonder what was thinking the team that designed that sensor...

Anyway maybe this can be of some help
http://dt.picbasic.co.uk/CODEX/N-BitMath

Ioannis

HenrikOlsson
- 1st October 2020, 17:55
Thank you Richard!
I see you too got the temperature conversion covered but not pressure and/or humidity which is where I'm currently got stuck. Haven't done anything with it for a couple of days, perhaps I'll get back to it - or I won't.

Ioannis,
Yes, I know about the N-bit routines and if I don't succeed in getting the "native" 32bit fixed point routines they do show in the datasheet to work I might try with N-bit but I suspect it won't actually make it much easier.

Right now, my guess is that the problem has to do with me niot be able to "translate" their mix of signed and unsigned numbers of various bit lengths into PBP lingo.
I'm reading the compensation values from the sensor and "manually" casts them into LONGs in order to make them signed. But then not all of them are supposed to BE signed but in PBP all longs ARE signed and it becomes a mess quite quickly. It would be nice to have set of input values with a known output so one could split the calculation in steps and figure out where it goes wrong.

/Henrik.

HenrikOlsson
- 3rd October 2020, 19:31
Does anyone have a BME280 sensor laying around?
Can you read the compensation values and post them?

I think I've now got pressure working as well but I'm curious to know another sensors comp values :-)

/Henrik.

richard
- 5th October 2020, 03:45
henrik here is a json dump from my nodemcu/bme280 regs from 0x80 to 0xff
{"bme":144,111,137,51,54,42,151,6,185,109,247,104,50,0,6 1,148,200,214,208,11,181,32,73,255,249,255,172,38, 10,216,189,16,0,75,61,0,0,0,0,0,0,0,0,0,51,0,0,192 ,0,84,0,0,0,0,96,2,0,1,255,255,31,78,8,0,0,64,183, 255,0,0,0,0,5,0,0,0,0,0,0,0,96,0,0,0,0,0,0,0,0,0,0 ,0,0,0,0,0,0,101,1,0,20,43,3,30,189,65,255,255,255 ,255,255,255,255,0,5,12,183,0,0,72,115,224,126,150 ,48,112,242,128} and the highlighted corresponding readings
{"pressure":1011,"roomt":22.06,"humidity":42,"setpoint":27,"damper":1800,"state":1,"fire":21,"bv":1340}

ps
hope it's ok looks like forum is not json friendly

HenrikOlsson
- 8th October 2020, 18:35
Thank you Richard, that did help.

I've got pressure working as well.
Temperature is within 0.05°C and pressure is within 1Pa compared to a commercially available BME280 based sensor module.
I thought I had humidity working although it read about 7% off compared to "real" one but today the difference is 30% so there must be something wrong still.

Will look at that later and hopefully be able to post some code.

But geez, these LONG math operatations eats away code space, 8k at the moment.

/Henrik.

Ioannis
- 8th October 2020, 19:35
There is always the possibility that humidity sensor may not had time to sense the environment. Or the other reference sensor is in a bit different position and gives wrong measures.

In my experience, humidity sensors are not very trusty.

HenrikOlsson
- 11th October 2020, 16:22
Richard,
Out of curiosity, have you tried the PBP code you posted with negative temperature values?

The reason I ask is that my temperature compensation code was pretty much exactly like yours but it went belly up as soon as the temperature went below 0°C.
Reason mainly being the shift operations where potentially negative values (T2, T3 and therfor t_fine) are involved.

I see you're handling the compensation values quite differently, simply pushing them into the lower 16bits of a LONG no matter if they're positive or negative. With that said, both T2 and T3 are positive in my case, like in yours, but they could potentially BE negative and then I don't think simplt stuffing the "signed short" into the lower 16bits of our LONG will work properly.

I had to replace the affected shift operations with * and / at quite some cost for the execution time and for any compensation values specified as signed I'm doing this sort of thing:

' dig_T2, signed, read to temporary variable and cast to LONG to preserve sign of value
SHIFTIN BME280_MISO, BME280_CLK, 6, [tmp_W.BYTE0, tmp_W.BYTE1]
IF tmp_W.15 = 1 THEN
dig_T2 = -ABS(tmp_W)
ELSE
dig_T2 = tmp_W
ENDIF


/Henrik.

/Henrik.

richard
- 11th October 2020, 21:15
Out of curiosity, have you tried the PBP code you posted with negative temperature values?

sorry no, i never actually used pbp for these sensors after discovering the real potential of esp chips


if the upper word was set appropriately here maybe that would help , adc_t might need similar treatment but the calculation should be
then ok ,i think?


T1.Byte0 = IIC_RX[0] ' Calibration data into Unsigned Word
T1.Byte1 = IIC_RX[1]
T2.Byte0 = IIC_RX[2] ' Calibration data into Signed Long
T2.Byte1 = IIC_RX[3]
if IIC_RX[3].7 then
T2.Byte3=255
T2.Byte4=255
else
T2.Byte3=0
T2.Byte4=0
endif
T3.Byte0 = IIC_RX[4] ' Calibration data into Signed Long
T3.Byte1 = IIC_RX[5]
if IIC_RX[5].7 then
T3.Byte3=255
T3.Byte4=255
else
T3.Byte3=0
T3.Byte4=0
endif

richard
- 12th October 2020, 11:34
the calculation should be
then ok ,i think?

nah, pbp needs a signed shift right command too. too hard me thinks. pic chip in bin, esp wins

HenrikOlsson
- 15th October 2020, 17:49
For anyone who are still interested in using this sensor with PBP I've posted my code as an example in the Wiki:
http://www.picbasic.co.uk/forum/content.php?r=558-BME280-Example

If any questions or suggestions should pop up I suggest we keep them in this thread.

/Henrik.

richard
- 15th October 2020, 23:16
excellent work henrik, way better than my fp attempt [nearly 10k in size] to get a result.
i confirm it gets same results temp and pressure wise as arduino calcs for same input data
not tried hum yet

richard
- 16th October 2020, 05:17
henrik
i made a little change

used this style
IF P2.15 = 1 THEN
p2.highWORD = 65535
ENDIF

for all the casts to long , it saves a worthwhile bit of code space

can't test humidity on pic yet , just discovered the dishonest ebayer has sold me 4 out of 5 bmp280's in lieu of bme280 boards.
i can't tell them apart with naked eye, must admit the temp seems more accurate in absolute terms for the bmp boards there is nearly a 3 deg difference between bme and bmp readings in the same aircon'ed room and thats closer to the mercury bulb . are cheap ebay things always a bit dodgy?

towlerg
- 16th October 2020, 20:09
"are cheap ebay things always a bit dodgy?" not in my experience, most seem surprisingly interested in protecting their feedback score. Try email seller thro ebay and explain the mistake.

richard
- 17th October 2020, 00:11
Try email seller thro ebay and explain the mistake.

did that , even though i have had the boards for 2 months or more , got a full refund within a couple of hours.
quite surprised in a good way

HenrikOlsson
- 17th October 2020, 07:21
Richard,
Your change to the "cast routine" saved some 400bytes worth of code space and probably also executes faster. Thanks!

Yeah, both of my sensors reports temperature which I believe to be 2-3°C above actual. I don't know if it's due to self heating of the sensor itself, the PCB assembly or something else but the fact that they run different code but both reports values very close to each other makes me fairly confident in the code.

Just now when I started it up again, the humidity reading was way high, around 70%.
A restart fixed it and it's now around 42% which is more inline with the other sensor. This seems to happen now and then and I'm not sure what's going on.

/Henrik.

Ioannis
- 17th October 2020, 11:30
Amazing piece of work by both of you! Thanks a lot for sharing!

Ioannis

richard
- 18th October 2020, 06:46
due to self heating of the sensor

seems possible , the fact that the bmp ver is less "hot" tallies with its lower power use [hum sensor nearly doubles the consumption]

my esp code uses forced mode letting it sleep between readings and fares no better anyway, so maybe it is what it is


Just now when I started it up again, the humidity reading was way high, around 70%.
data sheet says writes to config reg 0xf5 may be ignored if device not in sleep mode, maybe por does not always achieve that.
cannot say i have seen any issues with humidity readings from esp code.
the pressure readings are consistent within 2hpa spread across the chips i have


i find just reading the config reg 0xf5 can cause the device to stop responding completely some times