Black Box with a View, Part 2
Pages: 1, 2, 3, 4, 5, 6
Further Reading
Overall, the object-oriented approach used here is similar to the one described in the article Object-oriented programming in C.
Of course, more elaborate techniques are available, such as those discussed in the book Object-Oriented Programming with ANSI-C (PDF). They may not always be appropriate to the microcontroller environment, however.
Microcontroller manufacturers usually provide lots of highly detailed, free documentation. For the MSP430, the MSP430x1xx Family User's Guide (PDF) is a very important resource. The guide describes all the features of the MSP430 in detail. To supplement it, read TI's code examples in C and in assembly language. The examples clearly illustrate the various facilities of this microcontroller, making the information in the user's guide much more meaningful.
In order to compile the TI's C examples with MSPGCC, you will need to make two minor changes. First, #include <signal.h>. Then, you will need to alter the ISR routine declarations to match MSPGCC conventions. Use Example 7b in this article as a guide. There are also MSPGCC-specific examples at www.mikrocontroller.net.
You will occasionally need to refer to the GCC manual and possibly the GCC C99 standards compliance page (if you use the new ANSI 1999 C standard). Note that these links are relevant to the 3.2.3 version of GCC, which is the basis for MSPGCC at the time of this writing. Another necessary reference is the MSPGCC manual.
Finally, make sure to read the classic software design book Design Patterns if you have not done so already. The ideas presented there will help you improve the structure of your own software, which is particularly important in complex embedded systems.
Appendix A: Arithmetic on a Microcontroller
This appendix describes the nature of arithmetic on a microcontroller.
Arithmetic operations are a major concern in embedded programming. Microcontrollers such as the MSP430 do not have a floating-point unit (FPU), so any floating-point calculations require a lot of support in software. The resulting code is large, and the processing cost is high. When designing programs to run on a microcontroller, you should carefully analyze any floating-point operations, and try to avoid them if possible.
Even integer operations, however, can carry a heavy penalty. The MSP430 is a 16-bit device, which is a definite advantage over 8-bit microcontrollers that are the norm. Nevertheless, there is still no native support for 32-bit integers, with which many programmers are familiar. In embedded development, it is often wise to restrict most numbers to a maximum of 16 bits. Addition and subtraction of such quantities are very fast on the MSP430, but they also remain reasonable on 8-bit architectures. It is, of course, possible to use 8-bit integers, but often this is too restrictive.
Multiplication and division of integers is also problematic on microcontrollers, which typically have no dedicated circuitry for these operations. In the MSP430 family, for example, some variants actually include a hardware multiplier, but others do not. Without hardware support, multiplication and especially division require the CPU to execute a large number of instructions--a fact that you must take into account right at the design phase of your embedded project.
The exception to this rule is multiplication or division by a power of 2. Microcontrollers (like almost all digital circuits) count in binary, so you can replace a multiplication or division by a power of 2 with much more efficient shift operations. While an optimizing compiler will likely make such replacements automatically, you should consider coding the shift explicitly if your application relies on the enhanced performance. Here are a few examples.
| Multiplication | Left Shift Equivalent |
|---|---|
num * 2
|
num << 1
|
num * 4
|
num << 2
|
num * 8
|
num << 3
|
| Division | Right Shift Equivalent |
num / 2
|
num >> 1
|
num / 4
|
num >> 2
|
num / 8
|
num >> 3
|
Table 1. Multiplication and division with shift operations
Here is a table of powers of 2 (up to 2^16). Use this table to calculate the shift equivalents to multiplication and division operations.
| Power of 2 | Decimal | Hex | Octal |
|---|---|---|---|
| 0 | 1 | 0x1 | 01 |
| 1 | 2 | 0x2 | 02 |
| 2 | 4 | 0x4 | 04 |
| 3 | 8 | 0x8 | 010 |
| 4 | 16 | 0x10 | 020 |
| 5 | 32 | 0x20 | 040 |
| 6 | 64 | 0x40 | 0100 |
| 7 | 128 | 0x80 | 0200 |
| 8 | 256 | 0x100 | 0400 |
| 9 | 512 | 0x200 | 01000 |
| 10 | 1024 | 0x400 | 02000 |
| 11 | 2048 | 0x800 | 04000 |
| 12 | 4096 | 0x1000 | 010000 |
| 13 | 8192 | 0x2000 | 020000 |
| 14 | 16384 | 0x4000 | 040000 |
| 15 | 32768 | 0x8000 | 0100000 |
| 16 | 65536 | 0x10000 | 0200000 |
Note that the largest unsigned quantity expressible in any given number of bits b is 2^b-1. For an 8-bit unsigned number, this is 256-1, and for a 16-bit unsigned number it is 65,536-1 (see the table).
Here is a summary of the guidelines for arithmetic operations in microcontroller software:
- Avoid floating-point operations of any kind, if at all possible.
- Avoid multiplication and division.
- Try to use numbers that do not require more bits than the machine's native architecture can accommodate. For example, a 16-bit microcontroller will typically handle both 8-bit and 16-bit quantities efficiently but will be less efficient with 32-bit numbers. An 8-bit microcontroller will incur an even greater penalty when using 32-bit numbers.
- 16-bit integers are usually a good compromise for embedded applications; they are large enough for most purposes, while remaining reasonably efficient even on 8-bit architectures.
- Use unsigned arithmetic if you do not need to express negative quantities--it doubles the magnitude of the largest number that can be represented. For example, the largest signed 16-bit number is 32,767, while an unsigned 16-bit number can be as large as 65,535.