In embedded systems the term firmware is very common and describes the software that runs close to the hardware usually with limited resources and almost always in a deterministic execution time frame. Don’t be fooled however; Firmware can be many thousands of code lines and be a complete application.
And how you debug such a piece of software? It is often stated that debugging is an art. Imagine a motor control system where you need to step code (ie. stop executing the program) while the motor is running. It would be really hard to trace a problem in this case. So experts in the field use multiple approaches often not found in usual software development projects to trace intermittent errors or problems that relate with the unpredictable environment under real-time.
Software/firmware quality is something which cannot be easily assessed by non-experts. There are a few guidelines though, which give an indication of the written code quality.
How many bugs are revealed during testing?
How difficult are these faults to be pinpointed?
How easy is to change operation or add features?
How fast can you port to other architectures?
The first rule of debugging in embedded systems is to avoid creating the bugs in the first place. A good architectural design and coding practice are required to achieve a low bug count and reduce debug time. On a medium scale of an embedded project expect a significant amount of time before you see any actual line of code. This time goes for architectural decisions and tests that will pay-off later with faster coding and a quality product.
From almost 18 years of embedded firmware experience we have mastered these techniques. Using Test Driven Development methods, layered architectures, timing evaluations, best coding practices and system testing we achieve our goals on time. Furthermore we leave support for debugging in cases these are needed during later phases of the product’s lifecycle.
We use C and Assembly, creating code that can be ported to different microcontroller architectures fast and support development or product with Python and GUI scripting. Our debug strategies include combination of debuggers, oscilloscopes and logic analyzers to effectively pin-point difficult to resolve issues if ever arise.