Files
baby-mobile/pin_discovery.ino
T
2026-07-04 03:28:12 -07:00

391 lines
13 KiB
Arduino

/*
* 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 <Arduino.h>
#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> ");
}
}