shibosoftwaredev/f1c100s-linux-nema17-stepper-controller

Compact four-layer NEMA 17 carrier PCB combining an F1C100S Linux SoC, USB-C PD power and buck regulation, W5500 10/100 Ethernet, STM32 safety/motion control, and DRV8825 stepper-driver hardware with protection, sensing, connectors, and dual-sided SMT assembly.

Version
0.4.15
License
unset
Stars
0

motion-controller.tsx

import { Fragment } from "react"
import { STM32G030F6P6 } from "./imports/STM32G030F6P6"
import { BSS84_7_F } from "./imports/BSS84_7_F"

const wire = (name: string, from: string, to: string, thickness = 0.15) =>
  <trace name={name} from={from} to={to} thickness={thickness} />

const resistor = (name: string, value: string, lcsc: string, x: number, y: number,
  layer: "top" | "bottom" = "bottom", schX = x, schY = y) =>
  <resistor name={name} layer={layer} resistance={value} footprint="0402"
    supplierPartNumbers={{jlcpcb:[lcsc]}} pcbX={x} pcbY={y} schX={schX} schY={schY}
    schRotation={name === "R_MOTION_ENABLE_PD" ? -90 : undefined} />

const smdTestPoint = <footprint>
  <smtpad portHints={["pin1"]} pcbX={0} pcbY={0} width="1.5mm" height="1.5mm" shape="rect" />
</footprint>

/**
 * The STM32G0 owns STEP/DIR, driver enable and temperature polling. Linux sends
 * framed UART commands and a heartbeat, but never generates step pulses. The
 * MCU firmware must enable its independent watchdog and enforce a command
 * timeout. Reset/BOOT0 are driven by Linux so field firmware updates can use the
 * STM32 ROM UART bootloader. Both reset and loss of PD force the bridge asleep.
 */
export function MotionController() {
  return <group name="MOTION" pcbX={0} pcbY={0} schX={-30} schY={25.5} schSheetName="motion">
    <STM32G030F6P6 name="U_MOTION" layer="bottom" pcbX={-1.75} pcbY={2.0} pcbRotation={180}
      schX={18} schY={-22}
      noConnect={["PB7_PB8","PB9_PC14_OSC32_IN","PC15_OSC32_OUT","PA1","PB0_PB1_PB2_PA8","PB3_PB4_PB5_PB6"]} />
    <capacitor name="C_MOTION" layer="bottom" capacitance="100nF" maxVoltageRating={16} footprint="0402"
      maxDecouplingTraceLength={26}
      supplierPartNumbers={{jlcpcb:["C1525"]}} pcbX={-2.4} pcbY={7.1} pcbRotation={270}
      schX={12} schY={-20} schRotation={-90} />
    <capacitor name="C_MOTION_BULK" layer="bottom" capacitance="4.7uF" maxVoltageRating={16} footprint="0603"
      manufacturerPartNumber="CL10A475KO8NNNC" supplierPartNumbers={{jlcpcb:["C19666"]}}
      maxDecouplingTraceLength={25}
      pcbX={-17.0} pcbY={-16.3} schX={12} schY={-23} schRotation={-90} />
    {wire("MOTION_GND", ".U_MOTION > .pin5", "net.BOARD_GND", 0.3)}
    <trace name="MOTION_BYPASS_VDD" from=".C_MOTION > .pin1" to=".U_MOTION > .pin4"
      thickness={0.12} maxLength={4} pcbStraightLine />
    <trace name="MOTION_BYPASS_GND" from=".C_MOTION > .pin2" to="net.BOARD_GND"
      thickness={0.12} maxLength={4} pcbStraightLine />
    {wire("MOTION_BULK_VDD", ".C_MOTION_BULK > .pin1", ".C_MOTION > .pin1", 0.3)}
    {wire("MOTION_BULK_GND", ".C_MOTION_BULK > .pin2", "net.BOARD_GND", 0.3)}

    {/* Linux-to-MCU UART and the two programming controls. */}
    {wire("MOTION_UART_TX", ".U_MOTION > .pin9", "net.MOTION_TX")}
    {wire("MOTION_UART_RX", ".U_MOTION > .pin10", "net.MOTION_RX")}
    {wire("MOTION_NRST", ".U_MOTION > .NRST", "net.MOTION_NRST")}
    {wire("MOTION_BOOT", ".U_MOTION > .pin19", "net.MOTION_BOOT")}
    <resistor name="R_MOTION_RESET" layer="bottom" resistance="10k" footprint="0402"
      supplierPartNumbers={{jlcpcb:["C25744"]}} pcbX={-18.5} pcbY={-9.0}
      schX={22} schY={-15.8} schRotation={90} />
    <resistor name="R_MOTION_BOOT" layer="bottom" resistance="100k" footprint="0402"
      supplierPartNumbers={{jlcpcb:["C25741"]}} pcbX={15.72} pcbY={-15.5} pcbRotation={90}
      schX={24} schY={-22} schRotation={-90} />
    <capacitor name="C_MOTION_RESET" layer="bottom" capacitance="100nF" maxVoltageRating={16} footprint="0402"
      supplierPartNumbers={{jlcpcb:["C1525"]}} pcbX={24} pcbY={-25}
      schX={24} schY={-25} schRotation={-90} />
    {wire("MOTION_RESET_PULLUP", ".R_MOTION_RESET > .pin1", "net.MOTION_NRST")}
    {wire("MOTION_RESET_PULLUP_VDD", ".R_MOTION_RESET > .pin2", ".C_MOTION > .pin1")}
    {wire("MOTION_RESET_CAP", ".C_MOTION_RESET > .pin1", "net.MOTION_NRST")}
    {wire("MOTION_RESET_CAP_GND", ".C_MOTION_RESET > .pin2", "net.BOARD_GND")}
    {/* PA14 is both BOOT0 and SWCLK on this STM32G0 package. Put the Linux
        control, pulldown, MCU pin and factory pad on one explicit net. */}
    {wire("MOTION_BOOT_PULLDOWN", ".R_MOTION_BOOT > .pin1", "net.MOTION_BOOT")}
    {wire("MOTION_BOOT_PULLDOWN_GND", ".R_MOTION_BOOT > .pin2", "net.BOARD_GND")}

    {/* Timer output and safety inputs own the motor stage. */}
    {wire("MOTION_STEP", ".U_MOTION > .pin13", "net.MOTOR_STEP")}
    {wire("MOTION_DIR", ".U_MOTION > .pin14", "net.MOTOR_DIR")}
    {wire("MOTION_ENABLE_RAW", ".U_MOTION > .pin11", "net.MOTOR_ENABLE_RAW")}
    {wire("MOTION_FAULT", ".U_MOTION > .pin12", "net.MOTOR_FAULT")}
    {wire("MOTION_TEMP_ALERT", ".U_MOTION > .pin7", "net.MOTION_TEMP_ALERT")}
    {wire("MOTION_I2C_SCL", ".U_MOTION > .pin16", "net.MOTION_I2C_SCL")}
    {wire("MOTION_I2C_SDA", ".U_MOTION > .pin17", "net.MOTION_I2C_SDA")}

    {/* PG-low turns on the P-channel pass gate. Any reset leaves both sides low. */}
    <BSS84_7_F name="Q_PD_ENABLE" layer="top" pcbX={10.7} pcbY={-13.1388} pcbRotation={90}
      schX={29} schY={-18} />
    {resistor("R_MOTION_ENABLE_PD", "100k", "C25741", -9, -7.2, "bottom", 29, -21)}
    {wire("PD_GATE_SOURCE", ".Q_PD_ENABLE > .S", "net.MOTOR_ENABLE_RAW")}
    {wire("PD_GATE_DRAIN", ".Q_PD_ENABLE > .D", "net.MOTOR_ENABLE")}
    {wire("MOTION_ENABLE_RAW_PD", ".R_MOTION_ENABLE_PD > .pin1", "net.MOTOR_ENABLE_RAW")}
    {wire("MOTION_ENABLE_RAW_PD_GND", ".R_MOTION_ENABLE_PD > .pin2", "net.BOARD_GND")}

    {/* Factory/recovery access only; these are compact SMD pads, not expansion headers. */}
    {[
      ["SWDIO", ".U_MOTION > .pin18", 11],
      ["SWCLK", "net.MOTION_BOOT", 14],
      ["NRST", "net.MOTION_NRST", 17],
      ["GND", "net.BOARD_GND", 20],
    ].map(([label, target, x]) => <Fragment key={label as string}><group pcbX={0} pcbY={0} schX={0} schY={0}>
      <testpoint name={`TP_MOTION_${label}`} layer="bottom" footprint={smdTestPoint}
        pcbX={x as number} pcbY={-34} schX={x as number} schY={-34} />
      {wire(`MOTION_TP_${label}`, `.TP_MOTION_${label} > .pin1`, target as string)}
      <silkscreentext text={label as string} pcbX={x as number} pcbY={-35.5} fontSize={0.55} />
    </group></Fragment>)}

    <silkscreentext text="STM32 MOTION / WATCHDOG" pcbX={19} pcbY={-28} fontSize={0.65} />
  </group>
}