The MPL3115A2 is a precision pressure and temperature sensor. I bought mine from SparkFun.
MPL3115A2: https://www.sparkfun.com/products/11084
Installing I2C for Pi
Getting started you'll have to install the I2C packages for Raspberry Pi, and enable them.From a Raspberry Pi terminal use the following commands:
sudo apt-get install python-smbus
sudo apt-get install i2c-tools
Enable the modules by adding them to /etc/modules
sudo nano /etc/modules
and add the following two lines:
i2c-bcm2708
i2c-dev
Remove the modules from the blacklist by commenting them out "add # to the front"
sudo nano /etc/modprobe.d/raspi-blacklist.conf
Make sure the spi and i2c lines are commented out:
#blacklist spi-bcm2708
#blacklist i2c-bcm2708
Lastly, the MPL3115A2 requires a proper repeated start command in it's I2C communication. Raspberry Pi doesn't do this out of the box, but there is a kernel module that can be enabled to make it perform repeated start correctly. Run the following commands to enable repeated start on the Pi:
sudo su -
echo -n 1 > /sys/module/i2c_bcm2708/parameters/combined
exit
More details about the repeated start problem can be found here:http://www.raspberrypi.org/forums/viewtopic.php?f=44&t=15840&start=25
Connecting the Sensor
Next solder some headers to the breakout and connect it to the Raspberry Pi. You'll want to use the following Raspberry Pi GPIO pinout:pin | sensor |
---|---|
1 | VCC |
3 | SDA |
5 | SCL |
6 | Ground |
Python I2C Code
Finally, we need to write some code to read data from the sensor. The following is an example Python program to use smbus to read data from the sensor.MPL3115A2.py
from smbus import SMBus
import time
# Special Chars
deg = u'\N{DEGREE SIGN}'
# I2C Constants
ADDR = 0x60
CTRL_REG1 = 0x26
PT_DATA_CFG = 0x13
bus = SMBus(1)
who_am_i = bus.read_byte_data(ADDR, 0x0C)
print hex(who_am_i)
if who_am_i != 0xc4:
print "Device not active."
exit(1)
# Set oversample rate to 128
setting = bus.read_byte_data(ADDR, CTRL_REG1)
newSetting = setting | 0x38
bus.write_byte_data(ADDR, CTRL_REG1, newSetting)
# Enable event flags
bus.write_byte_data(ADDR, PT_DATA_CFG, 0x07)
# Toggel One Shot
setting = bus.read_byte_data(ADDR, CTRL_REG1)
if (setting & 0x02) == 0:
bus.write_byte_data(ADDR, CTRL_REG1, (setting | 0x02))
# Read sensor data
print "Waiting for data..."
status = bus.read_byte_data(ADDR,0x00)
while (status & 0x08) == 0:
#print bin(status)
status = bus.read_byte_data(ADDR,0x00)
time.sleep(0.5)
print "Reading sensor data..."
p_data = bus.read_i2c_block_data(ADDR,0x01,3)
t_data = bus.read_i2c_block_data(ADDR,0x04,2)
status = bus.read_byte_data(ADDR,0x00)
print "status: "+bin(status)
p_msb = p_data[0]
p_csb = p_data[1]
p_lsb = p_data[2]
t_msb = t_data[0]
t_lsb = t_data[1]
pressure = (p_msb << 10) | (p_csb << 2) | (p_lsb >> 6)
p_decimal = ((p_lsb & 0x30) >> 4)/4.0
celsius = t_msb + (t_lsb >> 4)/16.0
fahrenheit = (celsius * 9)/5 + 32
print "Pressure and Temperature at "+time.strftime('%m/%d/%Y %H:%M:%S%z')
print str(pressure+p_decimal)+" Pa"
print str(celsius)+deg+"C"
print str(fahrenheit)+deg+"F"
Sample Output:
pi@raspberrypi ~ $ sudo python MPL3115A2.py
0xc4
Waiting for data...
Reading sensor data...
status: 0b0
Pressure and Temperature at 12/10/2014 04:51:56+0000
99838.75 Pa
20.375°C
68.675°F
More Resources
MPL3115A2 Datasheet:http://dlnmh9ip6v2uc.cloudfront.net/datasheets/Sensors/Pressure/MPL3115A2.pdf
Arduino code for reference:
https://github.com/sparkfun/MPL3115A2_Breakout/blob/master/firmware/MPL3115A2/MPL3115A2.ino
Did you change any of the settings previously? When I copy and run your code 1:1 it works but shows odd values for the pressure. Instead of a value around 100,000 I get values around 130.
ReplyDeleteSo I wonder if there are some registers that you need to set before running this code for the first time? Since you have these two lines you are using the previous settings:
setting = bus.read_byte_data(ADDR, CTRL_REG1)
newSetting = setting | 0x38
The temperature values that my sensor returns are correct though so clearly it has to do with some settings for the barometer. Looking through the data sheet I don't quite see though what that could be.
I should add that the p_MSB byte always comes out as zero
DeleteFound the problem. You need to change the line
ReplyDeletenewSetting = setting | 0x38
to
newSetting = 0x38
This will guarantee that it works as a barometer. For some reason it was set to work as an altimeter by default. Although the data sheet claims that barometer is the default but maybe the factory quality control test when they assembled the module changed it to altimeter.
This comment has been removed by the author.
ReplyDeleteI keep getting some variation of the following:
ReplyDelete0xc4
Traceback (most recent call last):
File "mpl3115a2.py", line 20, in
setting = bus.read_byte_data(ADDR, CTRL_REG1)
IOError: [Errno 110] Connection timed out
Sometimes it doesn't even make it past who_am_i query.
I'm getting similar results with Node.js and am wondering if maybe someone has some advice?
Hey John,
DeleteI'm having the issue that you have, it never past who_am_i query. The display is always 0x0, Device not active.
Have you found any solutions to solve this problem yet?
Thanks in advanced.
Fixed it. Had an erroneous i2c_arm_baudrate set in /boot/config.txt
ReplyDeleteWhat exact setting did you use?
ReplyDeleteI had what I assume was a terminal connection issue (or maybe a vi macro mistake) that rendered a series of ones and zeros probably a dozen digits long. It wasn't even remotely a correct setting. Since I discovered that it has been working perfectly. I wasn't able to get the second i2c channel to work with another MPL3115A2 but luckily I had several multiplexers lying about. I'm currently using the two sensors to approximate air flow through an aperture and things seem to be working well. Thank you for this incredibly helpful writeup.
ReplyDeleteI had what I assume was a terminal connection issue (or maybe a vi macro mistake) that rendered a series of ones and zeros probably a dozen digits long. It wasn't even remotely a correct setting. Since I discovered that it has been working perfectly. I wasn't able to get the second i2c channel to work with another MPL3115A2 but luckily I had several multiplexers lying about. I'm currently using the two sensors to approximate air flow through an aperture and things seem to be working well. Thank you for this incredibly helpful writeup.
ReplyDeleteI got a MPL3115A2 from adafruit. I am having a problem where your script says my device is not active. Just wonder how to get pass this part. I think I have a active device and i2cdetect shows something working.
ReplyDeletepi@rpi ~ $ sudo python MPL3115A2.py
0x0
Device not active.
pi@rpi ~ $ sudo i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: 60 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
pi@rpi ~ $ cat /sys/module/i2c_bcm2708/parameters/combined
Y
Thanks for your help.
Doug
did this problem ever get fixed for you? I'm having the same problem
DeleteI discarded that bit of code when I translated from Python to javascript for Node. If I recall, I had issues with it too. I could still use the sensor without looking for the WHO_AM_I every time. Maybe the author has a solution.
ReplyDeleteCan you please answer these questions?
ReplyDelete1.
Where did you find out the MPL3115A2 requires a proper repeated start command in it's I2C communication? I browsed a datasheet, but did not find. I probably overlooked it or used a different manual.
2. After
sudo su -
echo -n 1 > /sys/module/i2c_bcm2708/parameters/combined
exit
. How can I check my Raspberry was setup properly?
3.
what param is the value '3' in command
p_data = bus.read_i2c_block_data(ADDR,0x01,3)
For those ones interested in using MPL3115A2 + python on Raspberry pi.
ReplyDeleteThere is one good guy who wrote a hole bunch of stuff for RPI including python code for MPL3115A2. Here is a link:
https://github.com/sensorian/sensorian-firmware/tree/master/Drivers_Python/MPL3115A2
After rebooting the Pi the 'combined' parameter is back to being turned off.
ReplyDeleteTo make the change permanent, you might want to create a file in /etc/modprobe.d containint the following line:
options i2c_bcm2708 combined=1
That will survive a reboot.
I used this http://www.instructables.com/id/Raspberry-Pi-MPL3115A2-Precision-Altimeter-Sensor--1/?ALLSTEPS works with Pi3 (enable I2C first, install Python SMBus libraries)
ReplyDelete