<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Debugging &amp; Observability on Embedded Systems Development</title><link>https://applied-ee.github.io/embedded/docs/development/debugging-and-observability/</link><description>Recent content in Debugging &amp; Observability on Embedded Systems Development</description><generator>Hugo</generator><language>en-us</language><atom:link href="https://applied-ee.github.io/embedded/docs/development/debugging-and-observability/index.xml" rel="self" type="application/rss+xml"/><item><title>SWD, JTAG &amp; Debug Probes</title><link>https://applied-ee.github.io/embedded/docs/development/debugging-and-observability/swd-jtag-and-debug-probes/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://applied-ee.github.io/embedded/docs/development/debugging-and-observability/swd-jtag-and-debug-probes/</guid><description>&lt;h1 id="swd-jtag--debug-probes"&gt;SWD, JTAG &amp;amp; Debug Probes&lt;a class="anchor" href="#swd-jtag--debug-probes"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Debug access to a microcontroller requires a physical interface between the host toolchain and the target silicon. The two dominant protocols — SWD and JTAG — differ in pin count, capability, and ecosystem support. Choosing the right debug probe and wiring it correctly determines whether breakpoints, flash programming, and register inspection work reliably or not at all.&lt;/p&gt;
&lt;h2 id="swd--serial-wire-debug"&gt;SWD — Serial Wire Debug&lt;a class="anchor" href="#swd--serial-wire-debug"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;SWD is an ARM-specific two-wire protocol using SWDIO (bidirectional data) and SWCLK (clock). It provides full debug access — breakpoints, watchpoints, flash programming, and register read/write — over just two signal lines plus ground. SWD clock speeds typically run at 1-4 MHz for reliable operation, though many probes support up to 10 MHz on short traces. The protocol also carries SWO (Serial Wire Output) on an optional third pin, enabling trace output without additional UART hardware.&lt;/p&gt;</description></item><item><title>Serial Debug Output — UART, SWO &amp; RTT</title><link>https://applied-ee.github.io/embedded/docs/development/debugging-and-observability/serial-debug-output/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://applied-ee.github.io/embedded/docs/development/debugging-and-observability/serial-debug-output/</guid><description>&lt;h1 id="serial-debug-output--uart-swo--rtt"&gt;Serial Debug Output — UART, SWO &amp;amp; RTT&lt;a class="anchor" href="#serial-debug-output--uart-swo--rtt"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Getting runtime information out of a microcontroller is fundamental to firmware development. Three approaches dominate: UART-based printf, ARM&amp;rsquo;s SWO trace output, and SEGGER&amp;rsquo;s RTT memory-based transfer. Each trades off pin usage, throughput, timing distortion, and toolchain dependency differently. Understanding these tradeoffs determines whether debug output is helpful or actively misleading.&lt;/p&gt;
&lt;h2 id="uart-debug-output"&gt;UART Debug Output&lt;a class="anchor" href="#uart-debug-output"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The most common debug channel uses a UART peripheral retargeted to &lt;code&gt;printf()&lt;/code&gt; via a syscall stub (e.g., &lt;code&gt;_write()&lt;/code&gt; on GCC/Newlib or &lt;code&gt;fputc()&lt;/code&gt; on Keil). Typical baud rates range from 115200 to 921600. At 115200 baud, a 64-byte message takes roughly 5.5 ms to transmit — long enough to distort millisecond-scale timing. A USB-to-serial adapter (CP2102, CH340, FTDI FT232) bridges the UART to the host. DMA-backed UART transmission reduces CPU blocking: the firmware queues a buffer and returns immediately, but the output still occupies the wire at baud-rate speed. UART debug requires two dedicated pins (TX/RX) and is available on virtually every MCU.&lt;/p&gt;</description></item><item><title>Logic Analyzers &amp; Oscilloscopes at the Bench</title><link>https://applied-ee.github.io/embedded/docs/development/debugging-and-observability/logic-analyzers-and-oscilloscopes/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://applied-ee.github.io/embedded/docs/development/debugging-and-observability/logic-analyzers-and-oscilloscopes/</guid><description>&lt;h1 id="logic-analyzers--oscilloscopes-at-the-bench"&gt;Logic Analyzers &amp;amp; Oscilloscopes at the Bench&lt;a class="anchor" href="#logic-analyzers--oscilloscopes-at-the-bench"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Software debugging reveals what firmware thinks is happening. Logic analyzers and oscilloscopes reveal what is actually happening on the wire. Protocol mismatches, signal integrity failures, and power delivery problems are invisible to software tools but immediately apparent with the right instrument and trigger configuration.&lt;/p&gt;
&lt;h2 id="logic-analyzers-for-protocol-decoding"&gt;Logic Analyzers for Protocol Decoding&lt;a class="anchor" href="#logic-analyzers-for-protocol-decoding"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A logic analyzer captures digital signals and decodes them into human-readable protocol transactions. The Saleae Logic Pro 8 (8 channels, 500 MS/s digital, $480) and Logic 8 (8 channels, 100 MS/s, $200) are the most common bench tools for embedded work. Budget alternatives using Cypress FX2-based clones ($10-15) work with the open-source sigrok/PulseView software at sample rates up to 24 MHz. For SPI decoding, sample at least 4x the clock rate — a 10 MHz SPI bus needs 40 MS/s or higher. I2C, running at 100-400 kHz, is comfortably captured at 1-2 MS/s. Protocol decoders overlay the raw waveform with decoded bytes, addresses, and ACK/NACK status, making it straightforward to confirm whether the MCU is sending what the firmware intends.&lt;/p&gt;</description></item><item><title>Hard Faults &amp; Crash Analysis</title><link>https://applied-ee.github.io/embedded/docs/development/debugging-and-observability/hard-faults-and-crash-analysis/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://applied-ee.github.io/embedded/docs/development/debugging-and-observability/hard-faults-and-crash-analysis/</guid><description>&lt;h1 id="hard-faults--crash-analysis"&gt;Hard Faults &amp;amp; Crash Analysis&lt;a class="anchor" href="#hard-faults--crash-analysis"&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;When an ARM Cortex-M processor encounters an unrecoverable error, it triggers a fault exception. Without a proper fault handler, the default behavior is an infinite loop — the system appears frozen with no indication of what went wrong. Implementing fault capture and understanding the fault registers transforms a mysterious hang into a diagnosable event with a precise faulting instruction and root cause.&lt;/p&gt;
&lt;h2 id="cortex-m-fault-types"&gt;Cortex-M Fault Types&lt;a class="anchor" href="#cortex-m-fault-types"&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Cortex-M fault architecture defines four exception types. &lt;strong&gt;HardFault&lt;/strong&gt; (exception 3) is the catch-all — any fault that cannot be handled by a more specific handler escalates here. &lt;strong&gt;BusFault&lt;/strong&gt; fires on invalid memory accesses: reads from unmapped addresses, writes to read-only regions, or peripheral access with clocks disabled. &lt;strong&gt;UsageFault&lt;/strong&gt; catches illegal instructions, unaligned access (when not permitted), and divide-by-zero (if enabled via CCR.DIV_0_TRP). &lt;strong&gt;MemManage&lt;/strong&gt; triggers on MPU violations — access to regions forbidden by the Memory Protection Unit configuration. On Cortex-M0/M0+, only HardFault exists; the other three require Cortex-M3 or higher and must be explicitly enabled via the SHCSR register.&lt;/p&gt;</description></item></channel></rss>