Wednesday, March 18, 2015

BMP180 Barometric sensor, with I2C bus

It's been more than a month since the last post, but anyways. This time around, we're messing around I2C (TWI) or so called Inter-Integrated Circuit (Two wire interface). For the example we'll take whatever the heck I have around, that works with I2C, luckily enough, I have a BMP180 digital pressure sensor (datasheet), with it's breakout board. I saw few around, some had on-board regulators, others not. However, check for your breakout board before connecting. Notice, that because SCL and SDA are open collectors, they in most cases will be 5 volt tolerant. Ok, let's get started..

A little about I2C

If you search for "I2C", you'll end up getting something that looks like this:
I2C is a multi-master, multi-slave, single-ended, serial computer bus invented by Philips Semiconductor, known today as NXP Semiconductors, used for attaching low-speed peripherals to computer motherboards and embedded systems.
Now what is the meaning of this hard words ? Well, at first, it's multi-slave, meaning more than one slave devices can be connected. Same for the multi-master, and single-ended, as for not differential, it's just one wire, that carries voltage over the common wire, and that voltage is representing data.
There are several signals over the bus, so there is the Start, Stop, ACK and NACK, and probably some others that we wouldn't care about right now. So all the transmission over I2C happens with 9 bits - 8 general data bits, and 1 acknowledgement bit. By general data I mean all the information transmitted over the bus, and the ACK bit is used for feedback from Master to Slave, or Slave to Master.
Everything starts with a Master device asking for the bus, as for asking for microphone to talk to all the Slaves .. well it got kindof dark, but hang with me here.. The asking for microphone so to say, is the Start signal. After the start signal, everyone listens to whatever the one with microphone will say. It addresses the desired slave, and it is being done by the special 7 bit address that should be unique for the slave device. After the 7 bit address, there is another bit, representing Read or !Write (1 to read, 0 to write), and as discussed earlier, the last bit is the ACK bit, which the slave device should send back, if it is being addressed. With 7 bit address range there would be 27 possible addresses, which is 128. But there is a broadcast address, 0x00, so 128 - 1 gives 127 possible slave devices on the same data bus.
After addressing the desired slave device (or all of them), the Master starts transmitting data bits, 8 by 8, listening to the ACK bit. The slave device, on it's own will send acknowledgement until it reads the data, once it's done, it will send a NACK, or in other words, won't send the ACK bit. Same goes on when the Master sends a read command, although in that case, Master is one sending ACK or NACK's, and is listening to data bits transmitted by the slave device.
On the hardware level, there are two lines - SDA or data line, and SCL or the clock. The clock line is always being driven by the Master. Both lines are being pulled high with pull up resistors, the value of which is depending on the number of devices, voltage and line capacity. In simple cases 4.7k to 10k would work. All data is transmitted by letting the line high, or grounding it. More info about I2C standard can be found here.

I2C on AVR's

Most of the AVR 8 bit microcontrollers have hardware implementation of I2C or TWI as they call it. It saves a lot of trouble, and allows to get pretty high speeds with it. It should be noted, that all the information to configure and get Two Wire interface rolling on AVRs is in the magical document, so called datasheet. Of course you could save trouble and use already made libraries, but .. whatever, choose yourself. I chose to make a simple library for later projects.
To get rolling, you'll need to know few registers. Names might change from my Atmega16 to your whatever the hell you'd use, but the general algorithm is the same.
  1. Set the TWBR - baud rate register, which is used to configure the clock frequency, together with the TWPS bits
  2. The start signal is done by setting TWSTA, TWEN, TWINT bits in TWCR in Two Wire Control register
  3. The stop signal is done by setting TWSTO, TWEN, TWINT bits in TWCR in Two Wire Control register
  4. You should poll for TWINT bit in TWCR
  5. You should take proper actions to the TWSR
I'll do a more specified tutorial/guide about TWI, if it is really necessary, but I'm pretty sure datasheet has plenty enough info in it already.

BMP 180 - the calculating mathematical hell

On BMP 180 datasheet, page 15, there is the algorithm of doing stuff with this sensor. You begin by reading all the calibrated variables, that at first sight you'd think nobody needs. It is done, by start TWI transmission, sending the address of register that you want to read, restarting transmission, this time with READ address, and reading as much as you want. Don't forget to send NACK after the last byte. Once you have those hellish 11 2 byte variables, some of them signed, few unsigned, you can start the next easy part..
Now, you can either select convert temperature, or convert pressure(page 21). Again, you start TWI transmission, send the control register address (0xF4), and send either convert temp(0x2E) or convert pressure(0x34). The OSS stands for oversampling, which is used to get more accurate data (up to 19 bits). However, for sake of simplicity, we'll do OSS=0, so 0x34 for convert pressure. Both of those processes, take some time. So after sending 0XF4(register address), send once for temperature, once for pressure. Stop TWI transmission, wait ~4.5 ms.
To read the unconverted, or unreal temperature and pressure data, start TWI transmission, send the MSB byte address (0xF6), restart, this time with read address, and read two bytes. At this moment, you should have both unconverted temperature and pressure data, as 16 bit unsigned integers.

The real value calculation ~_~

As you might have noticed, converting the unconverted data to useful information, takes quite some effort (page 15). Well at least this part doesn't take much of explanation, just do as the datasheet says. And after hours of conversation, you'll get unreal numbers, probably because you made few mistakes here and there. Try several other times, I'm sure you'll get it working afterall..
In my case, I did get something, it looked in my debug terminal something like this:

To check, and make sure that your data is somewhat real, use this web page to find altitude at your location, and this web page calculator thingy, to calculate weather using the pressure and temperature, your data is real or not. I got around 1259 m, which is quite about right. All the code part of this project can be found at this blog's bitbucket repository. Thanks for reading! :)