Skip to content

Debugging

You may be used to debugging code by using the inspection features built into an IDE. That would be my recommended first step, but there are other debugging strategies that you can employ that date back to the days before interactive debuggers. You can use those same strategies when it comes to debugging hardware or hardware/software combinations.

Isolate and test

A piece of software is typically separated into a series of functions which can each be tested individually. If your software is not working, a good strategy is to test each function in isolation. When you have tested one function without finding the error, you know that it must be elsewhere. You can therefore concentrate on the other functions, and you do not need to revisit the first one because you know that it works.

Applying the same approach to hardware means thinking about how to check individual elements or circuits. In a simple example such as blinking an external LED, there is only one circuit (from the digital IO pin, through the LED and resistor and back to GND. More complex examples might have several circuits for different components.

Even in the simple LED case, however, there are several parts that can be checked individually. The first thing to check is whether the LED is working. You can do that by connecting the long leg directly to the power supply pin on your microprocessor and the short leg directly to GND (via the resistor to prevent it burning out). This removes the code from the picture and is equivalent to connecting the LED directly to a battery. If it does not light up in that situation, check that you have it the right way round. If it still does not light up, try a different LED. If the second one works, the first is damaged and should be thrown away. Other parts of the circuit to check are the connections between the components on the breadboard. It is very easy to put one end of connector wire into the row next to the one it should actually be in.

The steps outlined above illustrate the main general point: testing an element of your circuit is easier if it is relatively simple. If you are debugging, this might mean that you have to temporarily simplify your layout in order to carry out a specific test. If you consider testability from the outset though, it can lead to better designs. This is the application of another strategy from software design known as divide-and-conquer.

Inspect the state of the system

The term inspection refers to the examination of variable values as the code is in operation. Interactive debuggers allow you to set breakpoints to stop the code and give you time to go through the variables of interest. You can achieve a similar outcome in the absence of an interactive debugger by outputting variable values at strategic points. Most microprocessor platforms give you the ability to output text-based messages on their serial interface (the statement may be called write or print), and the ability to monitor the traffic over the serial connection. The serial monitor may be implemented differently in different platforms. If you are using Arduino, for example, it is built into the IDE. On the other hand, if you are using a Particle device you can access the serial monitor using the command-line instruction

particle serial monitor

Find out how to create and read debug messages for your platform.

Use working examples as testing tools

It may be a big assumption to say that the majority of application code is now based on existing examples, but it does have some justification. Just consider the huge number of pre-written libraries and packages available in different coding environments. Add to that the use of applications frameworks as starting points and the ready availability of code examples on problem-solving sites such as StackOverflow and the proportion of software written from scratch is put into perspective.

You can use the same approach to the design and implementation of microprocessor-based applications. The majority of platforms provide working examples and tutorials. You can use these as a starting point for something more complex. The first step is to replicate the example to ensure that it works on your particular device. The next step is to make a series of incremental changes towards your target system.

When it comes to debugging, the simple examples can be very helpful. For example, if you want to check that your component layout is correct, you can sometimes test a hardware connection by using the blink sketch. If the component of interest responds to the blink signal on the appropriate pin, you know that the circuit is correctly constructed. Conversely, if you want to test that your code is producing a signal on a pin as expected, you could quickly attach an external LED.

One of the most useful features of microprocessors is the on-board LED. This is usually connected internally to one of the digital IO pins (e.g. D07 on a Particle Argon, D13 on an Arduino). You can see which pin to use by looking at the code of the blink example provided in your platform. If you connect an external LED to the same pin and it should go on and off at the same time as the on-board one. If the on-board LED works but the external one doesn’t, then there is a hardware problem. The same approach can be taken with external components other than LEDs. Basically, the on-board LED gives you some visual feedback to show whether the associated pin is active or not. To take advantage of that just means that you need to connect your external component to the correct pin which might be a temporary measure.

Common checks

Double-check that the pins you are using on the breadboard are the same as in the code The pin definitions in the code must correspond to the ones on the Argon; otherwise your instructions will not get through to your components. The pin definitions are an interface between the code and the hardware. As mentioned above, try using the example blink sketch first to see the on-board LED work. Next connect an external LED to D07. Then, connect the external LED to a different pin and change the code to match. It is very important to remember that if there is a pin mismatch, there are two solutions: one is to change the hardware (i.e. connect your component to the pin used in the code), and the other is to change the software (i.e. force the code to correspond to the existing hardware layout). The important thing is that the code and the hardware match. It is therefore unlikely that you will have to change both at the same time to fix a problem.

Further reading

Debugging tips 4 simple steps for debugging your Arduino project

Particle debugging How to Verify, Upload, and Debug code using the Particle IDE