Skip to main content

Command Palette

Search for a command to run...

How to debug FPGA board with live inputs?

Published
5 min read
How to debug FPGA board with live inputs?

Here’s a practical playbook for debugging an FPGA with live inputs (sensors/cameras/encoders/high-speed I/O). It balances non-intrusive capture, real-time visibility, and safety—plus copy-paste examples for Xilinx and Intel.


0) Before you touch anything (live = real hardware!)

  • Safety first: If your design can drive motors/relays, add a hard E-STOP and an “outputs-inhibit” bit you can force during debug.

  • Clock & voltage sanity: Verify input levels, terminations (50 Ω SE / 100 Ω diff), VREF/VCCO, and that your sampling clock is the right domain for the signals.

  • Repro knob: Add a way to freeze/slow the source (pause camera, halt encoder) or record & replay traffic.


1) Use an embedded logic analyzer (non-intrusive visibility)

Xilinx (Vivado): ILA + VIO (a.k.a. ChipScope)

  1. Tag nets so the tool keeps them and routes them to debug:
// Tag nets for debug
(* mark_debug = "true" *) wire        vsync, hsync, data_valid;
(* mark_debug = "true" *) wire [7:0]  rx_data;
  1. Instantiate an ILA (IP Catalog → ILA). Connect it in your RTL:
ila_0 u_ila (
  .clk       (pclk),              // sample in the same clock domain
  .probe0    (rx_data),
  .probe1    (vsync),
  .probe2    (hsync),
  .probe3    (data_valid)
);
  1. (Optional) VIO for live control (force test modes, thresholds, mux selects):
wire [1:0] dbg_sel;
vio_0 u_vio (.clk(pclk), .probe_out0(dbg_sel));
  1. In Hardware Manager, set triggers (e.g., “data_valid drops while rx_data=0xBC”), pick a depth (e.g., 8–128 k samples), run captures without halting the design.

Tips

  • Use the same clock as the signals you probe.

  • Start small (few probes, shallow depth) → scale up.

  • If nets get optimized away, add (* keep = "true" *) or set_property DONT_TOUCH true ….

Intel (Quartus): SignalTap + In-System Sources/Probes

  • Add a SignalTap file (.stp), select the clk domain, choose signals, set triggers, and compile.

  • For runtime controls, use In-System Sources/Probes IP (similar to VIO) to drive internal test muxes, resets, etc.

Synthesis keepers

  • Verilog: (* preserve *) on regs/wires, or /* synthesis keep */.

Lattice: Reveal Analyzer

  • Same idea: instantiate Reveal, choose probes/clock, set triggers, capture.

2) Design-for-debug patterns (so live debug is easy)

  • Debug MUX on inputs: switch between live and known test patterns with a register/VIO.
wire [7:0] prbs_out;
wire [7:0] in_mux = (dbg_sel==2'b00) ? live_rx
                : (dbg_sel==2'b01) ? prbs_out
                :                    8'h55; // fixed
  • Record & Replay: Tap the raw input → FIFO → DDR, then play it back via a traffic generator. Lets you repeat rare glitches.

  • Sticky flags & counters: Latch “bad things” once (CRC error, underflow, CDC violation) and expose them via a CSR/AXI-Lite block.

  • Timestamps: Free-running counter sampled on events; makes cross-domain correlation possible.

  • Heartbeat LEDs/UART prints: A 1 Hz LED per clock domain, and a minimal UART-TX for hexdumps (when you can’t hook a scope).


3) CDC & timing when inputs are live

  • Synchronize async inputs: at least 2-FF synchronizers for single-bit strobes; use async FIFOs or handshake for buses.

  • Prove timing: Constrain input delays (set_input_delay/set_output_delay) and check timing to the pin—don’t rely on “it seems fine.”

  • Catch metastability symptoms: Duplicate comparators in parallel and XOR the results; if they differ, you’re on the edge → slow edges/add sync.


4) External instruments (when you must)

  • MSO/logic analyzer: Clip on buffered test pads (don’t load the net).

  • Pattern generator: Feed a golden pattern to the FPGA while keeping the environment running (splitter/fixture).

  • Differential probes/terminations: Respect 100 Ω for LVDS; avoid long stubs.


5) Triggers that actually catch the bug

  • Protocol-aware conditions: e.g., “VSYNC while active line,” “gap > N cycles,” “CRC bad then good.”

  • Pre-trigger depth: Large pre-trigger helps you see why it broke, not just the crash.

  • Multi-stage triggers: Trigger A arms B; use it for “rare after common” sequences.


6) Minimal, reusable examples

A) Xilinx: mark, probe, trigger (camera-like stream)

RTL

(* mark_debug = "true" *) wire        dv, hs, vs;
(* mark_debug = "true" *) wire [7:0]  d;

ila_0 u_ila (.clk(pclk), .probe0(d), .probe1(dv), .probe2(hs), .probe3(vs));

// Optional: swap live input for test pattern during debug
wire [7:0] prbs;
prbs8 u_prbs(.clk(pclk), .en(test_en), .dout(prbs));
wire [7:0] d_in = test_en ? prbs : live_d;

Constraints (keep nets if needed)

set_property MARK_DEBUG true [get_nets -hier {d[*] dv hs vs}]

Trigger idea: dv falling edge AND d == 8'hBC within 3 cycles after hs—set in Hardware Manager.

B) Intel: quick SignalTap preserve

Attributes

(* preserve *) reg [7:0]  d_q;
(* preserve *) reg        dv_q;
always @(posedge pclk) begin
  d_q  <= live_d;
  dv_q <= live_dv;
end

Select d_q, dv_q in SignalTap, set clock = pclk, compile, capture.

C) One-wire UART-TX for quick prints (any FPGA)

module uart_tx #(parameter CLK=100_000_000, BAUD=115200) (
  input  wire clk, input wire strobe, input wire [7:0] data, output reg tx=1
);
  localparam DIV = CLK/BAUD;
  reg [15:0] cnt=0; reg [3:0] bitn=0; reg [9:0] sh=10'h3FF; // idle=1
  always @(posedge clk) begin
    if (strobe && bitn==0) begin sh <= {1'b1, data, 1'b0}; bitn <= 10; cnt <= DIV-1; end
    else if (bitn!=0) begin
      if (cnt==0) begin tx <= sh[0]; sh <= {1'b1, sh[9:1]}; bitn <= bitn-1; cnt <= DIV-1; end
      else cnt <= cnt-1;
    end else tx <= 1;
  end
endmodule

Hook tx to a header and view in a serial terminal for quick hex/status traces.


7) “It only fails at speed” tactics

  • Capture in the native domain (run ILA/SignalTap at the real input clock).

  • Relax probe fanout: Re-register tapped nets before probing to meet timing.

  • Reduce debug load: Fewer probes/depth → easier timing closure.

  • If still marginal, floorplan the ILA beside the logic (same SLR/column).


8) Quick checklist (print me)

  • Inputs have correct voltage/termination, clock domain identified.

  • Add debug MUX (live/test), sticky flags, counters, timestamps.

  • Tag suspect nets (mark_debug/preserve), instantiate ILA/SignalTap.

  • Set pre/post-trigger, capture at native clock.

  • Verify I/O timing; audit CDC paths.

  • (Optional) Record → DDR → replay.

  • Keep an outputs-inhibit bit during experiments.

More from this blog

A

Ampheo Electronic Blog-Chip and component knowledge sharing

181 posts

Original and Genuine Electronic Components Distributor