![]() |
|
C-Language Programming on Embedded Systems – Progress and Pitfalls Programming: it's not just for computers any more. These days, most electronic devices have some sort of intelligence, and therefore some sort of processor that needs to be programmed – even if it's just to enter the cooking time on a microwave's keypad. Though embedded processors have become more pervasive in recent years, they've been around for a long time. I first started writing code for eight-bit “embedded” micros back in the 1980's. Back then, if you were doing embedded programming, you used assembly language. This meant you had to know the architecture of each CPU chip. It also meant learning a new language for each processor – because different manufacturers have different ways of representing similar instructions. Of course you could also use assembly to program a PC, but PC-based developers have always had the option of higher-level languages such as Basic and C. For embedded systems, it wasn't an option. But it wasn't long until people started trying. In the mid 1980's, I worked at a company whose products used the Motorola 6809 – a versatile little 8-bit CPU. Mostly we coded in 6809 assembly, but we used C for some of the more complex applications. C is a natural choice for embedded devices, because it's a versatile language that lets you direct the processor's operation at the lowest level. But C compilers weren't available for every microprocessor. We had to acquire the compiler's source code and make modifications. The resulting code was significantly slower and less compact than hand-coded assembly programs. So C was seldom worthwhile, despite its considerable advantage for the developer in ease of use, testability and maintainability. We used C when a short schedule or a complex application made it a necessity. Over the years processors have gotten faster and memory has gotten cheaper, making embedded systems more powerful and more forgiving of losses of efficiency. At the same time, compilers have improved so that there was less of a trade off. The high-end CPU's, which went from 4 and 8 bit data words to 16, 32 and then 64, became so complex that compilers were a necessity. Practically nobody – except the people who wrote the compilers - had to use assembly language. But there was still a huge market for small, cheap 8 and 16-bit processors for use in devices ranging from toys to motor vehicles. Finally, C compilers have become practical to use for these devices. Nowadays it's becoming rare to see an embedded project done in assembly code. C seems to be the most popular language. Though much of the programming world has marched on to object-oriented languages such as C++, C# and Java, these aren't practical for low-end processors, due to its greater overhead. (Ironically, Java was originally envisioned as a common language for embedded devices.) Writing embedded software in C is a great improvement over assembly code, but there are still problems. Though the ANSI committee has done much to standardize the language, it varies widely for embedded applications. This is because, on small systems, there is usually no device driver to insulate the developer from the hardware. And there are numerous hardware-dependent constructs, such as code segments, interrupts, registers and bit flags. These help save the programmer the work of researching which bit is which, and help prevent errors. For example, a carry bit can be called “carry”, rather than bit 7 of the status register. But compiler writers (many of whom support a particular manufacturer) may implement these constructs in different ways. This means that code written for one vendor's compiler seldom works for another compiler without a significant porting effort, even when the processor does not change. Issues that are minor when writing for the PC become major concerns on an embedded processor. Optimization, the process whereby the compiler streamlines the developer's code, can be very helpful on systems with limited resources. It can also be dangerous. For example, the compiler might keep variables in temporary storage even if they are needed to communicate between interrupt handlers and the main program. Embedded programmers need to use the “volatile” keyword on any variables that are used in this fashion. A more serious problem arises when attempting to use C with the specialized devices known as digital signal processors (DSP). Standard C compilers provide no way to take advantage of the performance-enhancing features of these devices. For example, DSP's make extensive use of “saturated” arithmetic, which means that if an operation exceeds the maximum size of a particular variable, its value is automatically set to the maximum, rather than being set to some unexpected smaller number. The C language does not support this type of data. A C variable will “roll over” in the same way a car's odometer does at 100,000 miles. One of the most promising developments in recent years has been the emergence of Embedded C, which is an extension to the C language (devised by a working group of the International Standards Organization, or ISO.) Embedded C is based on an earlier C language extension called DSP-C, which was created by DSP manufacturers. Like its predecessor, Embedded C is intended to increase both the portability and the performance of embedded code, especially for DSP's. It provides several helpful features for the embedded programmer: * New data types, including _Sat (saturated), _Accum (fixed decimal point) and _Fract (fractional, that is limited to the range from -1 to +1.) * Variables can be assigned to named memory areas (e.g., “X” and “Y”), to take advantage of DSP's that have different memory areas for different purposes. * It provides access to special memory registers, such as the “condition code” register. (Many embedded C compilers provide this feature, but do so in incompatible ways.) * It provides standard ways to do data input and output on the hardware. This improves the portability of device driver code. Despite the effort to make Embedded C portable (that is, the same code can be reused for different devices), some programs will have portions that are dependent on the type of processor. This is unavoidable, since embedded processors differ in the features they provide, and basic architecture considerations such as the size of data registers. Embedded programming has come a long way in the last thirty years. Where a programmer once had to know a different language for each device, it's now practical to program embedded processors in higher level languages. This makes development quicker and maintenance easier. Programmers no longer need to be aware of all the quirks and details of every device they use. They are now free to concentrate on improving algorithms and ensuring the reliability of the code. Embedded C is a definite step in the right direction, though embedded program is still in many ways more challenging than writing for general-purpose machines such as PC's. References: The Embedded C Extension To C: Part I, in the C/C++ Users Journal, August 2005, by Marcel Beemster, Hans van Someren, Willem Wakker, and Walter Banks. |
| Copyright 2006 Nakota Software | Web design and photography - Dawn O'Doul.com (Lunar Imaging) click here |