Devesh36/facet-four
FACET Four: a USB-C macro controller with four angled keys, a volume encoder, blue LEDs, an OLED and a fitted enclosure. Includes assembled, exploded and routed PCB views. Hardware prototype; firmware required.
- Version
- 0.1.3
- License
- unset
- Stars
- 0
index.circuit.tsx
PCB
Schematic
import 'tscircuit'
import {Fragment} from 'react'
import {RP2040_Zero} from './imports/RP2040_Zero'
import {KH_6X6X5H_STM} from './imports/KH_6X6X5H_STM'
import {PEC11R_4020F_S0024} from './imports/PEC11R_4020F_S0024'
import {XL_1608UBC_04} from './imports/XL_1608UBC_04'
import {keys,leds,mounts} from './layout'
const loc=(x:number,y:number,sx:number,sy:number,s:string)=>({pcbX:x,pcbY:y,schX:sx,schY:sy,schSheetName:s,schSectionName:s})
export const nets:Record<string,string[]>={
GND:['U1.pin22','TP2.pin1','C1.pin2','C2.pin2','ENC1.pin2','ENC1.pin5','ENC1.pin7','ENC1.pin8'],
V3V3:['U1.pin21','TP1.pin1','C1.pin1','C2.pin1','RSDA.pin1','RSCL.pin1','REA.pin1','REB.pin1','REP.pin1'],
SDA:['U1.pin1','TP3.pin1','RSDA.pin2'],SCL:['U1.pin2','TP4.pin1','RSCL.pin2'],
ENCODER_A:['U1.pin7','ENC1.pin1','REA.pin2'],ENCODER_B:['U1.pin8','ENC1.pin3','REB.pin2'],ENCODER_PUSH_N:['U1.pin9','ENC1.pin4','REP.pin2'],
}
for(let i=1;i<=4;i++){
nets.GND.push(`SW${i}.pin3`,`SW${i}.pin4`,`LED${i}.pin1`)
nets.V3V3.push(`RK${i}.pin1`)
nets[`KEY${i}_N`]=[`U1.pin${i+2}`,`RK${i}.pin2`,`SW${i}.pin1`,`SW${i}.pin2`]
nets[`LED${i}_GPIO`]=[`U1.pin${i+9}`,`RL${i}.pin1`]
nets[`LED${i}_A`]=[`RL${i}.pin2`,`LED${i}.pin2`]
}
const unused=['pin14','pin15','pin16','pin17','pin18','pin19','pin20','pin23','pin24','pin25','pin26','pin27','pin28','pin29','pin30','pin31','pin32','pin33'] as const
export default function FacetBoard(){return <board width={80} height={64} thickness={1.6} layers={4} title="FACET Four • USB macro controller" solderMaskColor="blue" schTraceAutoLabelEnabled autorouter={{local:true,traceClearance:0.18}} minTraceWidth={0.2} minViaHoleDiameter={0.3} minViaPadDiameter={0.6} minBoardEdgeClearance={0.3}>
{['controller','keys','encoder'].map(s=><Fragment key={s}><schematicsheet name={s} displayName={{controller:'Native USB controller / OLED / 3.3 V',keys:'Four macro keys / blue indicators',encoder:'Volume encoder / push switch'}[s]}><schematicsection name={s}/></schematicsheet></Fragment>)}
<RP2040_Zero name="U1" layer="bottom" pcbRotation={180} {...loc(24,-17,-1,0,'controller')} schWidth={4} schHeight={4.5} noConnect={unused}/>
{[1,2,3,4].map(i=><testpoint key={i} name={`TP${i}`} doNotPlace footprintVariant="pad" padDiameter={1.8} {...loc(-20+i*3,16,5+i*2,5,'controller')}/>)}
<capacitor name="C1" capacitance="100nF" footprint="0603" manufacturerPartNumber="CL10B104KB8NNNC" {...loc(11,-24,8,-3,'controller')}/>
<capacitor name="C2" capacitance="1uF" footprint="0603" manufacturerPartNumber="CL10A105KB8NNNC" {...loc(11,-20,11,-3,'controller')}/>
<resistor name="RSDA" resistance="4.7k" footprint="0603" manufacturerPartNumber="RC0603FR-074K7L" {...loc(-8,19,8,0,'controller')}/>
<resistor name="RSCL" resistance="4.7k" footprint="0603" manufacturerPartNumber="RC0603FR-074K7L" {...loc(-15,19,11,0,'controller')}/>
{keys.map((k,i)=><Fragment key={i}>
<KH_6X6X5H_STM name={`SW${i+1}`} pcbRotation={k.angle} internallyConnectedPins={[["pin1","pin2"],["pin3","pin4"]]} {...loc(k.x,k.y,-9+i*6,0,'keys')}/>
<resistor name={`RK${i+1}`} resistance="10k" footprint="0603" manufacturerPartNumber="RC0603FR-0710KL" {...loc(k.x+7,k.y-5,-9+i*6,4,'keys')}/>
<XL_1608UBC_04 name={`LED${i+1}`} pcbRotation={k.angle} {...loc(leds[i].x,leds[i].y,-9+i*6,-5,'keys')}/>
<resistor name={`RL${i+1}`} resistance="1k" footprint="0603" manufacturerPartNumber="RC0603FR-071KL" {...loc(k.x+4,k.y-10,-9+i*6,-9,'keys')}/>
<silkscreentext text={`KEY ${i+1}`} pcbX={k.x} pcbY={k.y+7} fontSize={0.8}/>
</Fragment>)}
<PEC11R_4020F_S0024 name="ENC1" pcbRotation={45} {...loc(24,12,0,0,'encoder')} schWidth={4} schHeight={5}/>
{['REA','REB','REP'].map((name,i)=><resistor key={name} name={name} resistance="10k" footprint="0603" manufacturerPartNumber="RC0603FR-0710KL" {...loc(12+i*5,27,-5+i*5,6,'encoder')}/>)}
{mounts.map(([x,y])=><Fragment key={`${x},${y}`}><hole diameter={2.2} pcbX={x} pcbY={y}/></Fragment>)}
<silkscreentext text="FACET FOUR" pcbX={3} pcbY={30} fontSize={1.1}/>
<silkscreentext text="USB-C / DATA + 5V" pcbX={24} pcbY={-30} fontSize={0.65}/>
<silkscreentext text="V G SDA SCL" pcbX={-12.5} pcbY={14} fontSize={0.7}/>
<silkscreentext text="VOLUME / PUSH" pcbX={24} pcbY={-1} fontSize={0.65}/>
{Object.entries(nets).map(([name,pins])=><Fragment key={name}><net name={name} isGroundNet={name==='GND'} isPowerNet={name==='V3V3'} nominalTraceWidth={name==='GND'||name==='V3V3'?0.3:0.2}/>{pins.map(pin=><trace key={pin} from={`.${pin.split('.')[0]} > .${pin.split('.')[1]}`} to={`net.${name}`}/>)}</Fragment>)}
</board>}