Circuit review & bench-test guide
AXO-013 — analog joystick carrier PMOD module
Document purpose#
This document explains the axo-013-joystick module at component level and turns the design evidence into a practical manual-review and bench-test plan. It is based on generate_design.py, README.md, and reports/erc.rpt.
This board has never been fabricated or assembled. The schematic is ERC clean (0/0, see reports/erc.rpt) and the netlist has been reviewed, but the PCB layout has not been started — there are no gerbers, no renders, and no physical board. Every number here is a design target or a datasheet expectation to verify, not a proven result. Layout-dependent items (RC/decoupling placement, thumbstick socket clearance from the PMOD clip zone) cannot be reviewed yet and are flagged below.
This is a carrier: it does not contain the joystick. A common 5-pin XY thumbstick breakout (KY-023 class) plugs into socket J2. Because clone breakouts disagree on pin order, Section 4A is a mandatory plug-in-pin-order-verification-before-power gate.
1. What the board does#
AXO-013 digitizes a two-axis analog thumbstick plus its click switch and presents them to a PMOD host over SPI. The stick is mechanically two 10 kΩ potentiometers whose wipers (VRx, VRy) swing rail-to-rail as the stick moves, plus a normally-open switch (SW) that closes to GND when the stick is pressed. A Microchip MCP3202 dual-channel 12-bit SPI SAR ADC digitizes X on CH0 and Y on CH1; the click switch reaches the host as a plain active-low GPIO on PMOD pin 8. Each wiper passes a 1 kΩ + 10 nF RC (fc ≈ 16 kHz) that both filters wiper-scratch noise and acts as the SAR sample-cap charge reservoir.
It teaches SPI ADC transactions, dead-zone/centering math in fabric, and feeds later projects (Pong with the VGA module axo-007, robot teleop with the actuator line). It does not interpret the stick — center offset, dead zone, and axis inversion are all host/HDL responsibilities.
Functional block diagram#
PMOD plug J1 (2x6)
6/12: 3V3 ──┬────────────┬───────────┬────────────┐
C4 1uF C3 100nF R6 10k (VDD/VREF U1 pin 8)
(bulk) (VDD/VREF) (~CS PU)
1: CS_N ───────────────────────────┴──────────────> U1 ~CS (pin 1)
2: MOSI ──────────────────────────────────────────> U1 DIN (pin 5)
4: SCK ──────────────────────────────────────────> U1 CLK (pin 7)
3: MISO <── R5 100R ── ADC_DOUT ──────────────────── U1 DOUT (pin 6)
8: JOY_SW <── R4 100R ── SW_RAW ──┬── R3 10k ── 3V3
└────────────────< J2.5 SW (to GND when pressed)
J2 thumbstick socket (1x5): 1 VCC(3V3) 2 GND 3 VRx 4 VRy 5 SW
VRx ── R1 1k ──┬── U1 CH0 (pin 2) C1 10nF ── GND
└── JOY_X
VRy ── R2 1k ──┬── U1 CH1 (pin 3) C2 10nF ── GND
└── JOY_Y
5/11: GND ──────────────────────────────── U1 VSS (pin 4)
2. Safety and scope boundaries#
- Electrically benign for the operator: single 3.3 V rail, a few mA. Hazards are to the parts. Standard ESD handling.
- Everything on this board is a 3.3 V part. A 5 V PMOD socket or a mis-set bench supply drives VDD/VREF and every ADC input above rating. The MCP3202 absolute-max VDD is 7 V so it tolerates a brief 5 V event better than the ADXL343-class parts, but the stick and the design intent are 3.3 V — verify the rail before every first connection.
- Never back-drive MISO/CS/SCK/MOSI or JOY_SW above VDD+0.3 V, including while the module is unpowered.
- The thumbstick is a mechanical part: do not force it past its stops. Wiper contact bounce/scratch is expected and is what the RC filters and host dead-zone math exist to handle.
- Use a current-limited 3.3 V bench supply (≤50 mA limit is ample) for standalone tests. The whole module should draw well under 1 mA (MCP3202 ~550 µA active typ, plus ~0.66 mA through the two pot end-to-end paths at 10 kΩ across 3.3 V, plus 0.33 mA through R6/R3 pull-ups).
- Center/extents values below are geometry- and part-tolerance-dependent; they are expectations to calibrate, not a specification of this board.
3. Power and signal sequence#
- The host (or bench supply) applies 3.3 V to PMOD 6/12 and GND to 5/11. C3/C4 charge; U1 VDD/VREF (pin 8) comes up. VREF = VDD is the design intent so the 12-bit code maps linearly to wiper position.
- R6 (10 kΩ) holds ~CS high while the host FPGA is unconfigured, so U1 stays deselected and no accidental conversion starts on a floating chip-select.
- The thumbstick's two pots divide 3V3→GND; the wipers sit near mid-rail at physical center and swing toward 3V3 or GND at the extents. R1/C1 and R2/C2 low-pass each wiper (fc ≈ 16 kHz) and present the MCP3202's sample cap a low enough source impedance to settle within the acquisition window.
- The click switch SW is open at rest; R3 (10 kΩ) holds SW_RAW at 3V3. Press closes SW to GND, pulling SW_RAW low. R4 (100 Ω) series-protects the module-driven JOY_SW line into PMOD pin 8 (active-low).
- On demand the host asserts ~CS low, clocks a config frame on MOSI to select CH0 (X) or CH1 (Y), and reads the 12-bit result MSB-first on MISO (through R5's 100 Ω). One conversion per axis per transaction.
4. Interfaces#
| PMOD pin | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Net | ~CS | MOSI | MISO | SCK | GND | 3V3 | NC | JOY_SW | NC | NC | GND | 3V3 |
| Ref | Type | Signals | Intended use |
|---|---|---|---|
| J1 | PMOD 2×6 plug (Type 2A SPI) | SPI + JOY_SW + power | Host connection |
| J2 | 1×05 pin socket | 1 VCC 2 GND 3 VRx 4 VRy 5 SW | Thumbstick breakout carrier |
SPI framing (MCP3202): mode 0,0 or 1,1; ≤ ~0.9 MHz at 3.3 V (the part is 100 ksps class; a 12-bit conversion needs ~18 clocks). ~CS low starts each conversion; the host clocks in a 4-bit config (START=1, SGL/DIFF, ODD/SIGN, MSBF=1), the ADC returns a leading null (0) bit then 12 data bits, and ~CS high ends it. Single-ended CH0 = SGL/DIFF 1, ODD/SIGN 0; CH1 = SGL/DIFF 1, ODD/SIGN 1.
No dedicated test points exist; probe at J1, J2, and the R1–R6/C1–C4 pads. (Layout to-do: add probe-friendly pads before fabrication.)
4A. Plug-in pin-order verification BEFORE power (mandatory carrier gate)#
The thumbstick breakout is not on this BOM and clone pinouts vary. Do this before the breakout is ever plugged into a powered board.
- Read the breakout's own silkscreen. The J2 map expects, socket pin 1→5: VCC, GND, VRx, VRy, SW. Common clone deviations: VRx/VRy swapped (harmless — just swaps X/Y in software), or GND/VCC swapped or +5V labeled (dangerous — reverses supply into the stick and can feed the wrong rail into the RC nodes).
- With the breakout unplugged, DMM continuity/ohms across the breakout itself: VCC↔GND should read the two pots roughly in parallel to the wipers (kΩ scale), never a short. VRx and VRy should each read ~5 kΩ to both VCC and GND at mechanical center and sweep as you move the stick. SW should be open to GND at rest and close when pressed.
- Confirm the breakout is a 3.3 V-tolerant resistive stick (it always is — it is passive), and that it has no onboard regulator or logic that assumes 5 V.
- Only after the map matches, plug the breakout into J2 with the board unpowered, and re-run Section 9A resistance checks through J2 before applying 3.3 V. A reversed VCC/GND here is the one wiring error that this passive carrier cannot protect against.
5. Component-by-component review#
5.1 ADC and connectors#
| Ref. | Part | Function and why needed | If absent/open | If shorted, wrong, or misassembled |
|---|---|---|---|---|
| U1 | Microchip MCP3202-BI/SN, SOIC-8 dual 12-bit SPI SAR ADC | Digitizes both wiper voltages ratiometrically (VREF = VDD); returns 12-bit codes over SPI | No conversions; MISO reads all-0/all-1 | SOIC rotation shorts VDD/VSS; a DIN/DOUT swap yields garbage/no data; VREF pin not at 3V3 breaks the ratiometric mapping |
| J1 | Generic 2×6 right-angle PMOD plug | Host power + SPI + JOY_SW | No host connection | Pin-1/zigzag error puts 3V3 on signal pins; verify against the PMOD spec and a physical socket once a layout exists |
| J2 | Generic 1×05 2.54 mm socket | Thumbstick breakout carrier | No stick input; CH0/CH1 float toward mid-rail through pots-absent | Reversed VCC/GND (see 4A) mis-powers the stick; VRx/VRy swap only exchanges axes |
5.2 Per-axis RC (anti-alias + SAR source impedance)#
| Ref. | Value | Function | If omitted or wrong |
|---|---|---|---|
| R1 | 1 kΩ (RC0603FR-071KL) | X-wiper series element into CH0 | Open: CH0 floats/no X reading; ≫1 kΩ: with C1 pushes fc down and slows SAR settling, softening the response |
| C1 | 10 nF 50 V X7R | X shunt: fc = 1/(2π·1k·10n) ≈ 15.9 kHz, plus SAR charge reservoir | Open: wiper scratch and SAR kickback appear as X jitter; too large: sluggish X, possible under-settle at fast scan |
| R2 | 1 kΩ | Y-wiper series element into CH1 | As R1, for Y |
| C2 | 10 nF 50 V X7R | Y shunt, same fc | As C1, for Y |
5.3 Button conditioning, SPI support, decoupling#
| Ref. | Value | Function | If omitted or wrong |
|---|---|---|---|
| R3 | 10 kΩ | Stick-click pull-up: SW closes to GND, so SW_RAW idles high | Open: JOY_SW floats — random presses; too small: wasted current, still works |
| R4 | 100 Ω | Series protection on the module-driven JOY_SW line to PMOD 8 | Open: no button at host; shorted: works, no miswire protection |
| R5 | 100 Ω | Series protection on the ADC-driven DOUT→MISO line | Open: MISO dead (reads 0x00/0xFF); ≫100 Ω: RC into host input pin eats the DOUT-valid budget at high SCLK |
| R6 | 10 kΩ | ~CS idle pull-up: an unconfigured host cannot start a conversion | Open: ~CS floats before FPGA config — spurious conversions/undefined SPI; too small: host fights it (0.33 mA, negligible) |
| C3 | 100 nF 16 V X7R | MCP3202 VDD/VREF decoupling | Reference bounce during acquisition degrades LSBs |
| C4 | 1 µF 10 V X7R | Supply bulk at the socket | More rail droop under the pot/ADC load; noisier LSBs |
Power flags #FLG01 (3V3) and #FLG02 (GND) are ERC source markers, not physical parts. Every schematic reference designator (U1, J1, J2, R1–R6, C1–C4) is covered above. There are no jumpers on this module.
6. Datasheet summary and design interpretation#
Primary reference: Microchip MCP3202 datasheet (21034F). Check the revision before procurement.
| Datasheet fact | Value | Board-specific interpretation |
|---|---|---|
| Resolution / channels | 12-bit, 2-ch (single-ended or 1 pseudo-diff pair) | CH0 = X, CH1 = Y, both single-ended vs VSS |
| Reference | VREF = VDD tied here (pin 8) | Ratiometric: code = 4096·V_wiper/VDD; supply noise cancels since the stick divides the same VDD |
| Sample rate | 100 ksps at VDD = 5 V, ~50 ksps at 2.7 V; ~18 clocks/conversion | At 3.3 V keep SCLK ≤ ~0.9 MHz for full accuracy; a joystick needs only kHz-rate scans |
| SPI frame | START, SGL/DIFF, ODD/SIGN, MSBF config in; null bit + 12 data out | First returned bit is a 0 null — a stuck-high first bit means MISO/DOUT trouble |
| Input model | Switched sample cap (~20 pF class), needs low source Z | The 1 kΩ series is well within the part's source-impedance tolerance; C1/C2 supply the sample charge |
| Supply | 2.7–5.5 V, ~550 µA active, sub-µA standby (CS high powers down) | Single 3.3 V rail; CS-high between reads lets it idle |
The thumbstick itself: two ~10 kΩ linear pots and an SPST-NO click switch. Center voltage ≈ VDD/2 only if the pot is mechanically centered and linear; real sticks show a center offset and non-symmetric extents that the host must calibrate.
7. Expected values before bench testing#
None of these have been measured — no board exists.
| Quantity | Expected (design/datasheet) | How to measure |
|---|---|---|
| 3V3-to-GND resistance, unpowered | High (kΩ–MΩ scale after caps charge; a few kΩ once J2 stick is fitted, from the two pot end paths) | DMM both polarities |
| ~CS-to-3V3 resistance | ≈10 kΩ (R6) | DMM J1 pin 1 → pin 6 |
| JOY_SW-to-3V3 (stick released) | ≈10 kΩ (R3), through R4 in series | DMM J1 pin 8 → 3V3 |
| MISO continuity to U1 DOUT | ≈100 Ω (R5) | DMM J1 pin 3 → U1 pin 6 |
| X/Y wiper to CH0/CH1 | ≈1 kΩ (R1/R2) | DMM J2.3/J2.4 → U1 pin 2/3 |
| VRx/VRy at mechanical center | ≈ VDD/2 (≈1.65 V) ± stick offset | DMM at JOY_X/JOY_Y nodes, powered, stick centered |
| VRx/VRy at extents | swing toward ≈0 V and ≈3.3 V (not always full rail) | DMM while holding each extent |
| Center 12-bit code | ≈2048 ± offset (hundreds of counts of offset is normal) | First SPI reads, stick centered |
| Extent 12-bit codes | approach 0 and ~4095, asymmetrically | SPI reads at each extent |
| JOY_SW pressed | logic low at PMOD 8 | Scope/DMM while pressing |
| Active supply current | < 1 mA total | µA/mA meter, standalone supply |
The canonical first read: MCP3202 CH0 (X) over SPI#
Exact framing (single-ended CH0, MSBF, mode 0,0; the 3-byte host convention):
Assert ~CS low.
MOSI byte 0: 0x01 (START bit)
MOSI byte 1: 0xA0 (SGL/DIFF=1, ODD/SIGN=0 -> CH0, MSBF=1)
MOSI byte 2: 0x00 (clock out the low data bits)
MISO: byte1 lower bits + byte2 = null bit then D11..D0
X code = ((byte1 & 0x0F) << 8 | byte2) masked to 12 bits
Deassert ~CS. For CH1 (Y) use byte1 = 0xE0 (ODD/SIGN=1).
A first frame that returns 0x000 or 0xFFF stops bring-up: MISO dead (R5 open, DOUT unsoldered), DIN/DOUT swapped, ~CS never asserted, or the part unpowered. A value stuck near mid-scale that never moves with the stick points at a J2 wiring/pot problem, not the ADC.
8. Manual schematic and assembly review checklist#
Reviewable now:
- U1 pin map vs MCP3202 SOIC-8: 1 ~CS, 2 CH0, 3 CH1, 4 VSS, 5 DIN(MOSI), 6 DOUT, 7 CLK(SCK), 8 VDD/VREF. Confirm MOSI→DIN(5) and MISO comes from DOUT(6) through R5 — a DIN/DOUT swap is the classic dead-read cause.
- Confirm CH0 = X (JOY_X) and CH1 = Y (JOY_Y) match the intended axis labels.
- Confirm VREF (pin 8) is tied to 3V3, not left as a separate reference.
- Re-run ERC after any regeneration (
reports/erc.rptclean today).
Assembly items (for the eventual first article — none exists yet):
- J1 pin-1/zigzag vs the PMOD spec and a physical host socket.
- J2 socket orientation and the Section 4A pin-order gate.
- Measure R1–R6, confirm C1/C2 tight to their wiper nodes and C3 tight to U1 pin 8.
- Layout: socket clear of the PMOD clip zone; stick mechanically supported.
9. Ordered bench-test procedure#
Stop at the first abnormal result. Record board serial, supply voltage, equipment, SPI clock, and operator. Two host contexts: standalone (current-limited bench supply + SPI adapter, phases B–D) and PMOD host (FPGA/MCU provides 3.3 V, phase E). Standalone first. Complete Section 4A before J2 is populated and powered.
A. Unpowered inspection and resistance tests#
- Complete the Section 8 checklist under magnification; complete 4A.
- DMM 3V3-to-GND (J1 pin 6 → 5), both polarities: no hard short.
- ~CS (pin 1) → 3V3: ≈10 kΩ. JOY_SW (pin 8) → 3V3: ≈10 kΩ (stick released).
- MISO (pin 3) → U1 DOUT: ≈100 Ω. MOSI/SCK (pins 2/4) → U1 pins 5/7: ≈0 Ω.
- With the stick fitted: VRx/VRy (J2.3/J2.4) → U1 CH0/CH1: ≈1 kΩ; sweep the stick and watch resistance to 3V3/GND change smoothly.
B. Standalone first power#
- Bench supply 3.3 V (measure it), current limit 20–50 mA, output off. Wire + to J1 PMOD 6/12, − to 5/11 per the header map.
- Power on: no current-limit trip; total draw < 1 mA. Milliamps beyond that mean a solder fault or reversed stick supply.
- Verify 3.3 V at C3/C4/U1 pin 8; ~CS idling at 3.3 V through R6; JOY_SW near 3.3 V; VRx/VRy near mid-rail with the stick centered.
C. Standalone SPI bring-up and axis reads#
Use any 3.3 V SPI master, mode 0,0 (or 1,1), start at ~500 kHz, MSB first.
- CH0 (X): run the Section 7 frame. Expect a valid 12-bit code near 2048 at center. Capture the first frame regardless of result.
- CH1 (Y): byte1 = 0xE0. Same expectation.
- Sweep test: move the stick slowly corner to corner and log both codes. Each axis should move monotonically from near 0 to near 4095; note the center code and the two extents per axis (they are usually asymmetric).
- Button: read PMOD 8 while pressing the stick — high released, low pressed, clean through R4/R3.
D. Center and extents calibration#
- Center: stick released, average ≥ 100 samples per axis → X_center, Y_center. Expect ≈2048 ± offset; hundreds of counts offset is normal.
- Extents: hold each of the four mechanical stops, average → X_min, X_max, Y_min, Y_max. Record all four per axis; they bound the usable range.
- Dead zone: compute the peak-to-peak jitter at rest (should be a few LSB with the RC filters working); set the host dead zone above it.
- Repeat after re-centering; center code should return within noise. These numbers are per-stick and per-assembly — this is calibration data, not a pass/fail spec.
E. PMOD-host context (FPGA/MCU provides 3.3 V)#
- Measure the host socket rail: must be 3.3 V. Confirm the host I/O bank voltage.
- Plug in with the host unconfigured; verify ~CS reads 3.3 V at the module (R6 vs a floating host pin).
- Run the same ladder from the host SPI master (bit-banged or the AruviX HDL SPI+MCP3202 core): CH0/CH1 reads, center/extents, JOY_SW GPIO.
- Scope the first host-driven frame and compare with the phase C capture; confirm the leading null bit and 12 data bits.
- Demo: dead-zone + centering math in fabric driving Pong (axo-007 VGA) or robot teleop.
F. Release-only tests#
Pot linearity/repeatability characterization, mechanical endurance of the stick, ESD at J1/J2, and temperature behavior belong to a separate qualification plan, gated on a board existing at all.
10. Troubleshooting map#
| Symptom | First measurements | Likely areas |
|---|---|---|
| Current-limits at power-on | 3V3-to-GND resistance | Reversed stick VCC/GND (4A), U1 solder bridge, >rating event |
| Both axes read 0x000/0xFFF | Scope ~CS/SCK/MOSI/MISO during a frame | DIN/DOUT swap, R5 open, ~CS not reaching U1, unpowered |
| Reads shifted/garbage | SCLK edges vs SPI mode; leading null bit | Wrong mode, bit order, SCLK too fast for 3.3 V |
| One axis stuck mid-scale | That axis' wiper voltage at J2 and JOY_X/Y | Pot wiper open, R1/R2 open, J2 wiring, stick fault |
| Axes swapped | Which stick direction moves which code | VRx/VRy swapped on the breakout (harmless, fix in SW) |
| Codes inverted (max at rest) | VCC/GND at the stick | Reversed stick supply (4A) |
| No button | JOY_SW at U1 side of R4 vs J1 side | R3 open (floats), R4 open, switch fault |
| Noisy/jittery axes | Peak-to-peak at rest; C1/C2 presence | RC missing/wrong, long unshielded stick leads, dead zone too small |
| Works standalone, dead on host | Host rail and bank voltage, ~CS idle | Wrong socket voltage, host pin contention |
11. Bench record template#
| Field | Record |
|---|---|
| Board revision / serial | |
| Thumbstick breakout make + verified pin order (4A) | |
| Supply voltage (exact) and current limit | |
| Host or adapter, SPI clock, equipment + calibration | |
| Unpowered resistance results (A.2–A.5) | |
| Active supply current | |
| CH0/CH1 center codes + first-frame capture path | |
| Four extents per axis (X_min/max, Y_min/max) | |
| Rest jitter / chosen dead zone | |
| JOY_SW pressed/released result | |
| Deviations, photos, raw-file paths | |
| Reviewer / date / disposition |
12. Review conclusion#
The schematic is a clean minimal MCP3202 carrier: both axes digitized ratiometrically (VREF = VDD), 1 kΩ + 10 nF per wiper for scratch filtering and SAR charge, the click switch pulled up and passed out behind 100 Ω, ~CS defended by a 10 kΩ idle pull-up, and DOUT behind the standard 100 Ω line resistor. The principal risks are that nothing physical exists yet (no layout, no first-article data); the passive carrier's inability to protect against a reversed thumbstick VCC/GND, which makes the Section 4A pin-order gate mandatory; SPI framing discipline (leading null bit, correct config bits); and that center/extents are per-stick calibration data, not board specifications. The bring-up ladder — CH0/CH1 12-bit reads, center capture, four-extent sweep, button GPIO — is exactly what the AruviX SPI+MCP3202 HDL core and its dead-zone/centering math will need to reproduce.