/* * Pin Discovery Tool for Toy PCB Brain Transplant * * Upload this to the XIAO nRF52840, then connect one breakout pin * at a time to the PROBE_PIN. Open Serial Monitor at 115200 baud. * * The tool will tell you: * - Resting voltage (VCC, GND, floating, pulled up/down) * - Whether it responds to button presses * - Whether it looks like an analog resistor ladder * - Suggested function (power, button, output, NC) * * Workflow: * 1. Desolder original MCU, solder SOP-16 breakout adapter * 2. Install batteries in toy * 3. Connect XIAO GND to toy GND (battery negative) * 4. For each breakout pin, connect it to PROBE_PIN with a jumper * 5. Type the pin number in Serial Monitor and press Enter * 6. Follow prompts (press buttons when asked, etc.) * 7. Tool builds a pin map as you go */ #include #define PROBE_PIN A0 // Connect test jumper here #define NUM_MCU_PINS 16 // SOP-16 // Storage for discovered pin map struct PinInfo { char label[20]; float voltage; bool discovered; }; PinInfo pinMap[NUM_MCU_PINS + 1]; // 1-indexed void setup() { Serial.begin(115200); while (!Serial) delay(10); memset(pinMap, 0, sizeof(pinMap)); Serial.println("╔══════════════════════════════════════════╗"); Serial.println("║ Toy PCB Pin Discovery Tool v1.0 ║"); Serial.println("║ Connect XIAO GND to toy battery GND ║"); Serial.println("║ Connect one SOP pin at a time to A0 ║"); Serial.println("╚══════════════════════════════════════════╝"); Serial.println(); Serial.println("Commands:"); Serial.println(" 1-16 = Probe that SOP pin number"); Serial.println(" map = Show current pin map"); Serial.println(" auto = Auto-detect VCC and GND pins"); Serial.println(" btn = Button detection mode (tests all states)"); Serial.println(" ladder = Resistor ladder detection"); Serial.println(); Serial.print("> "); } // Read voltage on probe pin (0-3.3V range) float readVoltage() { analogReadResolution(12); // nRF52840 supports 12-bit ADC delay(10); // settle // Average multiple readings uint32_t sum = 0; for (int i = 0; i < 16; i++) { sum += analogRead(PROBE_PIN); delayMicroseconds(500); } float raw = sum / 16.0; return (raw / 4095.0) * 3.3; // Convert to voltage } // Check if pin is actively being driven or floating String classifyVoltage(float v) { if (v < 0.1) return "GND (hard low)"; if (v < 0.4) return "Weak pulldown or low output"; if (v > 3.1) return "VCC (hard high)"; if (v > 2.5) return "Weak pullup (~3V)"; if (v > 1.4 && v < 1.9) return "Floating (~mid-rail)"; return "Unknown voltage"; } // Test if the pin changes state (button detection) void testButton(int sopPin) { Serial.println("\n--- Button Detection ---"); Serial.println("Watch the voltage while pressing each toy button."); Serial.println("Monitoring for 10 seconds..."); Serial.println(); float baseline = readVoltage(); Serial.print("Baseline: "); Serial.print(baseline, 3); Serial.println("V"); float minV = baseline, maxV = baseline; unsigned long start = millis(); int changes = 0; float lastV = baseline; while (millis() - start < 10000) { float v = readVoltage(); if (v < minV) minV = v; if (v > maxV) maxV = v; // Detect transitions if (abs(v - lastV) > 0.3) { changes++; Serial.print(" Change detected! "); Serial.print(lastV, 2); Serial.print("V → "); Serial.print(v, 2); Serial.print("V at t="); Serial.print((millis() - start) / 1000.0, 1); Serial.println("s"); } lastV = v; delay(20); } Serial.println(); Serial.print("Range: "); Serial.print(minV, 3); Serial.print("V to "); Serial.print(maxV, 3); Serial.println("V"); Serial.print("Transitions detected: "); Serial.println(changes); if (changes > 0 && maxV - minV > 1.0) { Serial.println("→ LIKELY A BUTTON PIN (digital, active low)"); if (sopPin > 0) { snprintf(pinMap[sopPin].label, sizeof(pinMap[sopPin].label), "Button"); pinMap[sopPin].voltage = baseline; pinMap[sopPin].discovered = true; } } else if (changes > 0 && maxV - minV > 0.2) { Serial.println("→ POSSIBLE ANALOG INPUT or RESISTOR LADDER"); } else { Serial.println("→ No button activity detected on this pin"); } } // Detect resistor ladder (multiple buttons on one analog pin) void testResistorLadder() { Serial.println("\n--- Resistor Ladder Detection ---"); Serial.println("Press each button ONE AT A TIME when prompted."); Serial.println("Press Enter after pressing each button."); Serial.println("Type 'done' when finished."); Serial.println(); float voltages[10]; String names[10]; int count = 0; float baseline = readVoltage(); Serial.print("Baseline (no button): "); Serial.print(baseline, 3); Serial.println("V"); while (count < 10) { Serial.print("\nPress button #"); Serial.print(count + 1); Serial.println(" and type its name (or 'done'):"); Serial.print("> "); while (!Serial.available()) delay(10); String input = Serial.readStringUntil('\n'); input.trim(); if (input.equalsIgnoreCase("done")) break; float v = readVoltage(); voltages[count] = v; names[count] = input; Serial.print(" "); Serial.print(input); Serial.print(": "); Serial.print(v, 3); Serial.println("V"); count++; Serial.println(" Release button now."); delay(500); } if (count > 1) { Serial.println("\n--- Ladder Summary ---"); Serial.print("Baseline: "); Serial.print(baseline, 3); Serial.println("V"); for (int i = 0; i < count; i++) { Serial.print(" "); Serial.print(names[i]); Serial.print(": "); Serial.print(voltages[i], 3); Serial.print("V (ADC ~"); Serial.print((int)(voltages[i] / 3.3 * 4095)); Serial.println(")"); } // Check if voltages are distinct enough bool isLadder = true; for (int i = 0; i < count - 1; i++) { for (int j = i + 1; j < count; j++) { if (abs(voltages[i] - voltages[j]) < 0.15) { isLadder = false; } } } if (isLadder && count >= 2) { Serial.println("\n→ THIS IS A RESISTOR LADDER"); Serial.println(" Use analogRead() with thresholds to detect buttons."); Serial.println(" Suggested thresholds (midpoints between readings):"); // Sort by voltage for (int i = 0; i < count - 1; i++) { for (int j = i + 1; j < count; j++) { if (voltages[j] < voltages[i]) { float tv = voltages[i]; voltages[i] = voltages[j]; voltages[j] = tv; String ts = names[i]; names[i] = names[j]; names[j] = ts; } } } for (int i = 0; i < count; i++) { float lo = (i == 0) ? 0 : (voltages[i-1] + voltages[i]) / 2; float hi = (i == count-1) ? 3.3 : (voltages[i] + voltages[i+1]) / 2; Serial.print(" "); Serial.print(names[i]); Serial.print(": "); Serial.print(lo, 2); Serial.print("V - "); Serial.print(hi, 2); Serial.println("V"); } } else { Serial.println("\n→ Doesn't look like a resistor ladder"); Serial.println(" (Voltages too close together or too few buttons)"); } } } // Full probe of one pin void probePin(int sopPin) { Serial.print("\n═══ Probing SOP-16 Pin "); Serial.print(sopPin); Serial.println(" ═══"); // First read as analog input (high impedance) pinMode(PROBE_PIN, INPUT); delay(50); float v_floating = readVoltage(); Serial.print("Floating voltage: "); Serial.print(v_floating, 3); Serial.print("V → "); Serial.println(classifyVoltage(v_floating)); // Classify if (v_floating < 0.1) { Serial.println("→ This is a GND pin"); snprintf(pinMap[sopPin].label, sizeof(pinMap[sopPin].label), "GND"); pinMap[sopPin].voltage = v_floating; pinMap[sopPin].discovered = true; } else if (v_floating > 2.8) { // Could be VCC or a pulled-up button pin // Try briefly enabling internal pulldown to see if it drops pinMode(PROBE_PIN, INPUT_PULLDOWN); delay(50); float v_pulldown = readVoltage(); pinMode(PROBE_PIN, INPUT); if (v_pulldown > 2.5) { Serial.print("With pulldown: "); Serial.print(v_pulldown, 3); Serial.println("V — Still high → VCC (power) pin"); snprintf(pinMap[sopPin].label, sizeof(pinMap[sopPin].label), "VCC"); pinMap[sopPin].voltage = v_floating; pinMap[sopPin].discovered = true; } else { Serial.print("With pulldown: "); Serial.print(v_pulldown, 3); Serial.println("V — Dropped → Weak pullup (likely button input)"); Serial.println("→ Try pressing buttons to confirm. Running button test..."); testButton(sopPin); } } else if (v_floating > 0.4 && v_floating < 2.5) { Serial.println("Mid-range voltage. Could be:"); Serial.println(" - Floating (not connected)"); Serial.println(" - Part of a resistor ladder"); Serial.println(" - An analog output"); Serial.println("→ Try pressing buttons to see if it changes..."); testButton(sopPin); } else { Serial.println("Low but not GND. Could be pulled-down output."); testButton(sopPin); } Serial.println(); } // Print the current pin map void showMap() { Serial.println("\n╔════════════════════════════════════╗"); Serial.println("║ Current Pin Map ║"); Serial.println("╠════════════════════════════════════╣"); for (int i = 1; i <= NUM_MCU_PINS; i++) { Serial.print("║ Pin "); if (i < 10) Serial.print(" "); Serial.print(i); Serial.print(": "); if (pinMap[i].discovered) { Serial.print(pinMap[i].label); // Pad to align for (int j = strlen(pinMap[i].label); j < 12; j++) Serial.print(" "); Serial.print("("); Serial.print(pinMap[i].voltage, 2); Serial.print("V)"); } else { Serial.print("-- not probed -- "); } Serial.println(" ║"); } Serial.println("╚════════════════════════════════════╝"); // Count discovered int found = 0; for (int i = 1; i <= NUM_MCU_PINS; i++) { if (pinMap[i].discovered) found++; } Serial.print("Discovered: "); Serial.print(found); Serial.print("/"); Serial.println(NUM_MCU_PINS); } void loop() { if (Serial.available()) { String input = Serial.readStringUntil('\n'); input.trim(); if (input.equalsIgnoreCase("map")) { showMap(); } else if (input.equalsIgnoreCase("btn")) { Serial.println("Connect the pin you want to test to A0, then:"); testButton(0); } else if (input.equalsIgnoreCase("ladder")) { testResistorLadder(); } else if (input.equalsIgnoreCase("auto")) { Serial.println("\n--- Auto-detect mode ---"); Serial.println("Connect each pin to A0 one at a time."); Serial.println("Press Enter after connecting each pin."); for (int pin = 1; pin <= NUM_MCU_PINS; pin++) { Serial.print("\nConnect SOP pin "); Serial.print(pin); Serial.println(" to A0, then press Enter"); Serial.print("> "); while (!Serial.available()) delay(10); Serial.readStringUntil('\n'); probePin(pin); } showMap(); } else { int pin = input.toInt(); if (pin >= 1 && pin <= NUM_MCU_PINS) { probePin(pin); } else { Serial.println("Unknown command. Use 1-16, map, auto, btn, or ladder"); } } Serial.print("\n> "); } }