Skip to content
Home » Embedded Systems » Debugging Embedded Systems: Tools and Techniques

Debugging Embedded Systems: Tools and Techniques

Debugging Embedded Systems featured image with dark purple background, DEV TOOLS badge, DBG icon in purple circle, and Tools and Techniques Guide subtitle by nerdyelectronics.com
Embedded Systems Learning Path
Part 96 of 129View Full Path →

KEY TAKEAWAYS

  • JTAG and SWD interfaces enable hardware-level debugging with breakpoints and memory inspection
  • Printf-style debugging over UART is simple but can affect timing in real-time systems
  • Logic analyzers and oscilloscopes are essential for debugging communication protocols and timing issues
  • Systematic debugging (reproduce, isolate, identify, fix, verify) is more effective than random probing

Why Debugging Embedded Systems is Different

Debugging embedded systems is more challenging than debugging regular software. The code runs on a microcontroller, not on your computer. You cannot just add a breakpoint and inspect variables in a desktop debugger. The hardware and software are tightly coupled, and problems can be caused by code, wiring, timing, or a combination of all three.The key challenges include:
  • Limited output: no screen or keyboard on the target device
  • Real-time constraints: pausing the processor can change behavior
  • Hardware interaction: bugs may be electrical, not just logical
  • Limited resources: small memory means limited logging capability

Debugging Techniques

1. Serial Print Debugging (printf)

The simplest and most common technique. Send debug messages over UART to a serial monitor on your computer.
#include <stdio.h>
#include "uart.h"

void read_sensor(void) {
    int raw = adc_read(CHANNEL_0);
    printf("[DEBUG] ADC raw value: %drn", raw);

    float voltage = raw * 3.3f / 4096.0f;
    printf("[DEBUG] Voltage: %.3f Vrn", voltage);

    if (voltage > 2.5f) {
        printf("[WARN] Voltage exceeds threshold!rn");
    }
}
Pros: Easy to implement, works on any MCU with UART, no special tools needed. Cons: Slows down execution, consumes UART peripheral, can mask timing-sensitive bugs, limited by UART speed.Tip: Use compile-time flags to strip debug prints from release builds:
#ifdef DEBUG
    #define DBG_PRINT(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
    #define DBG_PRINT(fmt, ...)
#endif

2. LED Debugging (Toggle and Blink)

When UART is not available, LEDs are your best friend. Toggle an LED at specific points in your code to verify execution flow.
// Did we reach the main loop?
LED_ON(LED_GREEN);

while (1) {
    // Is the loop running?
    LED_TOGGLE(LED_BLUE);

    if (sensor_read() < 0) {
        // Did an error occur?
        LED_ON(LED_RED);
    }

    delay_ms(100);
}
Blink patterns can encode different states:
  • Steady on = running normally
  • Fast blink = processing data
  • Slow blink = waiting/idle
  • SOS pattern = error condition

3. Hardware Debugger (JTAG/SWD)

A hardware debugger connects to the microcontroller’s debug interface (JTAG or SWD for ARM) and allows you to:
  • Set breakpoints and step through code line by line
  • Inspect and modify variables and registers in real time
  • View the call stack
  • Read and write memory
  • Flash firmware onto the target
Common hardware debuggers:
DebuggerInterfaceMCU Support
ST-LinkSWDSTM32
J-Link (Segger)JTAG/SWDARM, RISC-V, and more
CMSIS-DAPSWDARM Cortex-M
PICkitICSPPIC microcontrollers
AVR ISP / AVRICEISP/JTAGAVR/ATmega
Software tools for debugging:
  • GDB (GNU Debugger) – command-line debugger, works with most toolchains
  • OpenOCD – connects GDB to hardware debuggers
  • IDE debuggers – STM32CubeIDE, Keil, IAR, PlatformIO all have integrated debugging

4. Logic Analyzer

A logic analyzer captures digital signals over time and displays them visually. It is invaluable for debugging communication protocols.Use a logic analyzer to:
  • Verify UART baud rate and data frames
  • Check SPI clock polarity, phase, and data
  • Decode I2C addresses and data
  • Measure signal timing and frequency
  • Debug GPIO toggling and interrupt timing
Affordable options like the Saleae Logic or open-source alternatives work well for most embedded debugging.

5. Oscilloscope

An oscilloscope shows analog waveforms. While a logic analyzer shows only high/low digital states, an oscilloscope shows the actual voltage over time. Use it for:
  • Checking power supply stability and noise
  • Measuring rise/fall times of signals
  • Debugging analog sensor outputs
  • Identifying electrical noise and crosstalk
  • Verifying PWM duty cycle and frequency

6. Multimeter

A basic multimeter helps verify:
  • Power supply voltages at different points
  • Continuity (is this wire connected?)
  • Resistance of pull-ups, sensors, etc.
  • Current draw of the circuit

Common Debugging Strategies

Divide and Conquer

When something does not work, isolate the problem. Test each component independently:
  1. Is the power supply correct? (Multimeter)
  2. Is the MCU running? (LED blink test)
  3. Is the communication working? (Logic analyzer or serial print)
  4. Is the peripheral responding? (Check with known-good code)

Rubber Duck Debugging

Explain your code line by line, out loud. The act of explaining often reveals the bug. It sounds silly, but it works remarkably well.

Check the Obvious First

Before diving into complex debugging:
  • Is the board powered?
  • Is the correct firmware flashed?
  • Are all wires connected properly?
  • Is the baud rate correct?
  • Is the correct COM port / serial device selected?

Debugging Checklist for Embedded Systems

  1. Power: Verify correct voltage on VCC and GND pins
  2. Clock: Confirm the MCU is running at the expected frequency
  3. Reset: Check that the reset pin is not held low
  4. Connections: Verify wiring matches the schematic
  5. Firmware: Confirm the latest code is actually flashed
  6. Peripherals: Test each peripheral independently
  7. Timing: Check for race conditions and timing issues
  8. Memory: Check for stack overflow or memory corruption

Summary

Debugging embedded systems requires a mix of software and hardware tools. Start with the simplest technique (serial prints, LED toggles) and escalate to hardware debuggers, logic analyzers, and oscilloscopes as needed. The most effective approach is systematic: isolate the problem, verify assumptions, and test one thing at a time. With practice, debugging becomes faster and more intuitive.

📖 Related: Debugging Communication Protocols: UART, SPI, and I2C TroubleshootingPower Supply and Voltage Regulators for Embedded Systems

Leave a Reply

Your email address will not be published. Required fields are marked *