embedded software boot camp

Electrical Engineers versus Computer Scientists

February 6th, 2009 by Nigel Jones

Looking back at my various blog postings, I’ve noticed that although I may be controversial on technical topics, I haven’t to date written anything that is controversial on a, shall I say, human side. Well no more Mr. Nice Guy, since today I intend to wade in on the topic of whether Embedded Systems should be programmed by Electrical Engineers or Computer Scientists. Regular readers will know I’m an EE (actually my degree is in EE & ME – but that’s another story) and so you won’t be surprised to hear that my usual preference is for Electrical Engineers. Although I am a (very) opinionated person, I’d like to think that most of my opinions have some basis in reality, and so here’s my opinion and its supporting observations…

The more embedded a product is, the better off you are with an EE, the less embedded it is, the better off you are with a CS.

So what’s the basis for this overblown, sweeping generalization and what exactly do I mean by ‘more embedded’?

Well, I consider a product to be highly embedded if it meets one or more of the following criteria:

  • It has no or very simple user interfaces.
  • It performs a lot of hardware type functions in software. For example a DSP that performs a lot of signal processing is essentially doing in software what was once done in hardware.
  • It contains a lot of complicated hardware that needs extensive configuration and software support (For example a PowerQUICC processor).

By contrast, I consider a product to be lightly embedded if it meets either of the following criteria:

  • It has a sophisticated user interface (especially if the interface is web based)
  • It is database centric.

Evidently there exists products that meet the criteria for both sides of the dichotomy. For example, my new flat screen TV has a very sophisticated user interface, but I’m sure it does an extensive amount of signal processing.

If you accept this dichotomy, then it is evident that folks working on highly embedded systems really need to understand the hardware (since that’s what the product is about) whereas those working on lightly embedded systems need a good understanding of how to build large software systems. Having said this, my experience is that whereas EE’s (OK some EE’s) are able to quickly learn the principles of building large software systems, I’ve never yet met a CS major that had anything beyond a casual understanding of what’s really happening at the hardware level. I’ve seen this lack of knowledge (interest?) manifest itself in many ways. Examples include:

  • Not knowing / understanding the Nyquist Sampling theorem
  • Failure to realize that EEPROM / Flash have extraordinarily long write times
  • Not realizing that sampling jitter can destroy the performance of a digital filter

What about the other way? Have I seen EE’s write 1000 line functions, and be completely clueless about principles such as data encapsulation? Absolutely! However, I have also seen EE’s successfully craft very large systems. As a result I’ve come to two basic observations:

  • A deeply embedded system written entirely by a CS major will have major problems.
  • A lightly embedded system written entirely by an EE major may have major problems.

On this basis, I prefer (slightly) to have EE’s work on embedded systems.

It doesn’t take a rocket scientist to conclude that perhaps the best approach is to have a team where the EE’s handle the hardware centric stuff and the CS’s handle the computer centric stuff. Indeed, this is the approach I see taken in most organizations.

As a final thought, although it is common to find EE majors that have gone back to college to get a Masters in Computer Science, I haven’t yet met a CS major that has gone back to college to get a Masters in Electrical Engineering.

Home

First do no harm …

February 2nd, 2009 by Nigel Jones

One of the pleasures of working for myself is that it allows me to experiment with some rather non-traditional approaches to the whole concept of ‘work’. In fact, looking back at some of my postings, here, here and here it’s clear that this is a recurring theme in my writing. I mention this because a number of years ago I instituted the policy of

Two idiotic mistakes and I quit.

What exactly is this you ask? Well over the years I have noticed that I have days in which rather than progressing on problems, I actually regress, often by huge amounts. I do stupid things such as apply power with the wrong polarity to a board, or I design a circuit that will evidently never work. If I make two of these bone headed mistakes in quick succession, I take it as a clear indicator that my head really isn’t where it needs to be – and I quit for the day.

Now, back when I was an employee, I simply had no choice other than to continue ‘working’, even though I knew full well that I’d be doing my employer a favor if I did nothing more than sit in the corner for the rest of the day. Today, I simply walk away and return to the problem the next day.

It would be an unusual manager who recognized that these days occur – and encouraged his staff to ‘quit’ when they did. I’m sure for many managers, this concept is too radical. However, if Engineers are indeed professionals, then we could do worse than adopt the abbreviated form of the Hippocratic oath given in the title to this posting.

Home

Common programming errors and presidential inaugurations

January 20th, 2009 by Nigel Jones

I don’t normally link politics and embedded systems, but something happened today at the inauguration of Barack Obama that struck me as an obvious error, but which my family and I suspect 99.999% of the rest of the viewers accepted without question. I’m referring to the third paragraph of Rick Warren’s invocation where he stated:

Now, today, we rejoice not only in America’s peaceful transfer of power for the 44th time. We celebrate a …

Well it seems to me that if Barack Obama is the 44th president of the USA, then there can only have ever been 43 transitions of power. I suppose that one could claim that when Washington became president, it was a transition of power. However no one could possibly claim it was peaceful!

What’s my point? Well Rick Warren had just made a classic programming blunder. I’m guessing that his invocation was scrutinized by an army of political hacks, many with advanced degrees from top universities – yet despite this the error was not caught. I guess next time you make this mistake in your code, you can console yourself with this information.

BTW, you will not be surprised to know that my wife and kids just think that this confirms their belief that I’m a complete Nerd who is in desperate need of a life!

Using Espresso to simplify embedded systems

January 18th, 2009 by Nigel Jones

In this case, Espresso does not refer to the highly caffeinated drink, but rather to the public domain logic minimization tool. What does this have to do with embedded systems? Well, several months back I was faced with an interesting problem. A product I was working on had nine different alarm outputs (some of which are contradictory), which together were dependent upon about thirty different inputs. Furthermore, the interaction between the various inputs leads to situations where the desired alarm outputs are non obvious, and certainly difficult to determine algorithmically. At this point I realized that what was needed was essentially a giant truth table, where the outputs for any given set of inputs was determined by an expert who could look at the various inputs and determine the optimal alarm strategy. Thus the question was, how to tackle this problem? This is what we ultimately ended up doing. First of all the truth table was entered in a database. This was done simply so that we could easily run queries, such as “show me all cases where output 3 is asserted when inputs 6 12 and 13 are negated”. This essentially then was the environment in which the human expert worked. Once the expert was happy with the truth table, it was outputted in CSV format. The CSV file was then pre-processed by a Perl script (thanks Don) and fed to the Espresso logic minimization program. The output of Espresso was then post-processed by the Perl script and converted into compilable C code. To give you a feel for what the output looks like, here’s an excerpt (with the comments removed):

 if(((!(inputs[0] & 0x20)) && (!(inputs[2] & 0x30)) && ((inputs[3] & 0x10) == 0x10) && (!(inputs[3] & 0xa0))) ||
    ((!(inputs[0] & 0x20)) && (!(inputs[1] & 0x60)) && (!(inputs[2] & 0x30)) && ((inputs[3] & 0x10) == 0x10)) ||
    ((!(inputs[0] & 0x20)) && ((inputs[2] & 0x4) == 0x4) && (!(inputs[2] & 0x30)) && ((inputs[3] & 0x10) == 0x10)) ||
    ((!(inputs[0] & 0x20)) && ((inputs[1] & 0x1) == 0x1) && (!(inputs[2] & 0x30)) && ((inputs[3] & 0x10) == 0x10)) ||
    ((!(inputs[0] & 0x20)) && ((inputs[2] & 0x2) == 0x2) && (!(inputs[2] & 0x30)) && ((inputs[3] & 0x10) == 0x10)) ||
    ((!(inputs[0] & 0x24)) && (!(inputs[2] & 0x30)) && ((inputs[3] & 0x10) == 0x10)) ||
    ((!(inputs[0] & 0x28)) && (!(inputs[2] & 0x30)) && ((inputs[3] & 0x10) == 0x10)) ||
    ((!(inputs[0] & 0x30)) && (!(inputs[2] & 0x30)) && ((inputs[3] & 0x10) == 0x10)) ||
    ((!(inputs[0] & 0x20)) && (!(inputs[1] & 0x4)) && (!(inputs[2] & 0x30)) && ((inputs[3] & 0x10) == 0x10)))
{
 out |= 2048;
}

Evidently, it’s enough to make your head spin! For me, the real benefits of such an approach are as follows:

  • I was able to completely divorce the code from the desired functionality. That is, the functionality of the product was completely driven by the client and was in no way dependent upon me doing anything. Thus, when the client asks me ‘what does it do when the following occurs”, I can honestly answer “it’s whatever you told it to do”.
  • By setting this up using a database and a Perl script we recognized that changes to the truth table would inevitably occur, and thus made the process as painless as possible. Now, when a change in functionality is desired, the client simply makes the changes in the database, presses a button to output a new file and I then run a ‘make’.
  • The approach is rigorous. We have considered every possible combination of inputs – no matter how unlikely they are to occur. In my experience, this is something that firmware is not very good at.

Although I think this is neat in its own right, I think there are several larger points worth making:

  • Just because a tool was designed ostensibly for one environment (in this case Espresso was really designed for logic minimization in electrical circuits), don’t be afraid to use it in other ways.
  • Recognize that certain elements in your design are highly prone to change – and design them with this in mind.
  • Either learn a scripting language or have a scripting expert at your disposal to help build your tool sets. (In my case, I do the latter).
  • If you can divorce your code from the required functionality (i.e. data driven coding), then seriously consider it.

An apology

For all of you that subscribe via RSS, I apologize for the recent blitz of data. I decided to go back through all my postings and add links where appropriate, which seems to have forced the posts to be regenerated.

Home

Using volatile to achieve persistence!

January 11th, 2009 by Nigel Jones

Once in a while the real world and the arcane world of language standards collide, resulting in surprising results. To see what I mean, read on …

Many of the products I design incorporate a Bootstrap Loader, so that the application firmware may be updated in the field. In most cases, the bootstrap loader is a completely different program to the main application. Despite this, I find it useful for the main application to pass information to the bootstrap loader and vice versa. Thus the question arises, how best to do this? Well in the processor family I am using, although it is technically possible to store information in Flash, EEPROM or RAM, by far the easiest and most secure way of doing it is to place the information into EEPROM. Furthermore, in order to enter the bootstrap loader it is highly desirable to force a reset of the processor by allowing the watchdog timer to time out.

Thus, the code to enter the bootstrap loader looks something like this:

__eeprom uint8_t msg_for_bootloader;

...

msg_for_bootloader = 0x42;

...

for(;;)
{
 /* Wait for watchdog to generate a reset and force entry in to the bootstrap loader */
}

Well, on the face of it, there is not much wrong with this code. However, if one turns on the optimizer, then the compiler examines the code, decides that no code may be executed beyond the infinite loop and thus concludes that the write to msg_for_bootloader is pointless, and promptly optimizes it away. (For a discussion on this topic, see my posting here)

Now you will note that msg_for_bootloader was qualified with __eeprom. This is a compiler extension that allows one to inform the compiler that the variable msg_for_bootloader resides in a special memory space and to be treated accordingly. Now I know that the compiler knows enough about the EEPROM space to generate the correct coding sequences such that reads and writes are performed correctly. However, in my naivete, I also assumed that the compiler knew something about the properties of EEPROM, such that it would realize writing to EEPROM without ostensibly reading it again is intrinsically useful in many applications.

Well it does not. Furthermore, on balance I think the compiler writer’s got it right and the error was completely mine.

So what to do? Well, declaring msg_for_bootloader as volatile fixes the problem. Thus my code now looks like this:

__eeprom volatile uint8_t msg_for_bootloader;

...

msg_for_bootloader = 0x42;

...

for(;;)
{
 /* Wait for watchdog to generate a reset and force entry in to the bootstrap loader */
}

Thus I ended up in the rather bizarre situation of having to declare a variable as volatile in order to make it persistent!

Although I can appreciate the wry irony of this situation, I think it points to a larger problem. The fact is that we are all (ok, most of us) programming in a language (C) that was not designed for use in embedded systems. Indeed, when C was written, I’m not sure EEPROM even existed. As a result, the compiler vendors have added extensions to the C standard in an effort to overcome its shortcomings for embedded systems, while still desperately striving to achieve “full compliance with the standard”. Despite this, I find myself all too frequently falling into traps such as this one. What we really need is a language explicitly designed for embedded systems. It isn’t going to happen, but it doesn’t stop me wishing for it.

Home