pixalynx/usb3-hub-10g
A USB 3.2 Gen 2 six-port hub board with USB-C PD power input, regulated 5 V/3.3 V/1.15 V rails, one upstream and four protected downstream USB-A/USB-C ports, SuperSpeed muxes, ESD protection, and controlled port power.
- Version
- 0.0.1
- License
- unset
- Stars
- 0
lib/footprints.tsx
import { Children, Fragment, type ReactElement } from "react"
/** Land-pattern generators. Every dimension is in millimetres and is annotated
* with the manufacturer document it was read from (see docs/sources.md and research/).
* Pin numbering follows the manufacturer's pin table; pin 1 is top-left in the
* unrotated footprint and numbering proceeds counter-clockwise for QFN/LGA
* packages (left side downwards, bottom left-to-right, right upwards, top
* right-to-left), which is the JEDEC convention used by Nordic, TI and ST. */
export const pad = (pin: number | string, x: number, y: number, w: number, h: number) => (
<Fragment key={`p${pin}-${x}-${y}`}>
<smtpad portHints={[typeof pin === "number" ? `pin${pin}` : pin]} pcbX={x} pcbY={y} width={w} height={h} shape="rect" />
</Fragment>
)
export const circlePad = (pin: number | string, x: number, y: number, d: number) => (
<Fragment key={`c${pin}-${x}-${y}`}>
<smtpad portHints={[typeof pin === "number" ? `pin${pin}` : pin]} pcbX={x} pcbY={y} radius={d / 2} shape="circle" />
</Fragment>
)
export const via = (pin: number | string, x: number, y: number, drill: number, padD: number) => (
<Fragment key={`v${pin}-${x}-${y}`}>
<platedhole portHints={[typeof pin === "number" ? `pin${pin}` : pin]} pcbX={x} pcbY={y} holeDiameter={drill} outerDiameter={padD} shape="circle" />
</Fragment>
)
export const outline = (w: number, h: number, stroke = 0.12) => (
<silkscreenpath route={[{ x: -w / 2, y: -h / 2 }, { x: w / 2, y: -h / 2 }, { x: w / 2, y: h / 2 }, { x: -w / 2, y: h / 2 }, { x: -w / 2, y: -h / 2 }]} strokeWidth={stroke} />
)
export const courtyard = (w: number, h: number) => (
<courtyardoutline outline={[{ x: -w / 2, y: h / 2 }, { x: w / 2, y: h / 2 }, { x: w / 2, y: -h / 2 }, { x: -w / 2, y: -h / 2 }, { x: -w / 2, y: h / 2 }]} />
)
const pin1Mark = (x: number, y: number) => <silkscreencircle pcbX={x} pcbY={y} radius={0.15} strokeWidth={0.1} />
/** Generic QFN/DFN land pattern.
* @param nx pins per horizontal side (top/bottom); @param ny pins per vertical side (left/right)
* @param pitch pin pitch; @param span centre-to-centre distance of opposite land rows
* @param landL land length (radial); @param landW land width (tangential)
* @param ep exposed-pad copper size (0 = none); @param epVias grid of ground vias in the EP
*/
export function Qfn(p: { nx: number; ny: number; pitch: number; spanX: number; spanY?: number; landL: number; landW: number; ep?: number | [number, number]; epVias?: { n: number; pitch: number; drill: number; pad: number }; body: [number, number]; epPin?: number }) {
const { nx, ny, pitch, spanX, landL, landW } = p
const spanY = p.spanY ?? spanX
const total = 2 * nx + 2 * ny
const epPin = p.epPin ?? total + 1
const pads: ReactElement[] = []
let n = 1
// left side, top to bottom
for (let i = 0; i < ny; i++) pads.push(pad(n++, -spanX / 2, ((ny - 1) / 2 - i) * pitch, landL, landW))
// bottom, left to right
for (let i = 0; i < nx; i++) pads.push(pad(n++, (i - (nx - 1) / 2) * pitch, -spanY / 2, landW, landL))
// right, bottom to top
for (let i = 0; i < ny; i++) pads.push(pad(n++, spanX / 2, (i - (ny - 1) / 2) * pitch, landL, landW))
// top, right to left
for (let i = 0; i < nx; i++) pads.push(pad(n++, ((nx - 1) / 2 - i) * pitch, spanY / 2, landW, landL))
const [epW, epH] = p.ep ? (Array.isArray(p.ep) ? p.ep : [p.ep, p.ep]) : [0, 0]
const vias: ReactElement[] = []
if (p.epVias && epW) {
const { n: g, pitch: vp, drill, pad: vpad } = p.epVias
for (let i = 0; i < g; i++) for (let j = 0; j < g; j++)
vias.push(via(epPin, (i - (g - 1) / 2) * vp, (j - (g - 1) / 2) * vp, drill, vpad))
}
return (
<footprint>
{Children.toArray(pads)}
{epW > 0 && pad(epPin, 0, 0, epW, epH)}
{Children.toArray(vias)}
{outline(p.body[0], p.body[1])}
{pin1Mark(-p.body[0] / 2 - 0.45, p.body[1] / 2 - 0.1)}
{courtyard(spanX + landL + 0.3, spanY + landL + 0.3)}
</footprint>
)
}
/** 0201 chip capacitor: the footprinter's 0201 lands (0.46 x 0.40 mm at +/-0.33 mm) with a courtyard drawn at the
* pad extents + 0.05 mm, so 0201 decoupling can sit at a QFN pin tip as in Nordic's nRF7002 reference layout. */
export const Cap0201 = () => (
<footprint>
{pad(1, -0.33, 0, 0.46, 0.4)}
{pad(2, 0.33, 0, 0.46, 0.4)}
{courtyard(1.22, 0.5)}
</footprint>
)
/** 0201 "least" land for decouplers that sit in a 0.40 mm QFN lead lane between two SuperSpeed pairs: 0.30 x 0.30 mm
* lands at +/-0.30 mm (IPC-7351 least; sync-stream-media-hub used the same land for the USB7206C). A 0.27 mm pair
* conductor on the neighbouring 0.4 mm-pitch lead then clears the land by 0.115 mm without jogging. */
export const Cap0201Lane = () => (
<footprint>
{pad(1, -0.3, 0, 0.3, 0.3)}
{pad(2, 0.3, 0, 0.3, 0.3)}
{courtyard(1.2, 0.6)}
</footprint>
)