shibosoftwaredev/f1c100s-linux-nema17-stepper-controller
A four-layer NEMA 17 motor-controller PCB combining an Allwinner F1C100S Linux computer, USB‑PD/buck power system, W5500 Ethernet, STM32 real-time motion control, DRV8825 stepper driver, protection/temperature/current telemetry, USB interfaces, and local LED/buzzer diagnostics.
- Version
- 0.4.56
- License
- unset
- Stars
- 0
schematic-plan.ts
/** Schematic-only, sheet-local placements. No PCB coordinates or nets here. */
import refinements from "./schematic-refinements.json"
type Position = { x: number; y: number; rotation?: number; sheet?: string }
const positions: Record<string, Position> = {}
function row(names: string[], origin: { x: number; y: number; step?: number }) {
names.forEach((name, i) => { positions[name] = { x: origin.x + i * (origin.step ?? 2.1), y: origin.y } })
}
function place(name: string, position: Position) { positions[name] = position }
// 01: small local supply banks, then analog references and startup bias.
row(["C_D4", "C_B_VCC_HP", "C_D5", "C_D20", "C_D50", "C_B_VCC_IO"], { x: -14, y: 8 })
row(["C_D22", "C_D35", "C_D71", "C_B_VDD_CORE"], { x: -14, y: 3 })
row(["C_D30", "C_D31", "C_D32", "C_D34", "C_D36", "C_B_VCC_DRAM"], { x: -14, y: -2 })
row(["C_D67", "C_B_VCC_USB", "C_D73", "C_B_VCC_TV"], { x: 1.5, y: 3 })
row(["C_D80", "C_B_AVCC"], { x: 8, y: -2 })
row(["C_VRA1", "R_VRA1", "C_VRA2", "R_VRA2", "C_TV_VRN", "C_TV_VRP", "C_TV_REF"], { x: -14, y: -7, step: 4.2 })
row(["R_PU_SDMMC0_CMD", "R_PU_SDMMC0_D0", "R_PU_SDMMC0_D1", "R_PU_SDMMC0_D2", "R_PU_SDMMC0_D3", "R_PU_SPI0_CS", "R_PU_TWI0_SDA", "R_PU_TWI0_SCL"], { x: -14, y: -11.5, step: 4 })
// Put local support beside the processor bank which uses it.
place("Y1", { x: -11, y: 9, rotation: 0, sheet: "linux_io" })
place("C_OSCI", { x: -13.5, y: 8, sheet: "linux_io" })
place("C_OSCO", { x: -8.5, y: 8, sheet: "linux_io" })
place("R_RESET", { x: -14, y: 0, sheet: "linux_io" })
place("C_RESET", { x: -8, y: -3, sheet: "linux_io" })
place("R_SV_H", { x: 8, y: -6, sheet: "power_rails" })
place("R_SV_L", { x: 8, y: -9, sheet: "power_rails" })
place("C_SV_H", { x: 12, y: -6, sheet: "power_rails" })
place("C_SV_L", { x: 12, y: -9, sheet: "power_rails" })
// 02: processor units above the circuitry they actually connect to.
place("SOC_U1F", { x: -11, y: 4 })
place("SOC_U1B", { x: 0, y: 5 })
place("SOC_U1C", { x: 11, y: 5 })
place("SW_RESET", { x: -11, y: -2 })
place("U_FLASH", { x: -1, y: -2 })
place("C_FLASH", { x: 5, y: -2 })
place("R_FLASH_CS", { x: -5, y: -5 })
place("R_HOLD", { x: 1, y: -5 })
place("R_WP", { x: 5, y: -5 })
place("JP_BOOT", { x: -1, y: -8 })
// 03: unused interfaces, arranged in one row rather than scattered banks.
place("SOC_U1A", { x: -10, y: 2 })
place("SOC_U1D", { x: 1, y: 4 })
place("SOC_U1E", { x: 11, y: 4 })
// 04: POWER connector -> negotiation -> switched VBUS; conversion below.
place("J_USB_PWR", { x: -13, y: 7 })
place("U_PD", { x: -5, y: 7 })
place("C_PD_VDD", { x: -8.5, y: 3 })
place("R_PD_DEBUG", { x: -9, y: 9 })
place("R_PD_VSET", { x: -3, y: 3 })
place("R_PD_12V", { x: 0, y: 3 })
place("R_PD_ISET", { x: -5.5, y: 3 })
place("Q_VBUS", { x: 5, y: 7 })
place("R_PD_GOOD_PU", { x: 5, y: 3 })
// The DATA socket and its CC resistors get their own local section, rather
// than leaving the CC resistors on the opposite side of the power drawing.
place("J_USB_DATA", { x: 12, y: 6 })
place("R_USB_DATA_CC1", { x: 10, y: 1.5 })
place("R_USB_DATA_CC2", { x: 14, y: 1.5 })
place("U_BUCK", { x: -9, y: -5 })
place("C_BUCK_IN", { x: -14, y: -7 })
place("C_BUCK_IN_HF", { x: -11.5, y: -8.5 })
place("C_BUCK_BOOT", { x: -6, y: -3 })
place("L_BUCK", { x: -3, y: -5 })
place("C_BUCK_OUT1", { x: 1, y: -7 })
place("C_BUCK_OUT2", { x: 3.1, y: -7 })
place("R_BUCK_FF", { x: 8, y: -5 })
place("C_BUCK_FF", { x: 8, y: -8 })
place("R_BUCK_TOP", { x: 12, y: -6 })
place("R_BUCK_BOTTOM", { x: 12, y: -10 })
// 05: each regulator is read IN -> OUT with its capacitors alongside it.
place("SOC_U1G", { x: 13, y: -2 })
for (const [name, y] of [["U_3V3", 8], ["U_2V5", 3], ["U_2V8", -2], ["U_1V2", -7]] as const) {
place(name, { x: -6, y })
place(`C_${name}_IN`, { x: -11, y: y - 1.5 })
place(`C_${name}_OUT`, { x: -2, y: y - 1.5 })
}
place("U_2V5", { x:6, y:8 })
place("C_U_2V5_IN", { x:.5, y:6.5 })
place("C_U_2V5_OUT", { x:10, y:6.5 })
place("C_U_2V8_IN", { x:-11, y:-2.5 })
place("C_U_1V2_IN", { x:-11, y:-4.5 })
place("R_SV_H", { x:5, y:-6, sheet:"power_rails" })
place("R_SV_L", { x:5, y:-9, sheet:"power_rails" })
place("C_SV_H", { x:8, y:-6, sheet:"power_rails" })
place("C_SV_L", { x:8, y:-9, sheet:"power_rails" })
row(["R_V3V3_RIGHT", "R_V3V3_ETH", "R_V3V3_MOTION", "R_V3V3_MOTOR"], { x: -11, y: -11.5, step: 6 })
// 06: PHY and connector at the top, independent clock/supply banks below.
place("U_ETH", { x: -8, y: 6 })
place("J_ETH", { x: 10, y: 6 })
for (const [i, name] of ["R_ETH_TXN", "R_ETH_TXP", "R_ETH_RXN", "R_ETH_RXP"].entries()) place(name, { x: 0, y: 8 - i * 2 })
place("C_ETH_RXN_AC", { x: 5, y: 4 })
place("C_ETH_RXP_AC", { x: 5, y: 0 })
place("R_ETH_TCT", { x: 12, y: 0 })
place("C_ETH_TCT", { x: 15, y: 0 })
place("C_ETH_RCT", { x: 12, y: -2.5 })
place("R_ETH_SCLK", { x: -14, y: 6 })
place("R_ETH_RST", { x: -14, y: 3 })
place("R_ETH_INT", { x: -14, y: 0 })
row(["R_ETH_PMODE2", "R_ETH_PMODE1", "R_ETH_PMODE0"], { x: -12, y: -3, step: 3.5 })
place("Y_ETH", { x: 4, y: -3, rotation: 0 })
place("C_ETH_XI", { x: 1, y: -3.8 })
place("C_ETH_XO", { x: 7, y: -3.8 })
place("R_ETH_EXRES", { x: -12, y: -3 })
place("C_ETH_TOCAP", { x: 11, y: -6 })
place("C_ETH_1V2", { x: 15, y: -6 })
place("FB_ETH", { x: -14, y: -6 })
place("C_ETH_BULK", { x: -10, y: -6 })
row(["R_ETH_RAIL_AB", "R_ETH_RAIL_BC", "R_ETH_A_CORE", "R_ETH_A_TCT", "R_ETH_B_CORE", "R_ETH_B_CTRL", "R_ETH_B_TX"], { x: -14, y: -9.5, step: 4.6 })
row(["C_ETH_1", "C_ETH_2", "C_ETH_3", "C_ETH_4", "C_ETH_5", "C_ETH_6", "C_ETH_7"], { x: -14, y: -13, step: 4.6 })
place("C_ETH_7", { x:11.1, y:-13 })
// 07: real-time MCU, recovery/programming at left, hardware interlock right.
place("U_MOTION", { x: -2, y: 4 })
place("C_MOTION", { x: -11, y: 7 })
place("C_MOTION_BULK", { x: -8.9, y: 7 })
place("R_MOTION_RESET", { x: -11, y: 1 })
place("C_MOTION_RESET", { x: -8, y: -2 })
place("R_MOTION_BOOT", { x: 4, y: 0 })
place("Q_PD_ENABLE", { x: 11, y: 5 })
place("R_MOTION_ENABLE_PD", { x: 11, y: 1 })
row(["TP_MOTION_SWDIO", "TP_MOTION_SWCLK", "TP_MOTION_NRST", "TP_MOTION_GND"], { x: -11, y: -8, step: 7 })
// 08: power protection above the bridge; current reference and TMP102 below.
place("F_VM", { x: -12, y: 9, rotation: 0 })
place("D_VM_BLOCK", { x: -8, y: 9, rotation: 0 })
place("D_VM_TVS", { x: -4, y: 7 })
place("C_VM_BULK", { x: 0, y: 7 })
place("C_VM_CER", { x: 3, y: 7 })
place("C_VMA", { x: 7, y: 7 })
place("C_VMB", { x: 10, y: 7 })
place("U_MOTOR", { x: -1, y: 1 })
place("J_MOTOR", { x: 12, y: 1 })
place("C_VCP", { x: -12, y: 4 })
place("C_CP", { x: -9, y: 4 })
place("R_VCP", { x: -5, y: 9 })
place("R_ENABLE_PD", { x: -8, y: 0 })
place("R_FAULT_PU", { x: -7, y: -1 })
place("R_ISEN_A", { x: 5, y: -3 })
place("R_ISEN_B", { x: 8, y: -3 })
place("C_DRV_3V3", { x: -13, y: -7 })
place("R_REF_TOP", { x: -9, y: -7 })
place("R_REF_BOTTOM", { x: -6, y: -7 })
place("C_REF", { x: -3, y: -7 })
place("R_ISET_210", { x: 0, y: -7 })
place("U_TEMP", { x: 8, y: -8 })
place("C_TEMP", { x: 13, y: -8 })
place("R_TEMP_ALERT", { x: 4, y: -8 })
// 09: data flow goes buffer -> series resistor -> RGB LED, then buzzer stage.
place("U_STATUS_BUFFER", { x: -12, y: 5 })
place("R_STATUS_DATA", { x: -7, y: 5 })
place("D_STATUS", { x: -2, y: 5 })
place("R_STATUS_PD", { x: -12, y: 1 })
place("C_STATUS_BUFFER", { x: -6, y: 1 })
place("C_STATUS_LED", { x: -3.9, y: 1 })
place("BZ1", { x: 9, y: 5 })
place("D_BUZZER", { x: 13, y: 5 })
place("Q_BUZZER", { x: 9, y: 0 })
place("R_BUZZER_GATE", { x: 4, y: 0 })
place("R_BUZZER_PD", { x: 7, y: -3 })
place("C_BUZZER", { x: 13, y: -2 })
// 10: voltage divider and level-shifted status, explicitly separate functions.
place("R_PD_ADC_TOP", { x: -10, y: 7 })
place("R_PD_ADC_BOTTOM", { x: -10, y: 3 })
place("C_PD_ADC", { x: -6, y: 3 })
place("R_PD_STATUS_TOP", { x: 1, y: 7 })
place("R_PD_STATUS_BOTTOM_A", { x: 1, y: 3 })
place("R_PD_STATUS_BOTTOM_B", { x: 1, y: 0 })
place("Q_PD_STATUS", { x: 8, y: 4 })
place("R_PD_STATUS_PULLUP", { x: 12, y: 7 })
// 11: identical, aligned channels; input shunt -> amplifier -> ADC filter.
for (const [phase, y] of [["A", 6], ["B", -3]] as const) {
place(`R_INLINE_${phase}`, { x: -11, y })
place(`U_CURRENT_${phase}`, { x: -4, y })
place(`C_CURRENT_${phase}_SUPPLY`, { x: phase === "A" ? 12 : 14.1, y: 3 })
place(`R_CURRENT_${phase}_FILTER`, { x: 3, y })
place(`C_CURRENT_${phase}_FILTER`, { x: 8, y: y - 2 })
}
row(["C_VM_BULK","C_VM_CER","C_VMA","C_VMB"], { x:0,y:7 })
// 12: USB data flows left -> right; host detector is underneath the gate.
place("U_USB_ESD", { x: -10, y: 6 })
place("C_ESD", { x: -14, y: 3 })
place("U_USB_GATE", { x: 4, y: 6 })
place("C_USB_GATE", { x: 9, y: 8 })
place("Q_USB_ATTACH", { x: 0, y: -3 })
place("R_USB_BASE", { x: -6, y: -3 })
place("R_USB_BASE_PD", { x: -3, y: -6 })
place("R_USB_OE_PU", { x: 4, y: 1 })
/** Set native schematic props BEFORE symbol, port and wire generation.
* The normal tscircuit schematic router/checkers remain responsible for every
* emitted connection; no rendered JSON is moved or replaced after the fact.
*/
export function prepareSchematicPlan(board: any) {
if (board.__cleanSchematicPrepared) return
board.__cleanSchematicPrepared = true
const visit = (node: any) => {
const props = node._parsedProps
if (props && ["Group", "Subcircuit", "Board", "SchematicSection"].includes(node.componentName)) {
const local = { schX: 0, schY: 0, schTraceAutoLabelEnabled: true, schMaxTraceDistance: 2 }
node.props = { ...node.props, ...local }
Object.assign(props, local)
if (node.componentName === "SchematicSection") {
node.props = { ...node.props, displayName: undefined }
props.displayName = undefined
}
}
const position = positions[node.props?.name]
if (position && props && !["Port", "Symbol"].includes(node.componentName)) {
const refined = (refinements as Record<string,Position>)[node.props.name]
const rotation = refined?.rotation ?? position.rotation
const layout = { schX: refined?.x ?? position.x * .75, schY: refined?.y ?? position.y * .5,
...(position.sheet ? { schSheetName: position.sheet, schSectionName: undefined } : {}),
...(rotation === undefined ? {} : { schRotation: rotation, schOrientation: undefined }) }
node.props = { ...node.props, ...layout }
Object.assign(props, layout)
}
for (const child of node.children ?? []) visit(child)
}
visit(board)
}
export const schematicPositions = positions