Embedded Ruby—First Steps

I spent the beginning of my career working on embedded systems for some audio company. These embedded systems were my first love in programming and to me, no flashy css on a web page can beat the thrill of writing some code that flashes an LED.

I've been working lately with Ruby a lot. I love it. I love that the language nearly disappears and I am able to express pure intent. Ok, so there is still syntax and such, but I can create so much more with so much less code.

I hate living a fragmented existence, so I’ve been working the last few days on bridging these two worlds of mine. I figured it would also give me a chance to get familiar with Linux and the latest in the embedded world.

First up, pick a platform.

I chose this single board computer from Glomation. It has an ARM920T core and an LCD/ touch screen interface which may be fun later.

Next, Tools.

I was determined that I could get a toolchain up and running on my Mac, but eventually ended up running linux in a virtual machine.

Glomation had a set of tools and a pre-patched kernel already to go on their support page and our apprentice had a virtualbox linux image that he let me copy, so I was up and running quickly.

I do want to share with you a few of the resources I found in the processes.

  • I began with the GNUARM project.

  • Tom Walsh on the gnuarm mailing list was helpful and pointed me to his scripts. I came real close to a working toolchain on the Mac with his help.

  • I also gave the Crosstools project a try but ended up in the same place I was before.

  • Thanks to David Goodlad's RubyConf 2008 presentation I discovered Open Embedded. This seems to be where the momentum is right now. I imagine I will give this project a careful look soon. I wish I would have started here.

Cross-Compiling Ruby

A few folks have had some success cross compiling ruby and Goodlad’s presentation claimed that ruby is a part of the open embedded project.

I built ruby 1.8.6-p111 because that what was on my Linux distribution and it seems to be a well distributed release. Here is the script I used to configure ruby for cross compilation. Thanks to The Zen Machine blog for the skeleton of this script.

1 #! /bin/sh
2 export ARM_TOOLS=/usr/.../arm-unknown-linux-gnu/bin
3 export CC=$ARM_TOOLS/arm-unknown-linux-gnu-gcc
4 export LD=$ARM_TOOLS/arm-unknown-linux-gnu-gcc
5 export AR=$ARM_TOOLS/arm-unknown-linux-gnu-ar
6 export RANLIB=$ARM_TOOLS/arm-unknown-linux-gnu-ranlib
7 export ac_cv_func_getpgrp_void=yes
8 export ac_cv_func_setpgrp_void=yes
9 ./configure --host=arm-unknown-linux --prefix=$HOME/ruby/install

ARM_TOOLS is where I installed the cross compiler. The prefix is just the place where 'make install' will drop the results of the build. The configure script generates a file in the ruby root director called fake.rb that causes some problems when I went to 'make':

1 /ruby-1.8.6-p111/fake.rb:12: unterminated string meets end of file (SyntaxError)

I opened it up and it has a very obvious syntax error in it. I added the missing backslash on line 12 and ruby built fine from there.

1 ALT_SEPARATOR = "\";

becomes…

1 ALT_SEPARATOR = "\\";

'make' then 'make install' and I had my cross compiled ruby.

Getting Ruby onto the Target

The last step to seeing little rubies flying on my ARM core was to get the build onto the target. The Glomation board came preloaded with a kernel and a root file system. The kernel source was provided on the support page but not the root file system.

I asked their support guy and he kindly posted it for me. I was dreading having to rebuild a file system from scratch, so I was grateful for his help. I decided that the best option would be to just have the target load of the root file system over the network on boot.

I followed these instructions for mounting the image on my linux VM and these instructions for setting up an NFS Server.

Mounting the file system over the network is a great option because now I can edit the file system from my Mac or Linux VM and have the target see the changes without even rebooting.

Perfect! The 2440 board came loaded with UBoot and all I had to do to load the file system over the network was to set the nfsroot in the bootargs from the bootloader’s command line.

1 set bootargs 'nfsroot=10.0.1.151:/arm/fs rw console=ttySAC0,115200 ip=dhcp init=/linuxrc'

Once booted, I only needed to set the RUBYLIB environment variable so that ruby knows where to find the libraries. I added this to my init script.

1 export RUBYLIB=/lib/ruby/1.8

And there you have it. Ruby running on my ARM board:

Next Steps

Here is where I want to go from here:

  • Sockets. I need to build openssl support for ruby so that I can talk to the world from Ruby. The Zen Machine ought to help me out here.

  • Sinatra—I’d like to run Sinatra on the target and start serving up some web pages

  • RTC—I want to get that on chip Real Time Clock working so that it’s not always 1970

  • Drivers and extensions—I want to be able to control some hardware from Ruby. I've got a lot to learn here but I’ll have to find or write a Linux driver and then build a Ruby extension on top of it. I’m imagining something like led.on and led.flash.

  • Submit to ESC. I’m hoping to submit my work to the Embedded Systems Conference. I hope that Ruby can start picking up some momentum in the space and save embedded developers gobs of time like it has done in the web development world.

Thanks for reading. Let me know if you have any ideas or suggestions!

Doug Bradbury, Software Craftsman

Doug Bradbury is a maker, a thinker, a craftsman, and a learner.