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.)
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.
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.
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.
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.
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.
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.
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.)
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.
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).
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."
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.
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.
Update (2014-11-08)
Because so much of my paid work is on ARM-based processors of one kind or another, it pays for me to have an ARM-based reference platform. You can see this strategy in play going all the way back to the earliest platform discussed in this article. Here's the latest one: an Nvidia Jetson TK1 evaluation board, for a project code-named Stampede. The round device in the middle is the integrated cooling fan on top of the Nvidia Tegra TK1 SoC, which has four ARM Cortex-A15 cores, a fifth low-power Cortex-A15 core, and 192 graphical processing units (GPUs).
The fact that you can buy this much horsepower for only USD$192 is amazing to me. At that price, the GPUs are merely a nice to have and don't represent my core interest in the board. The ARM Cortex-A15 implements the 32-bit ARMv7 architecture. When Nvidia inevitably comes out with one of these boards using their new Denver processor, which has two ARM Cortex-A57 cores implementing the 64-bit ARMv8 architecture, I'll be in line for one of those too.
(A Google Nexus 9 tablet using the Nvidia Denver processor is already winging its way to me. I have three Google Nexus 7 tablets and a Google Nexus 5 phone, all 32-bit, that I use for development on the Android platform.)
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.
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.)
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.
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).
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."
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.
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.
Update (2014-11-08)
Because so much of my paid work is on ARM-based processors of one kind or another, it pays for me to have an ARM-based reference platform. You can see this strategy in play going all the way back to the earliest platform discussed in this article. Here's the latest one: an Nvidia Jetson TK1 evaluation board, for a project code-named Stampede. The round device in the middle is the integrated cooling fan on top of the Nvidia Tegra TK1 SoC, which has four ARM Cortex-A15 cores, a fifth low-power Cortex-A15 core, and 192 graphical processing units (GPUs).
The fact that you can buy this much horsepower for only USD$192 is amazing to me. At that price, the GPUs are merely a nice to have and don't represent my core interest in the board. The ARM Cortex-A15 implements the 32-bit ARMv7 architecture. When Nvidia inevitably comes out with one of these boards using their new Denver processor, which has two ARM Cortex-A57 cores implementing the 64-bit ARMv8 architecture, I'll be in line for one of those too.
(A Google Nexus 9 tablet using the Nvidia Denver processor is already winging its way to me. I have three Google Nexus 7 tablets and a Google Nexus 5 phone, all 32-bit, that I use for development on the Android platform.)