embedded software boot camp

Application notes code quality

August 2nd, 2007 by Nigel Jones

All manufacturers of microcontrollers publish application notes. Some of these application notes are of course nothing more than gussied up advertising drivel. However, many of these application notes contain useful information that can cut days, and sometimes weeks off a project. Having read hundreds of these application notes over the 25 years I’ve been doing this, I’ve come to the conclusion that whereas the application notes usually get the algorithms correct, the same can’t be said for the code. Too often the code is sloppy, with bugs that are apparent merely by code inspection. May be it’s just me, but whenever I see a sloppy piece of code, it makes me wonder about the underlying quality of the IC design.

I think this is unfortunate, since the manufacturer’s could do much to improve things in the industry by setting a great example. To this end, I think they should:

  1. Adopt a set of coding standards that all their code adheres to.
  2. Have the code reviewed, such that egregious bugs are caught.
  3. Make the code Lint free
  4. If they are aiming the product at the automotive industry, ensure it is MISRA C compliant.

The advantages to the IC manufacturer are legion:

  1. They look good (never a bad thing)
  2. All their application note code has the same “look and feel”. This encourages engineers to use their application notes, and hence their products.
  3. The code in the application note is usable “as is”, speeding time to market and generally giving the perception that their product is easy to use.
  4. Less experienced engineers are taught how to do things correctly – which presumably leads to higher quality products- which presumably translates into more sales.

I guess the thing that I find maddening about this, is that the manufacturers probably spend weeks or months developing the application note, and then let themselves down by presenting their solution in such a poor way. When I talk to the marketing folks for the CPU manufacturers, I make a point of bringing some of the more egregious errors to their attention. Perhaps if all of us did this, we could get a bit of a sea change in the industry.

Home

Comments on code comments

July 13th, 2007 by Nigel Jones

People’s opinion on code commenting is a bit like their opinion on speeding (you know the adage – anyone that drives faster than you is a maniac, anyone that drives slower than you is a doddering old fool). With this in mind, I recently got into a bit of a disagreement with a faculty member of one of America’s finer engineering schools. Here’s a summary of our positions.

Me
I’ve looked at this 750 SLOC file. It contains no header, no comments, or any other explanation as to what it does. The code itself is non-trivial, involving a large amount of recursion, dynamic memory allocation etc and thus what the code does and how it does it, and indeed why it exists is not obvious to me.

Faculty
Based upon the file name it should be obvious what the code does. If you don’t understand the theory of this entity, then you have no business looking at the code. P.s. the code is documented

Home

Size matters

June 13th, 2007 by Nigel Jones

Periodically I get printed propaganda from the semiconductor manufacturers touting their latest and greatest ICs. Evidently the marketing folks are convinced that size matters because the size of the IC is almost the first thing they tell you now. A recent example from Maxim has the headline: “Smallest, Most Efficient and Flexible Notebook Fuel-Gauging Solution“.

Well size does matter. However, it seems to me that the industry has gone too far. More and more devices are being offered only in chip scale packaging (CSP). As a result, it is all but impossible to hand build a prototype, let alone cobble together a breadboard. The result of this is that in many cases it simply doesn’t make economic sense to use the part simply because CSP requires the prototype board to be machine built at a cost of thousands of dollars.

I think the manufacturers are aware of this problem and are trying to address it by offering evaluation boards. While these are OK for the breadboarding phase, they don’t solve the prototyping problem. Furthermore even if the project can justify the cost of machine built prototypes, probing the part or (heaven forbid) making modifications to the board is virtually impossible. The bottom line IC manufacturers. Offer all your parts in a package that can be handled by people. Please.

Home

Understanding Stack Overflow

June 4th, 2007 by Nigel Jones

I suspect that many, if not all bloggers are somewhat narcissistic. In my case it shows through in that I use one of the free services that keeps track of how many visitors I get and what brought them to this blog. Well, it turns out that many of the visitors to this blog get here not because of the brilliance of my writing, but because they did a Google search on “stack overflow” often qualified by PIC, or MSP430 etc. For many of these visitors I suspect they leave empty handed. Thus in an attempt to make these visits less pointless, let me give you my take on what causes a stack overflow in an embedded system.

First of all, go read the Wikipedia description of stack overflow. There’s nothing wrong with the description – it’s just incomplete from an embedded systems perspective.

If you are having problems with 8 bit PICs, then you should read this. For other architectures, read on…

On the assumption that you are getting a stack overflow and that you aren’t performing recursion or attempting to allocate a large amount of storage on the stack, what can be going wrong? Here’s a check list.

  1. What’s your stack size set to? If you don’t understand the question then you need an introductory course to embedded systems programming. If you do understand the question – but don’t know the answer – then this is the most likely source of your problem. How can this be you ask? Well, most embedded systems compilers are designed to work with a particular family of processors. The low end of the family may have a tiny amount of memory (e.g. 128 bytes). As such setting the default stack size to 16 bytes may be a sensible thing to do. Thus, your first step is to ensure that the stack size is set to something reasonable for your system. Click here for advice on how to do this.
  2. Which stack is overflowing? Many processors / compilers support / implement multiple stacks. A typical dichotomy is a call stack (upon which the return addresses of functions are stored) and a data or parameter stack (upon which automatic variables are stored). If you are using an RTOS, then typically there will be a shared call stack while each thread will have its own data stack. Thus is it the shared call stack that is overflowing, or is it the parameter stack associated with a particular task? Once you’ve made the determination which stack is overflowing then finding out exactly what gets placed on that stack will help lead you to the solution to your problem. If you can see no obvious high level language construct that is causing the problem, then the single most likely cause of your misery is an interrupt service routine…
  3. An interrupt service routine can use up an extraordinary amount of space on the stack. For a discussion of how this arises and its impact on performance, see this article. This problem is compounded if your system allows interrupts to be nested (that is, it allows an ISR to itself be interrupted).
  4. Certain library functions (printf() and its brethren are prime offenders) can use an enormous amount of stack space.
  5. If you are writing partially in assembly language, are you failing to pop every register that you pushed? This often occurs if you have more than one exit point from a function or ISR.
  6. If you are writing entirely in assembly language, did you set up the stack pointer correctly and do you know which way the stack grows?
  7. Have you made the mistake of programming a microcontroller that you don’t understand? For example, low end PIC processors have a tiny call stack which is easily overflowed. If you are programming a PIC and don’t know about this limitation, then quite frankly, I’m not surprised you are having problems.
  8. If none of the above solve your problem, then I’m afraid you are most likely in to a stack over-write problem. That is, a pointer is being de-referenced that results in the stack being overwritten. This can often arise when you allocate an array on the stack and then access an element beyond the end of the array. Lint will find a lot of these problems for you. If you don’t know what Lint is, see this article. If you do know what Lint is and aren’t using it then you deserve to be faced with these sorts of problems.

I have also written a related article on setting your stack size that you may find useful.

Home

Continued Fractions

May 19th, 2007 by Nigel Jones

Once in a while something happens that makes me realize that techniques that I routinely use are simply not widely known in the embedded world. I had such an epiphany recently concerning continued fractions. If you don’t know what these are, then check out this link.

As entertaining as the link is, let me cut to the chase as to why you need to know this technique. In a nutshell , in the embedded world we often need to perform fixed point arithmetic for cost / performance reasons. Although this is not a problem in many cases, what happens when you need to multiply something by say 1.2764? The naive way to do this might be:

uint16_t scale(uint8_t x)
{
 uint16_t y;
 y = (x * 12764) / 10000;
 return y;
}

As written, this will fail because of numeric overflow in the expression (x * 12764). Thus it’s necessary to throw in some very expensive casts. E.g.

uint16_t scale(uint8_t x)
{
 uint16_t y;
 y = ((uint32_t)x * 12764) / 10000;
 return y;
}

Our speedy integer arithmetic isn’t looking so good now is it?

What we really want to do is to use a fraction (a/b) that is a close approximation to 1.2764 – but (in this case) has a numerator that doesn’t exceed 255 (so that we can do the calculation in 16 bit arithmetic).

Enter continued fractions. One of the many uses for this technique is finding fractions (a/b) that are approximations to real numbers. In this case using the calculator here, we get the following results:

Convergents:
1: 1/1 = 1
3: 4/3 = 1.3333333333333333
1: 5/4 = 1.25
1: 9/7 = 1.2857142857142858
1: 14/11 = 1.2727272727272727
1: 23/18 = 1.2777777777777777
1: 37/29 = 1.2758620689655173
1: 60/47 = 1.2765957446808511
1: 97/76 = 1.2763157894736843
1: 157/123 = 1.2764227642276422
2: 411/322 = 1.2763975155279503
1: 1801/1411 = 1.2763997165131113
1: 3191/2500 = 1.2764

We get higher accuracy as we go down the list. In this case, I chose the approximation (157 / 123) because it’s the highest accuracy fraction that has a numerator less than 255. Thus my code now becomes:

uint16_t scale(uint8_t x)
{
 uint16_t y;
 y = ((uint16_t)x * 157) / 123;
 return y;
}

The error is less than 0.002% – but the calculation speed is dramatically improved because I don’t need to resort to 32 bit arithmetic. [On an ATmega88 processor, calling scale() for every value from 0-255 took 148,677 cycles for the naive approach and 53,300 cycles for the continued fraction approach.]

Incidentally, you might be wondering if there are other fractions that give better results than the ones generated by this technique. The mathematicians tell us no.

So there you have it. A nifty technique that once you know about it will make you wonder how you got along without it for all these years.

Home