seveibar/nema17-rp2040-stepper-controller
A tscircuit package created by seveibar.
- Version
- 0.3.1
- License
- unset
- Stars
- 0
schematic/UnifiedUsbSection.tsx
import { Children, cloneElement, isValidElement, Fragment, type ReactElement, type ReactNode } from "react";
import { USBLC6_2SC6 } from "../imports/USBLC6_2SC6";
import { MotorUsbC } from "../imports/usb-c-20v";
import { DTC114EETL } from "../imports/DTC114EETL";
import { CH9442Q } from "../imports/CH9442Q";
import { LMR16006XDDCR } from "../imports/LMR16006XDDCR";
import { PMEG6020ELRX } from "../imports/PMEG6020ELRX";
const sheets: Record<string,string> = {laptop_island:"usb_laptop",usb_isolation:"usb_laptop",usb_selection:"usb_selection",isolated_power:"logic_power",logic_buck:"logic_power"};
const section = (name:string) => ({schSheetName:sheets[name],schSectionName:name});
// Explicit sourcing keeps assembly export independent of fuzzy part searches.
const assemblyParts: Record<string,string> = {
R_LAPTOP_CC1:"C25905",R_LAPTOP_CC2:"C25905",R_USB_SELECT:"C25792",
R_BUCK_EN:"C25741",R_BUCK_FB_TOP:"C122548",R_BUCK_FB_BOTTOM:"C25744",
C_LE:"C1525",C_UG:"C1525",C_PE:"C1525",C_UM:"C1525",C_BST:"C1525",C_BO_HF:"C1525",
C_BI:"C132170",C_BI_HF:"C105882",C_BO:"C92814",
};
const cap = (name:string,value:string,x:number,y:number,a:string,b:string,group:string,voltage="16V",footprint="0402") => <capacitor key={name} name={name} supplierPartNumbers={{jlcpcb:[assemblyParts[name]]}} schMarginRight={0.8} capacitance={value} maxVoltageRating={voltage} footprint={footprint} pcbX={x} pcbY={y} connections={{pin1:a,pin2:b}} {...section(group)}/>;
const res = (name:string,value:string,x:number,y:number,a:string,b:string,group:string) => <resistor key={name} name={name} supplierPartNumbers={{jlcpcb:[assemblyParts[name]]}} schMarginRight={0.8} resistance={value} footprint="0402" pcbX={x} pcbY={y} connections={{pin1:a,pin2:b}} {...section(group)}/>;
const wire = (name:string,from:string,to:string,width="0.2mm") => <trace key={name} name={name} from={from} to={to} thickness={width}/>;
const usbTraceLabel=(name:string,pin:string,to:string):string|undefined=> {
if(to.startsWith("net."))return to.slice(4);
if(name==="J_LAPTOP" && ["A6","B6"].includes(pin))return "LAPTOP_DP";
if(name==="J_LAPTOP" && ["A7","B7"].includes(pin))return "LAPTOP_DM";
if(name==="U_USB_ISO" && pin==="DD_POS")return "ISO_USB_DP";
if(name==="U_USB_ISO" && pin==="DD_NEG")return "ISO_USB_DM";
if(name.startsWith("R_LAPTOP_CC"))return name.endsWith("1")?"LAPTOP_CC1":"LAPTOP_CC2";
const labels:Record<string,string>={R_HOST_LED:"HOST_DETECT_LED",C_PE:"PWR_ESD_CLAMP",R_BUCK_EN:"BUCK_ENABLE",C_BST:"BUCK_BOOT"};
return labels[name];
};
// Bottom-side power and switching parts keep the board inside the motor face.
const compactPlacement:Record<string,[number,number]>={
J_LAPTOP:[-6,15.3],R_LAPTOP_CC1:[-8,19],R_LAPTOP_CC2:[-4,19],
U_LAPTOP_ESD:[-8,12],C_LE:[-11,10],U_PWR_USB_GUARD:[8,11],C_UG:[11,11],
U_PWR_ESD:[8,7],C_PE:[11,7],U_USB_MUX:[-4,8],C_UM:[-1,8],
R_USB_SELECT:[-5,4],Q_HOST_DETECT:[-9,5],
D_LAPTOP_OR:[-5.3,1],D_PWR_OR:[3,5],U_LOGIC_BUCK:[7,0],R_BUCK_EN:[7,3],
C_BI:[12,0],C_BI_HF:[10,-3],C_BST:[7,-3],D_BUCK_FREEWHEEL:[3,-5],
L_LOGIC_BUCK:[7,8],C_BO:[10.5,3.25],C_BO_HF:[12.25,1.5],
R_BUCK_FB_TOP:[16,3.5],R_BUCK_FB_BOTTOM:[16.25,5.5]
};
// Named board-level traces keep cross-section selectors out of local group scopes.
function explicitConnections(node: ReactNode): ReactNode {
if(!isValidElement(node)) return node;
const el=node as ReactElement<any>;
const children=Children.map(el.props.children,explicitConnections);
const connections=el.props.connections as Record<string,string>|undefined;
const placement=compactPlacement[el.props.name];
const component=cloneElement(el,{...(["C_BI","C_BI_HF"].includes(el.props.name)?{pcbRotation:180}:{}),...(placement ? {pcbX:placement[0],pcbY:placement[1],layer:["J_LAPTOP","L_LOGIC_BUCK","C_BO","C_BO_HF"].includes(el.props.name)?"top":"bottom"} : {}),...(connections ? {connections:undefined} : {})},children);
if(!connections)return component;
return <Fragment>{component}{Object.entries(connections).map(([pin,to])=>
<trace key={`${el.props.name}_${pin}`} name={`USBREV_${el.props.name}_${pin}`} from={`.${el.props.name} > .${pin}`} to={to} schDisplayLabel={usbTraceLabel(el.props.name,pin,to)} thickness="0.2mm"/>)}</Fragment>;
}
/** Common-ground USB selection with reverse-blocking power OR. */
export const UnifiedUsbSection = () => explicitConnections(<>
<schematicsheet name="usb_laptop" displayName="Laptop USB and ESD" sheetIndex={11}>
<schematicsection name="laptop_island" displayName="Laptop connector and ESD"/>
</schematicsheet>
<schematicsheet name="usb_selection" displayName="USB Selection and PWR Data Protection" sheetIndex={12}>
<schematicsection name="usb_selection" displayName="Laptop priority and PWR protection"/>
</schematicsheet>
<schematicsheet name="logic_power" displayName="Dual Input Logic Supply" sheetIndex={13}>
<schematicsection name="logic_buck" displayName="Power OR and 3.3 V buck"/>
</schematicsheet>
<net name="LAPTOP_VBUS" isPowerNet/>
<net name="LOGIC_IN" isPowerNet/>
<net name="LOGIC_3V3" isPowerNet/>
<net name="PWR_DP"/><net name="PWR_DM"/>
<net name="PWR_SAFE_DP"/><net name="PWR_SAFE_DM"/>
<net name="USB_SELECT_PWR"/>
<MotorUsbC name="J_LAPTOP" schWidth={2.6} schHeight={4.5} schPinArrangement={{leftSide:[1,2,3,4],rightSide:[15,8,14,10,12,11,9,13,7,16],topSide:[6],bottomSide:[5]}} pcbX={-40} pcbY={16.7} pcbRotation={180} noConnect={["A8","B8"]} {...section("laptop_island")}
connections={{A4B9:"net.LAPTOP_VBUS",B4A9:"net.LAPTOP_VBUS",A1B12:"net.GND",B1A12:"net.GND",EH1:"net.GND",EH2:"net.GND",EH3:"net.GND",EH4:"net.GND",A6:".U_USB_MUX > .S0A",B6:".U_USB_MUX > .S0A",A7:".U_USB_MUX > .S0B",B7:".U_USB_MUX > .S0B"}}/>
{res("R_LAPTOP_CC1","5.1k",-48,10,".J_LAPTOP > .A5","net.GND","laptop_island")}
{res("R_LAPTOP_CC2","5.1k",-45,10,".J_LAPTOP > .B5","net.GND","laptop_island")}
<USBLC6_2SC6 name="U_LAPTOP_ESD" pcbX={-43} pcbY={6} {...section("laptop_island")} connections={{pin1:".U_USB_MUX > .S0A",pin6:".U_USB_MUX > .S0A",pin3:".U_USB_MUX > .S0B",pin4:".U_USB_MUX > .S0B",pin2:"net.GND",pin5:"net.LAPTOP_VBUS"}}/>
{cap("C_LE","100nF",-43,3,"net.LAPTOP_VBUS","net.GND","laptop_island")}
{/* WCH CH9442 v1.0: only common XA/XB have 28V OVP. Keep these toward PWR.
Main selector's common pins face the MCU, so use a separate connector guard. */}
<CH9442Q name="U_PWR_USB_GUARD" schWidth={1.65} schHeight={1.2} schPinArrangement={{leftSide:[1,2],rightSide:[5,4,7,6],topSide:[9],bottomSide:[3,8,10]}} pcbX={22} pcbY={14}
noConnect={["S1A","S1B"]} {...section("usb_selection")}
connections={{XA:"net.PWR_DP",XB:"net.PWR_DM",S0A:"net.PWR_SAFE_DP",S0B:"net.PWR_SAFE_DM",SEL:"net.GND",N_EN:"net.GND",VCC:"net.LOGIC_3V3",GND:"net.GND"}}/>
{cap("C_UG","100nF",25,14,"net.LOGIC_3V3","net.GND","usb_selection")}
<USBLC6_2SC6 name="U_PWR_ESD" pcbX={28} pcbY={11} {...section("usb_selection")} connections={{pin1:"net.PWR_SAFE_DP",pin6:"net.PWR_SAFE_DP",pin3:"net.PWR_SAFE_DM",pin4:"net.PWR_SAFE_DM",pin2:"net.GND"}}/>
{/* Internal TVS clamp reservoir; NEVER connect this 6 V clamp rail to PD VBUS. */}
{cap("C_PE","100nF",32,11,".U_PWR_ESD > .pin5","net.GND","usb_selection")}
<CH9442Q name="U_USB_MUX" schWidth={1.65} schHeight={1.2} schPinArrangement={{leftSide:[1,2],rightSide:[5,4,7,6],topSide:[9],bottomSide:[3,8,10]}} pcbX={-20} pcbY={5} {...section("usb_selection")}
connections={{VCC:"net.LOGIC_3V3",GND:"net.GND",N_EN:"net.GND",SEL:"net.USB_SELECT_PWR",S1A:"net.PWR_SAFE_DP",S1B:"net.PWR_SAFE_DM"}}/>
{wire("MUX_TO_MCU_DP",".U_USB_MUX > .XA",".MCU > .R_USB2 > .pin1")}
{wire("MUX_TO_MCU_DM",".U_USB_MUX > .XB",".MCU > .R_USB1 > .pin1")}
{cap("C_UM","100nF",-20,7.5,"net.LOGIC_3V3","net.GND","usb_selection")}
{res("R_USB_SELECT","47k",-22,-18,"net.LOGIC_3V3","net.USB_SELECT_PWR","usb_selection")}
<DTC114EETL name="Q_HOST_DETECT" pcbX={-9} pcbY={5} {...section("usb_selection")}
connections={{IN:"net.LAPTOP_VBUS",GND:"net.GND",OUT:"net.USB_SELECT_PWR"}}/>
<PMEG6020ELRX name="D_LAPTOP_OR" pcbX={-24} pcbY={0} {...section("logic_buck")} connections={{anode:"net.LAPTOP_VBUS",cathode:"net.LOGIC_IN"}}/>
<PMEG6020ELRX name="D_PWR_OR" pcbX={26} pcbY={8} {...section("logic_buck")} connections={{anode:".D_MOTOR_BLOCK > .cathode",cathode:"net.LOGIC_IN"}}/>
<LMR16006XDDCR name="U_LOGIC_BUCK" pcbX={29} pcbY={0} {...section("logic_buck")}
connections={{VIN:"net.LOGIC_IN",GND:"net.GND"}}/>
{res("R_BUCK_EN","100k",26,3,"net.LOGIC_IN",".U_LOGIC_BUCK > .SHDN","logic_buck")}
{cap("C_BI","4.7uF",24,0,"net.LOGIC_IN","net.GND","logic_buck","50V","1206")}
{cap("C_BI_HF","100nF",25,-2,"net.LOGIC_IN","net.GND","logic_buck","50V")}
{cap("C_BST","100nF",29,-3,".U_LOGIC_BUCK > .CB",".U_LOGIC_BUCK > .SW","logic_buck","16V")}
<PMEG6020ELRX name="D_BUCK_FREEWHEEL" pcbX={24} pcbY={-5} {...section("logic_buck")} connections={{anode:"net.GND",cathode:".U_LOGIC_BUCK > .SW"}}/>
<inductor name="L_LOGIC_BUCK" inductance="22uH" manufacturerPartNumber="SRN6045-220M" supplierPartNumbers={{jlcpcb:["C780213"]}} footprint="smdpads2_p4.3mm_pw2mm_ph6mm" pcbX={30} pcbY={-9} {...section("logic_buck")}
connections={{pin1:".U_LOGIC_BUCK > .SW",pin2:"net.LOGIC_3V3"}}/>
{cap("C_BO","22uF",37,-8,"net.LOGIC_3V3","net.GND","logic_buck","10V","0805")}
{cap("C_BO_HF","100nF",35,-4,"net.LOGIC_3V3","net.GND","logic_buck")}
{res("R_BUCK_FB_TOP","33.2k",34,1,"net.LOGIC_3V3",".U_LOGIC_BUCK > .FB","logic_buck")}
{res("R_BUCK_FB_BOTTOM","10k",34,3,".U_LOGIC_BUCK > .FB","net.GND","logic_buck")}
{wire("BUCK_TO_MCU","net.LOGIC_3V3",".MCU > .L_AVDD > .pin1","0.4mm")}
</>);