mohan-bee/mini-mp3-player
Portable, battery-powered MP3 player hardware with USB charging, microSD storage, an MCU, VS10xx audio decoder, headphone output, status controls, and regulated power rails.
- Version
- 1.2.0
- License
- unset
- Stars
- 0
index.circuit.tsx
PCB
Schematic
import { savedAutorouting } from './routing/saved-autorouting'
import { PlayerAssembly } from './mechanical/PlayerAssembly'
import { CH32V203C8T6 } from './imports/CH32V203C8T6'
import { VS1003B_L } from './imports/VS1003B_L'
import { BQ24074RGTR } from './imports/BQ24074RGTR'
import { ME6211C33M5G_N } from './imports/ME6211C33M5G_N'
import { ME6211A25M3G_N } from './imports/ME6211A25M3G_N'
import { ME6219C27M5G } from './imports/ME6219C27M5G'
import { TF_01A } from './imports/TF_01A'
import { PJ_320D } from './imports/PJ_320D'
import { TS_1088_AR02016 } from './imports/TS_1088_AR02016'
import { MSK12C02 } from './imports/MSK12C02'
import { X32258MOB4SI } from './imports/X32258MOB4SI'
import { Fragment } from 'react'
import { KT_0603R } from './imports/KT_0603R'
import { KT_0805G } from './imports/KT_0805G'
import { AO3401A } from './imports/AO3401A'
import { A_3225_12_288_20_10_10_A } from './imports/A_3225_12_288_20_10_10_A'
import { resistorParts, capacitorParts } from './parts'
import { pinNets, resistors, caps } from './design'
import { B3B_PH_SM4_TB_LF__SN_ } from './imports/B3B_PH_SM4_TB_LF__SN_'
import { RVT0J221M0605_220UF_6_3V } from './imports/RVT0J221M0605_220UF_6_3V'
const N = (s:string) => `net.${s}`
const conn = (pins:Record<string,string>) => Object.fromEntries(Object.entries(pins).map(([p,n])=>[/^\d+$/.test(p)?`pin${p}`:p,N(n)]))
const buttons = [['SW1','PLAY',-12],['SW2','PREV',0],['SW3','NEXT',12],['SW4','MODE',24]] as const
const chips = [
[BQ24074RGTR,'U1',-20,-8.6,'Power'],[ME6211C33M5G_N,'U2',-12,-13,'Power'],
[ME6211A25M3G_N,'U3',-3,-12,'Power'],[ME6219C27M5G,'U4',8,-12,'Power'],
[CH32V203C8T6,'U5',-13,6,'MCU'],[VS1003B_L,'U6',12,12,'Decoder'],
] as const
const sheetBySection: Record<string, string> = {
Power: "power", MCU: "controller", Debug: "controller",
Decoder: "audio", Audio: "audio", Storage: "interface", Controls: "interface",
}
function SheetNotes({ x, y, lines }: { x: number; y: number; lines: string[] }) {
return <>{lines.map((text, i) => <Fragment key={text}><schematictext text={text} schX={x} schY={y-i*1.4} fontSize={0.7} anchor="left" /></Fragment>)}</>
}
export default function MiniMp3Player({ exploded = false }: { exploded?: boolean } = {}) {
return <board width="82mm" height="62mm" layers={2} thickness="1.6mm"
schAutoLayoutEnabled autorouterVersion="beta_pipeline9" autorouterEffortLevel="2x"
autorouter={{local:true,allowViaInPad:false,traceClearance:"0.25mm",algorithmFn:savedAutorouting}} minTraceWidth="0.18mm"
minViaHoleDiameter="0.3mm" minViaPadDiameter="0.45mm"
minViaEdgeToPadEdgeClearance="0.15mm" minViaHoleEdgeToViaHoleEdgeClearance="0.25mm">
<schematicsheet name="power" displayName="01 · USB-C, Battery & Power" sheetIndex={1} sheetWidth={750} sheetHeight={500}>
<schematicsection name="Power" displayName="Power" />
<SheetNotes x={-44} y={-28} lines={[
'POWER: USB-C input, protected battery, charger and regulated supplies.',
'J1: 5 V charging only. Separate 5.1k CC resistors identify a USB-C sink.',
'U1 BQ24074: power path; about 300 mA charge current, USB500 input limit.',
'J2: pin 1 BAT+, pin 2 cell-mounted 10k NTC, pin 3 GND. Protected 1S pack only.',
'SW7 controls Q1 system power. Charging remains available with the switch OFF.',
'Q2 disconnects the battery ADC divider while OFF, preventing MCU back-power.',
'U2 = 3.3 V logic/card; U3 = 2.5 V decoder core; U4 = 2.7 V decoder analog.',
'D1 red = charging. Local capacitors filter rails and supply transient current.',
]} />
</schematicsheet>
<schematicsheet name="controller" displayName="02 · MCU & Programming" sheetIndex={2} sheetWidth={800} sheetHeight={950}>
<schematicsection name="MCU" displayName="MCU" />
<schematicsection name="Debug" displayName="Debug" />
<SheetNotes x={-16} y={-76} lines={[
'U5 CH32V203: reads FAT files, streams compressed MP3 bytes, handles buttons.',
'Y1: 8 MHz MCU reference. Firmware uses a 72 MHz PLL clock; MCU does not decode audio.',
'Supply capacitors serve every VDD group; reset RC and boot straps select user flash.',
'WCH-Link: TP1 GND, TP2 3.3 V reference, TP3 PA13/SWDIO, TP4 PA14/SWCLK.',
'TP5 = reset; TP6/TP7 = 3.3 V UART TX/RX, 115200 baud. Do not backfeed TP2.',
'PA0 measures half the battery voltage. Calibrate ADC; low-battery stop is not power-off.',
'D2 green: play/pause, volume mode and numbered firmware error indication.',
'TP16 PGOOD is open drain: add an external pull-up to 3.3 V when measuring logic.',
]} />
</schematicsheet>
<schematicsheet name="audio" displayName="03 · MP3 Decoder & Headphones" sheetIndex={3} sheetWidth={850} sheetHeight={800}>
<schematicsection name="Decoder" displayName="Decoder" />
<schematicsection name="Audio" displayName="Audio" />
<SheetNotes x={-10} y={-59} lines={[
'U6 VS1003: hardware MP3 decoder and stereo headphone DAC. Y2 = 12.288 MHz.',
'SPI2 carries SCI commands via XCS and compressed audio via XDCS.',
'DREQ tells the MCU when another burst of up to 32 audio bytes can be accepted.',
'Core = 2.5 V; I/O = 3.3 V; analog = 2.7 V. Never feed analog pins with 3.3 V.',
'C43/C44: 220 uF DC-blocking capacitors; positive terminals face decoder outputs.',
'J4: standard ground-referenced headphones. GBUF must never be shorted to GND.',
'Output RC networks stabilize the headphone drivers. No speaker amplifier is fitted.',
'Volume is set digitally through SCI_VOL; test with dummy loads before headphones.',
]} />
</schematicsheet>
<schematicsheet name="interface" displayName="04 · microSD & Buttons" sheetIndex={4} sheetWidth={800} sheetHeight={400}>
<schematicsection name="Storage" displayName="Storage" />
<schematicsection name="Controls" displayName="Controls" />
<SheetNotes x={-25} y={-59} lines={[
'J3 microSD: SPI1 storage at 3.3 V; FAT16/FAT32, root MP3 files with short 8.3 names.',
'Card CS pull-up keeps it deselected during reset. Local bulk capacitance buffers reads.',
'SW1 PLAY/PAUSE; SW2 PREV; SW3 NEXT; SW4 VOL toggles volume mode.',
'In volume mode PREV lowers volume and NEXT raises it; VOL returns to track mode.',
'R40-R43 pull inputs high; pressing a switch connects its signal to ground.',
'Firmware debounces presses for 25 ms. Switch OFF before removing the microSD.',
]} />
</schematicsheet>
{['USB5V','BAT','SYS_RAW','SYS','V3V3','V2V5','V2V7'].map(name=><Fragment key={name}><net name={name} isPowerNet nominalTraceWidth="0.3mm" /></Fragment>)}
<net name="GND" isGroundNet />
<copperpour connectsTo="net.GND" layer="bottom" clearance="0.4mm" boardEdgeMargin="0.5mm" />
<copperpour connectsTo="net.GND" layer="top" clearance="0.4mm" boardEdgeMargin="0.5mm" />
{chips.map(([Part,name,pcbX,pcbY,schSectionName])=><Part pcbRotation={name === "U6" ? 180 : 0} key={name} schMarginX={0.8} schMarginY={0.8} schSheetName={sheetBySection[schSectionName]} {...{name,pcbX,pcbY,schSectionName}} connections={conn(pinNets[name])} />)}
<connector name="J1" standard="usb_c" supplierPartNumbers={{jlcpcb:["C2765186"]}} pcbX={-34} pcbY={-27} schMarginX={0.8} schMarginY={0.8} schSectionName="Power" schSheetName="power"
connections={conn({VBUS1:'USB5V',VBUS2:'USB5V',CC1:'CC1',CC2:'CC2',GND1:'GND',GND2:'GND',SHELL1:'GND',SHELL2:'GND'})} />
{/* Protected 1S cell, with a 10k NTC thermally attached to the cell. */}
<B3B_PH_SM4_TB_LF__SN_ name="J2" pcbX={-32} pcbY={-4} schMarginX={0.8} schMarginY={0.8} schSectionName="Power" schSheetName="power" connections={conn({1:'BAT',2:'NTC',3:'GND'})} />
{/* Charger remains connected when the system is switched off. */}
<MSK12C02 name="SW7" pcbX={-23} pcbY={-27} schMarginX={0.8} schMarginY={0.8} schSectionName="Power" schSheetName="power" connections={conn({1:'GND',2:'PWR_GATE',4:'GND'})} />
<AO3401A name="Q1" pcbX={-16} pcbY={-14} schMarginX={0.8} schMarginY={0.8} schSectionName="Power" schSheetName="power" connections={conn({1:'PWR_GATE',2:'SYS_RAW',3:'SYS'})} />
<AO3401A name="Q2" pcbX={-28} pcbY={-11} schMarginX={0.8} schMarginY={0.8} schSectionName="Power" schSheetName="power" connections={conn({1:'PWR_GATE',2:'BAT',3:'BAT_SENSE'})} />
<resistor supplierPartNumbers={{jlcpcb:["C25803"]}} name="R36" resistance="100k" footprint="0603" pcbX={-16} pcbY={-17} schMarginX={0.8} schMarginY={0.8} schSectionName="Power" schSheetName="power" connections={conn({1:'PWR_GATE',2:'SYS_RAW'})} />
<X32258MOB4SI name="Y1" loadCapacitance="12pF" pcbX={-14} pcbY={-1.8} pcbRotation={270} schMarginX={0.8} schMarginY={0.8} schSectionName="MCU" schSheetName="controller" connections={conn({1:'MCU_XI',3:'MCU_XO',2:'GND',4:'GND'})} />
<A_3225_12_288_20_10_10_A name="Y2" pcbX={3.8} pcbY={12.5} schMarginX={0.8} schMarginY={0.8} schSectionName="Decoder" schSheetName="audio" connections={conn({1:'VS_XI',3:'VS_XO',2:'GND',4:'GND'})} />
<TF_01A name="J3" pcbX={-31} pcbY={18} pcbRotation={270} schMarginX={0.8} schMarginY={0.8} schSectionName="Storage" schSheetName="interface" connections={conn(pinNets.J3)} />
<PJ_320D name="J4" pcbX={31} pcbY={-14} pcbRotation={180} schMarginX={0.8} schMarginY={0.8} schSectionName="Audio" schSheetName="audio" connections={conn(pinNets.J4)} />
<RVT0J221M0605_220UF_6_3V name="C43" pcbX={17} pcbY={-11} pcbRotation={90} schMarginX={0.8} schMarginY={0.8} schSectionName="Audio" schSheetName="audio" connections={conn({1:'LEFT',2:'HP_L'})} />
<RVT0J221M0605_220UF_6_3V name="C44" pcbX={17} pcbY={-21} pcbRotation={90} schMarginX={0.8} schMarginY={0.8} schSectionName="Audio" schSheetName="audio" connections={conn({1:'RIGHT',2:'HP_R'})} />
{resistors.map(([name,resistance,a,b,pcbX,pcbY,schSectionName])=><resistor supplierPartNumbers={{jlcpcb:[resistorParts[resistance]]}} pcbRotation={["R11","R16","R26","R30","R34","R37"].includes(name)?180:0} key={name} schMarginX={0.8} schMarginY={0.8} schSheetName={sheetBySection[schSectionName]} {...{name,resistance,pcbX,pcbY,schSectionName}} footprint="0603" connections={conn({1:a,2:b})} />)}
{caps.map(([name,capacitance,a,b,pcbX,pcbY,schSectionName])=><capacitor supplierPartNumbers={{jlcpcb:[capacitorParts[capacitance]]}} pcbRotation={["C7","C18","C25","C31"].includes(name)?180:0} key={name} schMarginX={0.8} schMarginY={0.8} schSheetName={sheetBySection[schSectionName]} {...{name,capacitance,pcbX,pcbY,schSectionName}} footprint={capacitance==='10uF'?'0805':'0603'} connections={conn({1:a,2:b})} />)}
{buttons.map(([name,signal,x],i)=><Fragment key={name}>
<TS_1088_AR02016 name={name} pcbX={x} pcbY={-28} schMarginX={0.8} schMarginY={0.8} schSectionName="Controls" schSheetName="interface" connections={conn({1:signal,2:'GND'})} />
<resistor supplierPartNumbers={{jlcpcb:["C25804"]}} name={`R${40+i}`} resistance="10k" footprint="0603" pcbX={x+4.75} pcbY={-28} schMarginX={0.8} schMarginY={0.8} schSectionName="Controls" schSheetName="interface" connections={conn({1:signal,2:'V3V3'})} />
<silkscreentext text={signal === 'MODE' ? 'VOL' : signal} pcbX={x} pcbY={-30} fontSize="0.7mm" />
</Fragment>)}
<KT_0603R name="D1" pcbX={-34} pcbY={-11} schMarginX={0.8} schMarginY={0.8} schSectionName="Power" schSheetName="power" connections={conn({anode:'CHG_LED_A',cathode:'CHG'})} />
<KT_0805G name="D2" pcbX={-3} pcbY={23} schMarginX={0.8} schMarginY={0.8} schSectionName="MCU" schSheetName="controller" connections={conn({anode:'STATUS_A',cathode:'STATUS'})} />
{['GND','V3V3','SWDIO','SWCLK','NRST','UART_TX','UART_RX','BOOT0'].map((n,i)=><Fragment key={n}>
<testpoint name={`TP${i+1}`} pcbX={-16+i*2.5} pcbY={-7} doNotPlace padDiameter="1.2mm" footprintVariant="pad" schMarginX={0.8} schMarginY={0.8} schSectionName="Debug" schSheetName="controller" connections={{pin1:N(n)}} />
<silkscreentext text={n.replace('UART_','').replace('SWDIO','DIO').replace('SWCLK','CLK')} pcbX={-16+i*2.5} pcbY={-8.4} fontSize="0.5mm" />
</Fragment>)}
{['USB5V','BAT','SYS','V2V5','V2V7','VS_DREQ','VS_RESET','PGOOD'].map((n,i)=><Fragment key={n}>
<testpoint name={`TP${i+9}`} pcbX={-20+i*4} pcbY={-20} doNotPlace padDiameter="1.2mm" footprintVariant="pad" schMarginX={0.8} schMarginY={0.8} schSectionName="Debug" schSheetName="controller" connections={{pin1:N(n)}} />
<silkscreentext text={n.replace('VS_','')} pcbX={-20+i*4} pcbY={-21.4} fontSize="0.55mm" />
</Fragment>)}
{/* Bottom copper exclusions force vias clear of these top-side pad edges. */}
<keepout shape="rect" layer="bottom" pcbX={-13} pcbY={10.25} width="6.3mm" height="2.15mm" />
<keepout shape="rect" layer="bottom" pcbX={12} pcbY={16.25} width="6.3mm" height="2.15mm" />
<keepout shape="rect" layer="bottom" pcbX={-17.25} pcbY={3.75} width="1.85mm" height="0.5mm" />
<keepout shape="rect" layer="bottom" pcbX={-13.15} pcbY={-0.7} width="1.4mm" height="1.8mm" />
<keepout shape="rect" layer="bottom" pcbX={16.25} pcbY={12} width="1.75mm" height="6.1mm" />
<keepout shape="rect" layer="bottom" pcbX={-8.75} pcbY={6} width="1.85mm" height="6.1mm" />
<keepout shape="rect" layer="bottom" pcbX={-6.825} pcbY={9} width="1mm" height="1.2mm" />
{/* Oscillator loops are hand-routed; normal nets use the autorouter. */}
<trace from=".U5 > .pin5" to=".Y1 > .pin1" pcbPath={[".U5 > .pin5",{x:-0.75,y:-5.4},{x:-1.85,y:-6.5},".Y1 > .pin1"]} />
<trace from=".U5 > .pin6" to=".Y1 > .pin3" pcbPath={[".U5 > .pin6",{x:-0.25,y:-5.3},{x:1.1,y:-5.3},{x:1.1,y:-8.9},".Y1 > .pin3"]} />
<trace from=".Y1 > .pin1" to=".C18 > .pin1" pcbPath={[".Y1 > .pin1",{x:-1.3,y:-2.3},".C18 > .pin1"]} />
<trace from=".Y1 > .pin3" to=".C19 > .pin1" pcbPath={[".Y1 > .pin3",".C19 > .pin1"]} />
<trace from=".U6 > .pin18" to=".Y2 > .pin1" pcbPath={[".U6 > .pin18",{x:5.4,y:-0.25},{x:5.8,y:0.15},{x:5.8,y:1.4},{x:9.3,y:1.4},".Y2 > .pin1"]} />
<trace from=".U6 > .pin17" to=".Y2 > .pin3" pcbPath={[".U6 > .pin17",{x:5.4,y:-0.75},{x:6.025,y:-1.375},".Y2 > .pin3"]} />
<trace from=".Y2 > .pin1" to=".C31 > .pin1" pcbPath={[".Y2 > .pin1",".C31 > .pin1"]} />
<trace from=".Y2 > .pin3" to=".C32 > .pin1" pcbPath={[".Y2 > .pin3",".C32 > .pin1"]} />
<via name="VG1" pcbX={-22.5} pcbY={-6} holeDiameter="0.3mm" outerDiameter="0.6mm" fromLayer="top" toLayer="bottom" connectsTo="net.GND" />
<via name="VG2" pcbX={-18} pcbY={-6.5} holeDiameter="0.3mm" outerDiameter="0.6mm" fromLayer="top" toLayer="bottom" connectsTo="net.GND" />
<hole name="H1" pcbX={-8} pcbY={27} diameter="2.2mm" />
<hole name="H2" pcbX={16} pcbY={27} diameter="2.2mm" />
<hole name="H3" pcbX={37} pcbY={-26} diameter="2.2mm" />
<fiducial name="FID1" pcbX={-38} pcbY={28} padDiameter="1mm" soldermaskPullback="0.5mm" />
<fiducial name="FID2" pcbX={37} pcbY={-22} padDiameter="1mm" soldermaskPullback="0.5mm" />
<silkscreentext text="MINI MP3 / REV B" pcbX={28} pcbY={27} fontSize="1mm" />
<PlayerAssembly exploded={exploded} />
</board>
}