Embedded Systems Debugging – Can Good Code Practice in Embedded C++ Eliminate the Need for a Debugger?

cdebuggingembedded-systemsfirmwareobject-oriented

I am a C developer for an embedded system. YouTube has recently started recommending "C++ for embedded systems" talks. Having watched some of them, they pique my interest, but none of them answer the question they leave me with.

These talks (especially Modern C++ in Embedded Systems by Michael Caisse) advocate for a development process whereby, instead of:

  1. writing and edit code
  2. debugging it to confirm it works (or, more likely, debugging it to see what's wrong and where to go from here)
  3. repeat until working

…one should avoid the debugger completely, trusting that the choice of language and good practice makes bugs less likely, which then eliminates the need for the debugger.

But as someone who writes firmware for a microcontroller that controls analogue circuitry, many of my problems are found when hardware shows unexpected behaviour and I find I can only investigate this behaviour (especially the timing of events) by throwing breakpoints all over my code and waiting to see events happen out of order, or not happen at all.

This will then either reveal a mis-configured register, or unexpected behaviour by one of the microcontroller's peripherals, which was not obvious from the device manual and necessitates a small code re-design. These talks have my attention, but I cannot see how these techniques that are supposed to help people like me, actually help me with hardware issues.

Can abstractions and good code practice (which I'm all for) eliminate the need for the debugger (something I see as necessary for addressing hardware bugs)?

Best Answer

I think you are misrepresenting the message of the "Modern C++ in Embedded Systems" video. The point is that there are people in the embedded world that write code and then test it by running the code in the debugger to verify that it does what they think it does. He argues that a better alternative is to use abstractions so that the compiler can verify that certain assumptions about the code hold.

This method still allows to use the debugger to find bugs, especially hardware problems. You should just not use the debugger to understand code, it should be understandable and correct by writing it that way.

The advantage of using higher abstractions to validate assumptions is that there are certain types of bugs, e.g. having a function f(int mode, int value) which is called as f(value, mode), that can be completely avoided. Michael Caisse argues that using the right tools, e.g. strong types in C++, alleviates this and should therefore be used.

Related Topic