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/processor-support.tsx
import {ramPoint,ramPlacement,isRamRef} from "./ram-placement";
import { Fragment } from "react";
import ballMap from "./am3352-ballmap.json";
import decouplingPlacement from "./decoupling-placement.json";
import { TPS65217CRSLR } from "../components/pmic";
import { TF_01A } from "../components/microsd";
import { Cap as BasicCap, Res, link } from "./nets";
import { ramNet, ramConnections } from "./ddr-netlist";
function Cap(props: {
name: string;
net: string;
value?: string;
x?: number;
y?: number;
bottom?: boolean;
rotation?: number;
}) {
const placed = props.bottom
? (
decouplingPlacement as Record<
string,
{ x: number; y: number; rotation: number }
>
)[props.name]
: undefined;
if (props.bottom && !placed)
throw Error(`Missing decoupler placement: ${props.name}`);
const position={x:placed?.x ?? props.x ?? 0,y:placed?.y ?? props.y ?? 0};
const physical=isRamRef(props.name)?ramPoint(position.x,position.y):position;
return (
<BasicCap
{...props}
x={physical.x}
y={physical.y}
rotation={(placed?.rotation ?? props.rotation ?? 0)+(isRamRef(props.name)?ramPlacement.rotation:0)}
layer={props.bottom ? "bottom" : "top"}
/>
);
}
const cpuPower = (s: string): string | undefined => {
if (/^VSS/.test(s)) return "GND";
if (s === "VDD_MPU_MON") return "VDD_MPU";
if (s === "VDD_CORE" || s === "VDD_MPU") return s;
if (s === "VDDS_DDR") return "DDR_1V5";
if (s === "VDDS_RTC") return "RTC_1V8";
if (/^VDDSHV/.test(s)) return "V3V3";
if (/^VDDA3P3/.test(s)) return "A3V3";
if (
s === "VDDS" ||
/^VDDS_(PLL|OSC|SRAM)/.test(s) ||
/^VDDA1P8/.test(s) ||
s === "VDDA_ADC"
)
return "V1V8";
};
const cpuSignal = (s: string) =>
cpuPower(s) ??
{
VREFN: "GND",
VREFP: "V1V8",
RTC_KALDO_ENn: "GND",
VPP: "GND",
RTC_PWRONRSTn: "RTC_RESETn",
}[s] ??
s;
const usedSignals = new Set([
"DDR_VREF",
"DDR_VTP",
"I2C0_SDA",
"I2C0_SCL",
"UART0_TXD",
"UART0_RXD",
"TCK",
"TMS",
"TDI",
"TDO",
"TRSTn",
"EMU0",
"EMU1",
"PWRONRSTn",
"WARMRSTn",
"RTC_PWRONRSTn",
"RTC_KALDO_ENn",
"PMIC_POWER_EN",
"VPP",
"XTALIN",
"XTALOUT",
"RTC_XTALIN",
"RTC_XTALOUT",
"VREFN",
"VREFP",
"MMC0_CLK",
"MMC0_CMD",
...Array.from({ length: 4 }, (_, i) => `MMC0_DAT${i}`),
// RGB uses SPI0_D0 as MOSI; Linux requires ti,pindir-d0-out-d1-in.
// No SPI flash or external clock/input is fitted.
"SPI0_D0",
"USB0_VBUS",
"USB1_VBUS",
"USB0_DRVVBUS",
"USB1_DRVVBUS",
"CAP_VDD_RTC",
"CAP_VDD_SRAM_CORE",
"CAP_VDD_SRAM_MPU",
"CAP_VBB_MPU",
]);
const powerPins: Record<string, string> = {
AC: "VIN_5V",
SYS1: "SYS_5V",
SYS2: "SYS_5V",
VIN_DCDC1: "SYS_5V",
VIN_DCDC2: "SYS_5V",
VIN_DCDC3: "SYS_5V",
VINLDO: "SYS_5V",
LS1_IN: "SYS_5V",
LS2_IN: "SYS_5V",
VLDO1: "RTC_1V8",
VLDO2: "A3V3",
LS1_OUT: "V1V8",
LS2_OUT: "V3V3",
VDCDC1: "DDR_1V5",
VDCDC2: "VDD_MPU",
VDCDC3: "VDD_CORE",
PWR_EN: "PMIC_POWER_EN",
PGOOD: "PWRONRSTn",
nRESET: "RTC_RESETn",
SDA: "I2C0_SDA",
SCL: "I2C0_SCL",
VIO: "V3V3",
PGND: "GND",
AGND: "GND",
EP: "GND",
TS: "PMIC_TS",
INT_LDO: "PMIC_INT_LDO",
BYPASS: "PMIC_BYPASS",
PB_IN: "PMIC_PB",
USB: "GND",
};
export function ProcessorSupport() {
const supplies = Object.entries(ballMap).filter(
([, s]) => cpuPower(s) && cpuPower(s) !== "GND" && s !== "VDD_MPU_MON",
);
return (
<>
<TPS65217CRSLR name="U2" pcbX={-23} pcbY={-3} />
{link("U1", "G2", "DDR_RESETn")}
<TF_01A name="J_SD" pcbX={-23} pcbY={33} pcbRotation={180} />
{Object.entries(ballMap)
.filter(([, s]) => cpuPower(s) || usedSignals.has(s))
.map(([ball, s]) => link("U1", ball, cpuSignal(s)))}
{Object.entries(powerPins).map(([pin, net]) => link("U2", pin, net))}
{ramConnections
.filter(
({ net }) =>
net && ["GND", "DDR_1V5", "DDR_VREF", "DDR_ZQ"].includes(net),
)
.map(({ pin, net }) => link("U3", pin, net!))}
{[
"MMC0_DAT2",
"MMC0_DAT3",
"MMC0_CMD",
"V3V3",
"MMC0_CLK",
"GND",
"MMC0_DAT0",
"MMC0_DAT1",
"SD_CD",
"GND",
"GND",
"GND",
"GND",
].map((n, i) => link("J_SD", `pin${i + 1}`, n))}
{supplies.map(([ball, s], i) => (
<Cap key={ball} name={`C_U1_${ball}`} net={cpuPower(s)!} bottom />
))}
{["DDR_1V5", "VDD_MPU", "VDD_CORE"].map((rail, i) => (
<Fragment key={rail}>
<inductor
name={`L${i + 1}`}
manufacturerPartNumber="DFE201612E-2R2M=P2"
inductance="2.2uH"
footprint={
<footprint>
{[-1, 1].map((sign, j) => (
<smtpad
portHints={[`pin${j + 1}`]}
shape="rect"
pcbX={sign * 0.8}
pcbY={0}
width={0.8}
height={1.8}
/>
))}
<courtyardrect pcbX={0} pcbY={0} width={2.9} height={2.3} />
</footprint>
}
pcbX={[-17.5, -17.5, -23.2][i]}
pcbY={[-3.5, 0.5, 2.6][i]}
pcbRotation={i === 2 ? 90 : 0}
/>
{link("U2", `L${i + 1}`, `SW${i + 1}`)}
{link(`L${i + 1}`, "pin1", `SW${i + 1}`)}
{link(`L${i + 1}`, "pin2", rail)}
<Cap
name={`C_DCDC${i + 1}`}
net={rail}
value="22uF"
x={[-17.5, -17.5, -19.7][i]}
y={[-6.1, 3.1, 5.4][i]}
/>
</Fragment>
))}
{[
"VIN_5V",
"SYS_5V",
"RTC_1V8",
"A3V3",
"V1V8",
"V3V3",
"PMIC_BYPASS",
"PMIC_INT_LDO",
].map((n, i) => (
<Cap
key={n}
name={`C_P${i}`}
net={n}
value={n === "PMIC_INT_LDO" ? "100nF" : "4.7uF"}
x={[-20.8, -26.1, -24.4, -28, -28.6, -28.6, -28.6, -31.7][i]}
y={[-8.4, 2, -8.4, -8.4, -0.8, -3.2, -5.6, -4.4][i]}
rotation={i === 1 || i >= 3 ? 180 : 0}
/>
))}
{Array.from({ length: 16 }, (_, i) => (
<Cap key={i} name={`C_DDR${i}`} net="DDR_1V5" bottom />
))}
<Res name="R_VREF_H" a="DDR_1V5" b="DDR_VREF" value="10k" {...ramPoint(-7,-29)} rotation={ramPlacement.rotation} />
<Res name="R_VREF_L" a="DDR_VREF" b="GND" value="10k" {...ramPoint(-6.50000000,-29.70000000)} layer="bottom" rotation={(ramPlacement.rotation + 90) % 360} />
<Cap name="C_VREF" net="DDR_VREF" x={6} y={-33} />
<Res name="R_ZQ" a="DDR_ZQ" b="GND" value="240" {...ramPoint(6,-29)} rotation={ramPlacement.rotation} />
<Res
name="R_VTP"
a="DDR_VTP"
b="GND"
value="49.9"
x={1.51}
y={-3.8}
layer="bottom"
/>
<Res name="R_DDR_RST" a="DDR_RESETn" b="GND" value="10k" {...ramPoint(7,-36)} rotation={ramPlacement.rotation} />
{[
"I2C0_SDA",
"I2C0_SCL",
"PWRONRSTn",
"WARMRSTn",
"TRSTn",
"EMU0",
"EMU1",
].map((n, i) => (
<Res
key={n}
name={`R_CTRL${i}`}
a={n}
b="V3V3"
value={i < 2 ? "4.7k" : "10k"}
x={-17 + i * 3}
y={13}
/>
))}
<Res name="R_RTC_RST" a="RTC_RESETn" b="RTC_1V8" x={-20} y={8} />
<Res name="R_TS" a="PMIC_TS" b="GND" value="10k" x={-18} y={-8.5} />
{[
"CAP_VDD_RTC",
"CAP_VDD_SRAM_CORE",
"CAP_VDD_SRAM_MPU",
"CAP_VBB_MPU",
].map((n, i) => (
<Cap
key={n}
name={`C_CAP${i}`}
net={n}
value="1uF"
x={i === 1 || i === 2 ? -14.25 : -13}
y={-6 + i * 3}
/>
))}
<crystal
name="Y1"
manufacturerPartNumber="ABM3-24.000MHZ-D2Y-T"
frequency="24MHz"
loadCapacitance="18pF"
footprint={
<footprint>
<smtpad
portHints={["pin1"]}
shape="rect"
width={1.9}
height={2.4}
pcbX={-2.05}
/>
<smtpad
portHints={["pin2"]}
shape="rect"
width={1.9}
height={2.4}
pcbX={2.05}
/>
<courtyardrect pcbX={0} pcbY={0} width={6.5} height={3.9} />
<silkscreenrect pcbX={0} pcbY={0} width={5.8} height={3.4} />
</footprint>
}
pcbX={12}
pcbY={2.8}
pcbRotation={180}
/>
{link("Y1", "pin1", "XTALIN")}
{link("Y1", "pin2", "XTALOUT")}
<Cap name="C_X1" net="XTALIN" value="22pF" x={12} y={-0.15} rotation={270} />
<Cap
name="C_X2"
net="XTALOUT"
value="22pF"
x={10.2}
y={0.3}
rotation={0}
/>
{/* Epson FC-135: no circuit patterns between the two lands. */}
<keepout
shape="rect"
pcbX={-11}
pcbY={-2.8}
width={1.8}
height={1.5}
layers={["top"]}
allowPlacements
/>
<crystal
name="Y2"
manufacturerPartNumber="Q13FC13500004"
frequency="32.768kHz"
loadCapacitance="12.5pF"
footprint={
<footprint>
<smtpad
portHints={["pin1"]}
shape="rect"
width={1}
height={1.8}
pcbX={-1.25}
/>
<smtpad
portHints={["pin2"]}
shape="rect"
width={1}
height={1.8}
pcbX={1.25}
/>
<courtyardrect pcbX={0} pcbY={0} width={4} height={2.3} />
<silkscreenrect pcbX={0} pcbY={0} width={3.8} height={2} />
</footprint>
}
pcbX={-11}
pcbY={-2.8}
pcbRotation={270}
/>
{link("Y2", "pin1", "RTC_XTALIN")}
{link("Y2", "pin2", "RTC_XTALOUT")}
<Cap
name="C_RTCX1"
net="RTC_XTALIN"
value="18pF"
x={-10}
y={0}
rotation={0}
/>
<Cap
name="C_RTCX2"
net="RTC_XTALOUT"
value="18pF"
x={-10}
y={-5.75}
rotation={0}
/>
{[
"MMC0_CMD",
"MMC0_DAT0",
"MMC0_DAT1",
"MMC0_DAT2",
"MMC0_DAT3",
"SD_CD",
].map((n, i) => (
<Res
key={n}
name={`R_SD${i}`}
a={n}
b="V3V3"
value="47k"
x={-30 + i * 3}
y={12}
/>
))}
<Cap name="C_SD" net="V3V3" value="10uF" x={-7} y={16} />
{/* TI SPRUH73Q Table 26-7: 24 MHz and MMC0 -> SPI0 -> UART0 -> USB0. */}
{Array.from({ length: 16 }, (_, i) => (
<Res
key={i}
name={`R_BOOT${i}`}
a={`LCD_DATA${i}`}
b={0x4017 & (1 << i) ? "V3V3" : "GND"}
value="10k"
x={-31 + (i % 8) * 3.5}
y={18 + Math.floor(i / 8) * 4}
/>
))}
{[16, 17].map((i) => (
<Cap key={i} name={`C_DDR${i}`} net="DDR_1V5" bottom />
))}
<Cap name="C_SYS_LOCAL" net="SYS_5V" value="4.7uF" x={-17.5} y={-1.5} />
<pinheader name="J_UART" pinCount={4} pitch={2.54} pcbX={-8} pcbY={34} />
{["GND", "UART0_TXD", "UART0_RXD", "V3V3"].map((n, i) =>
link("J_UART", `pin${i + 1}`, n),
)}
<pinheader
name="J_JTAG"
pinCount={14}
pcbX={2}
pcbY={31}
footprint={
<footprint>
{Array.from({ length: 14 }, (_, i) => (
<platedhole
portHints={[`pin${i + 1}`]}
shape="circle"
pcbX={((i % 2) - 0.5) * 1.27}
pcbY={(Math.floor(i / 2) - 3) * 1.27}
holeDiameter={0.6}
outerDiameter={1}
/>
))}
</footprint>
}
/>
{[
"V3V3",
"TMS",
"GND",
"TCK",
"GND",
"TDO",
"GND",
"TDI",
"TRSTn",
"GND",
"EMU0",
"EMU1",
"WARMRSTn",
"GND",
].map((n, i) => link("J_JTAG", `pin${i + 1}`, n))}
<pinheader name="J_RESET" pinCount={2} pitch={2.54} pcbX={-31} pcbY={8} />
{link("J_RESET", "pin1", "WARMRSTn")}
{link("J_RESET", "pin2", "GND")}
<testpoint
name="TP_PB"
footprintVariant="pad"
padDiameter={1}
pcbX={-30}
pcbY={1}
/>
{link("TP_PB", "pin1", "PMIC_PB")}
</>
);
}