What is embedded software development?
If we were to ask a random person about operating systems, they would most likely have no trouble describing the most important ones such as Windows in personal computers or iOS in Apple iPhones. But what if we were to ask about embedded systems? I think that most people might find it difficult to describe what it is and how it works.
Embedded systems surround us in all parts of our everyday life and are a significant element of the industry. Even the simplest device must have a software. Otherwise, an automatic washing machine wouldn’t be able to wash our clothes, a toaster couldn’t make us toast and the alarm system would not protect our property.
What is an embedded system?
An embedded system, or in other words: micro, systemic, embedded or device software, is permanently installed in a device and serves to execute the programmed functions (a small number or even an individual sentence) which it executes in a certain time. Usually, such a software works without supervision, so it does not require the introduction of data and is not operated by a user. Often, it does not even come with a graphical interface. Its main purpose is to provide basic operating procedures for the device. The embedded system is fired along with the device’s ROM without the possibility of interference or in the case of newer technology, flash or EEPROM, which allows its updating.
An embedded system may work independently or as an element connected with another system. For example, a printer paired with a computer or even a network card has its own firmware, which, unlike controllers, is not part of it, but is only activated by external control. Firmware is managed by an internal microprocessor or microcontroller, but it can communicate with other devices, for example to restore functioning, calibration or diagnostics. Embedded software is an integral element of a self-operating device.
Beside everyday use devices, embedded systems are used to control much more complicated machines. Suffice to say that their history began with the Apollo spaceship. On a wider scale, they are present in medicine, industrial robotics, aviation, automotive or military industry. A software is as complex as the device which it controls. It can hardly be expected that the complexity of an 8-bit controller with a few kilobytes of memory in a digital watch could compete with algorithms in seeker missiles or process control systems, e.g., in planes. However, all embedded systems share common features - reliability and predictability. The more complicated the device, the more specialized the embedded software should be. This solutions allows the separation of tasks into smaller subsystems. Reliability can also be increased by means of redundancy, i.e., delegating two independent devices to the same task. In this way, the entire system can run smoothly even in the face of a critical failure. Platforms of embedded systems usually have high mechanical resistance and can work even in difficult environmental conditions.
The process of programming embedded systems
Because embedded systems are closely related to the hardware, dedicated units should cooperate equally as close. This is often difficult because the work methodology of engineers is distant from the habits of coders. While the first group focuses on organizing and clinging to the outline, the other is much more flexible and prefers the trial and error method. It is important to be very precise in specifying the requirements before commencing work and select the operating system, processor, peripherals, programming platform as well as set new milestones of production, which should be verified at the test level. When designing embedded systems, many companies lean towards a cascade model, or treating subsequent activities as separate “stairs” leading to finalization. These involve:
1. system planning (included in the requirements specification);
2. design;
3. building the code;
4. testing;
5. production;
6. product support.
Such a formalized method allows for greater control over the consistent implementation of individual project elements. At least when it comes to the hardware side, but is it equally well suited to programming? This model is nested in the belief that programmers should have a much easier time adapting the code for possible changes. Enough with the theory. In practice, any shift from the original specifications and design documents will entail delays and additional budget burdens. The software requires as much work as the equipment. So, is it possible to approach the problem differently and lead to the synergy of engineers and programmers?
Agile development in the creation of embedded systems
The agile software development methodology abandons a linear, sequential action framework for an iterative-incremental approach (such as Scrum). Product development is divided into sprints of a certain time interval and takes into account the current contact between teams or the creation of one interdisciplinary team of specialists. Such teams are multifunctional and self-regulating; they bring together planners, designers, engineers, programmers and testers while abandoning any organizational hierarchy. Instead of extensive planning and design in advance, the project is carried out from iteration to iteration. It should be possible to present the working version of the product to the product owner at every stage. Feedback can then be implemented at the next stage of work. Developers are the ones to decide how to achieve the set goals. The method focused on fast production of high-quality software and short feedback loops allows for constant verification of the client’s requirements and schedule, minimizes the need to create extensive code documentation (which is often out of date with the cascade approach), and the visibility of progress is motivating and allows ongoing product testing for the duration of the works. This is particularly important since software decisions are often reactivated, and developers complain about too late quality control, which translates into delays. This does not mean that you should entirely shift away from specification or defining milestones. However, the requirements defined at the beginning of the project are often too vague and subject to change, and their current definition allows better adjustment of the software to the real needs.
Because agile programming assumes close cooperation and effective communication, the team should set out the time needed for the next sprint, the necessary resources and divide tasks between themselves. However, short meetings should take place daily. Even if they were to boil down to contact between project managers and be conducted at a distance via a messenger. It is worth spending 15 minutes to detect any difficulties. During the sprints, the client should have insight into progress instead of being merely a passive observer. His satisfaction is a priority, and it leaves a free hand only in terms of methods for obtaining positive results.
It all boils down to the assumptions of agile software defined in 2001 in the so-called Agile Manifesto; the declaration reads:
“We are uncovering better ways of developing
software by doing it and helping others do it.
Through this work we have come to value:
Individuals and interactions over processes and tools
Working software over comprehensive documentation
Customer collaboration over contract negotiation
Responding to change over following a plan.
That is, while there is value in the items on
the right, we value the items on the left more.”
All Assumptions of the Agile Software Development Manifesto can be found on the dedicated website (https://agilemanifesto.org/principles.html).
Languages of embedded systems development
The most popular programming languages for embedded systems are definitely C and C ++. This may be surprising due to the fact that their beginnings date back to the 1970s. At that time, the machine code (set of processor commands in the form of binary numbers) originating from the times of zero-generation computers enjoyed great popularity. This meant writing a large number of lines of code by hand. In 1969 at Bell Labs, Ken Thompson invented the B programming language, which optimized this process. However, the new language lacked data types and structures. Dennis Ritchie took four years to complete the missing functions and thus invented the C language. In 1973, he managed to implement the UNIX operating system kernel and thereby standardize the programming language on this platform. The evolution was completed by Bjarne Stroustrup[KZ1] , a PhD student who compiled the C and Simula languages, which greatly facilitated object-oriented programming. In 1983, the hybrid was given the name C ++.
C is a high-level structural language created for programming operating systems and other low-level tasks. Why is this language still in widespread use today? Because of its low-level nature and its compact weight. It allows the developer to accurately control the computer’s operations, while allowing aggressive optimization on any platform. C works quickly even with limited equipment resources. Creating code in other languages, for example for a small microcontroller, requires building a C language compiler in advance. This involves additional work. However, writing C code is not recommended for novice programmers, as it is required to have in-depth understanding of the source code. Developers joke that if you understand the logic behind C, then no language is any longer a challenge. C ++ stands out from C primarily with its greater generality and objectivity.
Another language worth mentioning is Rust. It is a relatively new technology; a dedicated compiler and toolkit in version 1.0 were published in 2015 by the Mozilla Foundation. It is a compiled general-purpose language that primarily focuses on safety and practicality.
The list could not be complete without Python, the funniest among programming languages. Its nomenclature is full of references to contemporary pop culture. It made its debut in 1991 under the name “Monty Python’s Flying Circus”, hence its name today. Python is a general-purpose high-level programming language that focuses on the transparency and brevity of the source code. That’s why it is often the introductory language on most IT courses. Although it is not associated with embedded software, because of its modularity through the use of libraries written in C, it can be used in embedded systems whose performance and memory size allow to run Linux (the CPython interpreter works under this system).
Challenges and problems in the development of embedded software
The development of embedded software puts many difficult challenges before programmers. Let’s list the most important ones:
high business risk caused by the variability of customer requirements and short deadlines;
because later updates are not possible, hardware and software must be reliable after the production stage, which is associated with a large number of tests;
high divisibility of tasks makes communication between teams working on hardware and software critical.
Depending on the chosen management model, these challenges may cause various problems at the design stage. If we decide on a cascade model and we do not ensure that all changes are recorded in the documentation, then with time the assumptions will be significantly off from actual progress. This may make management more difficult and the final effect will be different than expected. Before the product is ready for testing, we will need an average of 6 months of work. This delayed entry of the quality department into action leads to last-minute detection of problems and repairs, which may in turn cause delays. Lack of smooth communication and – due to the formal hierarchy – anticipation for acceptance of the proposed solutions will also have negative consequences in the timeliness of the schedule. The agile development model can be the answer to most of these problems.
The agile programming manifesto sounds lofty, but does this method guarantee success in creating embedded systems? Of course not. Each project management method has its pros and cons. The first ones will emerge in the hands of a well-coordinated team, but the second will be reflected in activities to which chaos makes its way. Systematic work is the key to success in agile programming. Poorly coordinated communication will bring a domino effect. It is also very important to plan work during sprints and set realistic goals. If you cannot keep pace with your plans, find alternative ways to show your progress. Unnecessary rush can make sprints turn into discussions about the accumulating errors, and all work will be reduced to compensating for mistakes. This will not bring any good results.
Some companies cannot opt for one methodology or are afraid of transitioning to an agile software model. That is why they do it step by step. Therefore, they create a kind of hybrid called scrummerfall at their own discretion. Sitting back and doing nothing will not bring positive effects. In this way, the team does not benefit from any of the adopted assumptions, or worse, leads to disorganization of the set-out work schedule.
How to build embedded systems?
The creation of embedded systems should be similar to embedded systems themselves. Each team member should have clearly defined functions and be an integral part of a larger whole. In the event of problems, use the principle of redundancy. The effects of the work should be predictable and visible in the completed cycle. This will all add up to the image of a reliable mechanism.