Skip to content

11. Debugging and measurement

Time: 2 weeks · Board: STM32 Nucleo, logic analyzer, multimeter; an oscilloscope if you have access · Prerequisites: Module 10

Why this matters

Senior engineers are not faster typists. They find the bug in an hour that takes a junior a week, because they know the tools and they measure instead of guessing. On embedded systems the tools go beyond a debugger: a logic analyzer for digital timing, an oscilloscope for the analog truth, a multimeter for power, static analysis to catch bugs before they run, and the discipline to read a fault register instead of adding another printf.

You will be able to

  • Use GDB beyond breakpoints: watchpoints, backtraces from a crash, examining memory and registers, and scripting.
  • Read a Cortex-M HardFault: find the faulting instruction and the reason from the fault status registers.
  • Explain SWD vs JTAG and what OpenOCD, pyOCD, and probe-rs do.
  • Use a logic analyzer for timing and protocol decoding, and an oscilloscope for signal quality, noise, and power.
  • Run static analysis and host-side sanitizers on firmware code.

Learn

The debugger, properly

Instruments

Analysis before running

Do

  • Checkpoint 11.1: Fault forensics. Plant three bugs in your Nucleo project, one at a time: dereference a null pointer, execute from an invalid address (call through a garbage function pointer), and do an unaligned word access with the trap enabled. For each, write a HardFault handler that captures the stacked registers and fault status, and use GDB to identify the exact faulting instruction and line. Write the procedure down; it is your future self's checklist.
  • Checkpoint 11.2: Watchpoint hunt. Have one task corrupt another's variable through a stray pointer. Do not read the code. Find the culprit with a hardware watchpoint on the corrupted address.
  • Checkpoint 11.3: Interrupt latency, measured. Toggle a GPIO in your sensor ISR and another when the task that consumes the data runs. Capture both on the logic analyzer with the system busy. Measure ISR latency, task latency, and their jitter. Then raise the UART interrupt priority above the sensor's and measure again.
  • Checkpoint 11.4: Scope the truth. With an oscilloscope (yours, a school's, a hackerspace's): probe the 3.3 V rail while the MCU is busy and while it is asleep, with AC coupling, and look at the noise. Probe an I2C line at full speed and look at the rise time, then remove one pull-up and look again. Probe a PWM output driving an LED. Sketch each waveform and note what the logic analyzer would not have shown you.
  • Checkpoint 11.5: Analyze it. Run Cppcheck and clang-tidy on your whole project. Fix or explicitly justify every finding. Build your host-side unit tests with -fsanitize=address,undefined and run them. Add both to CI.

Check yourself

  • Your board resets and you find CFSR shows a precise bus fault. What are the first three things you look at?
  • What is the difference between a breakpoint and a watchpoint, and why are hardware watchpoints limited in number?
  • When would a logic analyzer mislead you, and a scope would not?
  • Why does probing a fast signal with a long ground lead show ringing that is not really there?
  • What class of bug can a sanitizer catch on the host that would appear as a random HardFault on the target?

Go deeper

Optional extras