ARM design on the mbed Integrated Development Environment - Part 2: program design and structure
Editor’s Note: In Part 2, excerpted from their book Fast and effective embedded systems design: Applying the ARM mbed, authors Tim Wilmshurstand Rob Toulson introduce a number of C/C++ programming methods for ARM designs using the open source mbed integrated development environment.
There are many different approaches to development in embedded systems. As noted in Part 1, with the mbed there is no software to install, and no extra development hardware needed for program download. All software tools are placed online so that you can compile and download wherever you have access to the Internet.
Notably, there is a C++ compiler and an extensive set of software libraries used to drive the peripherals. Thus, also as noted in Part 1, there is no need to write code to conﬁgure peripherals, which in some systems can be very time consuming.
BUT, although this book does not assume that you have any knowledge of C or C++, you have an advantage if you do.
The mbed Compiler and API
The mbed development environment uses the ARM RVDS (RealView Development Suite) compiler, currently Version 4.1. All features of this compiler relevant to the mbed are available through the mbed portal.
One thing that makes the mbed special is that it comes with an application programming interface (API). In brief, this is the set of programming building blocks, appearing as C++ utilities, which allow programs to be devised quickly and reliably. Therefore, we will be writing code in C or C++, but drawing on the features of the API.
As just mentioned, the mbed development environment uses a C++ compiler.That means that all ﬁles will carry the .cpp (Cplusplus) extension. C, however, is a subset of C++, and is simpler to learn and apply. This is because it does not use the more advanced ‘object-oriented’ aspects of C++.
In general, C code will C compile on a C++ compiler, but not the other way round. C is usually the language of choice for any embedded program of low or medium complexity, so will suit us well here. For simplicity, therefore, we aim to use only C in the programs we develop. It should be recognized, however, that the mbed API is written in C++ and uses the features of that language to the full. We will aim to outline any essential features when we come to them.
Program Design and Structure
There are numerous challenges when tackling an embedded system design project. It is usually wise first to consider the software design structure, particularly with large and multi-functional projects. It is not possible to program all functionality into a single control loop, so the approach for breaking up code into understandable features should be well thought out. In particular, it helps to ensure that the following can be achieved:
- that code is readable, structured and documented
- that code can be tested for performance in a modular form
- that development reuses existing code utilities to keep development time short
- that code design supports multiple engineers working on a single project
- that future upgrades to code can be implemented efficiently.
There are various C/C++ programming techniques that enable these design requirements to be considered, as discussed here, including: functions, flow charts, pseudocode and code reuse.
The role of Functions
A function is a portion of code within a larger program. The function performs a specific task and is relatively independent of the main code. Functions can be used to manipulate data; this is particularly useful if several similar data manipulations are required in the program. Data values can be input to the function and the function can return the result to the main program. Functions, therefore, are particularly useful for coding mathematical algorithms, look-up tables and data conversions, as well as control features that may operate on a number of different parallel data streams. It is also possible to use functions with no input or output data, simply to reduce code size and to improve readability of code. Figure 6.1 illustrates a function call.
There are several advantages when using functions. First, a function is written once and compiled into one area of memory, irrespective of the number of times that it is called from the main program, so program memory is reduced. Functions also allow clean and manageable code to be designed, allowing software to be well structured and readable at a number of levels of abstraction. The use of functions also enables the practice of modular coding, where teams of software engineers are often required to develop large and advanced applications. Writing code with functions therefore allows one engineer to develop a particular software feature, while another engineer may take responsibility for something else.
Using functions is not always completely beneficial, however. There is a small execution time overhead in storing program position data and jumping and returning from the function, but this should only be an issue for consideration in the most time-critical systems. Furthermore, it is possible to ‘nest’ functions within functions, which can sometimes make software challenging to follow. A limitation of C functions is that only a single value can be returned from the function, and arrays of data cannot be passed to or from a function (only single-value variables can be used). Working with functions and modular techniques therefore requires a considered software structure to be designed and evaluated before programming is started.
Using Flowcharts to Define Code Structure
It is often useful to use a flowchart to indicate the operation of program flow and the use of functions. Code flow can be designed using a flowchart prior to coding. Figure 6.2 shows some of the flowchart symbols that are used.
For example, take the following software design specification:
Design a program to increment continuously the output of a seven-segment numerical light-emitting diode (LED) display (as shown in Figure 6.3, and similar to the one used in Part 1) through the numbers 0 to 9, then reset back to 0 to continue counting. This includes:
- Use a function to convert a hexadecimal counter byte A to the relevant seven- segment LED output byte B.
- Output the LED output byte to light the correct segment LEDs.
- If the count value is greater than 9, then reset to zero.
- Delay for 500 ms to ensure that the LED output counts up at a rate that is easily visible.
The output of the seven-segment display has been discussed previously in Part 1 and in particular in Table 3.4. A feasible software design is shown in Figure 6.4.
Flowcharts allow us to visualize the order of operations of code and to make judgments on which sections of a program may require the most attention or take the most effort to develop. They also help with communicating a potential design with non-engineers, which may hold the key to designing a system that meets a very detailed specification.