Embedded software articles – from assembly language to software IP
I have always liked writing. From an early age, I had an ambition to write a book. My first attempt, in my mid-teens, was a science fiction novel. It was not a success. I wrote about 100 pages and I may even still have the typescript. I remember being embarrassed last time I looked at it. One of the best days of my life was back in 1986, when a jiffy bag arrived in the mail containing a book with my name on the cover.
Since then, I have never really stopped writing …
With a few exceptions, just about everything I have written has been about electronics and/or software. Until the last few years, much of my output has been in print – lots of collateral materials, countless magazine articles and another book. Nowadays, the vast majority of what I do is online. This blog is a prime example. I post frequently on a wide range of topics, but, to some extent, I feel rather constrained – both by time and space. It takes time to write a few thousand words and a blog post is necessarily quite brief. So, I welcome opportunities to get into more detail and explore a topic in more depth.
I publish articles – many of which pick up on themes of blog posts – in a number of places. I have a “column” on embedded.com – that means that they publish my pieces on a fairly regular basis. I realized that I do not do a very good job of publicizing those articles, so I figured that it might be useful to provide a guide to some of my recent work on that site:
Binary Anyone?
Embedded software developers quite commonly need to think about individual bits. This is most commonly the case when working with CPU or peripheral device control registers. High level languages, like C, do not accommodate developers’ needs very well in this respect. This article outlines an approach whereby developers can code low level routines using binary in a natural, intuitive way.
Is Assembly Language Best?
It is generally believed that hand-written assembly language code, though time consuming and requiring significant skill, will always yield the best result. This article questions that belief and illustrates common coding situations where using a high level language, like C, with a modern compiler can consistently do better. It is partly a matter of understanding compiler optimization and code generation and partly a question of appreciating human nature.
USB 3 – An Introduction for Embedded Software Developers
USB is widely deployed in embedded devices of all kinds, resulting in simple interconnectivity and interoperability. This simplicity comes at a cost: the internal functions of USB are quite complex. This is of no consequence to the user of a USB-enabled device, but the embedded software developer does need some understanding of USB internals. Even if a commercial USB stack is employed, an appreciation of how it works enables it to be used optimally.
In this article, the history and internal operation of USB will be reprised. Then, the changes and enhancements that come along with USB 3 are reviewed.
The Millennium Bug Revisited
A decade and a half ago, the software industry in general, and the embedded software industry in particular, was in a state of near panic. The concern was that much software, that controlled critical systems, may have been designed some years previously and not be able to cope with the date roll-over from 1999 to 2000 – the “millennium bug”. This problem is now just a distant memory, if recalled at all. This article looks at the significance of that problem and whether similar problems may arise before 2099.
Using Software IP
When developing embedded software, a key decision, that needs to be addressed, is “Make or buy?” It is common practice to utilize proven software IP, such as real time operating systems, in modern designs and the scope for licensing software components is expanding as time to market pressures make their use more attractive. The main concern of developers is the usability and quality of such IP. This article looks at the precautions that may be taken, the best practices for selecting IP, the role of standard validation suites and where open source fits in.
In future posts I will highlight more of these articles until I get fully up to date. Then I will post a “heads up” message in a more timely fashion. I am always interested in ideas for topics for articles [and blog posts]. If you have a suggestion, please comment or email.
Comments
Leave a Reply
You must be logged in to post a comment.
Hi Colin,
Good editorial. I have been working with embedded systems since my TRS-80 days and wonder where things will go. I still think for many small projects and circuit “glue” 8 bitters will still be practical…for a while. But many things are just continuing to get more complex so I think you are right on regarding Arm processors, etc. It has been an interesting journey and I hope to ride it for a little while longer, God willing! We will see…
I have enjoyed your articles as well as Jack Ganzle’s over the years. Keep it up and God speed!
Bob
Thanks Bob. I take it as a real complement to be mentioned in the same context as Jack, whose work I have admired for many years and always enjoy reading.
[Sorry, but I needed to remove the inappropriate link.]
At the end it is all machine language. Algorithms may change, and different processors support differing optimizations by cycle counts, and memory use, but in the end it is machine language. All higher level languages use artifacts to make the statements more general. This adds code bloat, and redundancy in the generated code, which optimizers do their best to remove. However an optimizer may also change the order of evaluation and in some cases, even the sequence of execution of low level language compared to the authors intent, which can lead to debugging and sometimes rephrasing of the code. In addition, there are different intents of optimization, either speed or memory use, or in some cases to target the best speed, with optimal memory use.
In reality it doesn’t matter whether it is embedded code or not. Well written, bug free code is basically the goal. And well written includes the target application as one of the criteria.
Moreover, security demands some more robustness. Should a buffer be used, how will its space be managed? I typically use a simple bit mask to restrict the index, but there are other methods, because this results in overwriting the earlier data entered. Some folk believe in limiting the increment, which simply truncates the data, but leaves the last character as unknown depending on the input.
Logic errors are basically undetectable by compilers or assemblers because they manifest in undesirable results, but typically won’t crash a program (unless the logical result is some how stored over a pointer.)
The biggest advantage of compilers is that they remove the need for really understanding what the machine is doing to achieve a usable result. However that means that different kinds of bugs and errors can creep in because of that lack of knowledge. Seeks to wrong addresses on disks, paging errors in memory, caches that are not initiailized, or variables not properly set or managed, among others, simply because their exact bit operations are not understood. And this is independent of the language. Operator over loading and inheritance can add complexity and hidden memory hogs if the underlying object is not well understood. And even instructors sometimes introduce the NULL pointer into C++ coding classes where it should never exist. Uninitialized file accesses are another error commonly found in C++ and other object languages, and is not typically detectable at compile time, but only evidenced during normal operation.
Choice of high level language, compiler, optimizer, lint, garbage collector or operating system will not make code safer. Writing safer code will.
And since the author offered his years of experience, I have over 40 years of coding experience.
Thanks for your post which is truly informative for us and we will surely keep visiting this website.