imrishabh18/desk-led-matrix

This code models a hardware setup comprising a WLED-compatible LED cascade array connected to a XIAO ESP32-C3 microcontroller, including power regulation components and detailed PCB layout with traces, pads, and silkscreen markings.

Version
1.0.4
License
unset
Stars
0

index.circuit.tsx

PCBPCB preview for index.circuit.tsx
SchematicSchematic preview for index.circuit.tsx
import { Fragment } from "react"
import { WLED } from "./imports/WLED"

const ROWS = 8
const COLS = 8
const LED_COUNT = ROWS * COLS
const LED_PITCH_MM = 8
const MATRIX_WIDTH_MM = (COLS - 1) * LED_PITCH_MM
const MATRIX_HEIGHT_MM = (ROWS - 1) * LED_PITCH_MM
const BOARD_SIZE_MM = 78
const MATRIX_CENTER_Y_MM = 0
const XIAO_CENTER_X_MM = 30
const XIAO_CENTER_Y_MM = 0

const xiaoBottomFootprint = (
  <footprint>
    {Array.from({ length: 7 }, (_, i) => (
      <Fragment key={`xiao-left-${i + 1}`}>
        <smtpad
          portHints={[`pin${i + 1}`]}
          layer="bottom"
          shape="rect"
          pcbX="-7.55mm"
          pcbY={`${7.62 - i * 2.54}mm`}
          width="2.4mm"
          height="1.6mm"
        />
      </Fragment>
    ))}
    {Array.from({ length: 7 }, (_, i) => (
      <Fragment key={`xiao-right-${i + 8}`}>
        <smtpad
          portHints={[`pin${i + 8}`]}
          layer="bottom"
          shape="rect"
          pcbX="7.55mm"
          pcbY={`${-7.62 + i * 2.54}mm`}
          width="2.4mm"
          height="1.6mm"
        />
      </Fragment>
    ))}
  </footprint>
)

const dataOrder = Array.from({ length: LED_COUNT }, (_, i) => i + 1)

const pixelPlacements = Array.from({ length: LED_COUNT }, (_, physicalIndex) => {
  const row = Math.floor(physicalIndex / COLS)
  const col = physicalIndex % COLS
  const serpentineIndex =
    row % 2 === 0 ? row * COLS + col : row * COLS + (COLS - 1 - col)

  return {
    name: `D${serpentineIndex + 1}`,
    col,
    row,
    x: (col - (COLS - 1) / 2) * LED_PITCH_MM,
    y: (row - (ROWS - 1) / 2) * LED_PITCH_MM + MATRIX_CENTER_Y_MM,
    rotation: row % 2 === 0 ? 0 : 180,
  }
})

export default function DeskLedMatrix() {
  return (
    <board
      title="Desk WLED Pixel Art Matrix"
      width={`${BOARD_SIZE_MM}mm`}
      height={`${BOARD_SIZE_MM}mm`}
      borderRadius="2mm"
      solderMaskColor="black"
      silkscreenColor="white"
    >
      <net
        name="V5"
        isPowerNet
        nominalTraceWidth="0.45mm"
        highlightColor="#ff4a36"
      />
      <net
        name="GND"
        isGroundNet
        nominalTraceWidth="0.45mm"
        highlightColor="#4aa3ff"
      />
      <net
        name="DATA_IN"
        nominalTraceWidth="0.2mm"
        highlightColor="#ffd166"
      />

      <chip
        name="U1"
        manufacturerPartNumber="Seeed Studio XIAO ESP32-C3"
        footprint={xiaoBottomFootprint}
        pcbX={XIAO_CENTER_X_MM}
        pcbY={XIAO_CENTER_Y_MM}
        pinLabels={{
          1: "D0_GPIO2",
          2: "D1_GPIO3",
          3: "D2_GPIO4",
          4: "D3_GPIO5",
          5: "D4_GPIO6",
          6: "D5_GPIO7",
          7: "D6_GPIO21",
          8: "D7_GPIO20",
          9: "D8_GPIO8",
          10: "D9_GPIO9",
          11: "D10_GPIO10",
          12: "3V3",
          13: "GND",
          14: "5V",
        }}
        pcbPinLabels={{
          pin1: "D0",
          pin2: "D1",
          pin3: "D2",
          pin4: "D3",
          pin5: "D4",
          pin6: "D5",
          pin7: "D6",
          pin8: "D7",
          pin9: "D8",
          pin10: "D9",
          pin11: "D10",
          pin12: "3V3",
          pin13: "GND",
          pin14: "5V",
        }}
        pcbRotation={90}
        pinAttributes={{
          D4_GPIO6: { isGpio: true },
          GND: { requiresGround: true },
          "5V": { requiresPower: true, requiresVoltage: "5V" },
          "3V3": { providesPower: true, providesVoltage: "3.3V" },
        }}
      />
      <resistor
        name="RDATA"
        resistance="330"
        footprint="0603"
        layer="bottom"
        pcbX={-18}
        pcbY={-BOARD_SIZE_MM / 2 + 12}
        schOrientation="horizontal"
      />
      <capacitor
        name="CBULK"
        capacitance="1000uF"
        polarized
        footprint="1206"
        layer="bottom"
        pcbX={18}
        pcbY={-BOARD_SIZE_MM / 2 + 12}
        schOrientation="vertical"
      />

      <trace from=".U1 > .pin14" to="net.V5" width="0.5mm" />
      <trace from=".U1 > .pin13" to="net.GND" width="0.5mm" />
      <trace from=".U1 > .pin5" to=".RDATA > .pin1" width="0.2mm" />
      <trace from=".RDATA > .pin2" to=".D1 > .DI" width="0.2mm" />

      <trace from=".CBULK > .pos" to="net.V5" width="0.7mm" />
      <trace from=".CBULK > .neg" to="net.GND" width="0.7mm" />

      {pixelPlacements.map((pixel) => (
        <Fragment key={pixel.name}>
          <WLED
            name={pixel.name}
            pcbX={pixel.x}
            pcbY={pixel.y}
            pcbRotation={pixel.rotation}
            pcbPinLabels={{
              pin1: "VDD",
              pin2: "DO",
              pin3: "GND",
              pin4: "DI",
            }}
            pinAttributes={{
              VDD: { requiresPower: true, requiresVoltage: "5V" },
              pin1: { requiresPower: true, requiresVoltage: "5V" },
              pin2: { isGpio: true },
              GND: { requiresGround: true },
              pin3: { requiresGround: true },
              pin4: { isGpio: true },
              DI: { isGpio: true },
              DO: { isGpio: true },
            }}
          />
        </Fragment>
      ))}

      {dataOrder.slice(0, -1).map((ledNumber) => (
        <Fragment key={`data-${ledNumber}`}>
          <trace
            from={`.D${ledNumber} > .DO`}
            to={`.D${ledNumber + 1} > .DI`}
            width="0.18mm"
          />
        </Fragment>
      ))}

      {dataOrder.map((ledNumber) => (
        <Fragment key={`v5-${ledNumber}`}>
          <trace
            from={`.D${ledNumber} > .VDD`}
            to="net.V5"
            width="0.35mm"
          />
        </Fragment>
      ))}
      {dataOrder.map((ledNumber) => (
        <Fragment key={`gnd-${ledNumber}`}>
          <trace
            from={`.D${ledNumber} > .GND`}
            to="net.GND"
            width="0.35mm"
          />
        </Fragment>
      ))}

      {Array.from({ length: ROWS }, (_, row) => (
        <Fragment key={`crow-${row + 1}`}>
          <capacitor
            name={`CROW${row + 1}`}
            capacitance="100nF"
            footprint="0402"
            layer="bottom"
            pcbX={-BOARD_SIZE_MM / 2 + 4}
            pcbY={(row - (ROWS - 1) / 2) * LED_PITCH_MM + MATRIX_CENTER_Y_MM}
            connections={{
              pin1: "net.V5",
              pin2: "net.GND",
            }}
          />
        </Fragment>
      ))}

      <silkscreenrect
        pcbX={0}
        pcbY={MATRIX_CENTER_Y_MM}
        width={`${MATRIX_WIDTH_MM + 5}mm`}
        height={`${MATRIX_HEIGHT_MM + 5}mm`}
        filled={false}
        stroke="solid"
        strokeWidth="0.18mm"
      />
      {pixelPlacements.map((pixel) => (
        <Fragment key={`pixel-frame-${pixel.name}`}>
          <silkscreenrect
            pcbX={pixel.x}
            pcbY={pixel.y}
            width="5.4mm"
            height="5.4mm"
            filled={false}
            stroke="solid"
            strokeWidth="0.08mm"
          />
        </Fragment>
      ))}
      <silkscreentext
        text="XIAO WLED 8x8 SERPENTINE"
        pcbX={0}
        pcbY={BOARD_SIZE_MM / 2 - 2.2}
        fontSize="1.2mm"
      />
      <silkscreenrect
        layer="bottom"
        pcbX={XIAO_CENTER_X_MM}
        pcbY={XIAO_CENTER_Y_MM}
        width="17.5mm"
        height="21mm"
        filled={false}
        stroke="dashed"
        strokeWidth="0.12mm"
      />
      <silkscreentext
        layer="bottom"
        text="XIAO ESP32-C3"
        pcbX={XIAO_CENTER_X_MM}
        pcbY={XIAO_CENTER_Y_MM + 11.5}
        fontSize="1mm"
      />
      <silkscreentext
        layer="bottom"
        text="USB"
        pcbX={XIAO_CENTER_X_MM}
        pcbY={XIAO_CENTER_Y_MM - 11.5}
        fontSize="0.9mm"
      />
      <silkscreentext
        text="D1"
        pcbX={-MATRIX_WIDTH_MM / 2}
        pcbY={MATRIX_CENTER_Y_MM - MATRIX_HEIGHT_MM / 2 - 1}
        fontSize="0.9mm"
      />
    </board>
  )
}