A Short Intro
In this article, some of the unique aspects of embedded programming design will be highlighted, and various standards and tools common to the field will be discussed. It is intended more for first-time designers and developers who have some programming experience, but are new to microcontrollers and things such as real-time operating systems. This is the first in a series of such articles.
A Bit About Embedded Systems
If you look around as you're reading this article, chances are there are at least a few devices nearby that would classify as or contain an embedded system: mobile phones, modems and routers, printers, and gaming consoles are some easy examples. In addition to consumer electronics, embedded devices have largely taken over numerous industries from aviation to mass manufacturing, driven in particular by the advent of digital electronics. Here are several more examples:
- Automotive: In modern vehicles, everything from ABS, keyless entry, the GPS system, and every sensor displayed on the dash is likely to be controlled by one or more microprocessors.
- Home appliances: Some examples here include microwave ovens, coffee makers, refrigerators, TVs and home entertainment systems, and thermostats.
- Financial: ATMs, debit/credit machines and cash registers are examples of embedded devices used in the exchange of money.
- Aerospace: This is a big one - from the 70lb Apollo Guidance Computer in the 60's to modern communication and control systems in aircraft and spacecraft, embedded systems are everywhere in this field. Along with automotive, this is also where some of the most stringent standards for design can be found (aerospace examples include DO-178B and the MISRA C standard for communications, which we'll mention again below).
This is not an exhaustive list, and the range of devices on the market in terms of complexity is huge, with varied levels of size, cost, robustness, and use. Your first excursion into the embedded world might be a simple microcontrolled-monitored sensor of some sort, but over time your designs can reach sophistication like many products available to consumers.
What Defines an Embedded System?
Using the examples given above, it's probably apparent that most embedded systems serve a very specific purpose rather than being capable of multiple unique roles like a traditional PC or laptop would be. This is one of the defining features of any embedded device: it is made to perform a specific function or small set of functions, often with the requirement that it reacts quickly to a change in its environment. Along with this need, there are a few other characteristics that make them unique from larger, more versatile systems:
- Reliability: Embedded systems are often employed in situations where it is unsafe or very costly to perform a system shutdown to make modifications. This is especially common in space, aircraft, and navigational systems, which can cause serious issues when encountering errors. It is also important that systems are made to be capable of recovering from faults on their own.
- User interfaces: While some systems are designed with a simple interface in mind, most have none at all. Where you would see pop-ups, windows, toolbars, or even just text-only terminals in larger operating systems, an embedded device is more likely to provide control via push-buttons and indicators via solid and/or flashing LEDs. Even when such a system does employ a small LCD, it is limited in what it can display.
- Real-time response: This isn't always a requirement for an embedded device, but those that are used in critical systems will inevitably have to provide consistent response to connected systems so that performance and safety needs are met. A large number of real-time operating systems (RTOS; femtoOS is an example of one that is built for AVR micros) exist to this end, which in addition to assisting in meeting scheduling and timing requirements will often provide developers the ability to trace RTOS behavior to better optimize system performance.
- Embedded software or firmware: This is where someone new to embedded design is likely to get their first taste of the unique aspects of embedded system design. With limited size, input/output options, storage, and performance constraints, firmware can seem daunting even for someone who has spent extensive time with low-level programming languages. The next sections of this article will cover some of these concerns in more detail.
Embedded Software and Tools
The IEEE posted a tool earlier this summer that allows you to filter languages by popularity for particular applications. Turning off all results except "Embedded" will show you that the top three embedded languages are C, C++ and Assembly in that order. If the tools and technology behind embedded and electronics development are your passion, then these will be your bread and butter despite being older languages, because they are fast, portable, and have much smaller footprints than many others. My personal recommendation is C for these reasons and because it is used (along with Assembly) in the Linux kernel.
When using C for embedded design - or reading someone else's code - you're probably going to run into a few keywords that won't be found in many more large-scale applications. In addition, some control structures such as interrupt service routines (ISRs) may seem strange. Providing an overview of all of these keywords and conventions would require much more space (and might be covered in a later article), but as a reference I suggest this list of embedded interview questions which covers the volatile keyword, interrupts, bit manipulation and more.
The tools you will use to implement your design depend largely on the hardware you choose. My own experience is predominantly with AVR microcontrollers (the ATMega328P and ATTiny84 in particular), and from AVRStudio to IAR Embedded Workbench to command-line tools such as avr-gdb and avrdude, there is no shortage of options. The most important piece of equipment you will need, however, is an in-circuit programmer (also known as an in-system programmer (ISP) or in-circuit serial programmer (ICSP)). Many popular prototyping boards feature an ICSP (the Arduino is a good example, and I've included a photo below). These are usually connected to by a header on a ribbon cable and allow you to flash a program directly to the chip without removing it.
You can find entire boards geared towards programming your ICs, but when you're starting out, a portable and low-cost programmer is probably the better choice. Some examples of these include the AVR-ISP500 ($48 USD), the Tiny AVR Programmer ($20 USD, specifically for 8-pin AVR ICs), and the PICkit3 ($50) for PIC microcontrollers. If you own an Arduino, you can even use it as an ISP instead of buying one separately.
My own AVR-ISP500 connected to an ATMega328p to demonstrate a simple LED flashing program
Design Standards for the Embedded World
In the embedded world there are many different coding guidelines intended to produce reliability and safety in products, two of which I mentioned earlier: DO-178B (which is just one out of many documents intended for quality code in the avionics world), and MISRA C, which is geared more towards the automotive industry. The latter includes mandatory (must-meet), required (must-meet unless a formal exception procedure is followed), and advisory (optional) guidelines for clean and reliable code, covering everything from commenting to pointers, preprocessing directives and storage access. The standard is available on the MISRA website for £15 (they also publish a C++ standard along with automatic code generation standards). Additionally, depending on which development environment you are using for your projects, it may support it and other standards, and allow you to check your code against them as you work (IAR Embedded Workbench is one such IDE that has this feature).
While you might not be intending to develop robust, safety-critical systems any time soon, simply reading and familiarizing yourself with these standards helps keep your firmware cleaner and more efficient, and gives you insight into how industrial products work internally.
Final Words: An Assembly Game
I didn't say much about Assembly as a choice of language earlier, which is a shame - it's certainly viable in its own right and does give you a bit more freedom when it comes to communicating with a CPU directly. However, I wanted to mention an entertaining game called TIS-100 by Zachtronics. In TIS-100 you are tasked with reprogramming an older computer in assembly to find out its purpose. Although it only features single-register processors and a lack of memory access, it introduces multicore processing and is a fun introduction (or way to practice) the basics of assembly. If you're looking for a different sort of puzzle game to pass the time, check it out.