ShiboSoftwareDev/linux-gameboy-advance

A four-layer Linux handheld game-console carrier PCB built around an F1C100S SoC, USB-C and 2×AA power, LCD/microSD interfaces, flash, audio amplifier/speaker, controls, service headers, and RGB status LED.

Version
1.0.124
License
unset
Stars
0

index.circuit.tsx

import { TYPE_C_31_M_12 } from "./imports/TYPE_C_31_M_12"
import { Fragment, type ReactNode } from "react"
import { assembly, enclosure } from "@tscircuit/core"
import { StandardJstUartUpward } from "@tsci/tscircuit.standard-jst-programmer"
import { PCF8575DBR } from "./imports/PCF8575DBR"
import { SM04B_SRSS_TB_LF__SN_ } from "./imports/SM04B_SRSS_TB_LF__SN_"
import { SM06B_SRSS_TB_LF__SN_ } from "./imports/SM06B_SRSS_TB_LF__SN_"
import { footprints } from "./footprints"
import { F1C100SModule } from "./modules/f1c100s/src"
import { AFC07_S50FCC_00 } from "./handheld-imports/AFC07_S50FCC_00"
import { KH_6X6X15H_SMT_FS_D } from "./handheld-imports/KH_6X6X15H_SMT_FS_D"
import { TF_01A_Fabrication } from "./handheld-imports/TF_01A_Fabrication"
import { TPS63020DSJR } from "./imports/TPS63020DSJR/TPS63020DSJR"
import { YHNR4020_1R5M } from "./imports/YHNR4020_1R5M/YHNR4020_1R5M"
import { SS34 } from "./handheld-imports/SS34"
import { A_1812L200_16DR } from "./handheld-imports/A_1812L200_16DR"
import { SK_12E12_G5 } from "./handheld-imports/SK_12E12_G5"
import { TS6695ZJ_022 } from "./imports/TS6695ZJ_022"
import { F_1615_00026_P4_1615G2B2R4TS2_06T_001_24 as StatusRgbLed } from "./imports/F_1615_00026_P4_1615G2B2R4TS2_06T_001_24"
import { CL10A106KP8NNNC } from "./subcircuits/PowerBoost_MT3608/imports/CL10A106KP8NNNC"
import { CL05B104KO5NNNC } from "./handheld-imports/CL05B104KO5NNNC"
import { CL21A226MAQNNNE } from "./handheld-imports/CL21A226MAQNNNE"
import { CL05A105KA5NQNC } from "./handheld-imports/CL05A105KA5NQNC"
import { CL21A226MPQNNNE } from "./handheld-imports/CL21A226MPQNNNE"
import { A_0402WGF1002TCE } from "./handheld-imports/A_0402WGF1002TCE"
import { A_0402CG221J500NT } from "./handheld-imports/A_0402CG221J500NT"
import { AO3400A } from "./handheld-imports/AO3400A"
import { AO3401A } from "./subcircuits/PowerBoost_MT3608/imports/AO3401A"
import { RK10J12E002L_Fabrication as RK10J12E002L } from "./handheld-imports/RK10J12E002L_Fabrication"
import { PAM8403DR_H } from "./subcircuits/AudioAmplifier3W_PAM8403/imports/PAM8403DR_H"
import { BLM18PG121SN1D } from "./subcircuits/AudioAmplifier3W_PAM8403/imports/BLM18PG121SN1D"
import { SM02B_PASS_TBT_LF__SN_ } from "./subcircuits/AudioAmplifier3W_PAM8403/imports/SM02B_PASS_TBT_LF__SN_"
import { S2B_PH_K_S_LF__SN_ } from "./subcircuits/PowerBoost_MT3608/imports/S2B_PH_K_S_LF__SN_"
import { createCarrierAutorouter } from "./carrier-router"
import { SchematicSheets } from "./schematic/SchematicSheets"
import {
  BOARD_OUTLINE,
  GbaEnclosure,
  PCB_MOUNT_HOLES,
  PRODUCT_CONTROL_LAYOUT,
  SCREEN_CARRIER_HOLES,
  STATUS_INDICATOR_LAYOUT,
  VOLUME_CONTROL_LAYOUT,
} from "./mechanical/GbaEnclosure"
import screenAssemblyModelUrl from "./assets/er-tft035ips-6-oem-installed-v5.glb"
import sod123flModelUrl from "./assets/sod-123fl.glb"

const ground = { displayName: "GND", schDisplayLabel: "GND", maxLength: "10000mm" } as const
const v3v3 = { displayName: "3V3", schDisplayLabel: "3V3" } as const
const powerTrace = { thickness: "0.5mm" } as const
const signalTrace = { thickness: "0.12mm" } as const
const hideRef = { pcbSx: { "& silkscreentext": { visibility: "hidden" } } } as const

const CaseApertureMarker = ({
  name,
  x,
  y,
  direction,
  children,
}: {
  name: string
  x: number
  y: number
  direction: "from_above" | "from_below" | "from_top" | "from_bottom" | "from_left" | "from_right"
  children: ReactNode
}) => (
  <chip
    name={name}
    pcbX={x}
    pcbY={y}
    doNotPlace
    obstructsWithinBounds={false}
    noSchematicRepresentation
    footprint={(
      <footprint cutoutApertureDirection={direction}>
        {/* This DNP component is only an ownership anchor for an enclosure
            aperture. Its small courtyard describes the virtual anchor, not
            the much larger opening, and prevents it from masquerading as a
            missing physical footprint in PCB analysis. */}
        <courtyardrect width="2mm" height="3mm" />
      </footprint>
    )}
  >
    {children}
  </chip>
)

const schematicSheetFor = (name: string) => {
  if (/LCD_BL/.test(name)) return "backlight"
  if (/AUDIO|AMP|SPK|VOLUME/.test(name)) return "audio"
  if (/^U_(2V5|1V2|2V8)$|^C_U_/.test(name)) return "secondary_rails"
  if (/FLASH|(^|_)SD($|_)/.test(name)) return "storage"
  if (/LCD/.test(name)) return "display"
  if (/IO|UART|I2C|SPI/.test(name)) return "controls_service"
  return "usb_power"
}

const connect = (part: string, nets: string[]) => nets.map((net, index) =>
  net ? <trace key={`${part}-${index}`} name={`${part}_${index + 1}`} from={`.${part} > .pin${index + 1}`} to={`net.${net}`}
    {...(net === "BOARD_GND" ? ground : net === "V3V3" ? v3v3 : {})} /> : null)

const cap = (name: string, value: string, net: string, x: number, y: number, rotation = 0, target?: string, maxLength = 10,
  schematic?: { x: number, y: number, sheet?: string, rotation?: number }) => <>
  <capacitor name={name} capacitance={value} footprint={value === "4.7uF" ? "0805" : "0603"}
    supplierPartNumbers={{ jlcpcb: [value === "4.7uF" ? "C1779" : "C14663"] }}
    maxVoltageRating={value === "4.7uF" ? 16 : 50} pcbX={x} pcbY={y} pcbRotation={rotation}
    schX={schematic?.x ?? x} schY={schematic?.y ?? y} schRotation={schematic?.rotation ?? -90}
    schSheetName={schematic?.sheet ?? schematicSheetFor(name)} />
  <trace name={`${name}_P`} from={`.${name} > .pin1`} to={target ?? `net.${net}`} maxLength={target ? maxLength : undefined} />
  <trace name={`${name}_G`} from={`.${name} > .pin2`} to="net.BOARD_GND" {...ground} />
</>

const resistor = (name: string, value: string, a: string, b: string, x: number, y: number, rotation = 0,
  schematic?: { x: number, y: number, sheet?: string, rotation?: number }) => <>
  <resistor name={name} resistance={value} footprint="0603"
    supplierPartNumbers={{ jlcpcb: [value === "5.1k" ? "C23186" : value === "100k" ? "C25803" : "C2906982"] }}
    pcbX={x} pcbY={y} pcbRotation={rotation} schX={schematic?.x ?? x} schY={schematic?.y ?? y}
    schRotation={schematic?.rotation ?? (name.startsWith("R_FLASH") ? 90 : -90)}
    schSheetName={schematic?.sheet ?? schematicSheetFor(name)} />
  {connect(name, [a, b])}
</>

const ldoK = (name: string, voltage: string, output: string, x: number, y: number, mpn = `AP2112K-${voltage}TRG1`) => {
  const layouts = {
    U_2V5: { x: -4, inputX: -1.5, outputX: -5.5 },
    U_1V2: { x: 0, inputX: 0, outputX: 2.5 },
    U_2V8: { x: 4, inputX: 1.5, outputX: 5.5 },
  } as const
  const sch = layouts[name as keyof typeof layouts]
  return <>
  <chip name={name} manufacturerPartNumber={voltage === "1.2" ? "TPAP2112K-1.2TRG1" : mpn}
    supplierPartNumbers={{ jlcpcb: [voltage === "2.5" ? "C176945" : voltage === "1.2" ? "C49451994" : "C460327"] }}
    footprint="dfn6_missing(5)_p0.95mm_w3.5mm_pw0.5mm_pl0.9mm_pin1location(rightside,bottom)"
    pinLabels={{ pin1: "IN", pin2: "GND", pin3: "EN", pin4: "NC", pin5: "OUT" }}
    pinAttributes={{ pin1: { requiresPower: true }, pin2: { requiresGround: true }, pin3: { isInput: true }, pin4: { doNotConnect: true }, pin5: { isOutput: true } }}
    pcbX={x} pcbY={y} schX={sch.x} schY={3} schWidth={1.4} schHeight={0.6}
    schSheetName="secondary_rails" />
  {connect(name, ["V3V3", "BOARD_GND", "V3V3", "", output])}
  {cap(`C_${name}_IN`, "4.7uF", "V3V3", x + 4.2, y - 0.95, 0, `.${name} > .pin1`, 10,
    { x: sch.inputX, y: 0, sheet: "secondary_rails" })}
  {cap(`C_${name}_OUT`, "4.7uF", output, x - 4.2, y - 0.95, 180, `.${name} > .pin5`, 10,
    { x: sch.outputX, y: 0, sheet: "secondary_rails" })}
</>
}

const buttonDefinitions = [
  ["UP", -58, 9, "P00", -5, 6], ["DOWN", -58, -9, "P01", -5, 4],
  ["LEFT", -66.8, 0, "P02", -5, 2], ["RIGHT", -49, 0, "P03", -5, 0],
  ["A", 58, -9, "P04", 5, 6], ["B", 66.8, 0, "P05", 5, 4],
  ["X", 49, 0, "P06", 5, 2], ["Y", 58, 9, "P07", 5, 0],
  ["SELECT", PRODUCT_CONTROL_LAYOUT.select.x, PRODUCT_CONTROL_LAYOUT.select.y, "P10", -5, -2],
  ["START", PRODUCT_CONTROL_LAYOUT.start.x, PRODUCT_CONTROL_LAYOUT.start.y, "P11", 5, -2],
] as const

const Button = ({ label, x, y, io, schX, schY }: { label: string, x: number, y: number, io: string, schX: number, schY: number }) => <>
  <KH_6X6X15H_SMT_FS_D name={`SW_${label}`} pcbX={x} pcbY={y} schX={schX} schY={schY}
    schPinArrangement={{ leftSide: ["pin1", "pin2"], bottomSide: ["pin3", "pin4"] }}
    schWidth={0.8} schHeight={0.8} schSheetName="controls_service" {...hideRef}>
    <enclosure.cutoutaperture shape="circle" radius="2mm" margin="0.25mm" depth="14mm" />
  </KH_6X6X15H_SMT_FS_D>
  <trace name={`${label}_A`} from={`.SW_${label} > .pin1`} to={`.U_IO > .${io}`} {...signalTrace} />
  <trace name={`${label}_A_PAIR`} from={`.SW_${label} > .pin2`} to={`.U_IO > .${io}`} {...signalTrace} />
  <trace name={`${label}_G_PAIR`} from={`.SW_${label} > .pin3`} to={`.SW_${label} > .pin4`} />
  <trace name={`${label}_G`} from={`.SW_${label} > .pin4`} to="net.BOARD_GND" {...ground} />
  <silkscreentext text={label} fontSize="1.25mm" pcbX={x} pcbY={y - 4.7} />
</>

/** Mid-length right-angle shoulder controls from the original TS66xxZJ family.
 * The 9.5 mm actuator sits between the former 6.5 and 13.5 mm choices. The
 * housing finishes flush with the +Y board edge and only the round stem
 * projects through the enclosure. */
const ShoulderButton = ({ label, x, io }: { label: "L" | "R", x: number, io: "P12" | "P13" }) => <>
  <TS6695ZJ_022 name={`SW_${label}`} pcbX={x} pcbY={PRODUCT_CONTROL_LAYOUT.shoulderY} pcbRotation={0}
    schX={label === "L" ? -5 : 5} schY={-4} schSheetName="controls_service"
    noConnect={["pin3", "pin4"]} {...hideRef}>
    <enclosure.cutoutaperture shape="circle" radius="1.3mm" margin="0.25mm" depth="8mm" />
  </TS6695ZJ_022>
  {/* The normally-open contact is non-polarized. Assigning pin 1 to the GPIO
      keeps the reviewed physical signal/ground escape sides unchanged after
      moving from the reversed 6.5 mm footprint to this 9.5 mm footprint. */}
  <trace name={`${label}_A`} from={`.SW_${label} > .pin1`} to={`.U_IO > .${io}`} {...signalTrace} />
  <trace name={`${label}_G`} from={`.SW_${label} > .pin2`} to="net.BOARD_GND" {...ground} />
  <silkscreentext text={`${label} SHOULDER`} fontSize="0.9mm" pcbX={x} pcbY={29.7} />
</>

export default () => (
  <assembly.device name="LINUX_GBA">
  <board name="MAIN_BOARD" title="F1C100S Linux Game Boy Advance" width="144.5mm" height="84.27mm" layers={4} thickness="1.6mm"
    minTraceWidth="0.12mm" minViaHoleDiameter="0.3mm" minViaPadDiameter="0.45mm"
    pcbStyle={{ viaHoleDiameter: "0.3mm", viaPadDiameter: "0.45mm" }}
    isViaInPadAllowed
    minTraceToPadEdgeClearance="0.10mm" minPadEdgeToPadEdgeClearance="0.10mm" minViaEdgeToPadEdgeClearance="0.10mm"
    minViaHoleEdgeToViaHoleEdgeClearance="0.20mm" minPlatedHoleDrillEdgeToDrillEdgeClearance="0.45mm"
    routeRemaining
    autorouter={{ local: true, algorithmFn: createCarrierAutorouter }}
    schLayout={{ layoutMode: "relative" }} schTraceAutoLabelEnabled schMaxTraceDistance={2.5}
    outline={BOARD_OUTLINE}>
    {/* Physical carrier routing is replayed by terminal identity so schematic
        sheet labels cannot invalidate the reviewed copper solution. */}
    <SchematicSheets />
    <net name="BOARD_GND" isGroundNet />
    <net name="USB_VBUS" isPowerNet /><net name="BAT_RAW" isPowerNet /><net name="BAT_FUSED" isPowerNet />
    <net name="BAT_SWITCHED" isPowerNet /><net name="BAT_GATE" /><net name="SYS_IN" isPowerNet /><net name="V3V3" isPowerNet />
    <net name="V2V8" isPowerNet /><net name="V2V5" isPowerNet /><net name="V1V2" isPowerNet />
    <net name="AUDIO_L" /><net name="I2C_SDA" /><net name="I2C_SCL" />
    <net name="SPI1_CS" /><net name="SPI1_MOSI" /><net name="SPI1_MISO" /><net name="SPI1_SCLK" />
    <net name="STATUS_RED_N" /><net name="STATUS_GREEN_N" /><net name="STATUS_BLUE_N" />

    <F1C100SModule name="SOC" layoutProfile="lcd_top_storage_right" minViaHoleDiameter={0.3}
      pcbX={0} pcbY={0} schX={0} schY={0} schSheetName="soc_interfaces"
      connections={{
        GND: "net.BOARD_GND", VDD_CORE: "net.V1V2", VCC_DRAM: "net.V2V5", VCC_IO: "net.V3V3", VCC_USB: "net.V3V3",
        AVCC: "net.V2V8", VCC_HP: "net.V3V3", VCC_TV: "net.V3V3",
        SPI0_CLK: "net.FLASH_CLK", SPI0_CS: "net.SOC_FLASH_CS", SPI0_MOSI: "net.FLASH_MOSI", SPI0_MISO: "net.FLASH_MISO",
        SDMMC0_CLK: ".J_SD > .CLK", SDMMC0_CMD: ".J_SD > .CMD", SDMMC0_D0: ".J_SD > .DAT0",
        SDMMC0_D1: ".J_SD > .DAT1", SDMMC0_D2: ".J_SD > .DAT2", SDMMC0_D3: ".J_SD > .CD_DAT3",
        LCD_CLK: ".J_LCD > .pin13", LCD_DE: ".J_LCD > .pin14", LCD_HSYNC: ".J_LCD > .pin12", LCD_VSYNC: ".J_LCD > .pin11",
        LCD_D2: ".J_LCD > .pin15", LCD_D3: ".J_LCD > .pin16", LCD_D4: ".J_LCD > .pin17", LCD_D5: ".J_LCD > .pin18",
        LCD_D6: ".J_LCD > .pin19", LCD_D7: ".J_LCD > .pin20", LCD_D10: ".J_LCD > .pin21", LCD_D11: ".J_LCD > .pin22",
        LCD_D12: ".J_LCD > .pin23", LCD_D13: ".J_LCD > .pin24", LCD_D14: ".J_LCD > .pin25", LCD_D15: ".J_LCD > .pin26",
        LCD_D18: ".J_LCD > .pin27", LCD_D19: ".J_LCD > .pin28", LCD_D20: ".J_LCD > .pin29", LCD_D21: ".J_LCD > .pin30",
        LCD_D22: ".J_LCD > .pin31", LCD_D23: ".J_LCD > .pin32",
        TWI0_SDA: "net.I2C_SDA", TWI0_SCL: "net.I2C_SCL", PE2: ".U_IO > .N_INT", PE3: ".J_LCD > .pin47",
        PE4: ".J_LCD > .pin46", PE5: ".J_LCD > .pin10", PE6: ".J_LCD > .pin37", PE7: "net.SPI1_CS",
        PE8: "net.SPI1_MOSI", PE9: "net.SPI1_SCLK", PE10: "net.SPI1_MISO",
        UART0_TX: "net.UART_TX", UART0_RX: "net.UART_RX", USB_DM: "net.USB_N", USB_DP: "net.USB_P",
        RESET: "net.RESET_N", HPL: "net.AUDIO_L",
      }} />

    <AFC07_S50FCC_00 name="J_LCD" pcbX={40.8} pcbY={15} pcbRotation={270} schX={0} schY={3}
      schSheetName="display"
      noConnect={["pin4", "pin5", "pin6", "pin39"]} {...hideRef} />
    {connect("J_LCD", [
      "LCD_LED_A", "LCD_LED_K", "LCD_LED_K", "", "", "", "V3V3", "BOARD_GND", "V3V3", "", "", "", "", "", "", "", "", "", "", "",
      "", "", "", "", "", "", "", "", "", "", "", "", "", "", "V3V3", "", "", "", "", "V3V3", "V3V3", "V3V3", "BOARD_GND",
      "I2C_SCL", "I2C_SDA", "", "", "BOARD_GND", "BOARD_GND", "BOARD_GND", "BOARD_GND", "BOARD_GND",
    ])}
    {/* The panel's serial-init pins share SPI1 with the service connector.
        External SPI hardware must be disconnected during panel initialization. */}
    <trace name="LCD_SPI1_MISO" from=".J_LCD > .pin33" to="net.SPI1_MISO" />
    <trace name="LCD_SPI1_MOSI" from=".J_LCD > .pin34" to="net.SPI1_MOSI" />
    <trace name="LCD_SPI1_SCLK" from=".J_LCD > .pin36" to="net.SPI1_SCLK" />
    <trace name="LCD_SPI1_CS" from=".J_LCD > .pin38" to="net.SPI1_CS" />
    <capacitor name="C_LCD_VDDI" capacitance="1uF" footprint="0603" supplierPartNumbers={{ jlcpcb: ["C15849"] }} pcbX={34.5} pcbY={22} schX={-0.75} schY={-1} schRotation={-90} schSheetName="display" />
    <capacitor name="C_LCD_VCI" capacitance="1uF" footprint="0603" supplierPartNumbers={{ jlcpcb: ["C15849"] }} pcbX={34.5} pcbY={25} schX={0.75} schY={-1} schRotation={-90} schSheetName="display" />
    <trace name="LCD_VDDI_CAP" from=".C_LCD_VDDI > .pin1" to=".J_LCD > .pin40" maxLength="10mm" />
    <trace name="LCD_VDDI_CAP_GND" from=".C_LCD_VDDI > .pin2" to="net.BOARD_GND" {...ground} />
    <trace name="LCD_VCI_CAP" from=".C_LCD_VCI > .pin1" to=".J_LCD > .pin42" maxLength="10mm" />
    <trace name="LCD_VCI_CAP_GND" from=".C_LCD_VCI > .pin2" to="net.BOARD_GND" {...ground} />
    {/* Legacy resistor/MOSFET pads are retained as unpopulated isolation and
        landing points so the reviewed carrier routing stays deterministic. */}
    <resistor name="R_LCD_LED" resistance="4.7" footprint="1206" supplierPartNumbers={{ jlcpcb: ["C414936"] }} pcbX={33.5} pcbY={7} schX={-12} schY={4} schRotation={-90} schSheetName="backlight" doNotPlace />
    <AO3400A name="Q_LCD_BL" pcbX={33.5} pcbY={2.5} pcbRotation={90} schX={-9} schY={4} schSheetName="backlight" doNotPlace {...hideRef} />
    <A_0402WGF1002TCE name="R_LCD_BL_PD" pcbX={30.5} pcbY={0} pcbRotation={90} schX={-7} schY={4} schRotation={-90} schSheetName="backlight" doNotPlace {...hideRef} />
    <trace name="LCD_LED_SOURCE" from="net.V3V3" to=".R_LCD_LED > .pin1" {...powerTrace} {...v3v3} />
    <trace name="LCD_LED_ANODE" from=".R_LCD_LED > .pin2" to=".J_LCD > .pin1" />
    <trace name="LCD_LED_K2" from=".J_LCD > .pin2" to=".Q_LCD_BL > .D" />
    <trace name="LCD_LED_K3" from=".J_LCD > .pin3" to=".Q_LCD_BL > .D" />
    <trace name="LCD_BL_SOURCE_GND" from=".Q_LCD_BL > .S" to="net.BOARD_GND" {...ground} />
    <trace name="LCD_BL_GATE" from=".Q_LCD_BL > .G" to="net.V3V3" {...v3v3} />
    <trace name="LCD_BL_PULLDOWN" from=".R_LCD_BL_PD > .pin1" to=".Q_LCD_BL > .G" />
    <trace name="LCD_BL_PULLDOWN_G" from=".R_LCD_BL_PD > .pin2" to="net.BOARD_GND" {...ground} />

    {/* The real C91145 CAD model reaches 9.50131085 mm from its origin to the
        card-entry face. This center puts that face exactly on x=72.25 while
        keeping the full rigid housing on the PCB. */}
    <TF_01A_Fabrication name="J_SD" pcbX={62.74868915} pcbY={22} pcbRotation={90} schX={-10.51} schY={2}
      schWidth={2.045} schHeight={1.55}
      schPinArrangement={{
        leftSide: ["pin1", "pin2", "pin3", "pin5"],
        rightSide: ["pin7", "pin8", "pin9"],
        topSide: ["pin4"],
        bottomSide: ["pin6", "pin10", "pin11", "pin12", "pin13"],
      }} schSheetName="storage" noConnect={["CD"]} {...hideRef}>
      <enclosure.cutoutaperture shape="rect" width="14.5mm" height="2.3mm" margin="0.3mm" depth="12mm" />
    </TF_01A_Fabrication>
    {connect("J_SD", ["", "", "", "V3V3", "", "BOARD_GND", "", "", "", "BOARD_GND", "BOARD_GND", "BOARD_GND", "BOARD_GND"])}
    <CL05B104KO5NNNC name="C_SD" pcbX={49.5} pcbY={21} pcbRotation={90} schX={-3.57} schY={0} schRotation={-90} schSheetName="storage" {...hideRef} />
    {/* The planar path remains under 10 mm. The route-length checker also
        counts both 1.6 mm via barrels, so allow their vertical contribution. */}
    <trace name="SD_CAP_P" from=".C_SD > .pin1" to=".J_SD > .VDD" maxLength="15mm" />
    <trace name="SD_CAP_G" from=".C_SD > .pin2" to="net.BOARD_GND" {...ground} />

    <chip name="U_FLASH" manufacturerPartNumber="W25Q128JVSIQ" supplierPartNumbers={{ jlcpcb: ["C113767"] }} footprint={footprints.flash}
      pinLabels={{ pin1: "CS_N", pin2: "DO", pin3: "WP_N", pin4: "GND", pin5: "DI", pin6: "CLK", pin7: "HOLD_N", pin8: "VCC" }}
      pinAttributes={{ pin4: { requiresGround: true }, pin8: { requiresPower: true } }}
      schPinArrangement={{ leftSide: ["pin1", "pin2", "pin3"], rightSide: ["pin5", "pin6", "pin7"], topSide: ["pin8"], bottomSide: ["pin4"] }}
      cadModel={{
        objUrl: "https://modelcdn.tscircuit.com/easyeda_models/assets/C97521.obj?uuid=4652e19b90fa4dbb8662aa4cba61a532",
        stepUrl: "https://modelcdn.tscircuit.com/easyeda_models/assets/C97521.step?uuid=4652e19b90fa4dbb8662aa4cba61a532",
        pcbRotationOffset: 90,
        modelOriginPosition: { x: 0.000012700000070253736, y: -0.000012699999956566899, z: -0.069425 },
      }} pcbX={23} pcbY={-6} schX={-2.92} schY={2} schWidth={1.723} schHeight={1.17} schSheetName="storage" />
    {connect("U_FLASH", ["FLASH_CS", "FLASH_MISO", "FLASH_WP", "BOARD_GND", "FLASH_MOSI", "FLASH_CLK", "FLASH_HOLD", "V3V3"])}
    {cap("C_FLASH", "100nF", "V3V3", 29, -5, 90, ".U_FLASH > .pin8", 10,
      { x: -2, y: 0, sheet: "storage" })}
    {resistor("R_FLASH_WP", "10k", "FLASH_WP", "V3V3", 31, -9, 0,
      { x: 4, y: 1, sheet: "storage", rotation: 90 })}
    {resistor("R_FLASH_HOLD", "10k", "FLASH_HOLD", "V3V3", 29, -11.5, 0,
      { x: 7, y: 1, sheet: "storage", rotation: 90 })}
    {resistor("R_FLASH_CS", "10k", "FLASH_CS", "V3V3", 23, -12, 0,
      { x: 4, y: 5, sheet: "storage", rotation: 90 })}
    {/* Normally-open copper-only boot selector. Bridge with solder for SPI
        flash boot; leave open for FEL recovery. It is deliberately DNP and
        has no 3D body or enclosure access hole. */}
    <solderjumper name="JP_BOOT" footprint="solderjumper2_p2.54_pw1.5_ph1.5"
      pinCount={2} bridged={false} doNotPlace
      pinLabels={{ pin1: "SOC_CS", pin2: "FLASH_CS" }}
      pcbX={-49.27} pcbY={18} schX={8} schY={6} schSheetName="storage" />
    {connect("JP_BOOT", ["SOC_FLASH_CS", "FLASH_CS"])}

    {/* Start/Select occupy the ergonomic centre below the display.  Their pair
        is biased 6.5 mm left of the PCB datum to retain the proven I/O-expander
        fanout while remaining well separated from both hand controls. */}
    <PCF8575DBR name="U_IO" pcbX={12} pcbY={-24} pcbRotation={0} schX={0} schY={2} schSheetName="controls_service"
      noConnect={["P17"]} {...hideRef} />
    <trace name="IO_VCC" from=".U_IO > .VCC" to="net.V3V3" {...v3v3} /><trace name="IO_GND" from=".U_IO > .GND" to="net.BOARD_GND" {...ground} />
    <trace name="IO_SDA" from=".U_IO > .SDA" to="net.I2C_SDA" /><trace name="IO_SCL" from=".U_IO > .SCL" to="net.I2C_SCL" />
    <trace name="IO_A0" from=".U_IO > .A0" to="net.BOARD_GND" {...ground} /><trace name="IO_A1" from=".U_IO > .A1" to="net.BOARD_GND" {...ground} />
    <trace name="IO_A2" from=".U_IO > .A2" to="net.BOARD_GND" {...ground} />
    <CL05B104KO5NNNC name="C_IO" pcbX={6.5} pcbY={-17.5} pcbRotation={270} schX={-3} schY={2} schRotation={-90} schSheetName="controls_service" {...hideRef} />
    <trace name="IO_CAP_P" from=".C_IO > .pin1" to=".U_IO > .VCC" maxLength="10mm" /><trace name="IO_CAP_G" from=".C_IO > .pin2" to="net.BOARD_GND" {...ground} />
    {buttonDefinitions.map(([label, x, y, io, schX, schY]) => <Button key={label} label={label} x={x} y={y} io={io} schX={schX} schY={schY} />)}
    <ShoulderButton label="L" x={-45} io="P12" />
    <ShoulderButton label="R" x={45} io="P13" />

    <TYPE_C_31_M_12 name="J_USB" pcbX={0} pcbY={-36.5} pcbRotation={0}
      schX={-10} schY={-2} schWidth={1.575} schSheetName="usb_power">
      <enclosure.cutoutaperture shape="pill" width="9.2mm" height="3.2mm" margin="0.35mm" depth="10mm" />
    </TYPE_C_31_M_12>
    {connect("J_USB", ["BOARD_GND", "BOARD_GND", "BOARD_GND", "BOARD_GND", "", "USB_CC1", "USB_N", "USB_P", "", "", "", "USB_CC2", "BOARD_GND", "BOARD_GND", "USB_VBUS", "USB_VBUS"])}
    <trace name="USB_DM_REVERSIBLE" from=".J_USB > .pin7" to=".J_USB > .pin9" maxLength={4} />
    <trace name="USB_DP_REVERSIBLE" from=".J_USB > .pin8" to=".J_USB > .pin10" maxLength={4} />
    {resistor("R_CC1", "5.1k", "USB_CC1", "BOARD_GND", 7.5, -36, 0, { x: -13, y: -4, sheet: "usb_power" })}
    {resistor("R_CC2", "5.1k", "USB_CC2", "BOARD_GND", 7.5, -33.5, 0, { x: -13, y: -6, sheet: "usb_power" })}
    <chip name="U_USB_ESD" manufacturerPartNumber="USBLC6-2SC6" supplierPartNumbers={{ jlcpcb: ["C7519"] }} footprint="sot23_6"
      cadModel={{
        objUrl: "https://modelcdn.tscircuit.com/easyeda_models/assets/C7519.obj?uuid=229b69761e2c45dba6a83d8866dec72d",
        stepUrl: "https://modelcdn.tscircuit.com/easyeda_models/assets/C7519.step?uuid=229b69761e2c45dba6a83d8866dec72d",
        pcbRotationOffset: 90,
        modelOriginPosition: { x: -0.000012700000070253736, y: 0.000012700000070253736, z: -0.048939 },
      }}
      pinLabels={{ pin1: "DM1", pin2: "GND", pin3: "DP1", pin4: "DP2", pin5: "VBUS", pin6: "DM2" }} pcbX={-6} pcbY={-31} pcbRotation={0} schX={-6} schY={-2} schSheetName="usb_power" />
    {connect("U_USB_ESD", ["USB_N", "BOARD_GND", "USB_P", "USB_P", "USB_VBUS", "USB_N"])}
    {cap("C_USB_ESD", "100nF", "USB_VBUS", -10, -31, 90, ".U_USB_ESD > .pin5", 15,
      { x: -6, y: -5, sheet: "usb_power" })}

    <S2B_PH_K_S_LF__SN_ name="J_BAT" pcbX={-40} pcbY={-37.4} pcbRotation={270} schX={-11} schY={4}
      schPinArrangement={{ topSide: ["pin1"], bottomSide: ["pin2"] }} schSheetName="usb_power" {...hideRef} />
    <cutout
      name="BAT_CABLE_SLOT"
      shape="polygon"
      pcbX={-25}
      pcbY={-37}
      points={[
        { x: -2.5, y: -5.5 }, { x: 2.5, y: -5.5 }, { x: 2.5, y: 3 },
        { x: 2.415, y: 3.647 }, { x: 2.165, y: 4.25 }, { x: 1.768, y: 4.768 },
        { x: 1.25, y: 5.165 }, { x: 0.647, y: 5.415 }, { x: 0, y: 5.5 },
        { x: -0.647, y: 5.415 }, { x: -1.25, y: 5.165 }, { x: -1.768, y: 4.768 },
        { x: -2.165, y: 4.25 }, { x: -2.415, y: 3.647 }, { x: -2.5, y: 3 },
      ]}
    />
    <silkscreentext text="BAT CABLE" fontSize="0.7mm" pcbX={-25} pcbY={-28.5} />
    <silkscreentext text="BOOT" fontSize="0.8mm" pcbX={-55} pcbY={19.7} />
    <trace name="BAT_POS" from=".J_BAT > .pin1" to="net.BAT_RAW" {...powerTrace} /><trace name="BAT_NEG" from=".J_BAT > .pin2" to="net.BOARD_GND" {...powerTrace} {...ground} />
    <A_1812L200_16DR name="F_BAT" pcbX={-38} pcbY={-31} schX={-8.18} schY={4}
      schPinArrangement={{ topSide: ["pin1"], bottomSide: ["pin2"] }} schSheetName="usb_power" {...hideRef} />
    <trace name="BAT_FUSE_IN" from="net.BAT_RAW" to=".F_BAT > .pin1" {...powerTrace} /><trace name="BAT_FUSE_OUT" from=".F_BAT > .pin2" to="net.BAT_FUSED" {...powerTrace} />
    {/* Put the power slider on the straight left wall rather than the rounded
        lower corner. With the real C136720 CAD origin, x=-68.983 leaves the
        housing face 0.50 mm inside the PCB while the actuator points left and
        remains 4.50 mm proud of the edge. */}
    <SK_12E12_G5 name="J_PWR_SW" pcbX={-68.983} pcbY={-24} pcbRotation={180} schX={-4.82} schY={4} schHeight={0.6} schSheetName="usb_power" noConnect={["pin3"]} {...hideRef}>
      <enclosure.cutoutaperture shape="rect" width="6.2mm" height="3.4mm" margin="0.3mm" depth="10mm" />
    </SK_12E12_G5>
    <trace name="BAT_SWITCH_IN" from="net.BAT_FUSED" to=".J_PWR_SW > .pin1" {...powerTrace} /><trace name="BAT_SWITCH_OUT" from=".J_PWR_SW > .pin2" to="net.BAT_SWITCHED" {...powerTrace} />
    <trace name="BAT_SWITCH_G1" from=".J_PWR_SW > .pin4" to="net.BOARD_GND" {...ground} /><trace name="BAT_SWITCH_G2" from=".J_PWR_SW > .pin5" to="net.BOARD_GND" {...ground} />
    {/* USB asserts the P-channel gate high through 100 kΩ and disconnects the
        battery.  With USB absent, the 1 MΩ pull-down enables the battery path.
        This avoids wasting the voltage of two AA cells in a Schottky diode. */}
    <resistor name="R_BAT_GATE_USB" resistance="100k" footprint="0603"
      manufacturerPartNumber="0603WAF1003T5E" supplierPartNumbers={{ jlcpcb: ["C25803"] }}
      pcbX={-31} pcbY={-31} pcbRotation={0} schX={1} schY={4} schRotation={-90}
      schSheetName="usb_power" />
    <SS34 name="D_USB_OR" pcbX={-18} pcbY={-32} pcbRotation={0} schX={1} schY={8} schRotation={90} schSheetName="usb_power" {...hideRef} />
    <trace name="BAT_GATE_USB" from="net.USB_VBUS" to=".R_BAT_GATE_USB > .pin1" />
    <trace name="BAT_GATE_DRIVE" from=".R_BAT_GATE_USB > .pin2" to="net.BAT_GATE" />
    {/* The connector and ESD-device escapes use short 0.20/0.25 mm necks;
        the reviewed trunk is 0.50 mm. Avoid declaring a false 0.50 mm
        minimum across the complete merged VBUS net. */}
    <trace name="USB_OR_IN" from="net.USB_VBUS" to=".D_USB_OR > .anode" /><trace name="USB_OR_OUT" from=".D_USB_OR > .cathode" to="net.SYS_IN" {...powerTrace} />

    <TPS63020DSJR name="U_BUCK_3V3" pcbX={-25} pcbY={-20} pcbRotation={0}
      schX={1.6} schY={1} schWidth={2.055} schHeight={1.6} schSheetName="usb_power"
      noConnect={["PG"]} {...hideRef} />
    <YHNR4020_1R5M name="L_BUCK_3V3" pcbX={-19} pcbY={-20} pcbRotation={0}
      schX={5.31} schY={1} schSheetName="usb_power" {...hideRef} />
    <capacitor name="C_BUCK_IN" capacitance="10uF" maxVoltageRating={25}
      manufacturerPartNumber="CL21A106KAYNNNE" supplierPartNumbers={{ jlcpcb: ["C15850"] }}
      footprint="0805" cadModel={{
        objUrl: "https://modelcdn.tscircuit.com/easyeda_models/assets/C15850.obj?uuid=b87ab0c5465a48b3a1c9a6dac8d30bc5",
        stepUrl: "https://modelcdn.tscircuit.com/easyeda_models/assets/C15850.step?uuid=b87ab0c5465a48b3a1c9a6dac8d30bc5",
        pcbRotationOffset: 0,
        modelOriginPosition: { x: 0, y: -0.000012700000070253736, z: -0.65 },
      }} pcbX={-25} pcbY={-15.5} pcbRotation={90} schX={0} schY={-2} schRotation={-90}
      schSheetName="usb_power" />
    <capacitor name="C_BUCK_IN_B" capacitance="10uF" maxVoltageRating={25}
      manufacturerPartNumber="CL21A106KAYNNNE" supplierPartNumbers={{ jlcpcb: ["C15850"] }}
      footprint="0805" pcbX={-28} pcbY={-15.5} pcbRotation={90}
      schX={1.5} schY={-2} schRotation={-90} schSheetName="usb_power" />
    <CL21A226MAQNNNE name="C_BUCK_OUT_A" pcbX={-24} pcbY={-25.5} pcbRotation={270} schX={9} schY={-1} schRotation={-90} schSheetName="usb_power" {...hideRef} />
    <CL21A226MAQNNNE name="C_BUCK_OUT_B" pcbX={-27} pcbY={-25.5} pcbRotation={270} schX={10.5} schY={-1} schRotation={-90} schSheetName="usb_power" {...hideRef} />
    {/* Feed the converter through the input capacitor pad so the high-current
        path reaches the ceramic reservoir before the fine-pitch IC escape.
        The 0.5 mm trunk is necked to 0.12 mm only at the 0.5 mm-pitch DSJ
        package; declaring a 0.5 mm minimum on those necks would be physically
        impossible and would short adjacent pads. */}
    <trace name="BUCK_INPUT" from="net.SYS_IN" to=".C_BUCK_IN > .pin1" maxLength="100mm" />
    <trace name="BUCK_INPUT_PAIR" from=".U_BUCK_3V3 > .VIN1" to=".U_BUCK_3V3 > .VIN2" />
    {/* Keep VINA on the filtered input-capacitor node.  Routing it to VIN2
        would cross the exposed PGND comb in the DSJ package. */}
    <trace name="BUCK_ANALOG_INPUT" from=".U_BUCK_3V3 > .VINA" to=".C_BUCK_IN_B > .pin1" maxLength="10mm" />
    <trace name="BUCK_ENABLE" from=".U_BUCK_3V3 > .EN" to=".U_BUCK_3V3 > .VIN2" />
    <trace name="BUCK_GND" from=".U_BUCK_3V3 > .GND" to="net.BOARD_GND" {...ground} />
    <trace name="BUCK_POWER_GND" from=".U_BUCK_3V3 > .PGND" to=".U_BUCK_3V3 > .GND" {...ground} />
    <trace name="BUCK_POWER_SAVE" from=".U_BUCK_3V3 > .PS" to=".U_BUCK_3V3 > .GND" {...ground} />
    <trace name="BUCK_INPUT_CAP" from=".C_BUCK_IN > .pin1" to=".U_BUCK_3V3 > .VIN1" maxLength="10mm" />
    <trace name="BUCK_INPUT_CAP_GND" from=".C_BUCK_IN > .pin2" to="net.BOARD_GND" {...ground} />
    <trace name="BUCK_INPUT_CAP_B" from=".C_BUCK_IN_B > .pin1" to=".U_BUCK_3V3 > .VIN2" maxLength="10mm" />
    <trace name="BUCK_INPUT_CAP_B_GND" from=".C_BUCK_IN_B > .pin2" to="net.BOARD_GND" {...ground} />
    <trace name="BUCK_L1_PAIR" from=".U_BUCK_3V3 > .L11" to=".U_BUCK_3V3 > .L12" />
    <trace name="BUCK_L1" from=".U_BUCK_3V3 > .L11" to=".L_BUCK_3V3 > .pin1" maxLength="10mm" />
    <trace name="BUCK_L2_PAIR" from=".U_BUCK_3V3 > .L21" to=".U_BUCK_3V3 > .L22" />
    <trace name="BUCK_L2" from=".L_BUCK_3V3 > .pin2" to=".U_BUCK_3V3 > .L21" maxLength="10mm" />
    <trace name="BUCK_OUTPUT_PAIR" from=".U_BUCK_3V3 > .VOUT1" to=".U_BUCK_3V3 > .VOUT2" />
    <trace name="BUCK_OUTPUT" from=".C_BUCK_OUT_A > .pin1" to="net.V3V3" maxLength="100mm" {...v3v3} />
    {/* Width is enforced on the two reviewed saved routes and asserted by verify.mjs.
        Omitting min_trace_thickness here avoids core attributing unrelated 0.12 mm
        V3V3 fanout branches to these merged-net source traces. */}
    <trace name="BUCK_OUTPUT_CAP_A" from=".C_BUCK_OUT_A > .pin1" to=".U_BUCK_3V3 > .VOUT1" maxLength="10mm" />
    <trace name="BUCK_OUTPUT_CAP_B" from=".C_BUCK_OUT_B > .pin1" to=".U_BUCK_3V3 > .VOUT2" maxLength="10mm" />
    <trace name="BUCK_OUTPUT_CAP_A_G" from=".C_BUCK_OUT_A > .pin2" to="net.BOARD_GND" {...ground} /><trace name="BUCK_OUTPUT_CAP_B_G" from=".C_BUCK_OUT_B > .pin2" to="net.BOARD_GND" {...ground} />

    {ldoK("U_2V5", "2.5", "V2V5", -22, 11)}{ldoK("U_1V2", "1.2", "V1V2", -33, 4)}{ldoK("U_2V8", "2.8", "V2V8", -33, 13, "AP2127K-2.8TRG1")}

    <chip name="SW_RESET" footprint={footprints.reset} manufacturerPartNumber="TL3342F160QG" supplierPartNumbers={{ jlcpcb: ["C2886898"] }}
      cadModel={{
        objUrl: "https://modelcdn.tscircuit.com/easyeda_models/assets/C2886898.obj?uuid=4a64872a881b4ebbb48f92ea6bd596be",
        stepUrl: "https://modelcdn.tscircuit.com/easyeda_models/assets/C2886898.step?uuid=4a64872a881b4ebbb48f92ea6bd596be",
        pcbRotationOffset: 0,
        modelOriginPosition: { x: 0.00005080000005364127, y: 0, z: -0.05 },
      }} pinLabels={{ pin1: "RESET", pin2: "GND" }} pcbX={-38} pcbY={-12} schX={0} schY={7} schSheetName="controls_service" />
    {connect("SW_RESET", ["RESET_N", "BOARD_GND"])}
    {(["TX", "RX", "GND"] as const).map((signal, index) => <group key={signal} pcbX={0} pcbY={0}>
      <testpoint name={`TP_UART_${signal}`} pcbX={-42 + index * 2.54} pcbY={-20}
        schX={-8 + index * 2} schY={-10} schSheetName="controls_service"
        footprint={<footprint><platedhole portHints={["pin1"]} holeDiameter={1} outerDiameter={1.8} shape="circle" /></footprint>} />
      <trace name={`UART_${signal}`} from={`.TP_UART_${signal} > .pin1`} to={`net.${signal === "GND" ? "BOARD_GND" : `UART_${signal}`}`} />
    </group>)}

    <CL05A105KA5NQNC name="C_AUDIO_IN" pcbX={20} pcbY={-18} pcbRotation={270} schX={-12} schY={2} schRotation={-90} schSheetName="audio" {...hideRef} />
    {/* Aim the wheel along the exact bisector of the mirrored upper-left
        corner.  The enclosure exposes it through a fitted capsule slot rather
        than a rectangular bite out of the curved wall. */}
    <RK10J12E002L name="RV_VOLUME" pcbX={VOLUME_CONTROL_LAYOUT.x} pcbY={VOLUME_CONTROL_LAYOUT.y}
      pcbRotation={VOLUME_CONTROL_LAYOUT.rotationDeg} schX={-9} schY={2} schHeight={0.8}
      schSheetName="audio" allowOffBoard {...hideRef}>
      <enclosure.cutoutaperture shape="pill" width="15.2mm" height="3.2mm" margin="0mm" depth="15.2mm" />
    </RK10J12E002L>
    <CL05A105KA5NQNC name="C_AMP_IN" pcbX={27} pcbY={-18} pcbRotation={90} schX={-6} schY={2} schRotation={-90} schSheetName="audio" {...hideRef} />
    <PAM8403DR_H name="U_SPK_AMP" pcbX={34} pcbY={-22} pcbRotation={90} schX={-2} schY={2} schWidth={2.2}
      schSheetName="audio" noConnect={["OUT_R_POS", "OUT_R_NEG", "NC"]} {...hideRef} />
    <CL05A105KA5NQNC name="C_AMP_VDD" pcbX={40} pcbY={-26} pcbRotation={270} schX={-1.5} schY={-2} schRotation={-90} schSheetName="audio" {...hideRef} />
    <CL21A226MPQNNNE name="C_AMP_BULK" pcbX={37} pcbY={-31} pcbRotation={270} schX={0} schY={-2} schRotation={-90} schSheetName="audio" {...hideRef} />
    <CL05A105KA5NQNC name="C_AMP_VREF" pcbX={40} pcbY={-20} pcbRotation={270} schX={2} schY={2} schRotation={-90} schSheetName="audio" {...hideRef} />
    <BLM18PG121SN1D name="FB_SPK_POS" pcbX={44} pcbY={-27} pcbRotation={270} schX={5} schY={3} schSheetName="audio" {...hideRef} />
    <BLM18PG121SN1D name="FB_SPK_NEG" pcbX={44} pcbY={-33} pcbRotation={270} schX={5} schY={1} schSheetName="audio" {...hideRef} />
    <A_0402CG221J500NT name="C_SPK_POS" pcbX={42} pcbY={-27} pcbRotation={90} schX={8} schY={3} schRotation={-90} schSheetName="audio" {...hideRef} />
    <A_0402CG221J500NT name="C_SPK_NEG" pcbX={41} pcbY={-33} pcbRotation={90} schX={8} schY={1} schRotation={-90} schSheetName="audio" {...hideRef} />
    <SM02B_PASS_TBT_LF__SN_ name="J_SPK" pcbX={52} pcbY={-34} pcbRotation={270} schX={12} schY={2} schSheetName="audio" {...hideRef} />
    <trace name="AUDIO_TO_CAP" from="net.AUDIO_L" to=".C_AUDIO_IN > .pin1" /><trace name="AUDIO_TO_VOLUME" from=".C_AUDIO_IN > .pin2" to=".RV_VOLUME > .pin3" />
    <trace name="VOLUME_GND" from=".RV_VOLUME > .pin1" to="net.BOARD_GND" {...ground} /><trace name="VOLUME_WIPER" from=".RV_VOLUME > .pin2" to=".C_AMP_IN > .pin1" />
    <trace name="AMP_INPUT" from=".C_AMP_IN > .pin2" to=".U_SPK_AMP > .INL" /><trace name="AMP_INR_GND" from=".U_SPK_AMP > .INR" to="net.BOARD_GND" {...ground} />
    <trace name="AMP_MUTE" from=".U_SPK_AMP > .MUTE" to="net.V3V3" {...v3v3} /><trace name="AMP_SHDN" from=".U_SPK_AMP > .SHND" to="net.V3V3" {...v3v3} />
    <trace name="AMP_VDD" from=".U_SPK_AMP > .VDD" to="net.V3V3" {...powerTrace} /><trace name="AMP_PVDD1" from=".U_SPK_AMP > .PVDD1" to="net.V3V3" {...powerTrace} />
    <trace name="AMP_PVDD2" from=".U_SPK_AMP > .PVDD2" to="net.V3V3" {...powerTrace} /><trace name="AMP_GND" from=".U_SPK_AMP > .GND" to="net.BOARD_GND" {...powerTrace} {...ground} />
    <trace name="AMP_PGND1" from=".U_SPK_AMP > .PGND1" to="net.BOARD_GND" {...powerTrace} {...ground} /><trace name="AMP_PGND2" from=".U_SPK_AMP > .PGND2" to="net.BOARD_GND" {...powerTrace} {...ground} />
    {/* The merged V3V3 tree is longer than this local decoupling branch, so a
        source-level maxLength is misleading; verify the physical pair instead. */}
    <trace name="AMP_VDD_CAP" from=".C_AMP_VDD > .pin1" to=".U_SPK_AMP > .VDD" maxLength="50mm" /><trace name="AMP_VDD_CAP_G" from=".C_AMP_VDD > .pin2" to="net.BOARD_GND" {...ground} />
    <trace name="AMP_BULK_P" from=".C_AMP_BULK > .pin1" to="net.V3V3" {...powerTrace} /><trace name="AMP_BULK_G" from=".C_AMP_BULK > .pin2" to="net.BOARD_GND" {...powerTrace} {...ground} />
    <trace name="AMP_VREF" from=".U_SPK_AMP > .VREF" to=".C_AMP_VREF > .pin1" maxLength="10mm" /><trace name="AMP_VREF_G" from=".C_AMP_VREF > .pin2" to="net.BOARD_GND" {...ground} />
    {/* The short OUT_L_POS neck-down passes the local EMI capacitor pads at
        the proven 0.125 mm clearance-safe width; the rest of the speaker run
        remains 0.25 mm. Do not advertise a wider minimum than the copper. */}
    <trace name="SPK_POS_AMP" from=".U_SPK_AMP > .OUT_L_POS" to=".FB_SPK_POS > .pin1" thickness="0.12mm" /><trace name="SPK_POS_OUT" from=".FB_SPK_POS > .pin2" to=".J_SPK > .pin1" thickness="0.25mm" />
    <trace name="SPK_POS_EMI" from=".FB_SPK_POS > .pin2" to=".C_SPK_POS > .pin1" thickness="0.25mm" /><trace name="SPK_POS_EMI_G" from=".C_SPK_POS > .pin2" to="net.BOARD_GND" {...ground} />
    <trace name="SPK_NEG_AMP" from=".U_SPK_AMP > .OUT_L_NEG" to=".FB_SPK_NEG > .pin1" thickness="0.25mm" /><trace name="SPK_NEG_OUT" from=".FB_SPK_NEG > .pin2" to=".J_SPK > .pin2" thickness="0.25mm" />
    <trace name="SPK_NEG_EMI" from=".FB_SPK_NEG > .pin2" to=".C_SPK_NEG > .pin1" thickness="0.25mm" /><trace name="SPK_NEG_EMI_G" from=".C_SPK_NEG > .pin2" to="net.BOARD_GND" {...ground} />
    <trace name="SPK_G3" from=".J_SPK > .pin3" to="net.BOARD_GND" {...ground} /><trace name="SPK_G4" from=".J_SPK > .pin4" to="net.BOARD_GND" {...ground} />

    {/* AP3031 boost/current regulator for the ER-TFT035IPS-6 backlight.
        R_SET_A + R_SET_B = 2 ohm, so I_LED = 0.2 V / 2 ohm = 100 mA. */}
    <chip name="U_LCD_BL" manufacturerPartNumber="AP3031KTR-G1" supplierPartNumbers={{ jlcpcb: ["C82636"] }}
      footprint="sot23_6" pinLabels={{ pin1: "SW", pin2: "GND", pin3: "FB", pin4: "CTRL", pin5: "OV", pin6: "VIN" }}
      pinAttributes={{ pin1: { isOutput: true }, pin2: { requiresGround: true }, pin3: { isInput: true }, pin4: { isInput: true }, pin5: { isInput: true }, pin6: { requiresPower: true } }}
      cadModel={{
        objUrl: "https://modelcdn.tscircuit.com/easyeda_models/assets/C82636.obj?uuid=229b69761e2c45dba6a83d8866dec72d",
        stepUrl: "https://modelcdn.tscircuit.com/easyeda_models/assets/C82636.step?uuid=229b69761e2c45dba6a83d8866dec72d",
        pcbRotationOffset: 180,
        modelOriginPosition: { x: 0, y: 0, z: -0.713979699999993 },
      }}
      pcbX={-25} pcbY={23} pcbRotation={0} layer="top" schX={-3} schY={4} schSheetName="backlight" />
    <inductor name="L_LCD_BL" inductance="4.7uH" manufacturerPartNumber="PNLS4018-4R7M 4.7UH"
      supplierPartNumbers={{ jlcpcb: ["C2997603"] }} pcbX={-31} pcbY={23} layer="top" schX={1} schY={4} schSheetName="backlight"
      footprint="smdpads2_p3mm_pw1.2mm_ph3.4mm_cyw4.4mm_cyh4.4mm"
      cadModel={{
        objUrl: "https://modelcdn.tscircuit.com/easyeda_models/assets/C2997603.obj?uuid=54384860ccaa4399aecca69a879f17ac",
        stepUrl: "https://modelcdn.tscircuit.com/easyeda_models/assets/C2997603.step?uuid=54384860ccaa4399aecca69a879f17ac",
        pcbRotationOffset: 0,
        modelOriginPosition: { x: 0, y: 0, z: -0.949996499999952 },
      }} />
    <diode name="D_LCD_BL" manufacturerPartNumber="SS14" supplierPartNumbers={{ jlcpcb: ["C2909920"] }}
      footprint="smdpads2_p3.4mm_pw1.2mm_ph1.4mm" pinLabels={{ pin1: ["cathode", "neg"], pin2: ["anode", "pos"] }}
      cadModel={{ glbUrl: sod123flModelUrl, modelOriginPosition: { x: 0, y: 0, z: 0 } }}
      pcbX={-19} pcbY={23} pcbRotation={90} layer="top" schX={5} schY={4} schSheetName="backlight" />
    <capacitor name="C_LCD_BL_IN" capacitance="4.7uF" footprint="0805" supplierPartNumbers={{ jlcpcb: ["C1779"] }}
      maxVoltageRating={16} pcbX={-30} pcbY={18.5} pcbRotation={90} layer="top" schX={-3} schY={0} schRotation={-90} schSheetName="backlight" />
    <capacitor name="C_LCD_BL_OUT" capacitance="4.7uF" footprint="0805" supplierPartNumbers={{ jlcpcb: ["C1779"] }}
      maxVoltageRating={16} pcbX={-18} pcbY={18} pcbRotation={90} layer="top" schX={9} schY={0} schRotation={-90} schSheetName="backlight" />
    <resistor name="R_LCD_BL_SET_A" resistance="1" footprint="1206" supplierPartNumbers={{ jlcpcb: ["C137355"] }} pcbX={-23} pcbY={19} layer="top" schX={1} schY={0} schSheetName="backlight" />
    <resistor name="R_LCD_BL_SET_B" resistance="1" footprint="1206" supplierPartNumbers={{ jlcpcb: ["C137355"] }} pcbX={-23} pcbY={16.5} pcbRotation={180} layer="top" schX={5} schY={0} schRotation={-90} schSheetName="backlight" />
    {/* Keep the switching cell together on top. Its reviewed copper lives in
        carrier-router.ts so inner-layer transitions still emit ordinary
        0.30/0.45 mm through-vias rather than fabrication-specific blind vias. */}
    <trace name="LCD_BL_VIN" from=".C_U_2V5_IN > .pin1" to=".U_LCD_BL > .VIN" maxLength="30mm" {...powerTrace} {...v3v3} />
    <trace name="LCD_BL_ENABLE" from=".U_LCD_BL > .CTRL" to=".U_LCD_BL > .VIN" {...v3v3} />
    <trace name="LCD_BL_IC_GND" from=".U_LCD_BL > .GND" to="net.BOARD_GND" {...ground} />
    <trace name="LCD_BL_INPUT_L" from=".U_LCD_BL > .VIN" to=".L_LCD_BL > .pin1" {...powerTrace} {...v3v3} />
    <trace name="LCD_BL_INPUT_CAP" from=".C_LCD_BL_IN > .pin1" to=".U_LCD_BL > .VIN" maxLength="25mm" {...powerTrace} />
    <trace name="LCD_BL_INPUT_CAP_G" from=".C_LCD_BL_IN > .pin2" to="net.BOARD_GND" {...ground} />
    <trace name="LCD_BL_SWITCH_L" from=".L_LCD_BL > .pin2" to=".U_LCD_BL > .SW" maxLength="10mm" {...powerTrace} />
    <trace name="LCD_BL_SWITCH_D" from=".D_LCD_BL > .anode" to=".U_LCD_BL > .SW" {...powerTrace} />
    <trace name="LCD_BL_OUTPUT" from=".D_LCD_BL > .cathode" to=".R_LCD_LED > .pin2" thickness="0.12mm" />
    <trace name="LCD_BL_OVP" from=".U_LCD_BL > .OV" to=".D_LCD_BL > .cathode" />
    <trace name="LCD_BL_OUTPUT_CAP" from=".C_LCD_BL_OUT > .pin1" to=".D_LCD_BL > .cathode" maxLength="8mm" {...powerTrace} />
    <trace name="LCD_BL_OUTPUT_CAP_G" from=".C_LCD_BL_OUT > .pin2" to=".C_LCD_BL_IN > .pin2" {...ground} />
    <trace name="LCD_BL_SENSE" from=".Q_LCD_BL > .D" to=".U_LCD_BL > .FB" />
    <trace name="LCD_BL_SET_TOP" from=".U_LCD_BL > .FB" to=".R_LCD_BL_SET_A > .pin1" />
    <trace name="LCD_BL_SET_SERIES" from=".R_LCD_BL_SET_A > .pin2" to=".R_LCD_BL_SET_B > .pin1" />
    <trace name="LCD_BL_SET_GND" from=".R_LCD_BL_SET_B > .pin2" to=".C_LCD_BL_IN > .pin2" {...ground} />

    {/* Rear/top-edge service connectors follow the tested F1C100S dev-board
        pinouts. Their intentional X/Y positions stay fixed while top mounting
        keeps the whole board compatible with single-sided assembly. */}
    <StandardJstUartUpward name="J_UART" role="target" layer="top" pcbX={-18} pcbY={37} pcbRotation={180}
      schX={-8} schY={-8} schSheetName="controls_service" pcbStyle={{ silkscreenTextVisibility: "hidden" }} />
    <trace name="UART_JST_RX" from=".J_UART > .RX" to=".R_UART_RX_SER > .pin1" />
    <trace name="UART_JST_GND" from=".J_UART > .GND" to="net.BOARD_GND" {...ground} />
    <trace name="UART_JST_TX" from=".J_UART > .TX" to=".R_UART_TX_SER > .pin1" />

    <SM04B_SRSS_TB_LF__SN_ name="J_I2C" layer="top" pcbX={-28} pcbY={37} pcbRotation={180}
      schX={0} schY={-8} schSheetName="controls_service" {...hideRef} />
    <trace name="I2C_JST_GND" from=".J_I2C > .pin1" to="net.BOARD_GND" {...ground} />
    <trace name="I2C_JST_3V3" from=".J_I2C > .pin2" to=".J_SPI > .pin2" {...powerTrace} {...v3v3} />
    <trace name="I2C_JST_SDA" from=".J_I2C > .pin3" to="net.I2C_SDA" />
    <trace name="I2C_JST_SCL" from=".J_I2C > .pin4" to="net.I2C_SCL" />
    <trace name="I2C_JST_SHIELD_A" from=".J_I2C > .pin5" to="net.BOARD_GND" {...ground} />
    <trace name="I2C_JST_SHIELD_B" from=".J_I2C > .pin6" to="net.BOARD_GND" {...ground} />

    <SM06B_SRSS_TB_LF__SN_ name="J_SPI" layer="top" pcbX={22} pcbY={37} pcbRotation={180}
      schX={8} schY={-8} schSheetName="controls_service" {...hideRef} />
    {connect("J_SPI", ["BOARD_GND", "V3V3", "SPI1_SCLK", "SPI1_MOSI", "SPI1_MISO", "SPI1_CS", "BOARD_GND", "BOARD_GND"])}

    {/* The standard programmer recommends 100 ohm series isolation close to
        the target. */}
    <resistor name="R_UART_RX_SER" resistance="100" footprint="0402"
      manufacturerPartNumber="0402WGF1000TCE" supplierPartNumbers={{ jlcpcb: ["C25076"] }}
      pcbX={-39.46} pcbY={-23} pcbRotation={90}
      schX={-11} schY={-7} schSheetName="controls_service" />
    <resistor name="R_UART_TX_SER" resistance="100" footprint="0402"
      manufacturerPartNumber="0402WGF1000TCE" supplierPartNumbers={{ jlcpcb: ["C25076"] }}
      pcbX={-42} pcbY={-23} pcbRotation={90}
      schX={-11} schY={-9} schSheetName="controls_service" />
    <trace name="UART_RX_SER_MCU" from=".R_UART_RX_SER > .pin2" to="net.UART_RX" />
    <trace name="UART_TX_SER_MCU" from=".R_UART_TX_SER > .pin2" to="net.UART_TX" />

    {/* The following two-AA power parts are intentionally declared after the
        established carrier components. That keeps every existing terminal ID
        stable while adding the new power-stage copper as a reviewed local
        route set in carrier-router.ts. */}
    <AO3401A name="Q_BAT_IDEAL" pcbX={-31} pcbY={-36.5} pcbRotation={180}
      schX={-0.5} schY={6.5} schSheetName="usb_power" {...hideRef} />
    <resistor name="R_BAT_GATE_PULL" resistance="1M" footprint="0402"
      manufacturerPartNumber="RC0402FR-071ML" supplierPartNumbers={{ jlcpcb: ["C138033"] }}
      pcbX={-29} pcbY={-33} pcbRotation={90} schX={-2} schY={5.5}
      schRotation={-90} schSheetName="usb_power" />
    <trace name="BAT_IDEAL_DRAIN" from="net.BAT_SWITCHED" to=".Q_BAT_IDEAL > .drain" {...powerTrace} />
    <trace name="BAT_IDEAL_SOURCE" from=".Q_BAT_IDEAL > .source" to="net.SYS_IN" {...powerTrace} />
    <trace name="BAT_IDEAL_GATE" from=".Q_BAT_IDEAL > .gate" to="net.BAT_GATE" />
    <trace name="BAT_GATE_PULL" from=".R_BAT_GATE_PULL > .pin1" to="net.BAT_GATE" />
    <trace name="BAT_GATE_PULL_GND" from=".R_BAT_GATE_PULL > .pin2" to="net.BOARD_GND" {...ground} />

    <CL05B104KO5NNNC name="C_BUCK_VINA" pcbX={-29} pcbY={-20.4} pcbRotation={180}
      schX={3.4} schY={-2} schRotation={-90} schSheetName="usb_power" {...hideRef} />
    <CL21A226MAQNNNE name="C_BUCK_OUT_C" pcbX={-21} pcbY={-25.5} pcbRotation={270}
      schX={12} schY={-1} schRotation={-90} schSheetName="usb_power" {...hideRef} />
    <resistor name="R_BUCK_FB_TOP" resistance="1M" footprint="0402"
      manufacturerPartNumber="RC0402FR-071ML" supplierPartNumbers={{ jlcpcb: ["C138033"] }}
      pcbX={-29} pcbY={-22.9} pcbRotation={0} schX={7.69} schY={0}
      schRotation={-90} schSheetName="usb_power" />
    <resistor name="R_BUCK_FB_LOW" resistance="180k" footprint="0402"
      manufacturerPartNumber="RC0402FR-07180KL" supplierPartNumbers={{ jlcpcb: ["C138046"] }}
      pcbX={-29} pcbY={-24.2} pcbRotation={180} schX={7} schY={-2}
      schRotation={-90} schSheetName="usb_power" />
    <trace name="BUCK_VINA_CAP" from=".C_BUCK_VINA > .pin1" to=".U_BUCK_3V3 > .VINA" maxLength="10mm" />
    <trace name="BUCK_VINA_CAP_GND" from=".C_BUCK_VINA > .pin2" to="net.BOARD_GND" {...ground} />
    <trace name="BUCK_OUTPUT_CAP_C" from=".C_BUCK_OUT_C > .pin1" to=".U_BUCK_3V3 > .VOUT2" maxLength="10mm" />
    <trace name="BUCK_OUTPUT_CAP_C_GND" from=".C_BUCK_OUT_C > .pin2" to="net.BOARD_GND" {...ground} />
    <trace name="BUCK_FB_TOP_IN" from=".R_BUCK_FB_TOP > .pin1" to=".C_BUCK_OUT_B > .pin1" maxLength="10mm" />
    <trace name="BUCK_FB_TOP_OUT" from=".R_BUCK_FB_TOP > .pin2" to=".U_BUCK_3V3 > .FB" />
    <trace name="BUCK_FB_LOW_IN" from=".R_BUCK_FB_LOW > .pin1" to=".U_BUCK_3V3 > .FB" />
    <trace name="BUCK_FB_LOW_GND" from=".R_BUCK_FB_LOW > .pin2" to="net.BOARD_GND" {...ground} />

    {/* A common-anode RGB indicator uses the otherwise spare PCF8575 outputs.
        The expander powers up with all quasi-bidirectional lines high, so the
        active-low cathodes remain dark through reset and Linux boot.  This
        block stays after the reviewed power island so its added terminals do
        not renumber any deterministic route endpoint. */}
    <trace name="STATUS_RED_IO" from=".U_IO > .P14" to="net.STATUS_RED_N" />
    <trace name="STATUS_GREEN_IO" from=".U_IO > .P15" to="net.STATUS_GREEN_N" />
    <trace name="STATUS_BLUE_IO" from=".U_IO > .P16" to="net.STATUS_BLUE_N" />
    <StatusRgbLed name="D_STATUS" pcbX={STATUS_INDICATOR_LAYOUT.x} pcbY={STATUS_INDICATOR_LAYOUT.y}
      pcbRotation={0} schX={-4} schY={2} schWidth={2.4} schHeight={0.98}
      schPinArrangement={{ topSide: ["pin1"], rightSide: ["pin2", "pin3", "pin4"] }}
      schSheetName="status" {...hideRef} />
    <trace name="STATUS_LED_CA" from=".D_STATUS > .CA" to="net.V3V3" {...v3v3} />
    <resistor name="R_STATUS_R" resistance="330ohm" footprint="0603"
      manufacturerPartNumber="0603WAF3300T5E" supplierPartNumbers={{ jlcpcb: ["C23138"] }}
      pcbX={-10} pcbY={-16.5} pcbRotation={0} schX={-0.65} schY={3} schRotation={90} schSheetName="status" />
    <resistor name="R_STATUS_G" resistance="100ohm" footprint="0603"
      manufacturerPartNumber="0603WAF1000T5E" supplierPartNumbers={{ jlcpcb: ["C22775"] }}
      pcbX={2.5} pcbY={-18.5} pcbRotation={0} schX={0} schY={2} schRotation={90} schSheetName="status" />
    <resistor name="R_STATUS_B" resistance="100ohm" footprint="0603"
      manufacturerPartNumber="0603WAF1000T5E" supplierPartNumbers={{ jlcpcb: ["C22775"] }}
      pcbX={2.5} pcbY={-21} pcbRotation={0} schX={0.65} schY={1} schRotation={90} schSheetName="status" />
    <trace name="STATUS_RED_LED" from=".D_STATUS > .R_NEG" to=".R_STATUS_R > .pin1" />
    <trace name="STATUS_RED_LIMIT" from=".R_STATUS_R > .pin2" to="net.STATUS_RED_N" />
    <trace name="STATUS_GREEN_LED" from=".D_STATUS > .G_NEG" to=".R_STATUS_G > .pin1" />
    <trace name="STATUS_GREEN_LIMIT" from=".R_STATUS_G > .pin2" to="net.STATUS_GREEN_N" />
    <trace name="STATUS_BLUE_LED" from=".D_STATUS > .B_NEG" to=".R_STATUS_B > .pin1" />
    <trace name="STATUS_BLUE_LIMIT" from=".R_STATUS_B > .pin2" to="net.STATUS_BLUE_N" />

    {PCB_MOUNT_HOLES.map(({ name, x, y }) =>
      <Fragment key={name}><hole name={name} diameter="3.3mm" pcbX={x} pcbY={y} /></Fragment>)}
    {/* Dedicated LCD carrier holes.  These are intentionally separate from
        the PCB supports: four M2.5 screws locate the panel carrier without
        loading the FPC connector, while all hole edges retain >=0.20 mm to
        routed copper in the verified geometry. */}
    {SCREEN_CARRIER_HOLES.map(({ name, x, y }) =>
      <Fragment key={name}><hole name={name} diameter="2.7mm" pcbX={x} pcbY={y} /></Fragment>)}

    {/* Mechanical-only aperture owners for features that are not themselves
        PCB parts. They are DNP, copper-free, and excluded from the schematic. */}
    <CaseApertureMarker name="CASE_SCREEN_WINDOW" x={-2.68} y={15} direction="from_above">
      <enclosure.cutoutaperture shape="rect" width="73.44mm" height="48.96mm" margin="0.4mm" depth="16mm" />
    </CaseApertureMarker>
    <silkscreentext text="F1C100S LINUX ADVANCE" fontSize="1.5mm" pcbX={0} pcbY={38} />
    <silkscreentext text="LANDSCAPE LCD FPC" fontSize="0.8mm" pcbX={39} pcbY={0} pcbRotation={90} /><silkscreentext text="microSD EDGE" fontSize="0.8mm" pcbX={62.75} pcbY={10} />
    <silkscreentext text="2xAA 1.8-3.2V • NO CHARGE" fontSize="0.8mm" pcbX={-45} pcbY={-27} /><silkscreentext text="USB-C POWER + DATA / FEL" fontSize="0.7mm" pcbX={0} pcbY={-32} />
    <silkscreentext text="GUARDED POWER" fontSize="0.75mm" pcbX={-60} pcbY={-28.5} /><silkscreentext text="VOLUME" fontSize="1mm" pcbX={-52} pcbY={24} pcbRotation={90} />
    <silkscreentext text="SPK+  SPK-" fontSize="0.65mm" pcbX={52} pcbY={-29.5} />
    <silkscreentext text="I2C  G 3V3 SDA SCL" layer="top" fontSize="0.55mm" pcbX={-28} pcbY={33.1} />
    <silkscreentext text="UART  RX G TX" layer="top" fontSize="0.55mm" pcbX={-18} pcbY={33.1} />
    <silkscreentext text="SPI1 SHARED WITH LCD INIT" layer="top" fontSize="0.55mm" pcbX={22} pcbY={32.8} />

    <copperpour layer="top" connectsTo="net.BOARD_GND" clearance={0.3} boardEdgeMargin={0.3} useThermalReliefs coveredWithSolderMask />
    {(["inner1", "inner2", "bottom"] as const).map(layer =>
      <Fragment key={layer}><copperpour layer={layer} connectsTo="net.BOARD_GND" clearance={0.15} boardEdgeMargin={0.3} useThermalReliefs coveredWithSolderMask /></Fragment>)}
  </board>
  {/* OEM STEP-derived ER-TFT035IPS-6 assembly. The rigid panel geometry is
      unscaled; only the 30 mm flexible tail is folded into its installed path.
      The GLB origin stays at the FPC mating edge and the panel/FPC centerline
      remains straight. The top PCB datum follows the real 56.54 mm panel edge
      rather than introducing a fictitious sideways bend into the flex. */}
  <assembly.screen name="ER_TFT035IPS_6" connectsTo=".J_LCD"
    modelUrl={screenAssemblyModelUrl} />
  <GbaEnclosure />
  </assembly.device>
)