imrishabh18/rp2040-motor-controller
This circuit incorporates a USB-C Power Delivery (PD) interface with a CH224K controller, a WJ500V-5.08-04P motor output connector, multiple power conditioning components including capacitors, resistors, diodes, and an RP2040 microcontroller, to manage motor control, signal routing, and power management for a USB-powered stepper motor system.
- Version
- 1.0.14
- License
- unset
- Stars
- 0
tests/helpers/assertCommonGround.ts
import type { CircuitJson, SourceNet } from "circuit-json";
/** Follow electrical edges only: names and cached connectivity keys are not edges. */
export function assertCommonGround(json: CircuitJson) {
const parent = new Map<string, string>();
const root = (id: string): string => {
if (!parent.has(id)) parent.set(id, id);
const next = parent.get(id)!;
if (next !== id) parent.set(id, root(next));
return parent.get(id)!;
};
for (const element of json) {
const ids = element.type === "source_trace"
? [...element.connected_source_port_ids, ...element.connected_source_net_ids]
: element.type === "source_component_internal_connection"
? element.source_port_ids : [];
for (const id of ids.slice(1)) parent.set(root(id), root(ids[0]!));
}
const nets = json.filter((e): e is SourceNet => e.type === "source_net" && e.name === "GND");
if (!nets.length) throw new Error("Missing GND net");
const ground = root(nets[0]!.source_net_id);
for (const net of nets) {
if (root(net.source_net_id) !== ground) throw new Error("Disconnected GND networks");
}
const required = [
["U1", "GND"], ["TP_GND", "pin1"],
["DRIVER", "GND1"], ["DRIVER", "GND2"],
["DRIVER", "MODE"], ["DRIVER", "TRQ"],
["J_USB", "A1B12"], ["J_MOTOR_USB", "A1B12"],
["U_PD", "GND"], ["R_ISEN_A", "pin2"], ["R_ISEN_B", "pin2"],
["C_VM_BULK", "pin2"], ["C_VM_HF", "pin2"],
["C_PD_VDD", "pin2"], ["C_PD_VBUS", "pin2"],
["C_MOTOR_BULK", "pin2"], ["D_MOTOR_TVS", "pin1"],
["R_SLEEP_PD", "pin2"],
];
for (const [name, pin] of required) {
const component = json.find((e) => e.type === "source_component" && e.name === name);
if (component?.type !== "source_component") throw new Error(`Missing ${name}`);
const port = json.find((e) => e.type === "source_port" &&
e.source_component_id === component.source_component_id &&
(e.name === pin || e.port_hints?.includes(pin!)));
if (port?.type !== "source_port" || root(port.source_port_id) !== ground) {
throw new Error(`${name}.${pin} is not on common ground`);
}
}
for (const e of json) {
if (e.type === "pcb_copper_pour" && (!e.source_net_id || root(e.source_net_id) !== ground)) {
throw new Error("Copper pour is not assigned to common ground");
}
if (e.type === "source_net" && ["VBUS", "VSYS", "V3V3", "V1V1"].includes(e.name) &&
root(e.source_net_id) === ground) throw new Error(`${e.name} is shorted to ground`);
}
// Sense inputs must reach their own shunt, never bypass it to ground.
const portFor = (name: string, pin: string) => {
const component = json.find(e => e.type === "source_component" && e.name === name);
if (component?.type !== "source_component") throw new Error(`Missing ${name}`);
const port = json.find(e => e.type === "source_port" &&
e.source_component_id === component.source_component_id &&
(e.name === pin || e.port_hints?.includes(pin)));
if (port?.type !== "source_port") throw new Error(`Missing ${name}.${pin}`);
return root(port.source_port_id);
};
for (const channel of ["A", "B"]) {
const sense = portFor("DRIVER", `${channel}ISEN`);
if (sense === ground || sense !== portFor(`R_ISEN_${channel}`, "pin1")) {
throw new Error(`Invalid ${channel}-channel current-sense connection`);
}
}
const motorNets = ["AOUT1", "AOUT2", "BOUT1", "BOUT2"].map((pin, i) => {
const motor = portFor("DRIVER", pin);
if (motor === ground || motor !== portFor("J1", `pin${i + 1}`)) {
throw new Error(`Invalid motor output ${pin}`);
}
return motor;
});
if (new Set(motorNets).size !== 4) throw new Error("Motor outputs are shorted together");
return { groundNetDeclarations: nets.length, checkedGroundPorts: required.length, checkedCurrentSenseChannels: 2, checkedMotorOutputs: 4 };
}