Week 6 — On Painting with Copper

XIAO ESP32‑S3 • MAX98357A I²S amp • 8 Ω speaker • capacitive touch buttons

overview

This week I continued the “earphone earrings” dream. I started bold, then realized the first version used a part that isn’t in the lab inventory (oops). So I pivoted to a breakout‑friendly design: an Adafruit MAX98357A I²S amp and a discrete 8 Ω speaker. My custom board handles power, connectors, and shiny copper capacitive pads. Copper‑ation, if you will.

Tutorial board on cardboard
Warm‑up board to de‑risk the main build. Cardboard is the new eval kit.

pivot & resources

I read around on earphone PCB layouts and community projects to sanity‑check the new plan: earphone PCB overview · WirelessHardware repo. The goal was to minimize custom analog while still learning PCB layout on a wearable form factor.

parts & links

ItemLinkNotes
I²S amplifier breakout (MAX98357A) Adafruit 3006 DAC + class‑D. Inputs: BCLK / LRCLK / DIN. Output: SPK± (don’t ground SPK−).
8 Ω speaker Mallory PSR‑23F08S‑JQ Panel‑mount; wire directly to breakout’s SPK± terminals.
MCU Seeed XIAO ESP32‑S3 I²S output; touch‑capable GPIOs for the capacitive buttons.
Headers / sockets 1×7 female socket (2.54 mm) Matches the breakout’s 7‑pin header footprint (I originally thought 8, ha!).
Picking an LED
Choosing a status LED for charging/ready/connected vibes.
Soldering the speaker
Soldering the panel‑mount speaker leads: tin, place, breathe.

technical design summary

ESP32‑S3 doesn’t have a true DAC. I wanted clean audio without wrestling PWM filters, so I picked the MAX98357A: the ESP32 sends I²S (BCLK, LRCLK, DIN) and the breakout does the DAC + class‑D part to drive the 8 Ω speaker directly.

breakout header mapping

Adafruit‑style 7‑pin order (left→right): LRC, BCLK, DIN, GAIN, SD, GND, VIN. I used a 1×7 female socket so the module with male pins can plug in.

wiring plan

capacitive buttons

Two big copper pads → touch‑capable GPIOs, each with ~220 Ω–1 kΩ series resistor for ESD/RF sanity. Firmware plans: Play/Pause (tap) and Volume (tap=up; hold=down).

sd/mode quick reference

schematic & pcb notes (what I tried & why)

// example pins (firmware bring-up)
#define I2S_BCLK  8
#define I2S_LRCLK 9
#define I2S_DOUT  10
// init I²S → generate a sine → scale by 'volume'
  
Realizing I forgot the through-holes
That moment when you remember through‑holes… and labeling. Back to KiCad!

breakout footprint plan

I first allocated 8 sockets (optimism!), then corrected to 7 to match the breakout. Labels mirror the breakout silkscreen to be future‑me‑proof.

pcb iterations & mistakes

PCB v1 was a learning board. Things I messed up, and the fixes I shipped in v2:

Take 0 failed soldering practice
Take 0 — a few cold joints and little bridges. We do not bridge the gap metaphorically or electrically.
Take 1 all soldered up
Take 1 — cleaner joints and smarter placement. Practice makes presentable.

Fixes: USB‑C keep‑out, wider traces/clearances, bigger pads, solid GND fill.

Milled PCB take 1
Milled PCB — first pass.
Final board take 2
Second revision assembled and much less cursed.
Soldering the speaker after
Speaker connections cleaned up after rework.

milling notes

Milling on the monoFab became the plot twist: ~30 min cuts + ~20–30 min setup/debug. One tiny fail can cost an hour, and lines form fast. Copper patience is a virtue.

mods screenshot
mods settings used for trace/outline jobs.
mods position for milling
Positioning before committing the job.
mods traces path
Toolpath preview to verify isolation widths.
The PCB milling machine
The monoFab mill — MVP and time sink.
Milling traces take 1
First trace pass — learned the limits on minimum width.
Milling traces take 2
Second pass — better isolation after widening.
Milling result take 1
First complete milling result — still some fragile bits.
Milling timelapse (take 1).

pcb-as-earring idea

Because jewelry! I added small edge‑cut loops so the board can hang like an earring. It looks fun; we’ll see how the FR‑1 edges hold up in the wild.

Board with edge cuts
Edge‑cut loops for a jump ring or wire.

bring-up & testing

My plan was: continuity → power‑only → LED → touch → I²S wiring → audio. Here’s what I actually got through.

  1. Continuity/shorts: checked 5 V/3V3 rails, GND, headers, pads, LED net.
  2. Power‑only test: enumerated over USB‑C, no suspicious heat.
  3. LED sanity: wrote a tiny blink sketch to confirm GPIO mapping.

LED test code

First, verify the LED pin actually toggles. Simple, but catches wiring mistakes fast.

// Simple LED blink test for Xiao ESP32-S3
// Replace LED_PIN with the actual GPIO you wired the LED to.
// If you're using the *onboard* status LED, try LED_BUILTIN.

int LED_PIN = 8;  // change to your LED GPIO (or use LED_BUILTIN)

void setup() {
  pinMode(LED_PIN, OUTPUT);
  // optional: start LOW so you can see the first transition clearly
  digitalWrite(LED_PIN, LOW);
}

void loop() {
  digitalWrite(LED_PIN, HIGH);
  delay(500);
  digitalWrite(LED_PIN, LOW);
  delay(500);
}
All soldered up
Assembled board ready for firmware bring‑up.
Soldering session timelapse.

…and then we got stuck

I hit a wall talking to the Xiao (uploads failing). Classic lab hour plot twist. Here’s what I tried before time ran out:

Still no luck within the time window, so I parked firmware and focused on documenting the hardware steps (this page!). Next week I’ll get it talking and then add the I²S tone test.

people & thanks

MVP: Aidan (Architecture shop) — monoFab whisperer. Huge thank you to Gert for coming in on his days off (Sunday & Indigenous Peoples’ Day) to support the Arch section.

next steps