Back to Embedded Systems Hardware Engineering Series

Capstone 6: AI-Assisted Debugging Tool

April 17, 2026 Wasil Zafar 38 min read

Build an intelligent debug probe that captures digital signals, classifies anomalies with on-device ML, and provides real-time root cause suggestions for protocol and timing violations.

Table of Contents

  1. System Concept
  2. Signal Capture Engine
  3. ML Anomaly Pipeline
  4. Protocol Decode
  5. Debug Session Logger
  6. Conclusion

System Concept

ParameterSpecificationComponent
Digital Channels16 channels, 100 MHz samplingFPGA front-end
FPGALattice iCE40 UP5KSignal capture + trigger
MCUSTM32H7 @ 480 MHzML inference + USB host
Buffer64 MB SDRAM1M samples/channel
ProtocolsSPI, I2C, UART, SWDAuto-detect & decode
InterfaceUSB 2.0 HS + WiFiHost app + web UI
ML Model1D-CNN anomaly classifierTFLite Micro (INT8)
Anomaly TypesGlitch, runt, setup/hold, bus contention8 classes
AI Debug Probe Architecture
flowchart LR
    A["Target DUT
16 Channels"] --> B["FPGA
iCE40 UP5K
Capture + Trigger"] B -->|SPI 50MHz| C["STM32H7
ML Inference"] B --> D["SDRAM
64MB Buffer"] C --> E["USB 2.0 HS
Host App"] C --> F["ESP32
Web Dashboard"] C --> G["Anomaly
Classification"] G --> H["Root Cause
Suggestions"] style B fill:#16476A,color:#fff style C fill:#3B9797,color:#fff

Signal Capture Engine

/* FPGA signal capture — trigger and buffer management
   Communicates with STM32H7 via SPI at 50 MHz */

#include <stdint.h>

/* Trigger configuration */
typedef enum {
    TRIG_RISING_EDGE,
    TRIG_FALLING_EDGE,
    TRIG_PATTERN_MATCH,
    TRIG_PROTOCOL_ERROR,  /* Auto-detect protocol violation */
    TRIG_ML_ANOMALY,      /* ML model flags anomaly */
} trigger_mode_t;

typedef struct {
    trigger_mode_t mode;
    uint16_t  channel_mask;   /* Which channels to monitor */
    uint16_t  pattern;        /* For pattern match mode */
    uint16_t  pattern_mask;   /* Don't-care bits */
    uint32_t  pre_trigger;    /* Samples before trigger (% of buffer) */
    uint32_t  post_trigger;   /* Samples after trigger */
    uint32_t  sample_rate_hz; /* 1 MHz to 100 MHz */
} capture_config_t;

/* Capture buffer layout in SDRAM (64 MB)
 * 16 channels × 1M samples × 2 bytes = 32 MB per capture
 * Double-buffered: capture while transferring previous
 */
#define SAMPLES_PER_CHANNEL  (1024 * 1024)
#define NUM_CHANNELS         16
#define BUFFER_SIZE          (SAMPLES_PER_CHANNEL * NUM_CHANNELS * 2)

/* Anomaly types detected by the ML model */
typedef enum {
    ANOMALY_NONE,
    ANOMALY_GLITCH,         /* Sub-threshold pulse */
    ANOMALY_RUNT,           /* Incomplete logic transition */
    ANOMALY_SETUP_VIOLATION,/* Setup time too short */
    ANOMALY_HOLD_VIOLATION, /* Hold time too short */
    ANOMALY_BUS_CONTENTION, /* Multiple drivers */
    ANOMALY_CLOCK_JITTER,   /* Excessive clock variation */
    ANOMALY_CROSSTALK,      /* Adjacent channel coupling */
    ANOMALY_METASTABILITY,  /* Indeterminate logic level */
} anomaly_type_t;

typedef struct {
    anomaly_type_t type;
    uint8_t   channel;       /* Channel index (0-15) */
    uint32_t  sample_index;  /* Position in capture buffer */
    float     confidence;    /* ML confidence score (0.0-1.0) */
    char      suggestion[128]; /* Root cause suggestion */
} anomaly_report_t;

ML Anomaly Detection Pipeline

# Signal anomaly classification — training data generation
# Creates labeled windows from digital signal captures

import numpy as np

# Generate synthetic training data for 8 anomaly classes
np.random.seed(42)

def generate_normal_signal(length=256, freq_mhz=10.0, sample_rate_mhz=100.0):
    """Generate clean digital signal (square wave)."""
    t = np.arange(length) / sample_rate_mhz
    period = 1.0 / freq_mhz
    signal = (t % period < period / 2).astype(np.float32)
    return signal

def inject_glitch(signal, position, width=2):
    """Inject a narrow glitch pulse."""
    s = signal.copy()
    s[position:position + width] = 1.0 - s[position]
    return s

def inject_runt(signal, position, amplitude=0.4):
    """Inject a runt pulse (doesn't reach full logic level)."""
    s = signal.copy()
    s[position:position + 3] = amplitude
    return s

# Generate dataset: 1000 samples per class
n_per_class = 1000
window_size = 256
classes = ["Normal", "Glitch", "Runt", "Setup", "Hold",
           "Contention", "Jitter", "Crosstalk"]

total_samples = n_per_class * len(classes)
print("ML Training Data Generation")
print("=" * 50)
print(f"Window size:     {window_size} samples")
print(f"Sample rate:     100 MHz")
print(f"Classes:         {len(classes)}")
print(f"Samples/class:   {n_per_class}")
print(f"Total dataset:   {total_samples}")
print(f"Model input:     ({window_size},) INT8 quantized")
print(f"Model output:    {len(classes)} classes (softmax)")
print(f"\nEstimated model size: ~45 KB (INT8)")
print(f"Inference latency:   ~2 ms on Cortex-M7")
print(f"\nClass distribution:")
for i, name in enumerate(classes):
    print(f"  {i}: {name:<15} — {n_per_class} samples")

Protocol Auto-Decode

/* Protocol auto-detection and decode engine
   Analyzes captured signals to identify SPI, I2C, UART, SWD */

#include <stdint.h>

typedef enum {
    PROTO_UNKNOWN,
    PROTO_SPI,
    PROTO_I2C,
    PROTO_UART,
    PROTO_SWD,
} detected_protocol_t;

typedef struct {
    detected_protocol_t protocol;
    float               confidence;  /* Detection confidence */
    uint32_t            baud_rate;   /* Detected baud / clock rate */
    uint8_t             data_bits;   /* For UART: 7/8/9 */
    uint8_t             parity;      /* 0=none, 1=even, 2=odd */
    uint8_t             spi_mode;    /* SPI CPOL/CPHA (0-3) */
    uint8_t             i2c_addr;    /* Detected I2C address */
} protocol_info_t;

/* Detection heuristics (simplified):
 *
 * SPI:  Look for clock line with regular frequency,
 *       chip select (active low) framing transfers
 *
 * I2C:  Two-wire (SDA + SCL), open-drain behavior,
 *       START/STOP conditions, ACK/NACK patterns
 *
 * UART: Single line, idle-high, start bit (low),
 *       measure bit period for baud rate detection
 *
 * SWD:  SWDIO + SWCLK, detect turnaround sequences
 *       and parity bits in read/write frames
 */

/* Timing measurements for protocol detection */
typedef struct {
    uint32_t min_pulse_ns;    /* Shortest pulse width */
    uint32_t max_pulse_ns;    /* Longest pulse width */
    uint32_t avg_period_ns;   /* Average signal period */
    uint32_t edge_count;      /* Total transitions */
    float    duty_cycle;      /* Average duty cycle */
    uint8_t  idle_state;      /* Dominant idle level */
} signal_stats_t;

Debug Session Logger

Debug Session Logger

Log anomalies and findings from your debug session. Download as Word, Excel, or PDF.

Draft auto-saved

Conclusion

The AI debugging tool combines FPGA-based signal capture at 100 MHz with on-device ML anomaly detection, auto protocol decode, and root cause suggestions. This capstone integrates hardware design (FPGA + MCU co-processing), embedded ML, and practical debugging experience into a single project.

Next Capstone

In Capstone 7: Wearable Health Monitor, we’ll design a medical-grade wearable that tracks heart rate, SpO2, and ECG with BLE streaming and low-power optimization.