Delving the depths of computing,
hoping not to get eaten by a wumpus

By Timm Murray

Arduino/Raspberry Pi -- TWI

2013-10-14


NOTE: This post was moved over from WumpusUAV.com. The Indiegogo campaign was not successful, so I’m copying some key posts from there to over here and shutting the site down.

NOTE 2: I later found that these instructions are flawed. You need to convert between the 3.3V signal on the Raspberry Pi to the 5V signals on the Arduino. Or get a 3.3V Arduino. I’ve ordered the Sparkfun Bi-Direction Logic Level Converter and will report back once I’ve received it.

Two Wire Interface (TWI) is a simple means of communication between two systems. “I2C” is another name for basically the same thing. On the Arduino side, it is implemented by the Wire library. On Raspberry Pi under Perl, we will use HiPi::BCM2835::I2C.

Hardware Setup

Take a look at the Raspberry Pi version 2 header pinout. With the header on the top-left, the I2C pins are the second and third pins on the bottom row. The Arduino pins depend on the board; see the link above to the Wire library for details.

The SDA pin (Serial Data Line) and SCL pin (Serial Clock Line) between the two boards must be connected. We also need to connect the Raspberry Pi’s GND and +5V wires to the Arduino’s GND and Vin pins, respectively.

(If the Arduino is powered externally, then only the GND wire needs to be connected to the Raspbery Pi.)

When using Raspbian on the Raspberry Pi, you need to load the kernel modules i2c_dev and i2c_bcm2708. The second one is blacklisted by default in /etc/modprobe.d/raspi-blacklist.conf, so remove it from there. It’s also handy to add these modules to /etc/modules so that they get loaded on startup.

Add your user to the i2c group if you want to be able to connect without being root.

Raspberry Pi Programming

On Raspberry Pi revision 2, the I2C pins on the main header are actually the second I2C device. The first sits on a secondary ribbon header, which is currently used for the Raspberry Pi camera accessory. Thus, we use the device /dev/i2c-1.

Each slave (which will be the Arduino board) needs an address starting at 4 and up to 127. The currently connected devices can be scanned with i2cdetect -y 1.

Example Perl program:

#!perl
use v5.14;
use HiPi::BCM2835::I2C qw( :all );
use constant ADDR       => 0x28;
use constant DEVICE     => '/dev/i2c-1';
use constant BUSMODE    => 'i2c';
use constant SLAVE_ADDR => 0x04;
use constant REGISTER   => 0x00;

my $DATA = 0x05;

#say "Baudrate: " . HiPi::Device::I2C->get_baudrate;


my $dev = HiPi::BCM2835::I2C->new(
        peripheral => BB_I2C_PERI_1,
        address    => SLAVE_ADDR,
);

say "Sending [$DATA]";
$dev->i2c_write( REGISTER, $DATA );
my @recv = $dev->bus_read( REGISTER, 1 );
say 'Got [' . join( ", ", @recv ) . ']';

Arduino

We intitilize the Wire library with the slave address. It then takes functions as arguments to onReceive and onRequest.

The loop() function will simply delay.

A complete example:

#include 

#define SLAVE_ADDR 0x04


uint8_t last_read_byte = 42;

void setup()
{
    Wire.begin( SLAVE_ADDR );
    Wire.onReceive( read_event );
    Wire.onRequest( write_event );
}

void loop()
{
    delay( 1000 );
}

void read_event( int len )
{
    last_read_byte = Wire.read();
}

void write_event()
{
    Wire.write( last_read_byte ):
}

References

http://neophob.com/2013/04/i2c-communication-between-a-rpi-and-a-arduino/



Copyright © 2024 Timm Murray
CC BY-NC

Opinions expressed are solely my own and do not express the views or opinions of my employer.