3 Gordon Drive, P.O.Box 1347 Rockland, Maine 04841 U.S.A.
Find Tools for Your Chip


 

© 2004 Avocet Systems, Inc.
Call Us Today at 207-596-7766 ("Picton Press")
Avocet Systems, Inc. : The Complete Solution for Embedded Systems Development Tools
Embedded Update
Debugging Embedded Software

Since most of us write error-free code, debugging is hardly an issue. We carefully plan our design, include range checks on arguments, have associates read the code before trying it out, and do everything possible to insure that it runs correctly immediately.

Not.

The emulator/debugger industry thrives because of the fact the programmers make mistakes - LOTs of mistakes. Errors are expected and tolerated.

It would be awful to be a civil engineer. Can you imagine telling your boss that the bridge you just erected has a few bugs, "but don't worry - we'll release version 1.1 in a few months!"

Write your code assuming it will be riddled with bugs. Do all of the good things we know we should do.... yet that are too often ignored.

Crazy, complex, convoluted code is simply unacceptable. It's always either impossible to debug, or too costly to debug. By assuming it will be full of bugs, then you clearly should either document it to death or avoid the complex code altogether.

One old adage is "program for clarity first, optimize second". Nah. Never remove clarity. You might be a genius; assume your successor will be an idiot.

If, when reading your code, you ever see something that makes you scratch your head and wonder how it does something: instantly rewrite or recomment it!

Constrain time-sensitive code to small routines. Spawn tasks off that can process non-critical activities in the background. Clearly identify the timing limitations expected in each interrupt service routine.

Use decent tools. Your time is expensive.

Never, ever, not in a thousand years, write an I/O instruction in the body of the code. Yes, by their nature embedded systems interact constantly with the outside world. Restrict I/O to subroutines ("get_uart_data"). When performance is an issue, and you can't stand the overhead of the CALLs, RETURNs, and inherent argument stacking, then put the I/O in a C macro. Someday the I/O WILL change.

If you are using decent tools, remove them and burn a ROM once in a while. It's a quick way to insure there's not a lurking uninitialized variable, or weird hardware problem, that will keep the system from running standalone.

Use a reasonable debugging strategy. Don't start changing things for no reason. Never proceed without truly understanding the problem. This is the curse of all projects: a very smart person gets just a glimpse at a problem and immediately jumps to a conclusion before even finding out what all of the symptoms are.

Never make assumptions. It's easy to toss out one symptom because "it's clearly related to the other problem." Are you sure? Can you prove it? Symptoms are all you have to go on when debugging; be reluctant to discard them because they don't fit your model of possible causes.

Finally, use the scientific method: