Engineering requires technical skills and a deep understanding of the relevant technology. Writing good embedded software goes a step further, also requiring a devious mind with an affinity for puzzles.
Implementing the requirements on a system that has everything you need is a matter of turning the metaphorical crank to get the answer. Some solutions are more elegant than others, but most will work well enough to get the product shipped. It all gets a lot more interesting when you have a system that seems as if it can’t possibly contain everything you need. You can compromise on the features, but where is the fun in that?
For me, the great part of embedded systems implementation is the thrill of finding just the right tweak that liberates a few more processor cycles, being excited about freeing eight bytes of RAM, persevering through the map file to find a whole section that you can reclaim for the use of your code, and realizing you can get your product that coveted green award if you can just squeak out a few more milliseconds of deep sleep.
The downside to all of this is that you’ll probably make the system more fragile. For instance, when you free the RAM by having two otherwise decoupled subsystems share it, those subsystems become linked. Maintainers of the system become confused and frustrated by hidden linkages. The code is no longer modular, and subsystems cannot be reused. Flexibility is lost.
This chapter looks at the ways to get more out ...