Tuesday, March 12, 2013

Modules and GUI App Released

I've recently returned to tinkering with Perl on the Raspberry Pi and have published the results as a set of modules and a GUI application.

Unlike my previous effort I've abandoned the idea of a whole distribution of Perl containing the modules I required. The new module distribution is designed to be installed in the standard system Perl on Raspbian Wheezy and installs nearly all of its dependencies using apt-get.

The only exceptions  are the Perl GUI modules. As the current maintainer of wxPerl  I wanted the latest and working installation of Wx and wxWidgets. This isn't available in current Debian based distributions so I've provided pre-built binaries that are installed using PAR::Dist.

I'm quite new to coding access to device drivers and obviously new to accessing the hardware directly so having figured out how to do what I wanted to I decided to wrap up controlling the GPIO and device settings in a GUI.

I found some nice detail about board revisions on the Raspberry Pi Wiki and combined that with the content of /proc/cpuinfo to populate the first tab of my application.

Now I can wonder why my BogoMIPS seem to have reduced to a fixed value across my Model A and my Model B board. On balance I think running apt-get is a good thing but I wish it hadn't stolen 30% of my BogoMIPS. :-)

Onwards to controlling the GPIO pins directly using the bcm2835 library. I implemented just about everything available in the bcm2835 library for the second application tab and then put a few guards in place for combinations of actions that succeeded in hanging my Pi.

It was a bit indulgent implementing a specific GPIO pad control, but there was PAD 5 to think of and the opportunity of code reuse. It gave me a surprising degree of satisfaction switching the peripheral function assignments on and off and seeing the results populate my 'PAD Control'.

Reading the Broadcom information sheets, I found that it isn't possible to query the current state of the pull up and pull down resistors. The settings persist across reboots so it you play at applying resistors to see your input pins go high /low, remember you'll need to set them back at some point.

I'm also now pondering whether to take a soldering iron to a precious Pi to connect PAD 5.

Activating the peripheral function for I2C 0 assigns a couple of pins on this pad.

I took on the GPIO device driver next which exposes the interesting facility to use kernel interrupts with the GPIO pins.  It also offered the promise of having a setup that does not require running with root permissions to control the pins. This introduced me to udev rules and the documentation here. Searching the Raspberry Pi forum was also productive.

The next tab brought this together.

It writes or removes udev rules that give read / write  permissions to members of the group 'gpio' on the gpio device files. I added a button to allow easy management of the group. It is important for any interface that it supports attaching an LED to a pin and allows toggling  it on and off. This is no exception.

I found that changes made in the GPIO Device tab were reflected in the GPIO Pad tabs. However, changes made in the GPIO Pad tabs were not picked up by the device driver. It seems reasonable that should be the case.

Armed with my new knowledge of udev rules it was time to implement the tab for the I2C device.

And lo it was found that in the current Raspbian Wheezy the I2C driver already implements read write access for the group 'i2c'. All I needed to implement was a checkbox to load / unload the kernel modules and code to read and write some configuration files for the 'baudrate' kernel option.

I have a couple of I2C peripherals that seem to employ a communication method called 'clock stretching'. In short, it is a method by which a slave device (my peripherals) can tell the master ( the Raspberry Pi ) to hang on a bit while the slave prepares to reply to a request. It seems the combination of the i2c device driver and Raspberry Pi hardware ( I'm not sure which bit is responsible ) do not currently support 'clock stretching' and the Raspberry Pi ignores the slave's request to wait. However, there's an easy workaround as the device driver supports an option, 'baudrate', which is used to set the I2C bus clock rate. The default value of 100000 prevents some of my peripherals from working, but with a value of 32000, all is well.

It may not be an ideal solution. Everything on the bus is slowed down. For my usage though, it suits well. The settings made in the tab are written to configuration files so apply to any modprobe load / reload and across reboots.  As the default device driver settings apply permissions for the group 'i2c', the option to switch that on and off is disabled.

So, controlling the SPI device ought to be virtually a copy of the procedure for I2C. And so it proved.

The SPI device driver does not automatically give a group read / write permissions on its devices so I needed udev rules here. Because the SPI driver produces device files in /dev, the udev rules were much simpler here than for the GPIO driver. The SPI driver also exposes an option 'bufsiz' so I provided the opportunity to set a value for that. It's unlikely you'll need to alter the default 4096 value.

The settings made in the tab are written to configuration files so apply to any modprobe load / reload and across reboots.

Finally I have a 1 Wire temperature sensor so the HiPi modules include a thin wrapper for kernel device driver. The tab for 1 Wire just lists the attached slave devices and allows loading or unloading of the kernel modules.

And that's it. The GUI was just a fun exercise as a way of implementing something useful without needing any specific attached peripherals or circuits. There are some interesting modules in the distribution that provide high level wrappers for communication with some common ADCs, DACs and the MCP23017 extender ( it's greeeaaat !). There are also a couple of 'LCD control by serial' implementations.

My hope is that the GUI is interesting enough to download and try. Then I'll have captured ye all for the Gods of Perl  when you start making your own improvements and additions.