Friday, March 30, 2012

Small Town Big City

As far back as 1982 I was teaching a senior and graduate level computer engineering course at Wright State University called "Real-Time Software Design". The students wrote code in assembler language and tested their projects on one of two PDP-11/05 minicomputers. Both systems were equipped with a teletype terminal, a line printer, two floppy disk drives, and the dreaded card reader. To pass the course, students wrote a spooler program that read cards, spooled the data to disk, read it off, and printed it. To achieve the necessary performance the software had to be multi-threaded and interrupt driven. The course was required for seniors to graduate and for graduate students to proceed to their upper level courses. It was much hated. And much loved.

Things change. By 1996 I was writing embedded and real-time software for commercial products in the Denver Colorado area for one Bell Labs spin off or another. Because of that organization's long history of inventing stuff that we now take for granted but which are the backbone of the Internet, like UNIX, C, and C++, my colleagues and I were developing low level software in C++ when there were still assembler programmers complaining that C wasn't good enough. C was plenty good. C++ is even better. (And I've argued in this blog that Java may be good enough for many embedded applications.)

Fast forward to 2005 when I began to passionately and aggressively purse two goals.

  • Find an economical hardware and software platform on which to teach embedded and real-time software development. It must support a gradual learning curve, accomodating beginners needing a gentle introduction, but also experienced developers who need to learn the advanced concepts used in bleeding edge commercial development environments.
  • Demonstrate that the advanced object-oriented software techniques, idioms, patterns, and architectures that I have seen evolve for embedded software development over the past several decades can be applied to this small and inexpensive platform.

This has resulted in a number of projects that long-time readers of this blog (if there should be any) will recognize.

Desperado was my effort to capture many of the useful C++ architecture, design, and implementation patterns and idioms I encountered over my years of commercial product development. (Although no longer under active development, I have used Desperado as a foundation for other projects, like Hayloft, my C++ library for Amazon Web Services' Simple Storage Service. And it continues to serve as an inspiration and a working example for much of my subsequent paid C++ embedded development.)

Diminuto and Arroyo were my attempt to build a teaching environment on a commercially available evaluation board using an Atmel AT91RM9200 system on a chip with an ARM9 processor, a minimally configured Linux kernel, and a small set of utilities including BusyBox. (Diminuto turned out to have useful collateral in the form of a C-based systems programming library for Linux that I have leveraged in a number of other projects for paying clients.)

Arroyo/Diminuto with Three "Disk" Drives

Cascada reflected my decision to move this effort to a more capable yet less expensive C4 BeagleBoard with a Texas Instruments OMAP system on a chip with an ARM Cortex-A8 processor, a Zippy2 expansion board, and a standard Linux distribution.

BeagleBoard C4 and Zippy2 Expansion Card

Contraption had me upgrading to a xM BeagleBoard and moving to a standard Android distribution, which had the added benefit of a bundled development environment and support for Java, with a GNU environment co-hosted along side it.

BeagleBoard xM Rev C

Horsefly was where I tried using a commercial toy, the Parrot AR.drone quad-rotor helicopter, which featured a custom ARM processor, as a platform to illustrate how to reverse engineer an existing system.

Saleae Logic Analyzer and AR.drone

Although I would call all of these projects successful, none of them really satisfied my goals. The hardware was too expensive. The software was too complex for beginners. They were too closed. Or they presented a target that was moving too quickly in the market place.

Amigo is my latest attempt, using Arduino boards. These inexpensive platforms, available all over the web or even at your local Radio Shack, were originally built for teaching just the kinds of things I'm interested in. They have also proven immensely popular with hobbyists, do-it-yourselfers, and the Maker subculture, resulting in a huge hardware and software ecosystem growing up around them. They use low power but extremely capable Atmel megaAVR eight-bit microcontollers. The run-time software is already C++ based, and is simple enough that you can completely understand everything that is going on right from power up to running your application. The Arduino software distribution includes an easy-to-use integrated development environment (IDE) that makes it simple for beginners to get embedded projects up and running quickly.

Arduino IDE on the Mac

CIRC-01

But can you start with Arduino and its small town ways but graduate to the big city of learning about commercial product development? Can you use Eclipse? Build using make? Use source control control? Unit testing? Can you do multi-tasking? Write interrupt service routines? Do systems programming in C++? Learn about code reuse across product lines?

Could you use the open source FreeRTOS multi-tasking real-time operating system, write an interrupt-driven object-oriented device driver in C++, build it all with a makefile, maintain the code base in a Subversion repository, and run it on an inexpensive but highly versatile Arduino-compatible board?

Can you do all of this so cheaply that a student could download the software for nothing off the web to their Windows, Linux, or Mac laptop? That they could conceivably buy a board at their college bookstore and keep it to use in a series of courses ranging from beginner to advanced?

Remarkably: yes.

The shirt-pocket sized Freetronics EtherMega 2560 board uses the same Atmel ATmega2560 microcontroller as the Arduino Mega 2560 board. It includes a USB-to-serial interface to one serial port (and three more serial ports just waiting to be hooked up), an Ethernet controller with an RJ45 jack, a microSD card slot, and a big batch of general purpose I/O (GPIO) pins. It can talk to the Arduino IDE and run all the standard Arduino software.

Freetronics EtherMega2560 and Atmel AVRISP mkII

But this EtherMega isn't running Arduino. It's running FreeRTOS with a couple of concurrent tasks. Its interrupt-driven serial device device driver, and indeed all of the software stack sitting on top of FreeRTOS, was written by me, in C++. I built it via make using the GNU tool chain from my code base maintained in Subversion. I developed it using Eclipse running on my desktop Mac. A tarball of my entire code base, including all of the FreeRTOS code, is available via a link on my Amigo project page.

You have to love the global scope of this. Arduino originated in Italy with founders Massimo Banzi and David Cuartielles . The Freetronics board was designed by Marc Alexander and Jonathan Oxer in Australia. FreeRTOS was developed by Richard Barry and Real Time Engineers, Limited in the United Kingdom. The FreeRTOS port to the EtherMega was done by Phillip Stevens in New Zealand. Arduino, its clones, components, and accessories, are manufactured, well, everywhere, including Italy and the United States.

I can't remember when I've been this excited about one of my projects. I'm not kidding, my hands are shaking at the thought of it. The potential of this as a pedagogical tool is fraking huge. If you want to learn, or even better, to teach, embedded and real-time software development, it is time to quit making excuses. It hasn't ever been this easy, this accessible, or this inexpensive. Start now. If I can help you, I will.

Update (2012-05-17)

I did most of the development of Amigo, my noodlings with FreeRTOS, C++, and the AVR eight-bit microcontrollers, on the Freetronics EtherMega 2560. Here's a more recent photograph of the EtherMega with a test fixture wired up to it that the substantial Amigo unit test suite uses to exercise its various features, including its interrupt-driven USART, SPI, and ADC device drivers all written in C++. The unit test suite includes tests of the networking capabilities of the EtherMega to act as a client or as a sever.

Freetronics EtherMega 2560

The EtherMega is, from a software point of view, equivalent to an Arduino Mega board with an Arduino Ethernet shield mated to it. It uses the same ATmega2560 microcontroller as the Mega, and the same WIZnet networking chip as the Ethernet shield. I had an Arduino Mega ADK, a version of the Mega designed to work with the Android Developer's Kit and interface to Android devices. And I had an Ethernet shield. So it made sense to test the same unit test suite on that configuration. I did. It worked. With no changes to the nearly three thousand line C++ unit test main program or anything else (in fact I didn't even recompile). Here's a photo of that hardware with the same test fixture wired up to it. (Yes, that Ethernet shield is pin-aligned correctly with the Mega ADK's headers despite having a couple of pins hanging out in space.)

Arduino Mega ADK with Ethernet Shield

Of course I had to try to get at least a basic multitasking configuration working on the far more resource constrained ATmega328p microcontroller used on boards like the Arduino Uno, and the Freetronics EtherTen. The EtherTen is equivalent to the Uno with an Ethernet shield. I got it working, but it wasn't pretty. The 328p has one-eighth the flash memory and one-fourth the SRAM compared to the 2560. I ran the same Amigo software but with a radically lobotomized unit test program, enough to verify that I was multitasking and that the device drivers were working. The issue was tuning the stack sizes for each task and the heap that FreeRTOS requires so that each task could run without blowing its stack, and still leave room for the variables used by the unit test suite. This would have been an issue in C as well as C++. Here's a photo of that board without any test fixture wiring but running Amigo. This particular EtherTen has the optional Power over Ethernet (PoE) module attached to it.

Freetronics EtherTen

So while the 328p might be usable for a very limited application using FreeRTOS, I can't recommend using it as a learning or teaching platform for multitasking. You'll spend all your time (as I did) trying to find that memory allocation sweet spot.

Update (2012-09-28)

I've written before here about using Android as a platform on targets like the BeagleBoard. Recently I did some work on the Hardkernel ODROID-A4 as part of my Conestoga project. The ORDOID-A4 is Samsung's recommended product development platform for their Android-based Galaxy smartphones. The ODROID is not cheap, and architecture-wise it's extremely complex compared to the Arduino targets. But if your goal is to develop below the Java layer for Android smartphones, it and the other ODROID models are an interesting choice. Here's a photo of my ODROID-A4 plugged into its debug board, when an accessory I/O board sitting alone just above it. You'll also notice a lovingly handcrafted universal reset tool (a bent paper clip).

ODROID-A4 with Reset Tool and Debug Board

At the opposite end of the spectrum, I've been working on a gig recently in which I've been developing firmware for a line of commercial products based on the Microchip Technology PIC16F1823 microcontroller. This tiny beast, yet another Harvard architecture, has 2048 words of flash for executable code and a mere 94 bytes of RAM. That's a little tight for a teaching platform: even though I write in C, I have to carefully consider the resource tradeoffs of every single line of code and variable. Legitimate pedagogical issues for beginning embedded developers get squeezed out pretty quickly. It turns out that important concepts like abstraction and dependency injection are not free when a single byte takes up more then 1% of the entire available memory. But it's remarkable how complex your software can be within constraints as tight as these. One of my colleagues taunts me as he writes code for his larger microcontroller: "I think I'll have a variable. It'll be used for just one thing. I think I'll make it four bytes. It doesn't need to be four bytes. But what the heck."

I2C_debug_detail

There has never been a better time to learn how to develop software close to bare metal. Moore's Law works to your advantage when you're scaling down just as it does when you're scaling up.

Update (2013-11-18)

I needed an ARM-based board that could host Linux to test the latest version of Diminuto, my C-based Linux systems programming tool kit that has found its way into a number of commercial products. Instead of pulling one of my BeagleBoards out of storage for this project, code-named Cobbler, I instead spent a (very) few bucks and bought a Raspberry Pi. This credit-card sized board features a Broadcom BCM2835 system-on-a-chip with an ARM11 core running at 700MHz and hosts a version of the Debian distribution featuring the Linux 3.6.11 kernel.

Here's a photo of my lab bench setup where I am testing the general purpose input/output (GPIO) handling functions in my tool kit. The tiny RPi is festooned with cables (clockwise from the top): HDMI to my lab monitor, USB power, a ribbon cable to the breadboard, USB keyboard and mouse, and Ethernet. The breadboard has an FTDI Friend providing USB to logic-level serial access to the processor console port.

Raspberry Pi in Diminuto Test Fixture

I still recommend the Arduino if your goal is teaching very low-level device handling; Linux places too many layers of abstraction between your code and the hardware to make a good teaching platform for beginners. But once students have outgrown the Arduino, the RPi is an interesting next step.

6 comments:

Anonymous said...

Bravo! Excellent Article. I will be folding this into my Teaching as well. Thanks for the info!

Maxim Porges said...

Thanks for posting these articles, I'm really enjoying your adventures with embedded systems tool chains.

Just out of interest, since you are developing on a Mac, why did you chose to do your C++ development in Eclipse and not Xcode?

Chip Overclock said...

Besides my Mac Mini desktop I use for development, Mrs. O and I both use Mac laptops (I'm typing this on an Air). But I don't do development _for_ Macs, and so my use of Xcode is limited to using it as a casual code viewer when I'm not actively doing development. I use it this way both on my desktop and my laptop.

My experience with Eclipse however goes all the way back to the 1990s when I used its precursor VisualAge in development of a commercial product in which we wrote the bulk of the embedded code in Java. (It was a learning experience implementing ancient analog line and trunk signaling protocols which had hard real-time constraints in Java.)

So Eclipse and I go way back. I've since used it for server-side Enterprise Java development of an ESB/SOA-based product (using Apache ServiceMix), doing embedded development in C++, Linux kernel hacking and device driver and daemon development in C, telecommunications protocol stack development, developing application code using Amazon Web Service's Simple Storage Service, etc.

Chip Overclock said...

I should also mention too that one of the reasons I like Eclipse is it works on a wide variety of platforms. On a daily basis I routinely use a Mac laptop and desktop, a Windows laptop, and a couple of Linux servers. I can and have run Eclipse on all of them, although most of my Eclipse face time is spent on my Mac desktop.

Chip Overclock said...

BTW, both Anonymous and Maxim: thanks for the kind words! I'm on a bit of a campaign regarding the use of C++ on embedded platforms, ranging from extremely capable systems running full-blown multi-user Linux/GNU, to tiny eight-bit microcontrollers running at best a tiny RTOS.

Anonymous said...

Hi, thanks for this excellent article. I found your blog through you (also excellent) posts in the Arduino forums. You're bookmarked :-)

Marcello Romani (from Italy)