# Baby Mobile Audio Board — Design Document ## Overview Drop-in replacement board for a baby crib mobile. Plays custom audio from SPI flash memory, drives a DC motor, handles 8 button inputs, and runs for days on two AA batteries. **Key design decisions for long battery life:** - SPI flash instead of microSD (4mA vs 30–100mA read current) - Class-D amplifier at 90% efficiency (vs ~50% for class AB) - ATmega328P internal 8MHz oscillator (no crystal, lower BOM) - Logic-level MOSFET motor driver (no gate driver IC needed) - Aggressive sleep with pin-change interrupt wake ## Schematic Netlist (Logical Connections) ### Power ``` 2xAA Battery → SW9(PWR) → VCC rail VCC → C1(100µF) → GND bulk decoupling VCC → C2(100nF) → GND MCU VCC decoupling VCC → C3(100nF) → GND MCU AVCC decoupling VCC → C5(100nF) → GND Flash decoupling VCC → C8(10µF) → GND Amp supply bypass ``` ### MCU: U1 — ATmega328P-AU (TQFP-32) | MCU Pin | Port | Function | Connected To | |---------|----------|---------------|---------------------------| | 30 | PD0/RXD | Serial RX | J5 pin 3 (SERIAL header) | | 31 | PD1/TXD | Serial TX | J5 pin 2 (SERIAL header) | | 32 | PD2/INT0 | Button 3 | SW3 → GND (active LOW) | | 1 | PD3/INT1 | Button 4 | SW4 → GND (active LOW) | | 2 | PD4 | Button 5 | SW5 → GND (active LOW) | | 9 | PD5/OC0B | Motor PWM | R4(100Ω) → Q1 gate | | 10 | PD6/OC0A | Button 6 | SW6 → GND (active LOW) | | 11 | PD7 | Button 7 | SW7 → GND (active LOW) | | 12 | PB0 | Button 8 | SW8 → GND (active LOW) | | 13 | PB1/OC1A | Audio PWM | R2(4.7K) → C7(10nF) → U3 | | 14 | PB2/SS | Flash ~CS | U2 pin 1 | | 15 | PB3/MOSI | SPI MOSI | U2 pin 5, J4 MOSI | | 16 | PB4/MISO | SPI MISO | U2 pin 2, J4 MISO | | 17 | PB5/SCK | SPI SCK | U2 pin 6, J4 SCK | | 23 | PC0/ADC0 | Button 1 | SW1 → GND (active LOW) | | 24 | PC1/ADC1 | Button 2 | SW2 → GND (active LOW) | | 25 | PC2/ADC2 | Amp ~SD | U3 pin 1 + R3(100K)→GND | | 26 | PC3/ADC3 | Status LED | R6(1K) → D2(LED) → GND | | 27 | PC4/SDA | (spare/I2C) | — | | 28 | PC5/SCL | (spare/I2C) | — | | 29 | PC6/~RST | Reset | R1(10K)→VCC, C4(100nF)→GND| | 4 | VCC | Power | VCC rail | | 6 | AVCC | Analog power | VCC rail (via ferrite opt) | | 21 | AREF | Reference | C3(100nF) → GND | | 3, 5 | GND | Ground | GND rail | | 7 | XTAL1 | (unused) | leave floating | | 8 | XTAL2 | (unused) | leave floating | ### SPI Flash: U2 — W25Q128JVSIQ (SOIC-8) | Pin | Name | Connected To | |-----|-----------|-----------------| | 1 | ~CS | PB2 (FLASH_CS) | | 2 | DO (MISO) | PB4 (SPI_MISO) | | 3 | ~WP | VCC (tie high) | | 4 | GND | GND | | 5 | DI (MOSI) | PB3 (SPI_MOSI) | | 6 | CLK | PB5 (SPI_SCK) | | 7 | ~HOLD | VCC (tie high) | | 8 | VCC | VCC | ### Audio Amplifier: U3 — PAM8302AASCR (SOIC-8) | Pin | Name | Connected To | |-----|------|-------------------------------------------| | 1 | ~SD | PC2 (AMP_SD) + R3(100K) pulldown to GND | | 2 | VDD | VCC + C8(10µF) bypass | | 3 | GND | GND | | 4 | A+ | Audio signal from RC filter | | 5 | A- | GND (single-ended input) | | 6 | PAD | GND (thermal pad) | | 7 | VO- | Speaker - | | 8 | VO+ | Speaker + | **Audio signal path:** ``` PB1 (OC1A PWM) → R2 (4.7KΩ) → node → C6 (1µF coupling) → U3 A+ (pin 4) | C7 (10nF) → GND RC low-pass filter: fc = 1/(2π × 4700 × 10e-9) ≈ 3.4 kHz This removes the PWM carrier while passing audio baseband. ``` **Shutdown control:** - R3 (100K) pulls ~SD LOW by default = amplifier OFF - MCU drives PC2 HIGH to enable amplifier - Saves ~2mA quiescent current when not playing ### Motor Driver ``` PD5 (OC0B) → R4 (100Ω gate resistor) → Q1 Gate | R5 (100K) → GND (pulldown, ensures OFF at boot) Q1: AO3400A N-ch MOSFET (SOT-23) Drain → Motor terminal 1 Source → GND (Motor terminal 2 → VCC) D1: SS14 Schottky flyback diode across motor (Cathode → VCC, Anode → Drain) ``` **Motor specs:** - PWM on Timer0 (OC0B) for variable speed - AO3400A: Vgs(th) = 0.65V typ, fully enhanced at 1.8V → works at depleted AA voltage - R4 limits gate ringing; R5 ensures MOSFET OFF during MCU reset/programming ### Button Matrix All 8 buttons connect between their MCU pin and GND (active LOW). MCU internal pull-ups enabled (~30–50KΩ). No external pull-up resistors needed. Buttons are on PCINT-capable pins for wake-from-sleep: - SW1 (PC0) → PCINT8 - SW2 (PC1) → PCINT9 - SW3 (PD2) → INT0 (hardware interrupt) - SW4 (PD3) → INT1 (hardware interrupt) - SW5 (PD4) → PCINT20 - SW6 (PD6) → PCINT22 - SW7 (PD7) → PCINT23 - SW8 (PB0) → PCINT0 ### Headers **J4 — ISP (2×3, standard Atmel AVR ISP pinout):** ``` MISO 1 ● 2 VCC SCK 3 4 MOSI ~RST 5 6 GND ``` **J5 — Serial (1×3, for bootloader programming / debug):** ``` GND 1 TXD 2 (MCU TX out) RXD 3 (MCU RX in) ``` ## Bill of Materials | Ref | Value/Part | Package | Qty | ~Cost | Notes | |------|------------------|-------------------|-----|--------|-------------------------------| | U1 | ATmega328P-AU | TQFP-32 | 1 | $2.50 | Pre-burn Arduino bootloader | | U2 | W25Q128JVSIQ | SOIC-8 | 1 | $1.20 | 16MB, 33min @ 8kHz/8bit | | U3 | PAM8302AASCR | SOIC-8 | 1 | $0.80 | 2.5W class-D, Vmin=2.0V | | Q1 | AO3400A | SOT-23 | 1 | $0.15 | Logic-level N-ch MOSFET | | D1 | SS14 | SMA | 1 | $0.10 | Motor flyback protection | | D2 | LED (green) | 0805 | 1 | $0.05 | Status indicator | | R1 | 10KΩ | 0805 | 1 | $0.01 | Reset pull-up | | R2 | 4.7KΩ | 0805 | 1 | $0.01 | Audio LPF resistor | | R3 | 100KΩ | 0805 | 1 | $0.01 | Amp shutdown pull-down | | R4 | 100Ω | 0805 | 1 | $0.01 | MOSFET gate resistor | | R5 | 100KΩ | 0805 | 1 | $0.01 | MOSFET gate pull-down | | R6 | 1KΩ | 0805 | 1 | $0.01 | LED current limit | | C1 | 100µF/10V | Radial 5mm | 1 | $0.15 | Bulk power decoupling | | C2 | 100nF | 0805 | 1 | $0.01 | MCU VCC bypass | | C3 | 100nF | 0805 | 1 | $0.01 | MCU AVCC/AREF bypass | | C4 | 100nF | 0805 | 1 | $0.01 | Reset noise filter | | C5 | 100nF | 0805 | 1 | $0.01 | Flash bypass | | C6 | 1µF | 0805 | 1 | $0.02 | Audio AC coupling | | C7 | 10nF | 0805 | 1 | $0.01 | Audio LPF capacitor | | C8 | 10µF | 0805 | 1 | $0.05 | Amp supply bypass | | SW1-8| Tactile switch | 6mm SMD | 8 | $0.80 | Or reuse existing buttons | | SW9 | SPDT slide | THT | 1 | $0.20 | Power switch | | J1 | JST-PH 2-pin | THT | 1 | $0.15 | Battery connector | | J2 | JST-PH 2-pin | THT | 1 | $0.15 | Speaker connector | | J3 | JST-PH 2-pin | THT | 1 | $0.15 | Motor connector | | J4 | 2×3 pin header | 2.54mm | 1 | $0.10 | ISP programming | | J5 | 1×3 pin header | 2.54mm | 1 | $0.05 | Serial debug | | — | AA battery holder| 2×AA | 1 | $0.50 | Reuse existing | | | | | | | | | | **TOTAL** | | |**~$7** | | ## Power Analysis ### Current draw by state: | State | MCU | Flash | Amp | Motor | Total | |--------------------|--------|--------|--------|--------|---------| | Playing + spinning | 4 mA | 4 mA | 3 mA | 80 mA | ~91 mA | | Playing only | 4 mA | 4 mA | 3 mA | 0 | ~11 mA | | Idle (awake) | 4 mA | 0.001 | 0.001 | 0 | ~4 mA | | Deep sleep | 0.0001 | 0.001 | 0.001 | 0 | <0.01mA | ### Estimated runtime on 2× AA Alkaline (2500 mAh): | Mode | Current | Runtime | |--------------------|---------|-------------| | Audio + Motor | 91 mA | ~27 hours | | Audio only | 11 mA | ~227 hours | | Sleep | <10 µA | ~28 years | With typical use of 30 min/day (motor + audio), batteries last roughly **54 days**. With 1 hour/day, roughly **27 days** — well within AA change interval for a toy. ## PCB Layout Guidelines **Board size target:** 40mm × 30mm (fits inside most mobile housings) **Layer stackup:** 2-layer (plenty for this design) **Key layout rules:** 1. Place C2 and C3 as close to U1 pins 4/6 as physically possible 2. Place C5 directly adjacent to U2 pin 8 3. Keep SPI traces short and parallel-routed 4. Audio RC filter (R2, C7) close to U3 input 5. Wide traces for motor path (VCC → motor → Q1 drain): 0.5mm minimum 6. Ground pour on bottom layer 7. Thermal relief on U3 pad (pin 6) connected to ground pour 8. Keep battery/motor power traces away from audio section **Recommended trace widths:** - Power (VCC, GND, motor): 0.5mm+ - Signal (SPI, buttons): 0.25mm - Audio: 0.25mm (keep short, away from digital noise) ## Programming ### Bootloader Burn the Arduino bootloader for "ATmega328P 8MHz internal" using the ISP header (J4) and an Arduino-as-ISP or USBasp programmer. In Arduino IDE: - Board: "ATmega328P" - Clock: "Internal 8 MHz" - BOD: "BOD 1.8V" (for low-voltage operation) ### Loading audio onto W25Q128 Use the serial header (J5) with a USB-serial adapter. The firmware includes a serial protocol to receive audio data and write it to flash. Alternatively, program the flash chip directly with a CH341A SPI programmer before soldering (~$3 on Amazon). ### Audio format Raw unsigned 8-bit PCM, 8000 Hz sample rate, mono. Convert with ffmpeg: ``` ffmpeg -i input.mp3 -ar 8000 -ac 1 -f u8 -acodec pcm_u8 output.raw ``` At 8KB/s, the 16MB flash holds about **34 minutes** of audio. ## Possible Enhancements - **Volume control:** Use a digital pot on amp input, or just use the PWM duty cycle adjustment in software - **Battery voltage monitor:** Read VCC via bandgap reference trick on ATmega328P (no extra pin needed) — blink LED when low - **Touch sensing:** Replace buttons with copper pads; use ADC-based capacitive sensing on PC0/PC1 (ATmega328P supports this with careful firmware) - **More audio:** Swap W25Q128 (16MB) for W25Q256 (32MB) → 68 min - **Bluetooth:** Add HC-05 module on serial pins for wireless audio upload from phone (adds ~30mA when active)