Sunday, March 17, 2013

Raspberry Pi and Repeated Start I2C

Note : 04 April 2016 : I2C repeated start transfers have been supported by the kernel device drivers for some time. Explicit support has been added to the HiPi modules with Release 0.46 

The MPL3115A2 pressure and temperature sensor from Freescale looked like an interesting thing to connect to my Raspberry, so an order was made and the new toy awaited.

I should've Googled first. The sensor requires a particular sequence in the i2c communication protocol known as a repeated start that the i2c device driver on Raspberry doesn't support. Google, consulted belatedly, seemed to confirm it couldn't be done.

Many hours of manic manual reading and code tinkering later, HiPi Perl Modules 0.23 is released including support for repeated-start reads and a HiPi::Interface::MPL3115A2 module to demonstrate the basics.

The answer lay in the BCM2835 manual and its instruction on how to use 10 bit addressing on the i2c bus. To do this you require a repeated start and the manual provides a sequence to achieve this.

Hurrah!

Now my Pi is complete with accurate pressure readings.


The code is straightforward enough if using the provided wrappers. A quick browse of the source should make it clear how to code your own custom applications.

The code that produces the above output is:


#!/usr/bin/perl

use strict;

use warnings;

use HiPi::Interface::MPL3115A2;
# at this point HiPi::BCM2835 is already
# loaded as a dependency but we'll be
# explicit as this is an example
use HiPi::BCM2835;
# for permissions action
use HiPi::Utils;

# let user know if they need sudo
if( $< ) { die 'script must be run using sudo'; }

my $username = getpwuid($<);
print qq(Start up user $username\n);

# initialise the library early then reduce our permissions.
my $targetuser = getlogin() || 'pi';
HiPi::BCM2835->bcm2835_init();
HiPi::Utils::drop_permissions_name($targetuser, $targetuser);

$username = getpwuid($<);
print qq(Now running as user $username\n);

# do work with data
my $dev = HiPi::Interface::MPL3115A2->new;

my $devid = $dev->who_am_i;
print qq(Device ID   $devid\n);

my ( $alt, $pre, $tem ) = $dev->os_all_data() ;
print qq(Temperature $tem\n);
print qq(Pressure    $pre\n);
print qq(Altitude    $alt\n);


The module for HiPi::Interface::MPL3115A2  uses the module wrappers for Mike McCauley's bcm2835 library.  HiPi::BCM2835 and HiPi::BCM2835::I2C need root permissions for read write access to /dev/mem. We can reduce the security problem somewhat by reducing permissions to a less privileged user as demonstrated in the code immediately after initialising HiPi::BCM2835.

So, frustrated Pi owners with dormant MPL3115A2 devices, rejoice - Perl has saved the day.

The modules now have 3 different ways to access I2C, smbus, i2c and  the bcm2835 method shown here. Overkill but I had wrapped them anyway in an attempt to discover the secret of repeat starts.

Install instructions for modules are here.

If you were wise enough to install version 0.21, then upgrade is simple:

hipi-upgrade

If you want to browse the source, version 0.23 should be the default on CPAN soon.

The necessaries have also made it into version 1.24 of the C bcm2835 library released today ( see bcm2835_i2c_read_register_rs ).