Category Archives: Raspberry Pi

Reliable I2C with a Raspberry Pi and Arduino

There are many ways of connecting sensors and devices to a Raspberry Pi. One of the most popular is the I2C bus. It’s great for devices which don’t need to transfer too much data, like simple sensors and motor controllers, and it’s handy because lots of devices (up to 127, or even more) can be connected to the same pair of wires, which makes life really simple for the experimenter. I’ve mentioned using the I2C bus in another blog post, because sometimes a bit of software fiddling is needed to get it to work.

Recently I’ve been working on a project involving various devices connected to a Raspberry Pi. Some of them use I2C. The project is based around a breakout board I designed for the Multidisciplinary Design Project at Cambridge University Department of Engineering, in which students collaborate in teams to put together a robot. The breakout board is shown next to the Raspberry Pi in the photo below.

IMG_1381

It fits on top of the Pi, and has lots of useful features including a student-proof power supply, real time clock, accelerometer, space for a Zigbee module, analogue inputs, diagnostic LEDs and four motor driving outputs, all wired to convenient connectors.

The analogue inputs and motor outputs are implemented by a PIC microcontroller connected to the I2C bus. The software for the PIC was written by an undergraduate several years ago. It works well, but seems to have some odd habits. I found that it would apparently work, but sometimes an attempt to read data from the PIC would just fail, or return wrong data, and sometimes data would get written to the wrong register. At first I suspected a wiring problem, but examining the SDA and SCL signals with a scope showed nothing wrong. I tested another device on the same bus – a Philips PCF8575 I/O expander – and it worked perfectly every time. That narrowed the problem down to the PIC. Since there was nothing I could do about the PIC’s software, I had to find a workaround.

I spent some time experimenting with where the communications seemed to go wrong. Reading from an I2C device usually involves two separate operations on the bus. The first one tells the I2C device which register address we want to read, and the second does the actual read. The diagram below shows the sequence. The ‘control byte’ in each case sends the address of the I2C device (0x30 in this case) plus a bit indicating read or write.

smbus-transaction

I found a pattern in the failures. From time to time, the write operation which sets the register address would fail, reporting ‘I/O error’. After that, reading the data would return the wrong value. I modified my code so that if the write operation failed, it would retry a couple of times before giving up. It turned out that retrying was always successful, if not on the first attempt then on the second. However, the data read would still return the wrong value. The value returned was always the address of the register I wanted! It seemed as if something was getting stuck somewhere in the I2C system. Whether it was in the Linux drivers, or the PIC software, I don’t know, and I didn’t spend long enough to find out. My assumption is that the PIC software is sometimes just too busy to respond to the I2C operations correctly.

I tried the retry strategy again, and it turned out that the second attempt to read the data byte always got the right value. The algorithm to read reliably looks like this, in pseudo-code:

  if (write_register_address() fails)
    retry up to 3 times;

  read_data();
  if (we had to retry writing register address)
    read_data();

In practice I was using the Linux I2C dev interface to implement this. Yes, it’s a bit of a nasty hacky workaround, but it did get the communications working reliably.

There was another device I wanted to talk to: an Arduino Mini running a very simple sketch to return some sensor data. This also used the I2C bus. There are handy tutorials about how to get an Arduino to behave as an I2C slave device, like this one. The I2C interface is implemented nicely by the Wire library. Implementing a slave involves responding to two events: onReceive and onRequest.

The onReceive event is called when data, like the register address, is written to the slave, and the onRequest event is called when the master wants to read data. My initial code looked like this:

Wire.begin(I2C_ADDRESS)
Wire.onReceive(receiveEvent)
Wire.onRequest(requestEvent)

void receiveEvent(int bytes) {
  registerNumber = Wire.read();
}
void requestEvent() {
  Wire.write(registers[registerNumber];
}

This worked most of the time, but after a few thousand transactions, it would appear to ‘lock up’ and ignore any attempt to change registers – it would always return the same register, and in fact no more onReceive events were ever generated. Of course, it turned out to be my fault. When reading data in the onReceive event code, it turns out to be important to make sure that data is actually available, like this:

void receiveEvent(int bytes) {
  while(Wire.available())
    registerNumber = Wire.read();
}

That solved the problem. It’s annoying that reading non-existent data can lock up the whole I2C interface, so watch out for this one if you’re using an Arduino as an I2C slave.

Advertisements

Orange Internet and port forwarding, continued

A long time ago, I wrote an article about how I worked around the lack of NAT loopback support on the Orange LiveBox broadband router. At the time, it was a pain to get everything working right. Having just moved house, we made the sensible decision to stay with the same broadband provider, in order to avoid having to re-invent or at least re-configure all this stuff.

Well, it turned out not to be as easy as that. Nothing ever is, it seems. The new Orange broadband service comes with a ‘FunBox‘ instead of a ‘LiveBox’. Fun? Who said? Not in my experience. The web interface to the box looks comfortingly similar to the old LiveBox, so I thought it would work the same way. No chance.

funbox2

What’s the problem I’m trying to solve here? Well, I have a little SheevaPlug which hosts some services I need to use from various locations when I’m working. Yes, I know I should put those services ‘in the cloud’, but that would involve both paying money and solving a whole load of other problems. For years and years, I’ve simply had a port forwarding rule set up on my home broadband router so that the SheevaPlug is accessible from the internet. A little touch of dynamic DNS courtesy of dyn.com and it’s all worked fine.

Fast forward to 2015. I tried to recreate the setup I’d always used, but with the FunBox (hah!). The old setup went like this:

home_net_old

  • the broadband router just does the usual NAT routing and behaves as a dumb wi-fi access point. It has a port forwarding rule set up to forward port 22 (ssh) to the SheevaPlug
  • the SheevaPlug hosts my ssh server, and provides the DHCP and DNS services to everything on the network, so I get proper local hostname lookups, easy-to-manage IP addresses, and can solve the NAT loopback problem.

That’s it. I tried to set up the FunBox the same way. What could possibly go wrong?

I boldly switched off the DHCP and DNS servers in the FunBox and switched over to using the ones on my SheevaPlug. Everything seemed to work fine, except…the TV. Yes, the TV decoder is connected to the FunBox via Ethernet, so the whole shebang comes down the wire. No aerial required. Trouble is, the FunBox seems to need to set up the TV decoder by DHCP otherwise it doesn’t know it’s there, so you get no telly. Oh well, I’ll use the DHCP server in the FunBox and put up with the inconvenience.

Even that doesn’t work out. In order to solve the NAT loopback problem, which the miserable FunBox suffers from just like the LiveBox, I need to run my local DNS server. Except that the brain-dead FunBox won’t let you change the DNS settings on its built-in DHCP server. How annoying is that?

OK, accept that NAT loopback will remain a problem. Maybe I’ll find another way round that. Now for the showstopper: the blessed FunBox refuses to forward port 22. It will forward every other port under the sun, but not 22. The web configuration interface just won’t accept the setting: it ignores it. Doesn’t even give an error message. You’re just not having it. Oh well, maybe I have to expose my ssh server on a different port and put up with changing all the gazillion clients which know about it. Except I’ve still got the loopback problem. This is getting unpleasant.

Before tearing out what little remained of my hair by this point, I slept on the problem and had a brainwave. The FunBox supports a ‘DMZ’ feature, in which it’ll forward all incoming internet traffic to a particular IP address on the LAN. I tried it, experimentally sending all internet traffic to the poor, naked SheevaPlug, and it worked! At last, sweet relief: something which does what it says on the tin.

Clearly exposing the server in all its complacent insecurity to the internet isn’t a good idea. I needed to put a firewall in the way. A rummage in the cupboard produced a spare Raspberry Pi and a USB to Ethernet adapter. I programmed OpenWRT on to an SD card and booted up. It turned out to be easier to configure it through the command line than with the web interface, LuCI, which isn’t exactly finished yet. Some fiddling later and I’d managed to disable its DHCP and DNS features and enable incoming connections only on port 22.

Adding the firewall had another bonus: it meant I could re-enable my DNS and DHCP servers and let them look after the LAN without the wretched FunBox knowing anything about it. It just has to live a simple life, looking after the telly and the firewall. I disabled its built-in Wi-fi access point and added an ageing Linksys WAP54G running DD-WRT software after the firewall. Lovely.

home_net_new

There is one fly in the ointment: the Raspberry Pi turns out to make a rubbish router. Our 30 megabit internet connection is reduced to 3 megabits on its way through the Pi. I don’t know if it’s something to do with my configuration, or the release of OpenWRT (15.05-rc3) I’m using. When I’ve unpacked enough boxes to find another router, I’ll try that.

Installing balloonboard.org Debian Linux build on a Raspberry Pi

I’ve just successfully got Debian Linux running on a Raspberry Pi, having built it entirely from the balloonboard.org distribution. Why might you want to do this? Well, I did it because it gives me a small, clean Debian Linux installation which I can then customise. Here’s how I did it.

Get the software:

svn checkout svn://balloonboard.org/balloon/branches/menuconfig2
make menuconfig
  • Mode Expert mode
  • Balloon Board Raspberry Pi board
  • Choose which buildroot version to build -> Feb 2013
  • Select kernel version 3.8 (rpi)
  • Select Build boot image
  • Select Build kernel modules
  • Select Build initrd kernel
  • Select Build Raspberry Pi boot patition image
  • Select Build Debian Root Filesystem

Now type make and it should all build.

Create yourself an SD card with two partitions on it: one smallish FAT partition for the boot files, and a big ext4 one for the root filesystem. Don’t forget to format them.

Into the FAT partition copy the contents of build/kernel/rpi-initrd-boot. Into the ext4 partition untar the file build/rootfs/debianrootstrap.modules.tgz.

Now put the SD card into your Pi and switch it on. This should boot into a ‘recovery kernel’ which has a minimal root filesystem in its initial ramdisk, just enough to sort out the ‘proper’ root filesystem. I used the console serial port to work with it. The HDMI and USB ports might also work but I haven’t tried them. It should come up with a login prompt. Log in as root, password rootme.

Now to configure the root filesystem:

mount /dev/mmcblk0p2 /mnt/root
chroot /mnt/root

Finish the Debian installation (this has to be done now because some aspects of it need to run on the ARM processor, so it’s not easy to have your PC do it). It will ask you questions about time zones and things:

/var/lib/dpkg/info/dash.preinst install
dpkg --configure -a

Set a password for the root account so you can log in

passwd root

and add the serial port to the list of secure ports which are considered safe for root logins:

echo /dev/ttyAMA0 >> /etc/securetty

And shut things down

halt

That last step will probably produce an error message, but it doesn’t matter as long as it’s written everything to the SD card.

Now put the SD card back in your PC, and copy the contents of build/kernel/rpi-boot into the FAT partition. That contains the real kernel which will mount the newly-minted root filesystem. Put it back into the Pi and boot. It will ask you to change the root password at first login.

It worked for me, though I had to ‘ifdown eth0’ and ‘ifup eth0’ again to get Ethernet to work. From that point on I was able to install Debian packages normally.

How to get the second Raspberry Pi I2C bus to work

One of the useful interfaces on the Raspberry Pi is the I2C bus. Originally invented by Philips in the 1970s for controlling functions inside consumer electronics, especially TVs, it’s still very handy for connecting up lowish-speed peripherals to computers. Some of the most popular are real time clocks like the MCP7940, amongst many others, and general purpose input-output chips like the venerable PCF8574. One of its convenient features is that it only involves two wires: SCL (clock) and SDA (data).

pi2c

The Raspberry Pi originally exposed one I2C bus on its GPIO connector, P1. It had another I2C bus dedicated to the camera connector, S5. However, with revision 2 of the Raspberry Pi, another connector was added. This was P5, squeezed in next to P1, and it also carried the second I2C bus, making it easier to get at and use. However, for some reason the two I2C buses got swapped over between revision 1 and revision 2. And to add a further layer of complication, the camera connector and P5 are wired to different GPIO pins on the processor, even though they are both logically the same bus. I’ve tried to summarise the situation in the table below.

Revision 1 Revision 2
GPIO0 SDA0 P1 pin 3 SDA0 S5 pin 13
GPIO1 SCL0 P1 pin 5 SCL0 S5 pin 14
GPIO2 SDA1 S5 pin 13 SDA1 P5 pin 3
GPIO3 SCL1 S5 pin 14 SCL1 P5 pin 4
GPIO28 SDA0 P1 pin 3
GPIO29 SCL0 P1 pin 5

Working on the CUED MDP project recently, I had a need to get the both I2C buses working on a revision 2 Raspberry Pi. There was no problem with the one on P5: typing

i2cdetect -y 1

showed the devices I had connected to it. But

i2cdetect -y 0

showed nothing at all, and examining pins 3 and 5 of P1 showed no activity. Disappointing. After a bit of digging, it seemed to me that the standard Raspberry Pi Linux kernel configures the processor to use GPIO 0 and 1 as I2C bus 0, and GPIO 2 and 3 as I2C bus 1. I wanted the bus on P1 to work, so I needed GPIO 28 and 29 to be my bus 0.

The BCM2835 processor on the Raspberry Pi, like most modern integrated processors, can have its pins programmed to do various different functions. In this case I needed to disable I2C on GPIO 0 and 1 and enable it on GPIO 28 and 29. To do this I enlisted the help of Mike McCauley’s BCM2835 library. It makes reprogramming the GPIOs fairly straightforward.

To install the library on your Raspberry Pi, make sure it’s connected to the internet, then:

wget http://www.airspayce.com/mikem/bcm2835/bcm2835-1.26.tar.gz
tar xzvf bcm2835-1.26.tar.gz
cd bcm2835-1.26
./configure
make
sudo make check
sudo make install

By the time you read this, there might be a new version of the library, so check on Mike’s site to see what you’re getting.

The C code to set up the bus looks like this:

#include <bcm2835.h> 

#define BCM2835_GPIO_FSEL_INPT 0 
#define BCM2835_GPIO_FSEL_ALT0 4 

main() {
    bcm2835_init(); 
    bcm2835_gpio_fsel(0, BCM2835_GPIO_FSEL_INPT); 
    bcm2835_gpio_fsel(1, BCM2835_GPIO_FSEL_INPT); 
    bcm2835_gpio_fsel(28, BCM2835_GPIO_FSEL_INPT); 
    bcm2835_gpio_fsel(29, BCM2835_GPIO_FSEL_INPT); 

    bcm2835_gpio_fsel(28, BCM2835_GPIO_FSEL_ALT0); 
    bcm2835_gpio_set_pud(28, BCM2835_GPIO_PUD_UP); 
    bcm2835_gpio_fsel(29, BCM2835_GPIO_FSEL_ALT0); 
    bcm2835_gpio_set_pud(29, BCM2835_GPIO_PUD_UP); 
}

It initialises the library, sets GPIO 0 and 1 as normal inputs (thus disabling their I2C function) and enables GPIO 28 and 29 as alternate function 0 (I2C bus), with pullup enabled. To build it, cut and paste the code into a file. I called it i2c0.c. Then compile it:

cc i2c0.c -o i2c0 -lbcm2835

and run it:

sudo ./i2c0

Now I2C bus 0 will be active on P1. Well, it worked for me. Once the code is compiled, of course, you can just run ‘i2c0’ after booting the Pi.

I realise that in future this will probably be made obsolete by changing the device tree sent to the Linux kernel at boot time, but for now it’s useful!

Cross-building for ARM on Debian squeeze and lenny

I have to support some software running under Debian Linux 5.0 (lenny) on ARM hardware. The operating system on this hardware can’t easily be upgraded because it’s expensive to get at physically, but there is a mechanism for updating the application it runs. This is an interesting problem in maintaining old software. The ‘stable’ releases of Debian have a reputation for being rather infrequent and almost out-of-date by the time they’re released, but in this case, a release every two years is too often! In embedded applications, having the latest and greatest doesn’t matter as long as it works and doesn’t change.

I have recently had to build a new release of the application software for this ARM hardware. My main Linux machine is now running Debian 7.0 (wheezy), which does a great job of cross-building for ARM, but unfortunately the resulting binaries are linked with libstdc++.so.6.0.17. The old lenny machines have version 6.0.10, which is too old to run these binaries.

For those not familiar with Debian Linux, the relevant versions go like this:

5.0 lenny (released February 2009)
6.0 squeeze (released February 2011)
7.0 wheezy (current as of July 2013)

I fiddled around for a while trying to install older libstdc++ packages under wheezy, but found myself in dependency hell, so I decided simply to revive an ancient PC which was already running Debian 6.0 (squeeze) and press it into service for doing the build.

Getting the ARM toolchain installed wasn’t hard. I had to add the line

deb http://ftp.uk.debian.org/emdebian/toolchains squeeze main

to /etc/apt/sources.list, and do

apt-get install g++-4.4-arm-linux-gnueabi

and it all worked. However, the code I was working on depended on a library, which I needed to install in its ARM version. There’s a handy tool, xapt, which will arrange this for you. However, it’s not natively available on squeeze but has been backported from wheezy, so I had to add

deb http://ftp.uk.debian.org/debian-backports squeeze-backports main

to /etc/apt/sources.list. Then

apt-get install -t squeeze-backports xapt
xapt -a armel libxxx-dev

and my library package was built and installed automagically. Nice.

However, this wasn’t enough. It turned out that I really had to build everything on lenny in order to get it to work – it seems that the libstdc++ from wheezy is compatible with squeeze, but neither wheezy nor squeeze is compatible with lenny.

First, I had to set up a lenny machine. This isn’t as easy as it used to be because lenny is no longer supported by Debian, and exists only as an archive. We should be grateful that it’s there at all. I set up a new virtual machine using VirtualBox and downloaded the last lenny netinst CD image (5.0.10) from archive.debian.org. There’s a problem during installation: it asks which Debian package repository it should use, but all of the available choices fail because the lenny packages aren’t there any more. The solution is to select ‘Back’ and allow it to continue without a repository. It complains, but it works. After it had rebooted, I manually edited /etc/apt/sources.list, commenting out the cdrom line and adding a pointer to the archive:

deb http://archive.debian.org/debian-archive/debian/ lenny main

Then I could install the packages I wanted (subversion, scons and other tools). Now to get the cross-building tools. Sorting out the ARM version of gcc wasn’t too hard. I added

deb http://www.emdebian.org/debian lenny main

to sources.list and was able to install gcc-4.3-arm-linux-gnueabi and g++. Apt complains about a lack of signatures, but that doesn’t stop anything working. I still had to get libssl-dev, though. The xapt tool doesn’t exist on Lenny so I had to use apt-cross, a tool which is an earlier attempt at doing the same thing:

apt-get install apt-cross

and add a source entry to /etc/apt/sources.list:

deb-src http://archive.debian.org/debian-archive/debian/ lenny main

then do

apt-cross -a armel -S lenny -u
apt-cross -a armel -S lenny -i libxxx-dev

and everything happened as it should. Now at last I could build my code and, with fingers crossed, run it on my embedded Debian Lenny machine.

I have to say that I think Debian’s support for cross-building is outstandingly good. Tools like apt-cross and xapt make it much easier than it could be, and the work continues with the multiarch project which improves support still further.

Raspberry Pi portable development system

I’m often away from my lab and need to carry on working, in airports, co-working offices, at customer premises and so on. Of course, I have a laptop, but that only goes so far when you’re working on embedded Linux hardware. I need to be able to take the hardware with me, and work with it.

Recently I’ve been doing some work with the Raspberry Pi. The Pi is normally set up so that you plug a monitor, keyboard and mouse into it and use it as a desktop computer. That’s OK, but inconvenient for travelling with. You can also log in to it over a network, but that’s not a great idea when I have no idea what networking facilities, if any, will be available where I’m working.

My preferred way of talking to embedded systems is old-fashioned: over a serial port. It may not be the fastest, but it’s reliable and need no infrastructure at all. The Raspberry Pi has a serial port on its GPIO connector, pins 8 and 10, and the standard Raspbian Linux distribution has it set up to be a console. That’s just what I want. Now I just needed a way to connect it to my laptop.

As luck would have it, FTDI make some handy USB-to-serial converter cables. The one I chose for this application is the TTL-232R-3V3. They’re available from various places, but I bought mine from Farnell, part number 1329311.

The connector on the FTDI cable has six pins. As delivered, they are

DSC_0485

  1. Black GND
  2. Brown CTS
  3. Red VCC
  4. Orange TXD
  5. Yellow RXD
  6. Green RTS

The pins along the edge of the Raspberry Pi’s GPIO connector go:

2. +5V
4. +5V
6. 0V
8. TXD
10. RXD

Ooh! How convenient. The 5V power input is available next to the serial port. By rearranging the pins on the FTDI cable’s connector, it’s possible to make a cable which will both power the Raspberry Pi from USB and connect the console to the serial port. That’s perfect for mobile use. The cable is easy to modify: the pins are held in by little black plastic tabs which you can gently bend back with a jeweller’s screwdriver, tweezers or a scalpel. The modified cable is wired like this:

DSC_0487

  1. Red +5V
  2. not connected
  3. Black 0V
  4. Yellow TXD
  5. Orange RXD
  6. not connected

The spare brown and green should be cut off or insulated.

It works! I can drive a Raspberry Pi from my laptop with just this one cable. Very handy. Just be careful to plug it in to the right place on your Raspberry Pi’s GPIO connector, right in the corner. Any other location will apply 5 volts to a pin which isn’t expecting it, and could damage your Pi.

DSC_0488

There are a couple of finishing touches, however. I like to be allowed the responsibility of logging in as root, which Raspbian normally has disabled. It may not be good for schoolchildren to be able to do this, but for embedded developers fiddling with kernel drivers, it’s a great time-saver.

To enable root logins on the serial port, you’ll need to:

  • Enable the password on the root account:

Log in as the default user (user name pi, password raspberry), then

sudo passwd root

Then enter your desired root password twice.

  • Enable root login on the serial console:
echo ttyAMA0 >> /etc/securetty

That’s it. You’re all set.

Raspberry Pi Power Architecture

Embarking on some work with the Raspberry Pi recently, I wanted to know what its power architecture looked like. The schematic diagrams are freely available but a quick web search didn’t reveal any higher-level design documents like this, so I drew my own and here it is.

I offer no guarantees of accuracy. Don’t blame me if you use this documentation and destroy your Raspberry Pi or anything else. This is not an official document. I hope it’s useful to someone.

The original version of this that I posted in April 2013 had a mistake in it, which Kai kindly pointed out. The version below has been corrected.

Raspberry Pi Power Architecture2

There’s a nice shiny pdf of it here: Raspberry Pi Power Architecture