RasPiComm on Arch Linux ARM

I recently bought myself a RasPiComm add-on board for the Raspberry Pi. It has RS232 and RS485 ports, amongst other things, that I wanted to exploit as part of my home automation by using this device to bridge between the lighting control network and HVAC control. My Linux of choice these days is Arch Linux, because it isn’t bloated with extras that I don’t want (or need) that I consider to be in the Linux for Dummies category of tools. The only configuration tool needed for Linux is vi, and historically my “package manager” of choice has been gcc/make and tarballs. That said, pacman packages for Arch are pretty good, because they typically install what I ask for and then lists optional extras, rather than installing a whole series of dependencies.

I’d strongly suggest anyone that’s serious with their tinker projects, and a self admitted control freak over their systems, to take a look at Arch Linux if you haven’t already. Arch Linux ARM v6 is available for a Raspberry Pi.

All the steps below were worked out from the GitHub repositories posted by Amescon.  The supplied C API is labelled as obsolete, however, that’s only relevant if you intend to use their API as-is. I consider it, and use it, as examples on how to talk to the components on the board and stay closer to the hardware in my own code. You do not have to use the API, it’s really just some wrapper functions and classes for standard GPIO/I2C communication. The two serial ports are standard character devices in /dev, and the RTC is a normal clock once the kernel realises it is there and loads the right driver modules.

Requirements

  1. Identify your Raspberry Pi Revision (v1 or v2)
  2. Development tools (pacman packages gcc, make, binutils, and git at a minimum)
  3. Extra tools (pacman packages i2c-tools and setserial)
  4. Linux 3.6.11 (pacman packages linux-raspberrypi and linux-headers-raspberrypi)

The RS-485 driver does NOT compile and work with Linux 3.10.0, so if you’re using linux-raspberrypi-latest and linux-headers-raspberrypi-latest packages, you will have to roll back to the non-latest variant of those.

Update (29-12-2013): The current project on GitHub for the rs485 module builds just fine on 3.10.x, and I’ve updated the relevant sections on this post below.

From here on I’m going to assume a certain proficiency in Linux, so some steps will be pseudo steps (such as finding your way around a directory structure). There’s no specific order on getting each component active. This just happens to be the order in which I did it.

RTC

The base Linux rtc_ds1307 module works just fine with the clock. You just have to trigger the system into looking for it, which is done as follows depending on which revision of the RasPiComm board that you have.

# Revision 1 board
echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-0/new_device && hwclock --hctosys
# Revision 2 board
echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-1/new_device && hwclock --hctosys

After this, looking at lsmod you should see rtc_ds1307 loaded. If not, you might have to manually fire it up first using modprobe. Of course, the RTC is something you’d normally want running at boot, so in my case I created the systemd unit file /usr/lib/systemd/system/raspicomm-rtc.service, and entered the following into it. This is for a revision 1 board, so change the path of the sysfs location to what’s relevant in your case.

[Unit]
Description=RasPiComm RTC

[Service]
Type=oneshot
ExecStart=/usr/bin/sh -c 'modprobe rtc_ds1307 && echo ds1307 0x68 > /sys/class/i2c-adapter/i2c-0/new_device && /usr/bin/hwclock --hctosys'

[Install]
WantedBy=default.target

For the sake of completeness I really should add another systemd unit triggered on shutdown, that saves the system time back to the hardware clock, if the system is Internet connected and getting NTP updates. If it isn’t connected, spend some time determining who has the better time keeping skills, the OS or the RTC, and periodically synchronise them in the appropriate direction.

RS-232

If the RasPiComm is plugged in, and your Raspberry Pi is turned on, the serial port is active. From what I gather, and I could be wrong, is that the serial port is already onboard the Raspberry Pi, and the RasPiComm simply provides a more convenient connector and therefore it’s just a passthru. The serial port device is /dev/ttyAMA0. The only thing possibly stopping you from using it is that it may already in use by something else, such as a serial getty or console redirect.

To remove the console redirect on bootup, remove the following items from /boot/cmdline.txt.

console=ttyAMA0,115200 kgdboc=ttyAMA0,115200

The getty that’s running on the serial port, if any, can be removed with the following command.

systemctl disable serial-getty@ttyAMA0

To check for the existence of the serial port, you can use setserial as follows to get the current port information. You should see it set at spd_normal (38400 baud).

~/# setserial -G /dev/ttyAMA0
/dev/ttyAMA0 uart undefined port 0x0000 irq 83 baud_base 187500 spd_normal

If you do want to use the serial port as a console, leave the items in /boot/cmdline.txt but change the baud rate from 115200 to 38400.

RS-485

This one is a bit tricker than I first expected. The GitHub project, for reasons that I am unaware of, is set up to be built on a different machine and use architecture cross-compilation tools for ARM; or at least this is what it looked like to me. I found this strange, because it quite happily builds directly on the Raspberry Pi without any need for this extra step. Fortunately, to make that happen you just need a different Makefile. Building a kernel module isn’t what I consider to be an everyday skill, so below you’ll find one that I prepared earlier.

Update (29-12-2013): The current project on GitHub includes Makefile_rpi, which will compile directly on the Raspberry Pi. However, Makefile_rpi only builds the module. It has no install section. You’ll then have to manually copy raspicommrs485.ko to /lib/modules/…/extramodules/kernel/drivers/input and run “depmod -a” to rebuild the dependencies. Also, remember that ArchLinux ARM has an extramodules folder specific to each kernel version, including the build number, so every time you upgrade the kernel you’ll have to rebuild this module.

There’s two source trees from GitHub to clone; the driver and some examples. Don’t get confused by the use of “rpc” in the examples package, it’s an acronym for RasPiComm and not Remote Procedure Calls.

git clone https://github.com/amescon/raspicomm-module.git
git clone https://github.com/amescon/rpc-examples.git

The Makefile provided here works against 3.6.11, and installs the module into the extramodules directory, which doesn’t get overwritten when there’s kernel upgrades. All 3.6.x kernels in the future will continue to use the same extramodules directory, however, that doesn’t mean it’ll just work without a rebuild so keep the source tree handy. The driver does NOT build on Linux 3.10.0, so if you’re using linux-raspberrypi-latest you MUST roll back, and that includes the headers package.

Update (29-12-2013): Builds just fine.

To build the driver, look in the raspicomm-module directory, create a new Makefile as below, and make/install it as you would anything else. Don’t forget to substitute the indent space with tab characters if you copy/paste the values.

obj-m += raspicommrs485.o
raspicommrs485-objs := module.o queue.o
KVERSION = $(shell uname -r)
DEST = /lib/modules/$(KVERSION)/extramodules/kernel/drivers/input

all:
        make -C /lib/modules/$(KVERSION)/build M=$(PWD) modules

clean:
        make -C /lib/modules/$(KVERSION)/build M=$(PWD) clean

install:
        if [ ! -d $(DEST) ]; then mkdir -p $(DEST); fi
        cp raspicommrs485.ko $(DEST)
        depmod -a

To fire it up, just run “modprobe raspicommrs485”, and you should now see the character device /dev/ttyRPC0 and can use that to communicate over RS-485. The next step may be to configure a file in /etc/modules-load.d to have this driver automatically load on boot, but since failed modules can cause a stalled boot up (which is no fun on a headless device) I’d suggest it’s best not to and instead just load the module as part of the startup script of the service that requires it.

The rpc-examples directory that was previously also cloned from GitHub contains 3 small (tiny) subdirectories that has some example code for polling, reading and writing to RS-485. If you have some RS-485 devices hooked up, just tweak the source code of the examples first to properly reflect the line conditions (baud rate and so on) before building them. They’re short and simple, and designed to demonstrate the functionality rather than solve actual problems so don’t expect too much.

C API

The C API itself isn’t actually needed in the same sense as a driver. Talking to the remaining I/O on the RasPiComm is all done by GPIO/I2C, and the C API package that is available on GitHub can more or less be treated as a set of examples on how to find each item. The C API contains a shared library to talk to the entire RasPiComm, and then two additional libraries that use the base library specifically for the StepRocker and to drive a basic I2C LCD.

To fetch the source tree, simply clone it.

git clone https://github.com/amescon/raspicomm.git

Inside you’ll find 4 directories of interest.

  1. raspicomm: the base shared library
  2. steprocker: shared library for the steprocker
  3. display: shared library to control a basic I2C LCD
  4. demo: basic demo application that uses all the above functionalily.

To build it all, just run make in each of the 3 shared library directories and then copy the resulting *.so file into /lib. Then run make in the demo directory and run the resulting raspicommdemo binary. For some reason the steprocker, display and demo code looks in /lib for the shared libraries but looks through the cloned source tree for the include files.

If you intend to use the shared libraries, I’d suggest looking online if there’s anything more up to date, or in my case I just dig through the code to find out what calls I have to make to communicate with the device and integrate that directly into my own libraries and stay closer to the hardware.

All Done

From here all ports, inputs and outputs should be accessible and are ready for you to tinker with.