I bought a cheap as BMP180 sensor (it's a pin & software compatible updated version of the BMP085) from eBay for £1.19 and hooked it up to the first working Arduino I could find (which was about the third one I tried - really need to fix the others) and got out glorious pressure and temperature data over the serial port with the help of the Adafruit library.
Great! Getting this going on the Tilda should be easy as. I knew from a bit of tinkering with the badge I did on site over the EMF Camp weekend that they were using an RTOS and they'd helpfully added a 'Hello World' app in the firmware for hacking purposes. I quickly modified the Hello World app to display the temperature.
It didn't work.
Huh. Somewhere in the back of my mind, I recalled that the Arduino Due (which the Tilda is based on) has two I2C interfaces. My first thought, confirmed by a quick look at the schematic, was that perhaps the Tilda's SDA and SCL pins that were brought out on the Arduino header weren't connected to the first I2C interface, which is what would be referred to when you normally use the wire library.
No worries. I just had to modify the Adafruit library to use wire1 instead of wire. A bit of find/replace and I was getting temperature data displayed on the LCD. Yay.
From here, it should just be a case of adding in the call to read and display the pressure.
It didn't work.
But not in the way I had expected. I was geting some pressure data, but it was way, way too low. Like it thought I was up at 40,000m kind of atmospheric pressure.
I spent a bit of time futzing about with various things. I knew it had to be related to the Tilda somehow so I looked into the RTOS and delved deep into the BMP085 datasheet.
To measure the pressure with the BMP085 takes three steps:
- Firstly, each unit is individually calibrated at manufacture. The various calibration registers need to be read and their values saved for later calculations.
- The pressure value is temperature sensitive as well, so the (uncompensated) temperature needs to be read from the chip and the true temperature calculated with the calibration data.
- Lastly, read the uncompensated pressure value and, with the aid of the calibration data and the compensated temperature, you can go through a 15-step calculation to arrive at the correct pressure.
if (oversampling == BMP085_ULTRALOWPOWER)I knew that doing this kind of blocking delay would stop background tasks in the RTOS from working so I changed them all to Tilda::delay() as suggested, and crossed my fingers.
else if (oversampling == BMP085_STANDARD)
else if (oversampling == BMP085_HIGHRES)
It didn't work. I was getting a little bit annoyed at this point, so decided to take a little several week break.
When I came back to it I continued looking at the way the Tilda was reading in the pressure data from the BMP085. Since the temperature was being calculated correctly it didn't point to an error in the calibration data or temperature reading.
To confirm that it wasn't a hardware problem with my Tilda, I decided to try programming it as an Arduino (ie, without the RTOS). Unfortunately, if you try this in the latest Arduino software (currently 1.6.4) you'll get a heap of errors like this:
/home/peter/Downloads/Mk2-Firmware-master/hardware/emfcamp/sam/variants/tilda_mke_v0.333/variant.cpp:342:55: note: candidates are:The easiest solution was to use an older version of Arduino. I had a guess at which one they'd used to write the Tilda software in the first place and picked version 1.5.7, which worked fine.
In file included from /home/peter/Downloads/Mk2-Firmware-master/hardware/emfcamp/sam/variants/tilda_mke_v0.333/variant.h:43:0,
/home/peter/.arduino15/packages/arduino/hardware/sam/1.6.4/cores/arduino/UARTClass.h:45:5: note: UARTClass::UARTClass(Uart*, IRQn_Type, uint32_t, RingBuffer*, RingBuffer*)
I used the test sketch from the Adafruit BMP085 library (after modifying it to use wire1 again) and I was getting the correct temperature and pressure data out of the serial port!
Now I knew it wasn't a hardware problem, I needed to see the communication between the Tilda and the BMP180, and I had exactly the tool for the job, having recently acquired a Rigol DS1054Z Oscilloscope.
I fired it up and was quickly able to probe the SCL (clock, top in yellow) and SDA (data, bottom in blue)
Zooming in on the last burst, we can use the DS1054's decode function to see what all these blips actually correspond to:
This is with the Tilda in Arduino mode - the data being read is 0xA26C20 (decimal 10644512).
Obviously I was now going to have to delve into the calculations. Here's the page in the datasheet that describes the procedure:
Err... that looks complicated. I ended up making a spreadsheet to help. I plugged both uncorrected pressure values into the spreadsheet and got consistent pressure values out. Well fuck. I was pretty sure now that the bug was somewhere deep in the RTOS and I really didn't think I was going to be able to find it. Unless....
I'd been working on the assumption that the calibration data was being read ok because the temperature was being calculated correctly. However, after working through the calculation in my spreadsheet I knew that most of the calibration data doesn't get used until the pressure calculation.
I got the Tilda to spit out the calibration data in both Arduino mode and the RTOS and lo and behold, the values for AC1 and AC5 differed markedly. I guessed that some background task in the RTOS was interfering with the read. I had a stab at fixing it by adding in a delay into the library:
Wire1.begin();Which worked perfectly! All of that time and frustration was fixed by a 5ms delay in the right place, apparently.
if (read8(0xD0) != 0x55) return false;
/* read calibration data */
ac1 = read16(BMP085_CAL_AC1);
ac2 = read16(BMP085_CAL_AC2);
ac3 = read16(BMP085_CAL_AC3);
ac4 = read16(BMP085_CAL_AC4);
ac5 = read16(BMP085_CAL_AC5);
ac6 = read16(BMP085_CAL_AC6);
Niiiiiiiice! I'm not exactly convinced the temperature is 100% correct. It seems to be a couple of degrees warmer than I think it should be. The pressure looks to be correct though.
Next time: Making it into a usable barometer.