← AXL-003

Circuit review & bench-test guide

AXL-003 — Fast waveform generator PMOD module (8-bit R-2R DAC)

Design-stage — board not yet fabricated

Document purpose#

This document explains the axl-003-wavegen prototype at component level and turns the design evidence into a practical manual-review and bench-test plan. It is based on the generated schematic (generate_design.py, rev 0.1-schematic, 2026-07-12), the README, and the TI OPA356 datasheet.

The board is a design-stage prototype. The schematic is generated and ERC clean per reports/erc.rpt (0 errors / 0 warnings, 2026-07-12) and the netlist has been reviewed, but PCB layout has not started and no board has been fabricated or assembled. There is no first-article bench result of any kind, and the companion dds_fast HDL core does not exist yet. Every expected value below is a design target to verify, not a measurement.

One finding of this review is carried throughout: the README describes the OPA356 as "RRIO", but the datasheet gives an input common-mode range that stops 1.5 V below the positive rail. On a 3.3 V supply the buffer input is only in specification up to about 1.8 V, while the ladder produces up to about 3.29 V. See Sections 6, 7, 9.F, and 12.

1. What the board does#

The board is a 12-pin PMOD (Type 1 GPIO, all eight signal pins used) module carrying an 8-bit voltage-mode R-2R ladder DAC (R = 1 kΩ, 2R = 2 kΩ, 1% 0603, 16 resistors) driven directly by the host FPGA on D0–D7, buffered by a TI OPA356 (200 MHz CMOS, unity follower), and brought out through a 100 Ω series resistor to a 2-pin header and a BNC in parallel. Full scale is nominally 0–3.3 V (in practice 0 to 255/256 x VOH). There is no register, latch, or serial interface on the module: the DAC code is whatever the host drives on the PMOD pins at that instant, which is what lets the future dds_fast core update the output at the 25 MHz fabric clock for DDS up to ~10 MHz. The intended lab lessons are update-rate/settling limits and R-2R accuracy versus resistor tolerance, measured against the AXL-002 scope module. It is catalog #3, level L4 (instrument) in the AruviX lab line.

Functional block diagram#

PMOD J1                     R-2R ladder                     U1 OPA356
 1..4  D0..D3 ── 2k legs ──> LAD0..LAD3 ─┐ (1k chain        +in = LAD7
 7..10 D4..D7 ── 2k legs ──> LAD4..LAD7 ─┤  LAD0→...→LAD7)  −in = out
 5/11 GND ── R16 2k (LSB terminator, LAD0→GND)              (unity buffer)
 6/12 3V3 ── C1 100n + C2 10u ── U1 supply                      │ WAVE_BUF
                                                                v
                              WAVE_OUT <── R17 100R ────────────┘
                                 ├──> J2 pin 1 (header; pin 2 GND)
                                 └──> J3 BNC center (shield GND)

2. Safety and scope boundaries#

3. Power and control sequence#

There is no power sequencing, enable, or configuration on this module:

  1. 3V3 and GND arrive on PMOD pins 6/12 and 5/11. C1 (100 nF) decouples U1 and C2 (10 µF) provides bulk charge for fast edges into capacitive loads.
  2. U1 is always on; quiescent current is 8.3 mA typ / 11 mA max. It has internal thermal shutdown at ~160 °C junction (recovers at ~140 °C).
  3. The output is valid as soon as the rail is up and D0–D7 are driven. With an unconfigured FPGA the PMOD pins float or are weakly pulled; the ladder output (and therefore WAVE_OUT) is then undefined but harmless — the ladder pulls floating inputs toward a mid-ish level through the network.
  4. Whatever byte the host drives appears at LAD7 after the ladder settles (output resistance R = 1 kΩ into node capacitance — nanoseconds), is buffered by U1, and reaches J2/J3 through R17.

4. Interfaces and pin maps#

PMOD pin123456789101112
NetD0D1D2D3GND3V3D4D5D6D7GND3V3

D0 is the LSB, D7 the MSB. Note the GND/3V3 pins split the byte: bits 0–3 are on the top row, bits 4–7 on the bottom row of the PMOD connector.

J2 pin12
NetWAVE_OUTGND
J3 (BNC)centershield
NetWAVE_OUTGND

J2 and J3 are electrically in parallel. U1 pinout in the SOIC-8 (D) package, for assembly checks: 2 = −In (WAVE_BUF), 3 = +In (LAD7), 4 = V− (GND), 6 = Out (WAVE_BUF), 7 = V+ (3V3); 1, 5, 8 = NC.

5. Component-by-component review#

Every reference designator in generate_design.py appears below. This board has no DNP parts and no jumpers; #FLG01 and #FLG02 are ERC power-flag pseudo-components on 3V3 and GND with no physical footprint, listed only for completeness. Identical-value ladder resistors are grouped, with every ref-des listed explicitly.

Ref.Part / valueFunction and why neededIf absent/openIf shorted, wrong, or misassembled
J112-pin PMOD plug (Type 1 GPIO)Host power and the eight DAC bits D0–D7No power or dataOffset insertion puts 3V3 on data pins (ladder survives; check before repowering)
R1–R82 kΩ 1% 0603 (Yageo RC0603FR-072KL), 8 pcsR-2R bit legs (2R): R1 = D0→LAD0, R2 = D1→LAD1, R3 = D2→LAD2, R4 = D3→LAD3, R5 = D4→LAD4, R6 = D5→LAD5, R7 = D6→LAD6, R8 = D7→LAD7That bit's weight vanishes: missing codes, giant DNL step at that bit's transitionsWrong value (1 k for 2 k) doubles that bit's weight — gross INL/DNL; a short makes the digital level appear directly on the ladder node
R9–R151 kΩ 1% 0603 (Yageo RC0603FR-071KL), 7 pcsR-2R chain (R): R9 = LAD0→LAD1, R10 = LAD1→LAD2, R11 = LAD2→LAD3, R12 = LAD3→LAD4, R13 = LAD4→LAD5, R14 = LAD5→LAD6, R15 = LAD6→LAD7Ladder splits: all bits below the break stop contributing (large missing chunk of the transfer curve)Wrong value (2 k for 1 k) rescales every bit weight below it; a short merges two ladder nodes and corrupts two bit weights
R162 kΩ 1% 0603 (RC0603FR-072KL)R-2R LSB terminator, LAD0→GND; makes the LSB-end Thevenin resistance equal 1 kΩ so every stage divides by exactly 2Every bit weight shifts (the binary weighting breaks); output scale and linearity wrongShort grounds LAD0: D0 leg loads to a fixed divider, LSB nearly dead
U1TI OPA356AIDR, SOIC-8 (D)200 MHz CMOS unity buffer (+in = LAD7, −in tied to out); isolates the 1 kΩ ladder output impedance from the load so cable/termination loading does not corrupt the code voltageOutput floats; J2/J3 see nothing (ladder is not connected to R17 except through U1)Rotated package swaps supply onto inputs — likely fatal to U1; +in/−in swap makes a comparator-like latch, not a buffer
R17100 Ω 1% 0603 (RC0603FR-07100RL)Series back-termination and short-circuit protection between WAVE_BUF and WAVE_OUT; isolates U1 from cable capacitance (U1 is only comfortable with small direct C loads)U1 drives the cable directly: ringing/instability into open coax, no short protectionWrong high value forms a divider with 50 Ω terminated loads far from the intended 100:50; note 100 Ω is deliberately NOT a matched 50 Ω back-termination (see Section 12)
J21x2 2.54 mm header (MPN TBD in the script)Breadboard/jumper access to WAVE_OUT and GNDNo header output (BNC still works)Pin swap puts GND where the signal is expected — harmless but confusing
J3Amphenol RF B6252HB-NPP3G-50 BNC, horizontalCoax output to a scope / AXL-002; footprint verified against stock library per READMENo coax output (header still works)Center–shield solder bridge shorts WAVE_OUT to GND through R17 (U1 survives, output stuck low ×1/3... actually stuck at 0 V at the connector)
C1100 nF 16 V X7R 0603 (Murata GRM188R71C104KA01D)U1 high-frequency decouplingSupply bounce during fast edges; visible ringing/HD degradationShort kills the rail (host or bench limit should catch it)
C210 µF 10 V X5R 0805 (Murata GRM21BR61A106KE19L)U1 bulk decoupling — charge reservoir for fast edges into capacitive/50 Ω loadsRail droop on large fast steps; worse settling at MHz update ratesShort kills the rail
#FLG01/#FLG02ERC power flags (3V3, GND)Schematic ERC bookkeeping onlyERC warningsNot applicable; no physical part

One table-cell correction for honesty: a J3 center-to-shield bridge grounds WAVE_OUT itself, so both J2 and J3 read 0 V while U1 works into 100 Ω — a current of about V_BUF/100 Ω flows in R17 (33 mA at full scale; R17's 0603 rating makes this a "find it quickly" fault, not a fire).

6. Datasheet summary and design interpretation#

Consulted: TI OPA356/OPA2356 datasheet SBOS212A (November 2001), <https://www.ti.com/lit/ds/symlink/opa356.pdf>, product page <https://www.ti.com/product/OPA356>. The PDF was fetched and read directly for this review; specs below are from the SBOS212A electrical tables (V_S = 2.7–5.5 V single supply, T_A = 25 °C unless noted). Check for a newer revision before procurement.

Manufacturer fact (SBOS212A)Board-specific interpretation
200 MHz GBW, 450 MHz unity-gain small-signal bandwidth, unity-gain stable; slew rate 300–360 V/µsVastly faster than the 25 MHz update rate needs; a full-scale 3.3 V step slews in ~10 ns, so the ladder RC and FPGA edge skew dominate settling, not U1
Supply 2.5–5.5 V operating (2.7–5.5 specified); abs max 7.5 V3.3 V PMOD rail is legal but near the low end; all AC specs are characterized at 5 V — expect somewhat less swing/drive margin at 3.3 V
Quiescent current 8.3 mA typ / 11 mA max per amplifier (14 mA max over temp)Dominates module power: ~27–36 mW from the 3.3 V rail with no load
Input common-mode range (V−) − 0.1 V to (V+) − 1.5 V ("input range includes ground"); CMRR specified for −0.1 V < V_CM < +4.0 V at V_S = 5.5 VAt 3.3 V the buffer input is only in spec from 0 to ~1.8 V. The ladder produces 0 to ~3.29 V, so codes above ~0x8B put U1's +input beyond its specified CM range. The README's "RRIO" claim contradicts the datasheet: the OPA356 is rail-to-rail OUTPUT only (TI's own related-products table points to the OPA350 for rail-to-rail input). This is the design's principal open risk — see Sections 7, 9.F, and 12
Rail-to-rail output: swing within 0.2 V typ / 0.3 V max of each rail at R_L = 150 Ω; 0.1 V typ at R_L = 1 kΩ; 0.8 V typ / 1 V max at ±100 mAInto a high-impedance scope the output reaches within tens of mV of the rails; into a 50 Ω-terminated BNC (U1 sees 150 Ω) budget 0.2–0.3 V of headroom loss at each rail
V_OS ±2 mV typ / ±9 mV max (±15 mV over temp); I_B 3 pA typ / ±50 pA maxOffset is ±0.16 LSB typ, ±0.7 LSB max (LSB = 12.9 mV); bias current into the 1 kΩ ladder impedance is sub-µV — negligible
Output current ±60 mA continuous min, ±100 mA peak; short-circuit +250/−200 mA; thermal shutdown 160 °CA terminated 50 Ω load at 1.8 V draws 12 mA — comfortable; a hard short of WAVE_BUF (before R17) is survivable but hot
Settling 30 ns to 0.1% / 120 ns to 0.01% (2 V step, G = +2 at 5 V); HD2 −81 dBc / HD3 −93 dBc at 1 MHz, 2 Vp-p, R_L = 200 ΩAt a 40 ns update period (25 MHz) U1 settles to ~8-bit accuracy within one sample; U1's own distortion is far below the 8-bit quantization floor (~−50 dB), so measured THD reflects the ladder and glitches, not the buffer
Stable driving small capacitive loads; series isolation recommended for larger C loads (typical-characteristics section)R17 (100 Ω) is that isolation for cables; do not bypass it to "improve amplitude"
Inputs diode-clamped to the rails; signals beyond ±0.5 V of a rail must be limited to 10 mAThe ladder cannot generate such a signal from a shared rail; only relevant for external abuse of J2/J3

Additional design interpretation not from the datasheet but from the topology, needed for Section 7:

7. Expected values before bench testing#

Targets assume VOH = VDD = 3.300 V exactly and ideal resistors unless noted. All are design targets, not measured results.

LSB and static levels (at the ladder node LAD7, unloaded, into U1's pA input):

CodeV(LAD7) idealNote
0x000.000 VBuffer output adds V_OS and output-stage floor
0x0112.9 mVOne LSB
0x20412.5 mV
0x40825.0 mV
0x7F1.6371 VJust below mid-scale
0x801.6500 VMid-scale (MSB only)
0x8B1.7918 VLast code with U1's +input inside its ~1.8 V CM spec
0xC02.4750 VBeyond U1 CM spec — ladder node fine, buffer unspecified
0xFF3.2871 VFull scale = 255/256 x VOH; beyond U1 CM spec

Worst-case DNL from 1% resistors (the monotonicity math):

The MSB (D7) weight is set by the divider of its 2 kΩ leg (R8) against the rest-of-ladder Thevenin resistance at LAD7, which is exactly 2 kΩ when the network is ideal: weight = 2k/(2k+2k) x VOH = VOH/2 = 128 LSB. The weight's sensitivity to each of those two resistances is ±0.5 x (fractional error), and the "rest of ladder" 2 kΩ is itself an aggregate of ±1% parts, so the MSB weight can be wrong by roughly ±1%:

Monotonicity at the MSB requires the effective weight error to stay below 1 LSB out of 128, i.e. aggregate matching better than ~0.78%, or roughly 0.2–0.4% per resistor. 1% E24 parts therefore do not guarantee an 8-bit-monotonic R-2R — a typical board (RMS-combined errors ~0.3–0.5 LSB) usually is monotonic, and finding out which you got is the point of the lab. The same math at the D6 carry (0x3F→0x40) halves everything: worst case ~±1.3 LSB, still marginal; D5 and below are safe with 1% parts.

Other expected values:

QuantityDesign target / calculatedWhat to measure
Supply current, static code~8.3–11 mA (U1 I_Q) + 0–~1.5 mA ladder (code-dependent; 0.825 mA at 0x80: 3.3 V into 2k leg + 2k Thevenin)Bench supply, standalone context
Buffer offset, code 0x00V(WAVE_OUT) − V(LAD7) = ±2 mV typ, ±9 mV max, plus output-stage low-side floor into light loadDMM both nodes, Section 9.F
Buffer tracking, codes ≤ 0x8BWAVE_OUT = LAD7 ± offset; gain error ≪ 0.1% (unity follower)Section 9.C/9.F
Buffer behavior, codes > 0x8BUnspecified (CM range exceeded); characterize, do not assumeSection 9.F
Ladder output resistance (all D pins grounded)1.00 kΩ ± ~1% at LAD7Ohmmeter, Section 9.A
D7-to-GND resistance (other D pins grounded)4.0 kΩ (2k leg + 2k rest-of-ladder)Ohmmeter, Section 9.A
50 Ω-terminated BNC amplitude1/3 of WAVE_BUF (100 Ω R17 into 50 Ω); high-Z scope: ~1xScope on J3
Sine fundamental, 256-entry table at 25 MHz, phase step 125 MHz / 256 = 97.656 kHzScope FFT, Section 9.G
8-bit ideal SINAD6.02 x 8 + 1.76 = 49.9 dB; harmonics roughly ≥ 40 dB down is the sanity bound, not a specScope FFT
Sinc roll-off at 10 MHz out / 25 MHz update20 log10(sinc(0.4)) ≈ −2.4 dB, plus images at 15/35 MHzAXL-002 / spectrum view
Ladder settling time constant~1 kΩ x (node + trace + U1 input ~1.5 pF) ≈ few nsOnly visible as edge shaping at 25 MHz

8. Manual schematic and assembly review checklist#

9. Ordered bench-test procedure#

Stop at the first abnormal result. Record board serial, host identity and bitstream/drive-strength settings, measured VDD, and the DMM/scope IDs and calibration dates. Two bench contexts are used throughout:

A. Unpowered inspection and resistance tests#

  1. Complete the Section 8 checklist under magnification.
  2. Measure 3V3-to-GND resistance in both polarities; investigate < 1 kΩ (C2 charging tail is normal).
  3. With all eight D pins strapped to GND: LAD7-to-GND (probe U1 pin 3) should read 1.00 kΩ ± ~1% — this single number checks the whole ladder topology at once.
  4. Lift the D7 strap only: D7-to-GND should read 4.0 kΩ.
  5. WAVE_OUT-to-WAVE_BUF (J2 pin 1 to U1 pin 6) reads 100 Ω; WAVE_OUT to GND reads open (megaohms) with U1 unpowered.

B. First power, no signal#

  1. Standalone context, all D pins strapped to GND: current should sit in the ~8–11 mA band (U1 I_Q; ladder draws nothing at code 0x00). Well outside that band, stop: > 20 mA suggests a supply short or U1 misorientation; ~0 mA suggests U1 not powered (check pins 4/7).
  2. Measure VDD at U1 pin 7. Measure WAVE_OUT: expect ~0 V (0x00 plus offset).
  3. Context (a): plug into the FPGA host unconfigured, confirm the rail and that nothing heats. WAVE_OUT is undefined until the FPGA drives D0–D7 — that is expected, not a fault.

C. Instrument validation against a known source (static codes vs calibrated DMM)#

This is an instrument board: before it is used to generate anything, its static levels must be validated against a calibrated DMM and gain/offset corrections derived.

  1. Measure the actual drive level: with code 0xFF, DMM each D pin (at the PMOD connector). In context (b) this is the bench rail; in context (a) it is the ECP5 VOH under ladder load — expect a few tens of mV below 3.300 V, and record it as VOH_meas. The true LSB is VOH_meas/256, not 12.891 mV.
  2. Set codes 0x00, 0x20, 0x40, 0x80, 0x8B, 0xC0, 0xFF. At each, record V(LAD7) (U1 pin 3) and V(WAVE_OUT) (J2, unloaded) on the calibrated DMM.
  3. Fit V(WAVE_OUT) = G x code x LSB_ideal + O over the codes ≤ 0x8B (two-point 0x20/0x80 is acceptable; least-squares over all is better). Record gain correction G and offset O. Expect G within ~±2% of unity (driver R_O + resistor tolerance) and O within ±9 mV (U1 V_OS max).
  4. Codes above 0x8B are recorded but excluded from the fit until 9.F shows how the buffer behaves beyond its CM range.
  5. In context (a), repeat step 1–3 at two FPGA drive-strength settings; the gain difference directly demonstrates the driver-R_O error of Section 6.

D. Monotonicity walk, 0x00–0xFF#

  1. Context (a): the FPGA steps an up-counter through all 256 codes slowly (e.g. 10 codes/s for DMM logging, or ~1 kHz with a scope in roll mode).
  2. DMM-log or scope-capture WAVE_OUT (unloaded/high-Z). Every step must increase. Expected ideal step = LSB_meas ≈ 12.9 mV.
  3. Inspect the three biggest carries explicitly: 0x3F→0x40, 0x7F→0x80, 0xBF→0xC0. Compute DNL at each: (measured step − LSB)/LSB. Per Section 7, |DNL| up to ~2.5 LSB at the major carry is possible with 1% parts, and a negative step (non-monotonic) at 0x7F→0x80 is a legitimate outcome of the tolerance math, not automatically an assembly fault — but a DNL beyond ±3 LSB, or non-monotonicity at minor carries, means a wrong-value or wrong-position resistor (recheck Section 8).
  4. Note that above ~0x8B the walk is measuring ladder-through-buffer with the buffer out of CM spec; cross-check any anomaly there against the LAD7 node directly before blaming the ladder.

E. Mid-scale glitch capture (0x7F→0x80)#

The major carry switches all eight bits at once (01111111 → 10000000). Two mechanisms make a glitch: (1) FPGA output timing skew — if D7 rises a nanosecond before D0–D6 fall, the ladder momentarily sees 0xFF (or 0x00 for the opposite skew), a half-scale excursion; (2) the unequal, tolerance-error bit weights mean even simultaneous edges don't cancel exactly. The ladder's ~ns settling and U1's 450 MHz bandwidth will happily pass it.

  1. Context (a): toggle the code between 0x7F and 0x80 at a few hundred kHz.
  2. Scope on WAVE_OUT, high-Z or 50 Ω as intended for real use, trigger on D7 (PMOD pin 10) rising; use single-shot / infinite persistence, ≥200 MHz bandwidth.
  3. Expect a narrow spike riding the 1-LSB step: with ~1 ns skew the worst case is a ~1.65 V excursion lasting ~1 ns, low-pass-shaped by the ladder RC and probe — in practice expect a few hundred mV tall and a few ns wide. Record its impulse area (V·ns), the honest figure of merit.
  4. Acceptability is application-defined: for the DDS lab, a narrow (few ns) glitch is normal for an unlatched, unsegmented R-2R and shows up as the elevated spur floor budgeted in 9.G. A wide (tens of ns) or slow- settling disturbance is not skew — suspect ladder/buffer settling or a wrong resistor.
  5. Repeat 0x3F→0x40 for comparison (should be roughly half the area).

F. Buffer offset, swing, and CM-range characterization#

  1. Code 0x00: DMM V(LAD7) and V(WAVE_OUT). The difference is U1's offset plus its low-side output floor; expect within ±9 mV (V_OS max) plus a few mV of output-stage saturation floor into a light load. Record it.
  2. Code 0x8B (~1.79 V): difference should still be just the offset — the input is at the edge of its specified CM range.
  3. Codes 0xA0, 0xC0, 0xE0, 0xFF: record V(LAD7) vs V(WAVE_OUT) at each. The datasheet does not specify behavior here. Possible outcomes: the buffer keeps tracking with growing error (benign), plateaus, or misbehaves. Whatever is observed becomes the documented usable range of this instrument. If tracking fails above ~1.8 V, the module's honest spec is a 0–1.8 V output instrument until the buffer is redesigned (see Section 12).
  4. Swing check at the top: code 0xFF, compare WAVE_OUT unloaded vs with the BNC 50 Ω-terminated (U1 loaded by 150 Ω). Datasheet output stage allows within 0.2–0.3 V of the rail at 150 Ω — but only if the input stage is still functioning; this measurement and step 3 are read together.
  5. Load-current sanity: terminated at 50 Ω, code at the top of the usable range; U1 output current = V/150 Ω (12 mA at 1.8 V) — confirm no heating, no supply-current anomaly.

G. Sine table output and FFT sanity#

  1. Context (a): FPGA plays a 256-entry, full-scale-to-usable-range sine table (recommend centering on mid-scale with amplitude limited to the 9.F-validated range) at one entry per 25 MHz clock.
  2. Expected fundamental: f = 25 MHz/256 = 97.656 kHz (scaled by the actual fabric clock; verify the clock separately). Capture WAVE_OUT on a real oscilloscope, 50 Ω into the scope if it terminates, FFT with enough record length for a few kHz of resolution.
  3. Verify the fundamental frequency matches the table-rate math to within the host clock tolerance.
  4. Harmonic sanity bound (not a spec): ideal 8-bit SINAD is 49.9 dB, so with a good ladder expect harmonics/spurs roughly ≥ 40 dB below the fundamental, with the deficit vs 49.9 dB coming from DNL (Section 7 math) and glitch energy (9.E). Spurs only ~20–30 dB down indicate a ladder fault or a table/bit-order bug; chasing the last few dB toward 49.9 is not meaningful on an unlatched 1% R-2R.
  5. Look for the update-rate images at 25 MHz ± 97.7 kHz; their presence at the sinc-predicted level is correct behavior, not distortion.
  6. Optionally repeat with the AXL-002 scope module as the capture instrument once it exists in validated form — cross-validating the two instruments.

H. Update-rate ceiling (stretch, needs dds_fast)#

  1. Raise the output frequency (larger phase step) toward 10 MHz; measure amplitude roll-off vs the −2.4 dB sinc prediction at 0.4 x f_s and watch the images close in. This confirms the README's ~10 MHz usable-ceiling claim; it is a characterization goal, not a pass/fail gate.

10. Troubleshooting map#

SymptomFirst measurementsLikely areas
No output at J2/J3, ladder OK at LAD7U1 pins 4/7 supply, pin 2-to-6 continuity, R17U1 unpowered/rotated, follower strap open, R17 open, BNC bridge
Output stuck at ~0 VJ3 center-shield short, WAVE_OUT-to-GND resistanceSolder bridge at BNC or J2
Ladder resistance ≠ 1.00 kΩ in 9.AWalk node-by-node: D_i-to-GND with others grounded1 k/2 k swap, wrong-position resistor, cold joint
One code bit has no effectThat bit's D pin voltage at the connector and at the resistorPMOD pin numbering (bit split across rows), open leg resistor, FPGA constraint file
Giant step or reversal at a minor carryDNL at every carry of the suspect bitWrong-value resistor at that bit (tolerance math cannot explain minor-carry non-monotonicity)
Small negative step only at 0x7F→0x80DNL magnitude vs the ±2.5 LSB Section 7 boundLegitimate 1%-tolerance outcome — document it; swap in 0.1% resistors to confirm
Output tracks to ~1.8 V then misbehavesLAD7 vs WAVE_OUT divergence pointExpected OPA356 CM-range limit (Section 6), not a fault — record the usable range
Half/one-third expected amplitude on the scopeScope input impedance setting50 Ω termination forms 100:50 divider with R17 — arithmetic, not a fault
Big wide glitches at every code changeD0–D7 edges on a logic analyzer, glitch widthFPGA output timing/drive settings, unmatched trace lengths (layout), not the ladder
FFT fundamental at wrong frequencyFabric clock, table length, phase stepHost clocking/HDL, not the board
Spurs only 20–30 dB downRepeat 9.D monotonicity walkLadder fault, bit-order swap in HDL, table error
Supply current ≫ 11 mA + ladderCode dependence of the excessU1 damaged/oscillating (scope WAVE_BUF for MHz oscillation with no input change), C1 missing

11. Bench record template#

FieldRecord
Board revision / serial
Context ((a) FPGA host + bitstream ID / (b) standalone)
Measured VDD and VOH_meas (9.C.1); LSB_meas
DMM / scope IDs and calibration dates
Ladder resistance checks (9.A: 1.00 k / 4.0 k)
Supply current at 0x00 / 0x80 / 0xFF
Static-code table (9.C) and fitted G / O
Monotonicity walk result; DNL at 0x3F/0x7F/0xBF carries
Buffer offset at 0x00; divergence code and behavior above CM range (9.F)
Documented usable output range
Mid-scale glitch capture (V·ns), scope BW stated
Sine FFT: fundamental, worst spur (dBc), image levels
Deviations, captures, raw-file paths
Reviewer / date / disposition

12. Review conclusion#

The strengths: the ladder netlist is exactly the textbook voltage-mode R-2R (verified resistor-by-resistor against generate_design.py), the terminator and chain are correct, the follower strap and output network are simple and right, decoupling is appropriate for a fast buffer, the BNC footprint is a verified stock part, and the whole board is honest about being a lab instrument whose imperfections (1% DNL math, glitch energy, driver-R_O gain error) are the curriculum. ERC is clean (0/0).

The open risks, in order:

  1. OPA356 input common-mode range. The datasheet (SBOS212A) limits the input to (V+) − 1.5 V — about 1.8 V on this 3.3 V board — while the ladder demands 0–3.29 V. The README's "RRIO" description is wrong: the part is rail-to-rail output only. Unless bench characterization (9.F) shows benign out-of-spec behavior, the buffered output is a ~0–1.8 V instrument, roughly half the intended range. The clean fixes are a true RRIO part (TI's own table suggests the OPA350, 38 MHz — slower; or another fast RRIO buffer) or a gain-of-1 configuration from a ladder scaled to half amplitude. This should be resolved before layout.
  2. No PCB exists: matched-length ladder legs, decoupling placement, and ground return for the BNC are all unverified layout intentions.
  3. 1% resistors do not guarantee MSB monotonicity (Section 7 math, ~±2.5 LSB worst-case DNL at the major carry); acceptable for a teaching instrument, but the guide's correction-factor procedure (9.C) is what makes it usable as one.
  4. The DAC "reference" is the FPGA VOH through ~25–50 Ω of driver resistance: absolute accuracy is host- and drive-strength-dependent by design.
  5. R17 is short-circuit protection and cable isolation, not a matched 50 Ω back-termination; reflections on unterminated coax are damped, not absorbed.
  6. The dds_fast HDL, and therefore every dynamic result in Sections 9.D–9.H, does not exist yet; and every expected value in this guide is calculated from the schematic and datasheet rather than measured on hardware.