Designing Firmware for Embedded Systems Using Warnier-Orr Diagrams
Go from chaos to clarity by learning how to design programs for embedded systems leveraging the Warnier-Orr diagrams.
Coding and designing firmware are two different steps. Yet, most firmware developers overlook the design step. To rectify this, this article teaches a simple design method using Warnier-Orr diagrams.
The Beginning of Firmware Development Was Chaotic
For most of us who write firmware and software for embedded systems, it is a common desire to dive into coding immediately, neglecting or giving little attention to the critical program design phase. Unfortunately, this impulse is more pronounced in our field than in other fields.
For instance, builders or hardware engineers would never commence construction without a fully developed blueprint or schematic. On the other hand, upcoming firmware developers often jump straight into coding without fully developing their program’s logic, which can often lead to chaotic "spaghetti" programs (Figure 1).
Figure 1. Writing code before first designing it is a bad practice that results in chaotic “spaghetti” programs.
They do this in one of three ways:
- They simultaneously try to design and code (an approach known as “design-a-little, code-a-little")
- They rely too heavily on the programming language constraints when developing the logical design of the program
- They skip the design step completely because they think the project is “too easy,” or they have overconfidence in their abilities, a.k.a, "I am too smart.”
This kind of rush to code can backfire and ultimately cost more development time, as a poorly designed program is likely to result in many errors that could have been avoided through careful planning.
For example, if you use the design-a-little, code-a-little approach, you will probably have to erase or retype a lot as the design keeps changing. Your program will be twice as long and half as efficient as it should be. It can be a grand mistake to assume that skipping the design phase of your program will speed up the development process, and you will have your embedded system up and running in no time.
In fact, the key to building economic code for your microcontroller is to take the time to systematically design your program before writing a single line of code. This is also known as structured programming, and it results in code that occupies less memory, requires shorter processing time, and generally runs correctly at the first trial.
Structured programming means having a thorough understanding of the problem. It involves a top-down analysis of breaking down the problem into smaller and smaller pieces until each piece has an obvious solution or function. At the same time, it also involves organizing or putting together the functions using the three control structures (sequence, alternation, repetition, or loop).
To this end, one popular tool for designing programs in structured programming is to use Warnier-Orr diagrams, named after creators Jean-Dominique Warnier and Kenneth T. Orr, shown in Figure 2.
Figure 2. Jean-Dominique Warnier (left) and Kenneth T. Orr (right). Images used courtesy of Cutter and a blog by Segge Menuet
Warnier-Orr Diagrams Give Clarity
Jean-Dominique Warnier and Kenneth Orr created the Warnier-Orr diagram as a visualization tool to show the hierarchical breakdown of complex data or processes. Its primary use is to represent the logical structure of programs.
A program is a set of ordered instructions that processes input data to produce results. The microcontroller you are programming is simply just a fast information-processing tool.
The input data, results, and program are all information files. These information files are not fully independent data but can be nested within themselves. That is, they can be broken down into subparts and hierarchically organized in a parent-child manner.
The Warnier-Orr diagram lets you define the desired output and work backward, decomposing the input and process steps needed to produce the desired results. Then, it helps you to graphically represent the hierarchy of the program steps and the input and output data structures that have been broken down.
Warnier-Orr Diagram Overview and Considerations
1. The Warnier-Orr diagram draws your program or data structures horizontally across the page with brackets (Figure 3).
Figure 3. Example of a Warnier-Orr diagram. A is broken down into subparts B, C, and D. D is broken down into subparts E, F, J, and H.
Each bracket represents a functional breakdown of the data item or the process step in front of the bracket. The brackets represent separate hierarchical levels, and items within each bracket are logically related.
2. The Warnier-digram is read from left to right and from top to bottom within the bracket.
3. For program structure representation, each bracket of the Warnier-Orr diagram is a visual cue that represents a subroutine in the finished program.
4. When an item or function has the notation (0,1) under it, it means it is either present or absent or selected or not selected or false or true.
5. The “+” notation represents the inclusive OR. When two or more items or steps in a bracket are separated by “+,” it means either one or the other, or both are included.
6. The notation "⨁“ represents exclusive OR. When two or more items or steps within a bracket are separated by “⨁,” it means that one or the other, but not both items, are included or performed.
7. The notation “(n, N)" notation represents how many times a function will be executed (Figure 4).
Figure 4. Breaking down the smart lock data using the Wanier-Orr diagram.
8. The notation “?N” notation represents a condition to be tested to determine which function will be selected. The conditions are detailed in the diagram's footnotes shown in Figure 5.
Figure 5. Logical representation of a program that has been broken down into subparts. Image used courtesy of Diagramming Techniques for Analysts and Programmers
9. When representing a program, each hierarchical level or subfunction has three parts. These are BEGIN, the process steps, and END.
Now, with the Warnier-Orr tool in your hand, you are more than ready to design a program for your next embedded systems project.
Steps To Logically Design Programs For Microcontrollers
Building good programs for microcontrollers requires a systematic approach. Jean Warnier, along with other authors in the book, “Programming Techniques,” introduces four design steps that help you design good programs and to derive them from the problems which cause us to create them in the first place.
Step 1: Identify the Output
The first and most important step is identifying the program’s desired output. You must ask yourself the question: “What do I want the program to do?” Make sure you answer this question as clearly as possible.
Step 2: Define the Logical Database
Once the output is clearly defined, you can identify the inputs you need, as well as define the properties of those inputs. This step helps to ensure that all the necessary inputs are accounted for, and the last-minute additions such as “opps, I forgot to put in something to . . . .” are kept to a minimum.
When you can answer the questions in steps one and two, you’ve completed the highest level of design.
Step 3: Design the Program Structure
Next, designing the program structure is done in two steps: top-down analysis and synthesis.
Top-down analysis involves breaking the program into a number of more detailed subfunctions. Start with the highest level, which is a single block describing the overall function, and then progressively expand that function into detailed subfunctions. With this step, don’t worry too much about the order in which the subfunctions will be performed in your program. You’re only concerned with what should be done and not how it should be done.
Since much of this is intuitive, start the process slowly and don’t attempt to develop too many details too soon.
After the top-down analysis is done, you have reduced the program into a collection of basic components. Synthesis involves deciding in what order the functions should be performed. The three basic logic structures to organize these functions are the sequence, if-then-else, and loop. Combinations of these can be used to build complex functions.
Step 4: Use the Warnier-Orr Diagram to Represent Your Design
Translate this into an overview using Warnier-Orr diagrams. The entire diagram should only contain logical statements and not code. This makes the documentation easy to understand.
Unpacking the Challenge of Programming Microcontrollers
Programming microcontrollers can be a challenging task, and it often feels like a mysterious art. Once you have learned the basic instruction set or embedded C, you’re on your own. Those who do well seem to approach programming embedded systems in an organized and systematic way.
In this article, we've discussed one such approach. It's worth giving it a try, even if you're used to doing things a different way. Admittedly, it might take some time to get used to it, but you'll likely see the benefits in the form of less time spent debugging your program.