Archive for April, 2009

PIC stack overflow

Saturday, April 25th, 2009 Nigel Jones

For regular readers of this blog I apologize for turning once again to the topic of my Nom de Guerre. If you really don’t want to read about stack overflow again, then just skip to the second section of this posting where I address the far more interesting topic of why anyone uses an 8-bit PIC in the first place.

Anyway, the motivation for this post is that the most common search term that drives folks to this blog is ‘PIC stack overflow’. While I’ve expounded on the topic of stacks in general here and here, I’ve never explicitly addressed the problem with 8 bit PICs. So to make my PIC visitors happy, I thought I’ll give them all they need to know to solve the problem of stack overflow on their 8 bit PIC processors.

The key thing to understand about the 8 bit PIC architecture is that the stack size is fixed. It varies from a depth of 2 for the really low end devices to 31 for the high end 8 bit devices. The most popular parts (such as the 16F877) have a stack size of 8. Every (r)call consumes a level, as does the interrupt handler. To add insult to injury, if you use the In Circuit Debugger (ICD) rather than a full blown ICE, then support for the ICD also consumes a level. So if you are using a 16 series part (for example) with an ICD and interrupts, then you have at most 6 levels available to you. What does this mean? Well if you are programming in assembly language (which when you get down to it was always the intention of the PIC designers) it means that you can nest function calls no more than six deep. If you are programming in C then depending on your compiler you may not even be able to nest functions this deep, particularly if you are using size optimization.

So on the assumption that you are overflowing the call stack, what can you do? Here’s a checklist:

  • Switch from the ICD to an ICE. It’s only a few thousand dollars difference…
  • If you don’t really need interrupt support, then eliminate it.
  • If you need interrupt support then don’t make any function calls from within the ISR (as this subtracts from your available levels).
  • Inline low level functions
  • Use speed optimization (which effectively inlines functions)
  • Examine your call tree and determine where the greatest call depth occurs. At this point either restructure the code to reduce the call depth, or disable interrupts during the deepest point.
  • Structure your code such that calls can be replaced with jumps. You do this by only making calls at the very end of the function, so that the compiler can simply jump to the new function. (Yes this is a really ugly technique).
  • Buy a much better compiler.

If you are still stuck after trying all these, then you really are in a pickle. You could seek paid expert help (e.g. from me or some of the other folks that blog here at embeddedgurus) or you could change CPU architectures. Which leads me to:

So why are you using a PIC anyway?

The popularity of 8 bit PICs baffles me. Its architecture is awful – the limited call stack is just the first dreadful thing. Throw in the need for paging and banking together with the single interrupt vector and you have a nightmare of a programming model. It would be one thing if this was the norm for 8 bit devices – but it isn’t. The AVR architecture blows the PIC away, while the HC05 / HC08 are also streets ahead of the PIC. Given the choice I think I’d even take an 8051 over the PIC. I don’t see any cost advantages, packaging advantages (Atmel has just released a SOT23-6 AVR which is essentially instruction set compatible with their largest devices) or peripheral set advantages. In short, I don’t get it! Incidentally, this isn’t an indictment of Microchip – they are a great company and I really like a lot of their other products, their web site, tech support and so on (perhaps this is why the PIC is so widely used?). So to the (ir)regular readers of this blog – if you are you using 8 bit PICs perhaps you could use the comment section to explain why. Let the debate begin!

Home

Unused interrupt vectors

Sunday, April 19th, 2009 Nigel Jones

With the exception of low end PIC microcontrollers, most microcontrollers have anywhere from quite a few to an enormous number of interrupt vectors. It’s a rare application that uses every single interrupt vector, and so the question arises as to what, if anything, should one do with unused interrupt vectors? I have seen two approaches used – neither of which is particularly good.

Do nothing

I would say this is the most common approach. My guess is that when this approach is used, it’s not via conscious choice, but rather the result of inaction. So what’s the implication of this approach? Well if an interrupt occurs for which you have not installed an interrupt handler, then the microcontroller will vector to the appropriate address and start executing whatever code happens to be there. It’s fair to say that this will ultimately cause a system crash – the only question is how much damage will be done in the process? Having said that, I don’t necessarily consider that this approach is always awful. For example a reasonable argument might go something like this.

I know via design, code inspection, static analysis and testing that the probability of a coding error enabling the wrong interrupt is remote. Thus if it does happen it’s probably either via severe RF interference, or because the code has crashed. In either case the system has bigger problems than vectoring to an unsupported interrupt.

Of course anybody that’s put this much thought into it, will probably be conscientious enough to do something different.

Another valid argument on very memory constrained processors is that you need the unused interrupt vector space for the application. Indeed I have coded 8051 applications where this has been the case. Such is the price we sometimes have to pay on very small systems.

Install ‘RETI’ instructions at all unused vectors

In this approach, you arrange for there to be a ‘Return From Interrupt’ instruction at every unused interrupt vector. Indeed this approach is common enough that some compiler manufacturers offer it as a linker option. The concept with this approach is that if an unexpected interrupt occurs, then by executing a RETI instruction, the application will simply continue with very little harm done. All in all this isn’t a bad approach. However it has several weaknesses.

  • The biggest problem with this approach is that it doesn’t solve the problem of an interrupt source that keeps on interrupting. The most egregious example of this is a level triggered interrupt on a port pin. In this case, depending upon the CPU architecture, it is quite possible for the system to go into a mode whereby it essentially spends all its time vectoring to the interrupt and then returning. However this is by no means the only example. Others that spring to mind are ‘Transmit buffer empty’ interrupts, and timer overflow type interrupts. In the latter case, the system probably wouldn’t spend all of its time interrupting; however a certain fraction of the CPU bandwidth would be wasted, which in a battery powered application for instance, would be a big deal.
  • If you do this at the start of a project, you lose the opportunity to discover errors in which an interrupt source has been erroneously enabled. In short this approach can mask problems, while what is really needed is an approach that can reveal problems.

Recommended Approach

What I do is the following.

  1. At the start of a project I create a file called vector.c In vector.c I create an interrupt handler for every possible interrupt vector. Not only is this an essential first step in solving the problem, I also find it very illuminating as it forces me to read about and understand all the CPU’s interrupt sources. This is always a useful step, as in many ways the interrupt sources for a CPU tell you a lot about its capabilities and the designers intent.
  2. Within each interrupt handler, I explicitly mask the interrupt source. This will prevent the interrupt from reoccurring in all but the most extreme of cases.
  3. If necessary, I also clear the interrupt flag. (In some CPU architectures this occurs automatically by vectoring to the interrupt. In others you have to do it manually).
  4. After masking the interrupt source, I then make a call to my trap function. What this means is that while I’m debugging the code, if any unexpected interrupt occurs, then I’ll know about it in a hurry. Conversely, of course, with a release build, the trap function compiles down to nothing, essentially removing it from the code.

Here’s a code fragment that shows what I mean. In this case it’s for an AVR processor and the IAR compiler. However it should be trivial to port this to other architectures / compilers. Note that for the AVR it is in general not necessary to clear the interrupt flag as it is cleared automatically upon vectoring to the ISR.

#pragma vector=INT1_vect /* External Interrupt Request 1 */
__interrupt void int1_isr(void)
{
 EIMSK_INT1 = 0;  /* Disable the interrupt */
 /* Interrupt flag is cleared automatically */
 trap();
}
#pragma vector=PCINT0_vect /* Pin Change Interrupt Request 0 */
__interrupt void pcint0_isr(void)
{
 PCICR_PCIE0 = 0; /* Disable the interrupt */
 /* Interrupt flag is cleared automatically */
 trap();
}
...
#ifndef NDEBUG
/** Flag to allow us to exit the trap and see who caused the interrupt */
static volatile bool Exit_Trap = false;
#endif
static inline void trap(void)
{
#ifndef NDEBUG
 while (!Exit_Trap)
 {
 }
#endif
}

Home

Effective C Tip #3 – Exiting an intentional trap

Tuesday, April 14th, 2009 Nigel Jones

This is the third in a series of tips on writing what I call effective C. Today I’d like to give you a useful hint concerning traps. What exactly do I mean by a trap? Well while C++ has a ‘built in’ exception handler (try searching for ‘catch’ or ‘throw’), C does not (thanks to Uhmmmm for pointing this out). Instead, what I like to do when debugging code is to simply spin in an infinite loop when something unexpected happens. For example consider this code fragment:

switch (foo)
{
 case 0:
 ...
 break;

 case 1:
 ...
 break;

 ...

 default:
  trap();
 break;
}

My expectation is that the default case should never be taken. If it is, then I simply call the routine trap(). So what does trap() look like? Well the naive implementation looks something like this:

void trap(void)
{
 for(;;)
 {
 }
}

The idea is that when the system stops responding, stopping the debugger will show that something unexpected happened. However, while this mostly works, it has a number of significant shortcomings. The most important is that leaving code like this in a production release is definitely not a good idea, and so the first modification that needs to be made is to arrange to remove the infinite loop for a release build. This is usually done by defining NDEBUG. The code thus becomes:

void trap(void)
{
#ifndef NDEBUG
 for(;;)
 {
 }
#endif
}

The next problem with this trap function is that it would be ineffective in a system that executes most of its code under interrupt. As a result, it makes sense to disable interrupts when entering the trap. This is of course compiler / platform specific. However it will typically look something like this:

void trap(void)
{
#ifndef NDEBUG
 __disable_interrupts();
 for(;;)
 {
 }
#endif
}

The final major problem with this code is that it’s hard to tell what caused the trap. While you can of course examine the call stack and work backwards, it’s far easier if you instead do something like this:

static volatile bool Exit_Trap = false; 

void trap(void)
{
#ifndef NDEBUG
 __disable_interrupts();
 while (!Exit_Trap)
 {
 }
#endif
}

What I’ve done is declare a volatile variable called Exit_Trap and have initialized it to false. Thus when the trap occurs, the code spins in an infinite loop. However by setting Exit_Trap to true, I will cause the loop to be exited and I can then step the debugger and find out where the problem occurred.

Regular readers will perhaps have noticed that this isn’t the first time I’ve used volatile to achieve a useful result.

Incidentally I’m sure that many of you trap errors via the use of the assert macro. I do too – and I plan to write about how I do this at some point.

So does this meet the criteria for an effective C tip? I think so. It’s a very effective aid in debugging embedded systems. It’s highly portable and it’s easy to understand. That’s not a bad combination!

Next Effective C Tip
Previous Effective C Tip
Home

On the use of correct grammar in code comments

Saturday, April 11th, 2009 Nigel Jones

Back when I was in college the engineering students were fond of dismissing the liberal arts majors by doing such witty things as writing next to the toilet paper dispenser “Liberal Arts degree – please take one”. One of the better retaliatory pieces of graffito that I really liked was: “Four years ago I couldn’t spell Engineer – now I are one”. I think this appealed to me because there was more than a smidgen of truth in its sentiment. If you don’t believe me, just take a look at the comments found in most computer programs. I don’t think I’m being exactly controversial by noting that most comments :

  • Lack basic punctuation.
  • Contain numerous spelling errors.
  • Liberally use non-standard abbreviations.
  • Regularly omit verbs and / or other basic components of a sentence.

As a result, many comments are nonsensical. In fact I’ve been in situations where the comments are so badly written that it’s easier to read the code than it is the comments. Clearly this isn’t a good thing! When I question programmers about this, I typically get a shrug of the shoulders and a ‘what’s the big deal’ attitude. When pressed further, the honest ones will admit that they couldn’t be bothered to use correct grammar or spelling because it’s too much effort – and after all you can work out what they mean if you just try hard enough. They are of course correct. However taken to its logical conclusion, this is really an argument for not commenting at all – since with a bit (OK a lot) of effort it should be crystal clear what the code is doing (and why) simply by examining it.

I decided to write about this now since I recently heard from Brad Mosch concerning a pet peeve of his. He gave his permission for me to quote from his email:

I see all the time mixed occurrences of whether or not a space is used for things such as 3dB, 3 dB, 1MHz, 1 MHz, etc. I am hoping that someone in the embedded guru world propose that a space is ALWAYS used between the number and the unit of measure. That is the documented standard that was used in our technical writing at United Space Alliance and NASA. The funny thing is, even though that standard existed out there at Kennedy Space Center, not a whole lot of people knew about it because I saw the same problem in documents out there all the time. Anyway, my point is, isn’t “1 Hz” a lot more readable than “1Hz”?

I’m sure many of you may think that Brad is being overly picky. However I don’t. His real point (in the last sentence) concerns readability. If you are going to write a comment surely it should be as readable as possible? Now I consider myself a very conscientious commenter of code, and so as a matter of interest I did a quick search on my current project to see whether I was following Brad’s advice. Well I was – about 90 % of the time. I found that my style depended a bit on the units. For example, I always appended the % sign without a space, whereas mV, mA etc just about always had a space between the value and the units. You’ll be pleased to know Brad that I’ll be mending my ways!

Anyway, I’ll leave this topic for now. Next time I visit it I’ll tell you how I spell check my comments. Hopefully having read this post you’ll know why I do it.
Home

Commuting is crazy!

Friday, April 3rd, 2009 Nigel Jones

A few posts back I suggested that (American) employers would benefit from giving their engineers a lot more time off. In the comments section, Brad opined that he would very much like to work four 10-hour days. One of the reasons he gave was to avoid the stress and hassle of his daily commute. I agree completely with him. However, I’d like to take this one step further. Why is that (most) employers insist that their staff come to the office each day to work? This always strikes me as ludicrous. Of course there are days where one has to attend meetings, or where you need to use the specialized test equipment that your employer owns. In addition there are many of us who work for employers where secrecy demands that you be at work. However, for the vast majority of engineers there is absolutely no need to be in the office every day. Instead a decent home computer, a broad band connection and a VPN and you are pretty much all set to do exactly what you’d do if you went into the office for the day.

Now notwithstanding that allowing / encouraging / demanding that staff work from home whenever possible has great benefits to the the engineer and the environment, the real key is the boost in productivity that is possible. Any engineer I know will tell you that the best way to get a lot of (hard) work done in a hurry is to shut the door, turn off the telephone and block your email. Maybe it’s just me, but that’s exactly what can happen when you work from home.

But what about the staff that will go home and slough off for the day? Well I’m sure they exist. I’m also sure that anyone that managed to get through an engineering degree program has enough brains to work out how to goof off at work without being caught if that’s their inclination. In short I don’t see being at work as evidence that you’re actually doing anything useful.

What’s maddening about this is when you consider the list of jobs that don’t require you to come to the office each day. Examples that spring to mind include sales, truck drivers and home-care health workers. Apparently their employers somehow manage to come up with ways of determining whether they are productive or not.

So what to make of this? I think it’s largely inertia. Twenty years ago, the cost of engineering tools was so high that you had to go to work to use them. Today you can set up a well equipped laboratory for $10K. Despite this, the notion of engineers having to go to work persists. If I’m correct, and there aren’t any substantive reasons for most of us to go to the office every day, then ultimately logic should overcome the inertia – and working from home several days a week will become the norm. However it won’t start changing until more of us start pressuring management to explain why we shouldn’t do this.
Home