astra/am3352-sbc

A 4-layer AM3352 single-board computer with 128‑MiB DDR3, PMIC power regulation, USB‑C 5‑V PD input, dual USB host ports, HDMI output with ESD protection, microSD/UART/JTAG interfaces, addressable RGB indicators, and a PWM-driven buzzer.

Version
0.1.19
License
unset
Stars
0

design/nets.tsx

import decouplerFootprints from "./decoupler-footprints.json";
import type { TraceProps } from "@tscircuit/props";
import { Fragment, createContext, useContext } from "react";
import { escapeByTrace } from "./power-escapes";
import ballMap from "./am3352-ballmap.json";

export const PeripheralRoutingContext = createContext<boolean | number[]>(true);
export function SignalTrace(props: TraceProps) {
  const mode = useContext(PeripheralRoutingContext);
  const enabled = Array.isArray(mode) ? mode.includes(props.routingPhaseIndex ?? -1) : mode;
  const escape = process.env.SBC_SIGNAL_ROUTING === "1" ? undefined : props.name ? escapeByTrace.get(props.name) : undefined;
  if (escape) {
    const endpoint=(escape as {directPlaneEndpoint?: {x:number;y:number}|null}).directPlaneEndpoint;
    const end=endpoint ? {...endpoint,layer:escape.layer as "top"|"bottom"} : `.${escape.via} > .${escape.layer}`;
    return (
      <trace
        {...props}
        pcbPath={[
          escape.from,
          ...((escape as typeof escape & {waypoints?: {x:number;y:number}[]}).waypoints ?? []).map(w => ({
            ...w,
            layer: escape.layer as "top" | "bottom",
          })),
          end,
        ]}
        routingPhaseIndex={undefined}
      />
    );
  }
  return (
    <trace
      {...props}
      routingPhaseIndex={enabled ? props.routingPhaseIndex : undefined}
    />
  );
}

export const cpuPin = (signal: string) => {
  const ball = Object.entries(ballMap).find(([, name]) => name === signal)?.[0];
  if (!ball) throw new Error(`Unknown AM3352 signal ${signal}`);
  return `U1.${ball}`;
};
export const phaseForNet = (net: string) =>
  net === "GND"
    ? 7
    : /^(VDD|V[13]|DDR_1V5|RTC_1V8|A3V3|VIN|SYS|PD_VBUS|USB[01]_VBUS)/.test(net)
      ? 6
      : 5;
export function Link({
  refdes,
  pin,
  net,
}: {
  refdes: string;
  pin: string;
  net: string;
}) {
  return (
    <SignalTrace
      name={`T_${refdes}_${pin}`}
      from={`${refdes}.${pin}`}
      to={`net.${net}`}
      routingPhaseIndex={phaseForNet(net)}
    />
  );
}
export const link = (refdes: string, pin: string, net: string) => (
  <Link key={`${refdes}_${pin}`} refdes={refdes} pin={pin} net={net} />
);
export function Cap({
  name,
  net,
  value = "100nF",
  x,
  y,
  layer = "top",
  rotation = 0,
}: {
  name: string;
  net: string;
  value?: string;
  x: number;
  y: number;
  layer?: "top" | "bottom";
  rotation?: number;
}) {
  return (
    <Fragment>
      <capacitor
        name={name}
        capacitance={value}
        footprint={
          (decouplerFootprints as Record<string, string>)[name] ?? (name === "C_SYS_LOCAL"
            ? "0603"
            : value.includes("uF")
              ? "0805"
              : "0402")
        }
        pcbX={x}
        pcbY={y}
        layer={layer}
        pcbRotation={rotation}
      />
      {link(name, "pin1", net)}
      {link(name, "pin2", "GND")}
    </Fragment>
  );
}
export function Res({
  name,
  a,
  b,
  value = "10k",
  x,
  y,
  layer = "top",
  rotation = 0,
}: {
  name: string;
  a: string;
  b: string;
  value?: string;
  x: number;
  y: number;
  layer?: "top" | "bottom";
  rotation?: number;
}) {
  return (
    <Fragment>
      <resistor
        name={name}
        resistance={value}
        footprint="0402"
        pcbX={x}
        pcbY={y}
        layer={layer}
        pcbRotation={rotation}
      />
      {link(name, "pin1", a)}
      {link(name, "pin2", b)}
    </Fragment>
  );
}