From 5a18a689e0f64e1cc03affff959076566898f309 Mon Sep 17 00:00:00 2001 From: zyphlar Date: Sat, 4 Jul 2026 03:28:11 -0700 Subject: [PATCH] nRF --- DESIGN.md | 435 ++++++++---------- baby-mobile-v2.kicad_pro | 41 ++ baby-mobile-v2.kicad_sch | 815 +++++++++++++++++++++++++++++++++ baby-mobile.kicad_pro | 61 --- baby-mobile.kicad_sch | 628 -------------------------- baby_mobile_firmware.ino | 639 -------------------------- baby_mobile_v2.ino | 945 ++++++++++++++++++++++++++++++++++++++ flash_upload.py | 281 +++++------- generate_kicad.py | 949 ++++++++++++++++++--------------------- 9 files changed, 2561 insertions(+), 2233 deletions(-) create mode 100644 baby-mobile-v2.kicad_pro create mode 100644 baby-mobile-v2.kicad_sch delete mode 100644 baby-mobile.kicad_pro delete mode 100644 baby-mobile.kicad_sch delete mode 100644 baby_mobile_firmware.ino create mode 100644 baby_mobile_v2.ino diff --git a/DESIGN.md b/DESIGN.md index b81ebb6..2e160bd 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -1,278 +1,229 @@ -# Baby Mobile Audio Board — Design Document +# Baby Mobile Audio Board v2 — 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. +Drop-in replacement for baby crib mobile electronics. Custom audio from +SPI flash, DC motor control, 8 buttons, and long runtime on 2×AA batteries. +No programmer needed — upload audio via USB drag-and-drop or Bluetooth. -**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 +## Architecture ``` -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) +2×AA (1.8-3.2V) → SW9 → D1(BAT54S) → TPS61220 boost → 3.3V ──┐ + ├── MDBT50Q +USB-C VBUS (5V) → D3(BAT54S) → MCP1700 LDO → 3.3V ────────────┘ (nRF52840) + │ + ┌────────────── SPI ── IS25LP128F (16MB flash, 2.3-3.6V) │ + │ ┌───────── PWM ── R+C LPF ── PAM8302A ── 8Ω speaker │ + │ │ ┌───── GPIO ── AO3400A MOSFET ── DC motor │ + │ │ │ ┌─── GPIO ── 8× buttons (internal pull-ups) │ + │ │ │ │ ┌─ USB ── USB-C D+/D- (mass storage) │ + │ │ │ │ │ BLE ── phone (wireless upload) │ + └────┴───┴─┴─┴──────────────────────────────────────────────────┘ ``` -**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 +## Power Design — Diode OR-ing (Safe for ALL Battery Types) - -### 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 + BAT54S TPS61220 + 2×AA ──SW9──┤►├──────┐ ┌─ VIN VOUT ─── 3.3V rail + ├── node ┤ + USB VBUS ───┤►├── LDO ┘ └─ EN GND ─── GND + BAT54S MCP1700 L ─── L1(4.7µH) ``` -**J5 — Serial (1×3, for bootloader programming / debug):** +**Why this is safe:** The Schottky diodes only pass current in one direction. +When USB provides 3.3V via the LDO, the boost converter stops switching and +the battery diode is reverse-biased. Zero current flows into the batteries +regardless of chemistry (alkaline, NiMH, lithium). + +**Diode drop:** BAT54S drops ~0.25V. TPS61220 accepts inputs down to 0.7V. +Depleted 2×AA = 1.8V → boost sees 1.55V → still operational. + + +## Pin Mapping — MDBT50Q (nRF52840) + +| Module Pin | nRF52840 Port | Function | Connected To | +|------------|---------------|--------------|-------------------------------| +| 4 | P0.02/AIN0 | Button 1 | SW1 → GND (active LOW) | +| 5 | P0.03/AIN1 | Button 2 | SW2 → GND | +| 6 | P0.04/AIN2 | Button 3 | SW3 → GND | +| 7 | P0.05/AIN3 | Button 4 | SW4 → GND | +| 8 | P0.06 | Button 5 | SW5 → GND | +| 9 | P0.07 | Button 6 | SW6 → GND | +| 10 | P0.08 | Button 7 | SW7 → GND | +| 11 | P0.09 | Button 8 | SW8 → GND | +| 12 | P0.10 | Motor PWM | R4(100Ω) → Q1 gate | +| 13 | P0.11 | Audio PWM | R2(4.7K) → C7(10nF) → C6 → U3| +| 14 | P0.12 | Flash ~CS | U2 pin 1 | +| 15 | P0.13 | SPI MOSI | U2 pin 5 | +| 16 | P0.14 | SPI MISO | U2 pin 2 | +| 17 | P0.15 | SPI SCK | U2 pin 6 | +| 18 | P0.16 | LED output | R6(1K) → D2 → GND | +| 19 | P0.17 | Amp ~SD | U3 pin 1, R3(100K) → GND | +| 20 | P0.18/~RESET | Reset | (internal pull-up) | +| 21 | P0.19 | TXD (serial) | J5 pin 2 | +| 22 | P0.20 | RXD (serial) | J5 pin 3 | +| 28 | D- | USB Data - | J6 D- | +| 29 | D+ | USB Data + | J6 D+ | +| 33 | SWDIO | Debug | J4 pin 2 (SWD header) | +| 34 | SWDCLK | Debug | J4 pin 3 (SWD header) | +| 32 | VCC | Power | 3V3 rail | +| 1 | GND | Ground | GND rail | + + +## SPI Flash: U2 — IS25LP128F (SOIC-8) + +| Pin | Name | Connected To | +|-----|-----------|-------------------| +| 1 | ~CS | P0.12 (FLASH_CS) | +| 2 | SO (MISO) | P0.14 (SPI_MISO) | +| 3 | ~WP | 3V3 (tie high) | +| 4 | GND | GND | +| 5 | SI (MOSI) | P0.13 (SPI_MOSI) | +| 6 | SCLK | P0.15 (SPI_SCK) | +| 7 | ~HOLD | 3V3 (tie high) | +| 8 | VCC | 3V3 | + +**Operating voltage: 2.3V–3.6V** — works across entire boost output range. + + +## Audio Signal Path + ``` - GND 1 - TXD 2 (MCU TX out) - RXD 3 (MCU RX in) +P0.11 (PWM) → R2(4.7K) → node → C6(1µF coupling) → PAM8302A A+ + │ + C7(10nF) → GND + +RC LPF cutoff: 1/(2π × 4700 × 10e-9) ≈ 3.4 kHz +``` + + +## USB-C Wiring + +``` +USB-C Pin → Board +──────────────────── +VBUS (5V) → D3 anode → MCP1700 VIN +GND → GND +D+ → nRF52840 D+ (pin 29) +D- → nRF52840 D- (pin 28) +CC1 → R7(5.1K) → GND +CC2 → R8(5.1K) → GND ``` ## 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** | | +| Ref | Part | Package | Qty | ~Cost | +|--------|----------------------|---------------|-----|--------| +| U1 | MDBT50Q-P1MV2 | Module | 1 | $6.00 | +| U2 | IS25LP128F-JBLE | SOIC-8 | 1 | $2.00 | +| U3 | PAM8302AASCR | SOIC-8 | 1 | $0.80 | +| U4 | TPS61220DCKR | SC-70-5 | 1 | $0.80 | +| U5 | MCP1700-3302E/TT | SOT-23 | 1 | $0.20 | +| Q1 | AO3400A | SOT-23 | 1 | $0.15 | +| D1 | BAT54S | SOT-23 | 1 | $0.05 | +| D3 | BAT54S | SOT-23 | 1 | $0.05 | +| D4 | SS14 | SMA | 1 | $0.10 | +| D2 | LED green | 0805 | 1 | $0.05 | +| L1 | 4.7µH inductor | 0805 | 1 | $0.15 | +| R2 | 4.7KΩ | 0805 | 1 | $0.01 | +| R3 | 100KΩ | 0805 | 1 | $0.01 | +| R4 | 100Ω | 0805 | 1 | $0.01 | +| R5 | 100KΩ | 0805 | 1 | $0.01 | +| R6 | 1KΩ | 0805 | 1 | $0.01 | +| R7,R8 | 5.1KΩ | 0805 | 2 | $0.02 | +| C1 | 100µF/10V | Radial 5mm | 1 | $0.15 | +| C2 | 100nF | 0805 | 1 | $0.01 | +| C3 | 10µF | 0805 | 1 | $0.05 | +| C5 | 100nF | 0805 | 1 | $0.01 | +| C6 | 1µF | 0805 | 1 | $0.02 | +| C7 | 10nF | 0805 | 1 | $0.01 | +| C8 | 10µF | 0805 | 1 | $0.05 | +| C9,C10 | 10µF | 0805 | 2 | $0.10 | +| C11,C12| 1µF | 0805 | 2 | $0.04 | +| SW1-8 | Tactile switch | 6mm SMD | 8 | $0.80 | +| SW9 | SPDT slide | THT | 1 | $0.20 | +| J1 | JST-PH 2-pin | THT | 1 | $0.15 | +| J2 | JST-PH 2-pin | THT | 1 | $0.15 | +| J3 | JST-PH 2-pin | THT | 1 | $0.15 | +| J4 | 1×4 pin header | 2.54mm | 1 | $0.10 | +| J5 | 1×3 pin header | 2.54mm | 1 | $0.05 | +| J6 | USB-C receptacle | SMD | 1 | $0.30 | +| | **TOTAL** | | |**~$12**| ## Power Analysis -### Current draw by state: +| State | MCU | Flash | Amp | Motor | Boost η | Battery mA | +|--------------------|--------|--------|--------|--------|---------|------------| +| Audio + motor | 4 mA | 8 mA | 10 mA | 80 mA | 90% | ~113 mA | +| Audio only | 4 mA | 8 mA | 10 mA | 0 | 90% | ~24 mA | +| BLE idle | 0.5 mA | 0.001 | 0.001 | 0 | 85% | ~0.7 mA | +| Deep sleep | 0.002 | 0.001 | 0.001 | 0 | — | ~0.01 mA | -| 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 runtimes on 2×AA alkaline (2500 mAh usable with boost):** -### 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. +| Mode | Runtime | +|------------------|--------------| +| Audio + Motor | ~22 hours | +| Audio only | ~104 hours | +| BLE standby | ~149 days | +| Deep sleep | ~28 years | +| 30 min/day use | **~44 days** | -## PCB Layout Guidelines +## Module Options (Soldering Difficulty) -**Board size target:** 40mm × 30mm (fits inside most mobile housings) +The schematic is designed around the MDBT50Q module, but the firmware +works on any nRF52840 board. Here are your options from easiest to hardest: -**Layer stackup:** 2-layer (plenty for this design) +| Module | ~Cost | USB-C | Bootloader | Soldering | +|-----------------------------|-------|-------|------------|------------------| +| **Seeed XIAO nRF52840** | $10 | Yes | UF2 preloaded | **Through-hole headers** — solder like any DIP. Has castellated pads too. | +| **Adafruit Feather nRF52840** | $25 | Yes | UF2 preloaded | Through-hole headers | +| **SparkFun Pro nRF52840** | $20 | Yes | UF2 preloaded | Through-hole headers | +| **Ebyte E73-2G4M08S1C** | $3 | No | None | Castellated edge pads — hand-solderable with regular iron | +| **MDBT50Q-P1MV2 (Raytac)** | $6 | No | None | SMD pads — needs reflow or hot air | -**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 for beginners: Seeed XIAO nRF52840.** It plugs into standard +2.54mm headers like an Arduino Nano. USB-C and UF2 bootloader are built in, +so you never need a programmer. Just drag-and-drop firmware and audio files. -**Recommended trace widths:** -- Power (VCC, GND, motor): 0.5mm+ -- Signal (SPI, buttons): 0.25mm -- Audio: 0.25mm (keep short, away from digital noise) +**If using a XIAO or Feather:** you can skip the TPS61220 boost converter, +MCP1700 LDO, USB-C connector, and CC resistors from the BOM. The dev board +handles all of that. Feed the boost converter's 3.3V output to the board's +3V3 pin. Total BOM drops to ~$15 including the XIAO. + +**If using MDBT50Q or E73:** you need the full schematic as designed. The +E73 is the budget option — castellated pads are solderable with flux, a +fine tip, and patience. Pre-tin both the pads and the board footprint, +then tack one corner and reflow the rest. -## Programming +## User Experience -### Bootloader -Burn the Arduino bootloader for "ATmega328P 8MHz internal" using the ISP -header (J4) and an Arduino-as-ISP or USBasp programmer. +### Upload Audio (USB) +1. Plug USB-C cable into board +2. Board appears as USB mass storage drive +3. Drag .wav or .mp3 files onto drive +4. Eject and unplug — music ready to play -In Arduino IDE: -- Board: "ATmega328P" -- Clock: "Internal 8 MHz" -- BOD: "BOD 1.8V" (for low-voltage operation) +### Upload Audio (Bluetooth) +1. Open Web Bluetooth page on phone (no app install) +2. Connect to "BabyMobile" device +3. Select audio files → transfer +4. ~15 min for 30 minutes of audio at BLE speeds -### 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). +### Update Firmware +1. Double-tap reset button (or hold BTN1+BTN2 on power-on) +2. Board appears as UF2 drive +3. Drag .uf2 firmware file onto drive +4. Board reboots with new firmware -### 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) +### No-Programmer Setup +The MDBT50Q ships with the nRF52840 bootloader ROM. Flash the Adafruit +nRF52 UF2 bootloader once via SWD (J4 header) using any $3 CMSIS-DAP +probe, J-Link, or even a Raspberry Pi. After that, all future updates +are drag-and-drop over USB. The SWD header is only needed once. diff --git a/baby-mobile-v2.kicad_pro b/baby-mobile-v2.kicad_pro new file mode 100644 index 0000000..ae999c2 --- /dev/null +++ b/baby-mobile-v2.kicad_pro @@ -0,0 +1,41 @@ +{ + "meta": { + "filename": "baby-mobile-v2.kicad_pro", + "version": 1 + }, + "board": { + "design_settings": { + "defaults": { + "board_outline_line_width": 0.1, + "copper_line_width": 0.2 + }, + "rules": { + "min_copper_edge_clearance": 0.3, + "min_track_width": 0.2, + "min_via_diameter": 0.6, + "min_via_annular_width": 0.13 + } + } + }, + "net_settings": { + "classes": [ + { + "name": "Default", + "clearance": 0.2, + "track_width": 0.3, + "via_diameter": 0.6, + "via_drill": 0.3 + } + ] + }, + "schematic": { + "legacy_lib_dir": "", + "legacy_lib_list": [] + }, + "sheets": [ + [ + "", + "" + ] + ] +} \ No newline at end of file diff --git a/baby-mobile-v2.kicad_sch b/baby-mobile-v2.kicad_sch new file mode 100644 index 0000000..8a53938 --- /dev/null +++ b/baby-mobile-v2.kicad_sch @@ -0,0 +1,815 @@ +(kicad_sch (version 20230121) (generator "baby_mobile_gen_v2") + + (uuid "bcbf6700-9330-4856-9326-a804adb9eec3") + (paper "A3") + + (title_block + (title "Baby Mobile Audio Board v2") + (date "2026-03-09") + (rev "2.0") + (comment 1 "MDBT50Q (nRF52840) + IS25LP128F + PAM8302A") + (comment 2 "2xAA Battery + USB-C, Diode OR, TPS61220 Boost") + (comment 3 "BLE + USB mass storage for audio upload") + (comment 4 "8-ohm 0.25W Speaker, DC Motor, 8 Buttons") + ) + + (lib_symbols + + (symbol "baby_mobile:MDBT50Q" (in_bom yes) (on_board yes) + (property "Reference" "U" (at 0 1 0) (effects (font (size 1.27 1.27)))) + (property "Value" "MDBT50Q-P1MV2" (at 0 -1 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "RF_Module:Raytac_MDBT50Q" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + + (symbol "MDBT50Q_0_1" + (rectangle (start -20 30) (end 20 -30) (stroke (width 0.254) (type default)) (fill (type background))) + ) + (symbol "MDBT50Q_1_1" + (pin power_in line (at -5 -33 90) (length 3) (name "GND" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) + (pin power_in line (at -5 33 270) (length 3) (name "VCC" (effects (font (size 1 1)))) (number "32" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 20 0) (length 3) (name "P0.00/XL1" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 17.5 0) (length 3) (name "P0.01/XL2" (effects (font (size 1 1)))) (number "3" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 15 0) (length 3) (name "P0.02/AIN0" (effects (font (size 1 1)))) (number "4" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 12.5 0) (length 3) (name "P0.03/AIN1" (effects (font (size 1 1)))) (number "5" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 10 0) (length 3) (name "P0.04/AIN2" (effects (font (size 1 1)))) (number "6" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 7.5 0) (length 3) (name "P0.05/AIN3" (effects (font (size 1 1)))) (number "7" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 5 0) (length 3) (name "P0.06" (effects (font (size 1 1)))) (number "8" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 2.5 0) (length 3) (name "P0.07" (effects (font (size 1 1)))) (number "9" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 0 0) (length 3) (name "P0.08" (effects (font (size 1 1)))) (number "10" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 -2.5 0) (length 3) (name "P0.09/NFC1" (effects (font (size 1 1)))) (number "11" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 -5 0) (length 3) (name "P0.10/NFC2" (effects (font (size 1 1)))) (number "12" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 -7.5 0) (length 3) (name "P0.11" (effects (font (size 1 1)))) (number "13" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 -10 0) (length 3) (name "P0.12" (effects (font (size 1 1)))) (number "14" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 -12.5 0) (length 3) (name "P0.13" (effects (font (size 1 1)))) (number "15" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 -15 0) (length 3) (name "P0.14" (effects (font (size 1 1)))) (number "16" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 -17.5 0) (length 3) (name "P0.15" (effects (font (size 1 1)))) (number "17" (effects (font (size 1 1))))) + (pin bidirectional line (at 23 20 180) (length 3) (name "P0.16" (effects (font (size 1 1)))) (number "18" (effects (font (size 1 1))))) + (pin bidirectional line (at 23 17.5 180) (length 3) (name "P0.17" (effects (font (size 1 1)))) (number "19" (effects (font (size 1 1))))) + (pin bidirectional line (at 23 15 180) (length 3) (name "P0.18/~{RESET}" (effects (font (size 1 1)))) (number "20" (effects (font (size 1 1))))) + (pin bidirectional line (at 23 12.5 180) (length 3) (name "P0.19" (effects (font (size 1 1)))) (number "21" (effects (font (size 1 1))))) + (pin bidirectional line (at 23 10 180) (length 3) (name "P0.20" (effects (font (size 1 1)))) (number "22" (effects (font (size 1 1))))) + (pin bidirectional line (at 23 7.5 180) (length 3) (name "P0.21" (effects (font (size 1 1)))) (number "23" (effects (font (size 1 1))))) + (pin bidirectional line (at 23 5 180) (length 3) (name "P0.22" (effects (font (size 1 1)))) (number "24" (effects (font (size 1 1))))) + (pin bidirectional line (at 23 2.5 180) (length 3) (name "P0.23" (effects (font (size 1 1)))) (number "25" (effects (font (size 1 1))))) + (pin bidirectional line (at 23 0 180) (length 3) (name "P0.24" (effects (font (size 1 1)))) (number "26" (effects (font (size 1 1))))) + (pin bidirectional line (at 23 -2.5 180) (length 3) (name "P1.00" (effects (font (size 1 1)))) (number "27" (effects (font (size 1 1))))) + (pin bidirectional line (at 23 -5 180) (length 3) (name "D-" (effects (font (size 1 1)))) (number "28" (effects (font (size 1 1))))) + (pin bidirectional line (at 23 -7.5 180) (length 3) (name "D+" (effects (font (size 1 1)))) (number "29" (effects (font (size 1 1))))) + (pin bidirectional line (at 23 -10 180) (length 3) (name "P0.25" (effects (font (size 1 1)))) (number "30" (effects (font (size 1 1))))) + (pin bidirectional line (at 23 -12.5 180) (length 3) (name "P0.26" (effects (font (size 1 1)))) (number "31" (effects (font (size 1 1))))) + (pin input line (at 23 -17.5 180) (length 3) (name "SWDIO" (effects (font (size 1 1)))) (number "33" (effects (font (size 1 1))))) + (pin input line (at 23 -20 180) (length 3) (name "SWDCLK" (effects (font (size 1 1)))) (number "34" (effects (font (size 1 1))))) + ) + ) + + (symbol "baby_mobile:IS25LP128F" (in_bom yes) (on_board yes) + (property "Reference" "U" (at 0 1 0) (effects (font (size 1.27 1.27)))) + (property "Value" "IS25LP128F" (at 0 -1 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Package_SO:SOIC-8_3.9x4.9mm_P1.27mm" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + + (symbol "IS25LP128F_0_1" + (rectangle (start -7 6) (end 7 -6) (stroke (width 0.254) (type default)) (fill (type background))) + ) + (symbol "IS25LP128F_1_1" + (pin input line (at -10 4 0) (length 3) (name "~{CS}" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) + (pin output line (at -10 1.5 0) (length 3) (name "SO/IO1" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) + (pin input line (at -10 -1.5 0) (length 3) (name "~{WP}/IO2" (effects (font (size 1 1)))) (number "3" (effects (font (size 1 1))))) + (pin power_in line (at -10 -4 0) (length 3) (name "GND" (effects (font (size 1 1)))) (number "4" (effects (font (size 1 1))))) + (pin input line (at 10 -4 180) (length 3) (name "SI/IO0" (effects (font (size 1 1)))) (number "5" (effects (font (size 1 1))))) + (pin input line (at 10 -1.5 180) (length 3) (name "SCLK" (effects (font (size 1 1)))) (number "6" (effects (font (size 1 1))))) + (pin input line (at 10 1.5 180) (length 3) (name "~{HOLD}/IO3" (effects (font (size 1 1)))) (number "7" (effects (font (size 1 1))))) + (pin power_in line (at 10 4 180) (length 3) (name "VCC" (effects (font (size 1 1)))) (number "8" (effects (font (size 1 1))))) + ) + ) + + (symbol "baby_mobile:PAM8302A" (in_bom yes) (on_board yes) + (property "Reference" "U" (at 0 1 0) (effects (font (size 1.27 1.27)))) + (property "Value" "PAM8302A" (at 0 -1 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Package_SO:SOIC-8_3.9x4.9mm_P1.27mm" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + + (symbol "PAM8302A_0_1" + (rectangle (start -8 8) (end 8 -8) (stroke (width 0.254) (type default)) (fill (type background))) + ) + (symbol "PAM8302A_1_1" + (pin input line (at -11 5 0) (length 3) (name "~{SD}" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) + (pin power_in line (at -11 2 0) (length 3) (name "VDD" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) + (pin power_in line (at -11 -1 0) (length 3) (name "GND" (effects (font (size 1 1)))) (number "3" (effects (font (size 1 1))))) + (pin input line (at -11 -4 0) (length 3) (name "A+" (effects (font (size 1 1)))) (number "4" (effects (font (size 1 1))))) + (pin input line (at -11 -7 0) (length 3) (name "A-" (effects (font (size 1 1)))) (number "5" (effects (font (size 1 1))))) + (pin output line (at 11 2 180) (length 3) (name "VO+" (effects (font (size 1 1)))) (number "8" (effects (font (size 1 1))))) + (pin output line (at 11 -1 180) (length 3) (name "VO-" (effects (font (size 1 1)))) (number "7" (effects (font (size 1 1))))) + (pin power_in line (at 11 -4 180) (length 3) (name "PAD" (effects (font (size 1 1)))) (number "6" (effects (font (size 1 1))))) + ) + ) + + (symbol "baby_mobile:TPS61220" (in_bom yes) (on_board yes) + (property "Reference" "U" (at 0 1 0) (effects (font (size 1.27 1.27)))) + (property "Value" "TPS61220DCK" (at 0 -1 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Package_TO_SOT_SMD:SOT-353_SC-70-5" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + + (symbol "TPS61220_0_1" + (rectangle (start -7 5) (end 7 -5) (stroke (width 0.254) (type default)) (fill (type background))) + ) + (symbol "TPS61220_1_1" + (pin power_in line (at -10 3 0) (length 3) (name "VIN" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) + (pin power_in line (at -10 -3 0) (length 3) (name "GND" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) + (pin input line (at 10 -3 180) (length 3) (name "EN" (effects (font (size 1 1)))) (number "3" (effects (font (size 1 1))))) + (pin power_out line (at 10 3 180) (length 3) (name "VOUT" (effects (font (size 1 1)))) (number "4" (effects (font (size 1 1))))) + (pin passive line (at 0 8 270) (length 3) (name "L" (effects (font (size 1 1)))) (number "5" (effects (font (size 1 1))))) + ) + ) + + (symbol "baby_mobile:MCP1700" (in_bom yes) (on_board yes) + (property "Reference" "U" (at 0 1 0) (effects (font (size 1.27 1.27)))) + (property "Value" "MCP1700-3302E" (at 0 -1 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Package_TO_SOT_SMD:SOT-23" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + + (symbol "MCP1700_0_1" + (rectangle (start -6 4) (end 6 -4) (stroke (width 0.254) (type default)) (fill (type background))) + ) + (symbol "MCP1700_1_1" + (pin power_in line (at -9 2 0) (length 3) (name "VIN" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) + (pin power_in line (at 0 -7 90) (length 3) (name "GND" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) + (pin power_out line (at 9 2 180) (length 3) (name "VOUT" (effects (font (size 1 1)))) (number "3" (effects (font (size 1 1))))) + ) + ) + + (symbol "baby_mobile:Capacitor" (in_bom yes) (on_board yes) + (property "Reference" "C" (at 0 1 0) (effects (font (size 1.27 1.27)))) + (property "Value" "C" (at 0 -1 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Capacitor_SMD:C_0805_2012Metric" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + + (symbol "Capacitor_0_1" + (polyline (pts (xy -1.5 1) (xy 1.5 1)) (stroke (width 0.4) (type default)) (fill (type none))) + (polyline (pts (xy -1.5 -1) (xy 1.5 -1)) (stroke (width 0.4) (type default)) (fill (type none))) + ) + (symbol "Capacitor_1_1" + (pin passive line (at 0 3.5 270) (length 2.5) (name "1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) + (pin passive line (at 0 -3.5 90) (length 2.5) (name "2" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) + ) + ) + + (symbol "baby_mobile:Resistor" (in_bom yes) (on_board yes) + (property "Reference" "R" (at 0 1 0) (effects (font (size 1.27 1.27)))) + (property "Value" "R" (at 0 -1 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + + (symbol "Resistor_0_1" + (polyline (pts (xy -1.5 1) (xy 1.5 1)) (stroke (width 0.4) (type default)) (fill (type none))) + (polyline (pts (xy -1.5 -1) (xy 1.5 -1)) (stroke (width 0.4) (type default)) (fill (type none))) + ) + (symbol "Resistor_1_1" + (pin passive line (at 0 3.5 270) (length 2.5) (name "1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) + (pin passive line (at 0 -3.5 90) (length 2.5) (name "2" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) + ) + ) + + (symbol "baby_mobile:Diode_Schottky" (in_bom yes) (on_board yes) + (property "Reference" "D" (at 0 1 0) (effects (font (size 1.27 1.27)))) + (property "Value" "BAT54S" (at 0 -1 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Diode_SMD:D_SOT-23_ANK" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + + (symbol "Diode_Schottky_0_1" + (polyline (pts (xy -1.5 1) (xy 1.5 1)) (stroke (width 0.4) (type default)) (fill (type none))) + (polyline (pts (xy -1.5 -1) (xy 1.5 -1)) (stroke (width 0.4) (type default)) (fill (type none))) + ) + (symbol "Diode_Schottky_1_1" + (pin passive line (at 0 3.5 270) (length 2.5) (name "1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) + (pin passive line (at 0 -3.5 90) (length 2.5) (name "2" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) + ) + ) + + (symbol "baby_mobile:LED" (in_bom yes) (on_board yes) + (property "Reference" "D" (at 0 1 0) (effects (font (size 1.27 1.27)))) + (property "Value" "LED" (at 0 -1 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "LED_SMD:LED_0805_2012Metric" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + + (symbol "LED_0_1" + (polyline (pts (xy -1.5 1) (xy 1.5 1)) (stroke (width 0.4) (type default)) (fill (type none))) + (polyline (pts (xy -1.5 -1) (xy 1.5 -1)) (stroke (width 0.4) (type default)) (fill (type none))) + ) + (symbol "LED_1_1" + (pin passive line (at 0 3.5 270) (length 2.5) (name "1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) + (pin passive line (at 0 -3.5 90) (length 2.5) (name "2" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) + ) + ) + + (symbol "baby_mobile:Conn_2Pin" (in_bom yes) (on_board yes) + (property "Reference" "J" (at 0 1 0) (effects (font (size 1.27 1.27)))) + (property "Value" "Conn_2" (at 0 -1 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Connector_JST:JST_PH_S2B-PH-K_1x02_P2.00mm_Horizontal" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + + (symbol "Conn_2Pin_0_1" + (polyline (pts (xy -1.5 1) (xy 1.5 1)) (stroke (width 0.4) (type default)) (fill (type none))) + (polyline (pts (xy -1.5 -1) (xy 1.5 -1)) (stroke (width 0.4) (type default)) (fill (type none))) + ) + (symbol "Conn_2Pin_1_1" + (pin passive line (at 0 3.5 270) (length 2.5) (name "1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) + (pin passive line (at 0 -3.5 90) (length 2.5) (name "2" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) + ) + ) + + (symbol "baby_mobile:Switch" (in_bom yes) (on_board yes) + (property "Reference" "SW" (at 0 1 0) (effects (font (size 1.27 1.27)))) + (property "Value" "SW" (at 0 -1 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Button_Switch_SMD:SW_SPST_TL3342" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + + (symbol "Switch_0_1" + (circle (center -2 0) (radius 0.4) (stroke (width 0) (type default)) (fill (type none))) + (circle (center 2 0) (radius 0.4) (stroke (width 0) (type default)) (fill (type none))) + (polyline (pts (xy -1.6 0) (xy 1.6 1)) (stroke (width 0.254) (type default)) (fill (type none))) + ) + (symbol "Switch_1_1" + (pin passive line (at -5 0 0) (length 3) (name "1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) + (pin passive line (at 5 0 180) (length 3) (name "2" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) + ) + ) + + (symbol "baby_mobile:NMOS" (in_bom yes) (on_board yes) + (property "Reference" "Q" (at 0 1 0) (effects (font (size 1.27 1.27)))) + (property "Value" "AO3400A" (at 0 -1 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Package_TO_SOT_SMD:SOT-23" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + + (symbol "NMOS_0_1" + (polyline (pts (xy -0.5 2) (xy -0.5 -2)) (stroke (width 0.254) (type default)) (fill (type none))) + ) + (symbol "NMOS_1_1" + (pin passive line (at 0 5 270) (length 2.5) (name "D" (effects (font (size 1 1)))) (number "3" (effects (font (size 1 1))))) + (pin input line (at -4 0 0) (length 2.5) (name "G" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) + (pin passive line (at 0 -5 90) (length 2.5) (name "S" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) + ) + ) + + (symbol "baby_mobile:Inductor" (in_bom yes) (on_board yes) + (property "Reference" "L" (at 0 1 0) (effects (font (size 1.27 1.27)))) + (property "Value" "4.7uH" (at 0 -1 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Inductor_SMD:L_0805_2012Metric" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + + (symbol "Inductor_0_1" + (arc (start 0 2.5) (mid 0.75 1.875) (end 0 1.25) (stroke (width 0.254) (type default)) (fill (type none))) + (arc (start 0 1.25) (mid 0.75 0.625) (end 0 0) (stroke (width 0.254) (type default)) (fill (type none))) + (arc (start 0 0) (mid 0.75 -0.625) (end 0 -1.25) (stroke (width 0.254) (type default)) (fill (type none))) + (arc (start 0 -1.25) (mid 0.75 -1.875) (end 0 -2.5) (stroke (width 0.254) (type default)) (fill (type none))) + ) + (symbol "Inductor_1_1" + (pin passive line (at 0 5 270) (length 2.5) (name "1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) + (pin passive line (at 0 -5 90) (length 2.5) (name "2" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) + ) + ) + + (symbol "baby_mobile:USB_C" (in_bom yes) (on_board yes) + (property "Reference" "J" (at 0 1 0) (effects (font (size 1.27 1.27)))) + (property "Value" "USB_C_Receptacle" (at 0 -1 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Connector_USB:USB_C_Receptacle_GCT_USB4085" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + + (symbol "USB_C_0_1" + (rectangle (start -6 8) (end 6 -8) (stroke (width 0.254) (type default)) (fill (type background))) + ) + (symbol "USB_C_1_1" + (pin power_in line (at -9 6 0) (length 3) (name "VBUS" (effects (font (size 1 1)))) (number "A4" (effects (font (size 1 1))))) + (pin passive line (at -9 3 0) (length 3) (name "CC1" (effects (font (size 1 1)))) (number "A5" (effects (font (size 1 1))))) + (pin passive line (at -9 0 0) (length 3) (name "CC2" (effects (font (size 1 1)))) (number "B5" (effects (font (size 1 1))))) + (pin bidirectional line (at -9 -3 0) (length 3) (name "D+" (effects (font (size 1 1)))) (number "A6" (effects (font (size 1 1))))) + (pin bidirectional line (at -9 -6 0) (length 3) (name "D-" (effects (font (size 1 1)))) (number "A7" (effects (font (size 1 1))))) + (pin power_in line (at 9 -6 180) (length 3) (name "GND" (effects (font (size 1 1)))) (number "A1" (effects (font (size 1 1))))) + (pin passive line (at 9 0 180) (length 3) (name "SHIELD" (effects (font (size 1 1)))) (number "S1" (effects (font (size 1 1))))) + ) + ) + + (symbol "baby_mobile:SWD_Header" (in_bom yes) (on_board yes) + (property "Reference" "J" (at 0 1 0) (effects (font (size 1.27 1.27)))) + (property "Value" "SWD_Header" (at 0 -1 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Connector_PinHeader_2.54mm:PinHeader_1x04_P2.54mm_Vertical" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + + (symbol "SWD_Header_0_1" + (rectangle (start -3 11.0) (end 3 -11.0) (stroke (width 0.254) (type default)) (fill (type background))) + ) + (symbol "SWD_Header_1_1" + (pin passive line (at -6 9.0 0) (length 3) (name "P1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) + (pin passive line (at -6 6.5 0) (length 3) (name "P2" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) + (pin passive line (at -6 4.0 0) (length 3) (name "P3" (effects (font (size 1 1)))) (number "3" (effects (font (size 1 1))))) + (pin passive line (at -6 1.5 0) (length 3) (name "P4" (effects (font (size 1 1)))) (number "4" (effects (font (size 1 1))))) + ) + ) + + (symbol "baby_mobile:Serial_Header" (in_bom yes) (on_board yes) + (property "Reference" "J" (at 0 1 0) (effects (font (size 1.27 1.27)))) + (property "Value" "Serial_Header" (at 0 -1 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Connector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_Vertical" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + + (symbol "Serial_Header_0_1" + (rectangle (start -3 8.5) (end 3 -8.5) (stroke (width 0.254) (type default)) (fill (type background))) + ) + (symbol "Serial_Header_1_1" + (pin passive line (at -6 6.5 0) (length 3) (name "P1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) + (pin passive line (at -6 4.0 0) (length 3) (name "P2" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) + (pin passive line (at -6 1.5 0) (length 3) (name "P3" (effects (font (size 1 1)))) (number "3" (effects (font (size 1 1))))) + ) + ) + ) + (symbol (lib_id "baby_mobile:Conn_2Pin") (at 20 40 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "70d7070b-9b9d-48ab-8f07-7e955ee95852") + (property "Reference" "J1" (at 23 37 0) (effects (font (size 1.27 1.27)))) + (property "Value" "BATTERY" (at 23 43 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Connector_JST:JST_PH_S2B-PH-K_1x02_P2.00mm_Horizontal" (at 20 40 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 20 40 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Switch") (at 38 35 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "fa74c532-0744-4aea-a2d6-1086b3906684") + (property "Reference" "SW9" (at 41 32 0) (effects (font (size 1.27 1.27)))) + (property "Value" "PWR" (at 41 38 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Button_Switch_THT:SW_SPDT_CK-JS102011SAQN" (at 38 35 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 38 35 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Diode_Schottky") (at 55 35 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "6625ba09-9a7b-45e4-bb05-f5be950fe70a") + (property "Reference" "D1" (at 58 32 0) (effects (font (size 1.27 1.27)))) + (property "Value" "BAT54S" (at 58 38 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Diode_SMD:D_SOT-23_ANK" (at 55 35 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 55 35 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Capacitor") (at 48 45 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "5b7c8b52-73ae-48f5-92a3-ae01dce193f9") + (property "Reference" "C1" (at 51 42 0) (effects (font (size 1.27 1.27)))) + (property "Value" "100uF" (at 51 48 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Capacitor_THT:CP_Radial_D5.0mm_P2.00mm" (at 48 45 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 48 45 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:TPS61220") (at 80 40 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "a1d374e7-7486-4f8a-8b32-2683679e26a9") + (property "Reference" "U4" (at 83 37 0) (effects (font (size 1.27 1.27)))) + (property "Value" "TPS61220DCK" (at 83 43 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Package_TO_SOT_SMD:SOT-353_SC-70-5" (at 80 40 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 80 40 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Inductor") (at 80 28 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "71a98694-95de-44d2-9449-ea2e75c2d031") + (property "Reference" "L1" (at 83 25 0) (effects (font (size 1.27 1.27)))) + (property "Value" "4.7uH" (at 83 31 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Inductor_SMD:L_0805_2012Metric" (at 80 28 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 80 28 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Capacitor") (at 68 45 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "0594c449-f95c-4a95-9e38-2d39cd72fe7f") + (property "Reference" "C9" (at 71 42 0) (effects (font (size 1.27 1.27)))) + (property "Value" "10uF" (at 71 48 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Capacitor_SMD:C_0805_2012Metric" (at 68 45 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 68 45 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Capacitor") (at 95 45 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "21938427-01a0-4ec2-8e51-946b91b75873") + (property "Reference" "C10" (at 98 42 0) (effects (font (size 1.27 1.27)))) + (property "Value" "10uF" (at 98 48 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Capacitor_SMD:C_0805_2012Metric" (at 95 45 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 95 45 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:USB_C") (at 20 80 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "8d3dfb8b-38a7-4c72-b926-a3cfa199b606") + (property "Reference" "J6" (at 23 77 0) (effects (font (size 1.27 1.27)))) + (property "Value" "USB_C" (at 23 83 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Connector_USB:USB_C_Receptacle_GCT_USB4085" (at 20 80 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 20 80 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Resistor") (at 38 83 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "aad7b37e-5135-48f8-85a7-d10c2ae025f8") + (property "Reference" "R7" (at 41 80 0) (effects (font (size 1.27 1.27)))) + (property "Value" "5.1K" (at 41 86 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" (at 38 83 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 38 83 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Resistor") (at 38 88 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "acbcde11-54d1-4f44-908e-220214c79f0b") + (property "Reference" "R8" (at 41 85 0) (effects (font (size 1.27 1.27)))) + (property "Value" "5.1K" (at 41 91 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" (at 38 88 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 38 88 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Diode_Schottky") (at 55 74 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "e8998fe7-93f1-44bb-b19b-4464f77b6dd9") + (property "Reference" "D3" (at 58 71 0) (effects (font (size 1.27 1.27)))) + (property "Value" "BAT54S" (at 58 77 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Diode_SMD:D_SOT-23_ANK" (at 55 74 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 55 74 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:MCP1700") (at 72 74 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "d32653e5-c0d2-451f-a9d5-d1daf1bc082d") + (property "Reference" "U5" (at 75 71 0) (effects (font (size 1.27 1.27)))) + (property "Value" "MCP1700-3302E" (at 75 77 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Package_TO_SOT_SMD:SOT-23" (at 72 74 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 72 74 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Capacitor") (at 62 82 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "a931807e-4c4b-44a1-8d60-5d98aad60b7f") + (property "Reference" "C11" (at 65 79 0) (effects (font (size 1.27 1.27)))) + (property "Value" "1uF" (at 65 85 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Capacitor_SMD:C_0805_2012Metric" (at 62 82 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 62 82 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Capacitor") (at 82 82 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "d3de9a69-ceee-485c-a6c4-1c67c1b603d8") + (property "Reference" "C12" (at 85 79 0) (effects (font (size 1.27 1.27)))) + (property "Value" "1uF" (at 85 85 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Capacitor_SMD:C_0805_2012Metric" (at 82 82 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 82 82 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:MDBT50Q") (at 160 100 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "594bd8ce-6f7f-41a5-9e1a-d3960d0a099a") + (property "Reference" "U1" (at 163 97 0) (effects (font (size 1.27 1.27)))) + (property "Value" "MDBT50Q-P1MV2" (at 163 103 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "RF_Module:Raytac_MDBT50Q" (at 160 100 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 160 100 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Capacitor") (at 135 60 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "8d2f0126-6582-4abb-bb02-b468a2a7e303") + (property "Reference" "C2" (at 138 57 0) (effects (font (size 1.27 1.27)))) + (property "Value" "100nF" (at 138 63 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Capacitor_SMD:C_0805_2012Metric" (at 135 60 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 135 60 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Capacitor") (at 128 60 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "49fb3b95-d44a-4ad8-a22e-a44e0bb59f88") + (property "Reference" "C3" (at 131 57 0) (effects (font (size 1.27 1.27)))) + (property "Value" "10uF" (at 131 63 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Capacitor_SMD:C_0805_2012Metric" (at 128 60 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 128 60 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:IS25LP128F") (at 260 60 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "66c0d38b-8b39-4ca4-a5c2-ca6166c01990") + (property "Reference" "U2" (at 263 57 0) (effects (font (size 1.27 1.27)))) + (property "Value" "IS25LP128F" (at 263 63 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Package_SO:SOIC-8_3.9x4.9mm_P1.27mm" (at 260 60 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 260 60 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Capacitor") (at 285 50 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "70abbd58-d545-4aa6-907a-dc51d3e39b40") + (property "Reference" "C5" (at 288 47 0) (effects (font (size 1.27 1.27)))) + (property "Value" "100nF" (at 288 53 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Capacitor_SMD:C_0805_2012Metric" (at 285 50 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 285 50 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:PAM8302A") (at 260 140 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "36bdb273-1745-4ae6-a0c5-8ee5ce247b24") + (property "Reference" "U3" (at 263 137 0) (effects (font (size 1.27 1.27)))) + (property "Value" "PAM8302A" (at 263 143 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Package_SO:SOIC-8_3.9x4.9mm_P1.27mm" (at 260 140 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 260 140 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Resistor") (at 220 135 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "43e10163-561a-41ef-a818-083eb46dadbb") + (property "Reference" "R2" (at 223 132 0) (effects (font (size 1.27 1.27)))) + (property "Value" "4.7K" (at 223 138 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" (at 220 135 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 220 135 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Capacitor") (at 230 145 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "294f675b-caf9-46fb-a7e3-4f2b3f1e6278") + (property "Reference" "C7" (at 233 142 0) (effects (font (size 1.27 1.27)))) + (property "Value" "10nF" (at 233 148 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Capacitor_SMD:C_0805_2012Metric" (at 230 145 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 230 145 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Capacitor") (at 240 135 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "195a432e-ee1e-4cd3-8448-97b1efccd434") + (property "Reference" "C6" (at 243 132 0) (effects (font (size 1.27 1.27)))) + (property "Value" "1uF" (at 243 138 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Capacitor_SMD:C_0805_2012Metric" (at 240 135 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 240 135 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Capacitor") (at 285 130 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "a374fa1d-d300-401e-a298-17204d120f0b") + (property "Reference" "C8" (at 288 127 0) (effects (font (size 1.27 1.27)))) + (property "Value" "10uF" (at 288 133 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Capacitor_SMD:C_0805_2012Metric" (at 285 130 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 285 130 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Resistor") (at 240 155 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "26431bf8-ccbf-4a0d-9b17-4cf5a0660df2") + (property "Reference" "R3" (at 243 152 0) (effects (font (size 1.27 1.27)))) + (property "Value" "100K" (at 243 158 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" (at 240 155 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 240 155 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Conn_2Pin") (at 290 145 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "63c284ab-b058-480d-884f-ea0e5a23be78") + (property "Reference" "J2" (at 293 142 0) (effects (font (size 1.27 1.27)))) + (property "Value" "SPEAKER" (at 293 148 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Connector_JST:JST_PH_S2B-PH-K_1x02_P2.00mm_Horizontal" (at 290 145 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 290 145 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:NMOS") (at 160 200 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "8361bf44-050a-467e-a525-5cc39ff3aa0e") + (property "Reference" "Q1" (at 163 197 0) (effects (font (size 1.27 1.27)))) + (property "Value" "AO3400A" (at 163 203 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Package_TO_SOT_SMD:SOT-23" (at 160 200 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 160 200 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Resistor") (at 140 200 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "de5de389-8023-498e-a92c-82ae00e9e811") + (property "Reference" "R4" (at 143 197 0) (effects (font (size 1.27 1.27)))) + (property "Value" "100R" (at 143 203 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" (at 140 200 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 140 200 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Resistor") (at 150 212 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "91f0e3bf-5e2f-42b4-8da6-8a77e2ef1ad8") + (property "Reference" "R5" (at 153 209 0) (effects (font (size 1.27 1.27)))) + (property "Value" "100K" (at 153 215 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" (at 150 212 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 150 212 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Diode_Schottky") (at 175 190 90) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "d21b4325-c08a-4cf7-9598-f2eead5a0427") + (property "Reference" "D4" (at 178 187 0) (effects (font (size 1.27 1.27)))) + (property "Value" "SS14" (at 178 193 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Diode_SMD:D_SMA" (at 175 190 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 175 190 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Conn_2Pin") (at 180 180 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "d9fb0352-f82e-4858-bc84-824cdfd66411") + (property "Reference" "J3" (at 183 177 0) (effects (font (size 1.27 1.27)))) + (property "Value" "MOTOR" (at 183 183 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Connector_JST:JST_PH_S2B-PH-K_1x02_P2.00mm_Horizontal" (at 180 180 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 180 180 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Switch") (at 300 80 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "57360837-e551-42fd-92c4-90b47e3af1d7") + (property "Reference" "SW1" (at 303 77 0) (effects (font (size 1.27 1.27)))) + (property "Value" "BTN1" (at 303 83 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Button_Switch_SMD:SW_SPST_TL3342" (at 300 80 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 300 80 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Switch") (at 300 94 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "25df26f9-6b89-45c0-8247-d0fca36ce61d") + (property "Reference" "SW2" (at 303 91 0) (effects (font (size 1.27 1.27)))) + (property "Value" "BTN2" (at 303 97 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Button_Switch_SMD:SW_SPST_TL3342" (at 300 94 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 300 94 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Switch") (at 300 108 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "d10f35e2-3a88-464c-bad3-32d1b7dc37e7") + (property "Reference" "SW3" (at 303 105 0) (effects (font (size 1.27 1.27)))) + (property "Value" "BTN3" (at 303 111 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Button_Switch_SMD:SW_SPST_TL3342" (at 300 108 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 300 108 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Switch") (at 300 122 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "7422ffd7-92cd-4290-a5ef-a9725f9ce828") + (property "Reference" "SW4" (at 303 119 0) (effects (font (size 1.27 1.27)))) + (property "Value" "BTN4" (at 303 125 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Button_Switch_SMD:SW_SPST_TL3342" (at 300 122 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 300 122 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Switch") (at 300 136 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "72136978-3095-41af-9a20-710af6a51233") + (property "Reference" "SW5" (at 303 133 0) (effects (font (size 1.27 1.27)))) + (property "Value" "BTN5" (at 303 139 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Button_Switch_SMD:SW_SPST_TL3342" (at 300 136 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 300 136 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Switch") (at 300 150 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "eb1956dd-8fc8-428e-8a8a-732832b3046a") + (property "Reference" "SW6" (at 303 147 0) (effects (font (size 1.27 1.27)))) + (property "Value" "BTN6" (at 303 153 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Button_Switch_SMD:SW_SPST_TL3342" (at 300 150 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 300 150 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Switch") (at 300 164 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "838098eb-6069-4a93-803d-71f7bcc015ed") + (property "Reference" "SW7" (at 303 161 0) (effects (font (size 1.27 1.27)))) + (property "Value" "BTN7" (at 303 167 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Button_Switch_SMD:SW_SPST_TL3342" (at 300 164 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 300 164 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Switch") (at 300 178 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "4c7b5735-d245-4a22-b39e-da02d205dd6f") + (property "Reference" "SW8" (at 303 175 0) (effects (font (size 1.27 1.27)))) + (property "Value" "BTN8" (at 303 181 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Button_Switch_SMD:SW_SPST_TL3342" (at 300 178 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 300 178 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:LED") (at 115 200 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "381a075f-afed-41fe-8bee-e87a0c979fb5") + (property "Reference" "D2" (at 118 197 0) (effects (font (size 1.27 1.27)))) + (property "Value" "LED_GRN" (at 118 203 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "LED_SMD:LED_0805_2012Metric" (at 115 200 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 115 200 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Resistor") (at 105 200 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "29ff321d-9917-491b-aa90-e6857486d032") + (property "Reference" "R6" (at 108 197 0) (effects (font (size 1.27 1.27)))) + (property "Value" "1K" (at 108 203 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Resistor_SMD:R_0805_2012Metric" (at 105 200 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 105 200 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:SWD_Header") (at 200 60 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "e9f21ce7-386a-49f0-b58a-baa3c2c214fd") + (property "Reference" "J4" (at 203 57 0) (effects (font (size 1.27 1.27)))) + (property "Value" "SWD" (at 203 63 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Connector_PinHeader_2.54mm:PinHeader_1x04_P2.54mm_Vertical" (at 200 60 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 200 60 0) (effects (font (size 1.27 1.27)) hide)) + ) + (symbol (lib_id "baby_mobile:Serial_Header") (at 200 30 0) (unit 1) + (in_bom yes) (on_board yes) (dnp no) + (uuid "430fc64d-7b88-4340-93e7-7f62c2e6e768") + (property "Reference" "J5" (at 203 27 0) (effects (font (size 1.27 1.27)))) + (property "Value" "SERIAL" (at 203 33 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "Connector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_Vertical" (at 200 30 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 200 30 0) (effects (font (size 1.27 1.27)) hide)) + ) + (label "3V3" (at 95 37 0) (effects (font (size 1.27 1.27))) (uuid "8ed071e2-ba5f-47a3-94d1-f6573f0fc9e6")) + (label "3V3" (at 135 55 0) (effects (font (size 1.27 1.27))) (uuid "82c68cf0-245b-4579-9abd-df6a25942f65")) + (label "3V3" (at 128 55 0) (effects (font (size 1.27 1.27))) (uuid "b759afce-3d7a-43ae-a815-920f94039f06")) + (label "3V3" (at 285 45 0) (effects (font (size 1.27 1.27))) (uuid "14313904-f45a-4f5c-8e82-3e71fb09a66a")) + (label "3V3" (at 285 125 0) (effects (font (size 1.27 1.27))) (uuid "5fc1cdc3-7530-4122-ab28-2954b8f56786")) + (label "3V3" (at 155 67 0) (effects (font (size 1.27 1.27))) (uuid "e84c183d-2287-4a07-bd7f-2427b2373c61")) + (label "3V3" (at 82 72 0) (effects (font (size 1.27 1.27))) (uuid "a3c425cd-d49b-47ff-8ef2-a0796ad2421f")) + (label "3V3" (at 180 175 0) (effects (font (size 1.27 1.27))) (uuid "9eb533dd-82ed-459c-bddc-5394f3d00809")) + (label "VBAT" (at 48 35 0) (effects (font (size 1.27 1.27))) (uuid "e7d3519e-53fd-4369-9e31-d5f75ead4298")) + (label "VBAT" (at 55 30 0) (effects (font (size 1.27 1.27))) (uuid "ae7b918c-7601-447a-8523-7c71e3ff5acf")) + (label "VBAT" (at 68 37 0) (effects (font (size 1.27 1.27))) (uuid "26a13740-da13-42a7-b4e9-218732d83e0d")) + (label "VBOOST_IN" (at 65 37 0) (effects (font (size 1.27 1.27))) (uuid "ad461d02-0622-4db7-a37a-33ffedce49f1")) + (label "VBOOST_IN" (at 70 37 0) (effects (font (size 1.27 1.27))) (uuid "eff048a1-c542-479d-a2da-4b1574cc7645")) + (label "3V3" (at 90 37 0) (effects (font (size 1.27 1.27))) (uuid "77b6f1d8-570a-4483-ae22-d2f30387bec8")) + (label "USB_VBUS" (at 29 74 0) (effects (font (size 1.27 1.27))) (uuid "1c439b3b-db55-4ff6-81df-7b615e8e6c39")) + (label "USB_VBUS" (at 55 69 0) (effects (font (size 1.27 1.27))) (uuid "6126f227-20fc-4552-8088-543092d7d2c9")) + (label "USB_LDO_OUT" (at 81 72 0) (effects (font (size 1.27 1.27))) (uuid "22bc2b82-1cd3-4fbf-b722-7aec2e3e7ac6")) + (label "GND" (at 48 55 0) (effects (font (size 1.27 1.27))) (uuid "1d89d47f-e5cc-47c8-96ef-875a47dd3d7d")) + (label "GND" (at 68 55 0) (effects (font (size 1.27 1.27))) (uuid "d070d4a1-832d-4144-a8e7-62c665cb7c19")) + (label "GND" (at 95 55 0) (effects (font (size 1.27 1.27))) (uuid "19863f8b-aa0c-4a5b-a8ad-4c10e0df834c")) + (label "GND" (at 80 50 0) (effects (font (size 1.27 1.27))) (uuid "31dcf8fa-9fe5-49f7-898c-eb9bb164aecc")) + (label "GND" (at 155 133 0) (effects (font (size 1.27 1.27))) (uuid "3389eb1b-db83-4210-bb6a-73265aeaa3e8")) + (label "GND" (at 260 70 0) (effects (font (size 1.27 1.27))) (uuid "4454cdab-2b40-43cc-ad3a-593113577789")) + (label "GND" (at 285 55 0) (effects (font (size 1.27 1.27))) (uuid "39014c1d-a110-4de1-8340-ac91b0cf2cd8")) + (label "GND" (at 285 155 0) (effects (font (size 1.27 1.27))) (uuid "955fabd2-0a64-46fb-899b-880b837da381")) + (label "GND" (at 160 215 0) (effects (font (size 1.27 1.27))) (uuid "da5dcfa8-d9b3-4750-b5e8-e0249eb1aca7")) + (label "GND" (at 150 218 0) (effects (font (size 1.27 1.27))) (uuid "6ff8e8df-1e76-4220-9afb-0e8e64c0ed7b")) + (label "GND" (at 230 155 0) (effects (font (size 1.27 1.27))) (uuid "5837c09d-c9c6-4753-b127-65cf1fd82b7a")) + (label "GND" (at 240 165 0) (effects (font (size 1.27 1.27))) (uuid "95a99a98-2c30-42a6-a07e-0aa4f2b48488")) + (label "GND" (at 62 92 0) (effects (font (size 1.27 1.27))) (uuid "76e18ea2-8285-426f-9ef8-9fa76e7111eb")) + (label "GND" (at 82 92 0) (effects (font (size 1.27 1.27))) (uuid "8ea4dfaf-0d35-489a-80b6-78f27b959ae4")) + (label "GND" (at 72 81 0) (effects (font (size 1.27 1.27))) (uuid "b7470fc2-e399-46eb-9fd3-bd74e283e117")) + (label "GND" (at 38 93 0) (effects (font (size 1.27 1.27))) (uuid "e5aa3e17-1915-485d-88f2-e4c97b203429")) + (label "GND" (at 38 98 0) (effects (font (size 1.27 1.27))) (uuid "9e79744e-5eed-4812-84be-ac90ad982c39")) + (label "GND" (at 135 65 0) (effects (font (size 1.27 1.27))) (uuid "b3762e1f-492b-4a17-93bc-c59442290780")) + (label "GND" (at 128 65 0) (effects (font (size 1.27 1.27))) (uuid "1de86c1d-deef-4198-a7ad-b33d2084bbe4")) + (label "USB_D+" (at 29 77 0) (effects (font (size 1.27 1.27))) (uuid "cafef546-ab22-40e8-bf8e-5a1b4a866c7b")) + (label "USB_D+" (at 183 92.5 0) (effects (font (size 1.27 1.27))) (uuid "02cbe821-47c0-4b39-ab87-c0017f8610d0")) + (label "USB_D-" (at 29 80 0) (effects (font (size 1.27 1.27))) (uuid "12b0e3d5-044c-4e34-b046-c90d3a2eb5a6")) + (label "USB_D-" (at 183 95 0) (effects (font (size 1.27 1.27))) (uuid "148c349c-b923-4ee5-9770-8b45ca65230e")) + (label "USB_CC1" (at 29 83 0) (effects (font (size 1.27 1.27))) (uuid "03410510-b26c-408e-818a-067a7db0f5b8")) + (label "USB_CC1" (at 38 78 0) (effects (font (size 1.27 1.27))) (uuid "218b088a-8395-4491-9a0e-6d5db11ca7a4")) + (label "USB_CC2" (at 29 86 0) (effects (font (size 1.27 1.27))) (uuid "c3131644-9adc-40f6-b7ce-2206504a9a27")) + (label "USB_CC2" (at 38 83 0) (effects (font (size 1.27 1.27))) (uuid "4825f804-a15c-4194-b1ec-fa57f3d85eff")) + (label "SPI_MOSI" (at 183 87.5 0) (effects (font (size 1.27 1.27))) (uuid "da1257b0-9158-4049-bdfc-ac6750ac975a")) + (label "SPI_MOSI" (at 250 56 0) (effects (font (size 1.27 1.27))) (uuid "1b17c2f2-8313-4f5d-b7cc-b863d00796bb")) + (label "SPI_MISO" (at 183 85 0) (effects (font (size 1.27 1.27))) (uuid "0860088c-74d8-43fb-860e-15349a699593")) + (label "SPI_MISO" (at 250 61.5 0) (effects (font (size 1.27 1.27))) (uuid "3b2dc367-6d21-4735-8410-d30a500e74a5")) + (label "SPI_SCK" (at 183 82.5 0) (effects (font (size 1.27 1.27))) (uuid "53e5a5c7-e20f-4482-a55d-2688efc6f7ba")) + (label "SPI_SCK" (at 270 58.5 0) (effects (font (size 1.27 1.27))) (uuid "26492f79-696e-4aea-b80d-03bfd63c2c3f")) + (label "FLASH_CS" (at 183 80 0) (effects (font (size 1.27 1.27))) (uuid "3a5652cc-c614-4368-9c13-111744980544")) + (label "FLASH_CS" (at 250 64 0) (effects (font (size 1.27 1.27))) (uuid "6e5a8087-754e-481b-a1bb-3c7f3f3f5232")) + (label "AUDIO_PWM" (at 183 100 0) (effects (font (size 1.27 1.27))) (uuid "57c2b713-56f7-42e2-bd58-5b5d04bebd30")) + (label "AUDIO_PWM" (at 210 135 0) (effects (font (size 1.27 1.27))) (uuid "4631b763-c906-4580-8fd8-1a93edd729d3")) + (label "AMP_SD" (at 183 102.5 0) (effects (font (size 1.27 1.27))) (uuid "deb32a13-e972-41aa-8d41-d20a062e3cba")) + (label "AMP_SD" (at 240 150 0) (effects (font (size 1.27 1.27))) (uuid "9bdd3963-b925-4327-92c0-1c3679ea2ebe")) + (label "MOTOR_PWM" (at 137 112.5 0) (effects (font (size 1.27 1.27))) (uuid "5b5f8fba-9659-4dee-9aad-e4ff3779e804")) + (label "MOTOR_PWM" (at 130 200 0) (effects (font (size 1.27 1.27))) (uuid "73d245e9-56a0-4ce1-9410-9cc9522893b0")) + (label "BTN1" (at 295 80 0) (effects (font (size 1.27 1.27))) (uuid "32e72139-ab6e-48c9-a0cf-65e931a41274")) + (label "BTN1" (at 137 120 0) (effects (font (size 1.27 1.27))) (uuid "b4d8683f-1cd7-4f33-9eda-8398e1098d6a")) + (label "BTN2" (at 295 94 0) (effects (font (size 1.27 1.27))) (uuid "17aea161-ddd2-4d17-ba4a-feedd256f98b")) + (label "BTN2" (at 137 117.5 0) (effects (font (size 1.27 1.27))) (uuid "808daa01-07c4-4622-9bca-032aaa095ffe")) + (label "BTN3" (at 295 108 0) (effects (font (size 1.27 1.27))) (uuid "39886739-7865-48a6-88b3-40ce4caf35b8")) + (label "BTN3" (at 137 115 0) (effects (font (size 1.27 1.27))) (uuid "ff98c423-d019-4c3e-8ba8-b7fcda8c6d3b")) + (label "BTN4" (at 295 122 0) (effects (font (size 1.27 1.27))) (uuid "7be84ac2-a319-4e89-8912-a48308157a57")) + (label "BTN4" (at 137 112.5 0) (effects (font (size 1.27 1.27))) (uuid "2c5a6c32-a6d7-4a20-a777-f8e4bf9caf99")) + (label "BTN5" (at 295 136 0) (effects (font (size 1.27 1.27))) (uuid "d0569adf-df84-42ea-8fa4-9b19b8f5266a")) + (label "BTN5" (at 137 110 0) (effects (font (size 1.27 1.27))) (uuid "aee28d6b-be5d-4a1c-a2ee-17bc73d031bb")) + (label "BTN6" (at 295 150 0) (effects (font (size 1.27 1.27))) (uuid "dbe9e702-77e0-48af-8818-9f2154f62514")) + (label "BTN6" (at 137 107.5 0) (effects (font (size 1.27 1.27))) (uuid "ee40d98c-46b9-45f2-a122-471375cc3a26")) + (label "BTN7" (at 295 164 0) (effects (font (size 1.27 1.27))) (uuid "dbe03385-adea-4e6f-87f0-fda692538d54")) + (label "BTN7" (at 137 105 0) (effects (font (size 1.27 1.27))) (uuid "404ba48f-c3f9-4bd9-9e7c-7e4662f61fa5")) + (label "BTN8" (at 295 178 0) (effects (font (size 1.27 1.27))) (uuid "160da6ab-3b24-4688-9c7b-67d82a3d897b")) + (label "BTN8" (at 137 102.5 0) (effects (font (size 1.27 1.27))) (uuid "a53bf467-04c2-45bd-9b30-b0f3446d8c9f")) + (label "GND" (at 305 80 0) (effects (font (size 1.27 1.27))) (uuid "f6f4b71d-c1f2-45bb-b1eb-07c33f60c27f")) + (label "GND" (at 305 94 0) (effects (font (size 1.27 1.27))) (uuid "4a9f4779-5345-41a1-a039-727291be615e")) + (label "GND" (at 305 108 0) (effects (font (size 1.27 1.27))) (uuid "a396ef9e-6be6-4b73-9829-12db9b3e07b3")) + (label "GND" (at 305 122 0) (effects (font (size 1.27 1.27))) (uuid "0cf7df09-6c2d-40cf-815f-e080021dce6d")) + (label "GND" (at 305 136 0) (effects (font (size 1.27 1.27))) (uuid "016e1cf1-b3f5-4ad5-a212-3ffcefeed34f")) + (label "GND" (at 305 150 0) (effects (font (size 1.27 1.27))) (uuid "a2c17108-4c26-4ae7-ab8c-2def7d9478a7")) + (label "GND" (at 305 164 0) (effects (font (size 1.27 1.27))) (uuid "41c52008-b330-4723-8b7c-d4e6be680b6a")) + (label "GND" (at 305 178 0) (effects (font (size 1.27 1.27))) (uuid "1087b54a-297b-4224-b9e2-48695ff85b8d")) + (label "LED_OUT" (at 95 200 0) (effects (font (size 1.27 1.27))) (uuid "cc999662-caea-48b8-9222-78cab879fcdc")) + (label "LED_OUT" (at 137 100 0) (effects (font (size 1.27 1.27))) (uuid "013e7457-91fe-4fbd-a0ee-7ee89c54199d")) + (label "SWDIO" (at 194 55.5 0) (effects (font (size 1.27 1.27))) (uuid "25823cf8-69a9-41c6-9b9c-a5c49404406c")) + (label "SWDIO" (at 183 82.5 0) (effects (font (size 1.27 1.27))) (uuid "00074155-1634-4876-8d45-3fe907bf2db3")) + (label "SWDCLK" (at 194 58 0) (effects (font (size 1.27 1.27))) (uuid "ff3a7eec-2bb9-4f1e-967f-5cadd8e240dc")) + (label "SWDCLK" (at 183 80 0) (effects (font (size 1.27 1.27))) (uuid "a30d2c78-19ef-46c2-a458-36c2c5876254")) + (label "3V3" (at 194 53 0) (effects (font (size 1.27 1.27))) (uuid "f99c5f81-ea9a-41f5-960e-d2fae7d0a181")) + (label "GND" (at 194 60.5 0) (effects (font (size 1.27 1.27))) (uuid "e26ea204-b9ea-4447-8197-4e162160fd9d")) + (label "TXD" (at 194 25.5 0) (effects (font (size 1.27 1.27))) (uuid "301ed6e2-a2bd-4b45-9f9a-392d72600933")) + (label "TXD" (at 137 80 0) (effects (font (size 1.27 1.27))) (uuid "5ebc2fb5-79e1-41fc-94e0-ae66b9cfe1f5")) + (label "RXD" (at 194 28 0) (effects (font (size 1.27 1.27))) (uuid "8dbda22c-6ed0-427c-a7a2-3cb9994d6b43")) + (label "RXD" (at 137 82.5 0) (effects (font (size 1.27 1.27))) (uuid "cd81992e-9202-48d6-b995-d0f86e69f52e")) + (label "GND" (at 194 30.5 0) (effects (font (size 1.27 1.27))) (uuid "6fb29d8b-c74b-4471-b93c-4751e770957b")) + (label "3V3" (at 250 58.5 0) (effects (font (size 1.27 1.27))) (uuid "76f5880c-4436-4818-94bb-c78a7ee6fe4e")) + (label "3V3" (at 270 61.5 0) (effects (font (size 1.27 1.27))) (uuid "a4e298f8-b82b-4d58-8e1f-b0f80af8cc9e")) + (label "VBAT" (at 90 43 0) (effects (font (size 1.27 1.27))) (uuid "4e07ee15-a453-4fe9-805e-d131f584d1a8")) + (text "POWER: 2xAA → BAT54S → TPS61220 boost → 3.3V (1.8-3.2V input)" (at 10 12 0) + (effects (font (size 1.5 1.5)) (justify left)) + (uuid "10cfdea1-8a29-4bde-88d4-c91935a5e9ac") + ) + (text "USB: VBUS → BAT54S → MCP1700 LDO → 3.3V (safe with any battery chemistry)" (at 10 15 0) + (effects (font (size 1.5 1.5)) (justify left)) + (uuid "27e25aeb-a530-42a6-9e45-b196b84a0721") + ) + (text "MCU: MDBT50Q (nRF52840) — BLE 5.0, USB 2.0, 1.7-5.5V, UF2 bootloader" (at 10 18 0) + (effects (font (size 1.5 1.5)) (justify left)) + (uuid "5ec8a803-c645-49fb-936d-707f1a426ea0") + ) + (text "FLASH: IS25LP128F 16MB (2.3-3.6V) = ~33 min @ 8kHz 8-bit PCM" (at 10 21 0) + (effects (font (size 1.5 1.5)) (justify left)) + (uuid "3540a598-29a4-42b0-955e-10cfb84fcec3") + ) + (text "AMP: PAM8302A Class-D, 90% eff, Vmin=2.0V, shutdown pin for power save" (at 10 24 0) + (effects (font (size 1.5 1.5)) (justify left)) + (uuid "5b07f1c0-2adc-42e6-9792-d4d4c22a5559") + ) + (text "MOTOR: AO3400A logic-level N-MOSFET, PWM speed control" (at 10 27 0) + (effects (font (size 1.5 1.5)) (justify left)) + (uuid "f259ebac-06b9-4b51-84fd-855ca64743c6") + ) + (text "USB-C: Drag-and-drop audio as mass storage device" (at 10 230 0) + (effects (font (size 1.5 1.5)) (justify left)) + (uuid "9bb11b21-6fca-415e-9aa1-383cbc0bf675") + ) + (text "BLE: Wireless audio upload from phone (Web Bluetooth compatible)" (at 10 233 0) + (effects (font (size 1.5 1.5)) (justify left)) + (uuid "e3624e20-88ff-405d-99a6-634170b921f6") + ) + (text "FIRMWARE: UF2 bootloader — update by drag-and-drop, no programmer needed" (at 10 236 0) + (effects (font (size 1.5 1.5)) (justify left)) + (uuid "f25d994c-c32d-4858-a3ed-12707aea679c") + ) + (text "RUNTIME: Audio+Motor ~25h, Audio only ~167h, Sleep ~years on 2xAA" (at 10 239 0) + (effects (font (size 1.5 1.5)) (justify left)) + (uuid "9fdf6591-0f6e-4339-b052-f5593d9b3690") + ) +) \ No newline at end of file diff --git a/baby-mobile.kicad_pro b/baby-mobile.kicad_pro deleted file mode 100644 index 2acd155..0000000 --- a/baby-mobile.kicad_pro +++ /dev/null @@ -1,61 +0,0 @@ -{ - "meta": { - "filename": "baby-mobile.kicad_pro", - "version": 1 - }, - "board": { - "design_settings": { - "defaults": { - "board_outline_line_width": 0.1, - "copper_line_width": 0.2, - "copper_text_size_h": 1.5, - "copper_text_size_v": 1.5, - "other_line_width": 0.15 - }, - "rules": { - "min_copper_edge_clearance": 0.3, - "min_hole_clearance": 0.25, - "min_track_width": 0.2, - "min_via_annular_width": 0.13, - "min_via_diameter": 0.6, - "solder_mask_to_copper_clearance": 0 - } - }, - "layer_presets": [] - }, - "libraries": { - "pinned_footprint_libs": [], - "pinned_symbol_libs": [] - }, - "net_settings": { - "classes": [ - { - "bus_width": 12, - "clearance": 0.2, - "diff_pair_gap": 0.25, - "diff_pair_via_gap": 0.25, - "diff_pair_width": 0.2, - "line_style": 0, - "microvia_diameter": 0.3, - "microvia_drill": 0.1, - "name": "Default", - "pcb_color": "rgba(0, 0, 0, 0.000)", - "schematic_color": "rgba(0, 0, 0, 0.000)", - "track_width": 0.3, - "via_diameter": 0.6, - "via_drill": 0.3, - "wire_width": 6 - } - ] - }, - "schematic": { - "legacy_lib_dir": "", - "legacy_lib_list": [] - }, - "sheets": [ - [ - "", - "" - ] - ] -} \ No newline at end of file diff --git a/baby-mobile.kicad_sch b/baby-mobile.kicad_sch deleted file mode 100644 index 96c3522..0000000 --- a/baby-mobile.kicad_sch +++ /dev/null @@ -1,628 +0,0 @@ -(kicad_sch (version 20230121) (generator "custom_generator") - - (uuid "391da8c7-7217-4ed9-a918-95efab6bbe33") - (paper "A3") - - (title_block - (title "Baby Mobile Audio Board") - (date "2026-03-08") - (rev "1.0") - (comment 1 "ATmega328P + W25Q128 + PAM8302A") - (comment 2 "2xAA Battery Powered - Long Runtime Design") - (comment 3 "8-ohm 0.25W Speaker, DC Motor, 8 Buttons") - (comment 4 "Arduino Compatible (8MHz Internal Osc)") - ) - - (lib_symbols - - (symbol "baby_mobile:ATmega328P-AU" (in_bom yes) (on_board yes) - (property "Reference" "U" (at 0 26 0) (effects (font (size 1.27 1.27)))) - (property "Value" "ATmega328P-AU" (at 0 24 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Package_QFP:TQFP-32_7x7mm_P0.8mm" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (symbol "ATmega328P-AU_0_1" - (rectangle (start -17 23) (end 17 -23) (stroke (width 0.254) (type default)) (fill (type background))) - ) - (symbol "ATmega328P-AU_1_1" - (pin power_in line (at -7 -26 90) (length 3) (name "GND" (effects (font (size 1 1)))) (number "3" (effects (font (size 1 1))))) - (pin power_in line (at -5 -26 90) (length 3) (name "GND2" (effects (font (size 1 1)))) (number "5" (effects (font (size 1 1))))) - (pin power_in line (at -3 26 270) (length 3) (name "VCC" (effects (font (size 1 1)))) (number "4" (effects (font (size 1 1))))) - (pin power_in line (at -1 26 270) (length 3) (name "AVCC" (effects (font (size 1 1)))) (number "6" (effects (font (size 1 1))))) - (pin passive line (at 1 26 270) (length 3) (name "AREF" (effects (font (size 1 1)))) (number "21" (effects (font (size 1 1))))) - (pin bidirectional line (at -20 15 0) (length 3) (name "PD0/RXD" (effects (font (size 1 1)))) (number "30" (effects (font (size 1 1))))) - (pin bidirectional line (at -20 12.5 0) (length 3) (name "PD1/TXD" (effects (font (size 1 1)))) (number "31" (effects (font (size 1 1))))) - (pin bidirectional line (at -20 10 0) (length 3) (name "PD2/INT0" (effects (font (size 1 1)))) (number "32" (effects (font (size 1 1))))) - (pin bidirectional line (at -20 7.5 0) (length 3) (name "PD3/INT1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) - (pin bidirectional line (at -20 5 0) (length 3) (name "PD4" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) - (pin bidirectional line (at -20 2.5 0) (length 3) (name "PD5/OC0B" (effects (font (size 1 1)))) (number "9" (effects (font (size 1 1))))) - (pin bidirectional line (at -20 0 0) (length 3) (name "PD6/OC0A" (effects (font (size 1 1)))) (number "10" (effects (font (size 1 1))))) - (pin bidirectional line (at -20 -2.5 0) (length 3) (name "PD7" (effects (font (size 1 1)))) (number "11" (effects (font (size 1 1))))) - (pin bidirectional line (at 20 15 180) (length 3) (name "PB0" (effects (font (size 1 1)))) (number "12" (effects (font (size 1 1))))) - (pin bidirectional line (at 20 12.5 180) (length 3) (name "PB1/OC1A" (effects (font (size 1 1)))) (number "13" (effects (font (size 1 1))))) - (pin bidirectional line (at 20 10 180) (length 3) (name "PB2/SS" (effects (font (size 1 1)))) (number "14" (effects (font (size 1 1))))) - (pin bidirectional line (at 20 7.5 180) (length 3) (name "PB3/MOSI" (effects (font (size 1 1)))) (number "15" (effects (font (size 1 1))))) - (pin bidirectional line (at 20 5 180) (length 3) (name "PB4/MISO" (effects (font (size 1 1)))) (number "16" (effects (font (size 1 1))))) - (pin bidirectional line (at 20 2.5 180) (length 3) (name "PB5/SCK" (effects (font (size 1 1)))) (number "17" (effects (font (size 1 1))))) - (pin bidirectional line (at 20 -2.5 180) (length 3) (name "PC0/ADC0" (effects (font (size 1 1)))) (number "23" (effects (font (size 1 1))))) - (pin bidirectional line (at 20 -5 180) (length 3) (name "PC1/ADC1" (effects (font (size 1 1)))) (number "24" (effects (font (size 1 1))))) - (pin bidirectional line (at 20 -7.5 180) (length 3) (name "PC2/ADC2" (effects (font (size 1 1)))) (number "25" (effects (font (size 1 1))))) - (pin bidirectional line (at 20 -10 180) (length 3) (name "PC3/ADC3" (effects (font (size 1 1)))) (number "26" (effects (font (size 1 1))))) - (pin bidirectional line (at 20 -12.5 180) (length 3) (name "PC4/SDA" (effects (font (size 1 1)))) (number "27" (effects (font (size 1 1))))) - (pin bidirectional line (at 20 -15 180) (length 3) (name "PC5/SCL" (effects (font (size 1 1)))) (number "28" (effects (font (size 1 1))))) - (pin input line (at -20 -10 0) (length 3) (name "~{RESET}" (effects (font (size 1 1)))) (number "29" (effects (font (size 1 1))))) - (pin input line (at -20 -15 0) (length 3) (name "XTAL1" (effects (font (size 1 1)))) (number "7" (effects (font (size 1 1))))) - (pin output line (at -20 -17.5 0) (length 3) (name "XTAL2" (effects (font (size 1 1)))) (number "8" (effects (font (size 1 1))))) - ) - ) - - (symbol "baby_mobile:W25Q128" (in_bom yes) (on_board yes) - (property "Reference" "U" (at 0 9 0) (effects (font (size 1.27 1.27)))) - (property "Value" "W25Q128JVSIQ" (at 0 7 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Package_SO:SOIC-8_3.9x4.9mm_P1.27mm" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (symbol "W25Q128_0_1" - (rectangle (start -7 6) (end 7 -6) (stroke (width 0.254) (type default)) (fill (type background))) - ) - (symbol "W25Q128_1_1" - (pin input line (at -10 4 0) (length 3) (name "~{CS}" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) - (pin output line (at -10 1.5 0) (length 3) (name "DO/IO1" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) - (pin input line (at -10 -1.5 0) (length 3) (name "~{WP}/IO2" (effects (font (size 1 1)))) (number "3" (effects (font (size 1 1))))) - (pin power_in line (at -10 -4 0) (length 3) (name "GND" (effects (font (size 1 1)))) (number "4" (effects (font (size 1 1))))) - (pin input line (at 10 -4 180) (length 3) (name "DI/IO0" (effects (font (size 1 1)))) (number "5" (effects (font (size 1 1))))) - (pin input line (at 10 -1.5 180) (length 3) (name "CLK" (effects (font (size 1 1)))) (number "6" (effects (font (size 1 1))))) - (pin input line (at 10 1.5 180) (length 3) (name "~{HOLD}/IO3" (effects (font (size 1 1)))) (number "7" (effects (font (size 1 1))))) - (pin power_in line (at 10 4 180) (length 3) (name "VCC" (effects (font (size 1 1)))) (number "8" (effects (font (size 1 1))))) - ) - ) - - (symbol "baby_mobile:PAM8302A" (in_bom yes) (on_board yes) - (property "Reference" "U" (at 0 11 0) (effects (font (size 1.27 1.27)))) - (property "Value" "PAM8302A" (at 0 9 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Package_SO:SOIC-8_3.9x4.9mm_P1.27mm" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (symbol "PAM8302A_0_1" - (rectangle (start -8 8) (end 8 -8) (stroke (width 0.254) (type default)) (fill (type background))) - ) - (symbol "PAM8302A_1_1" - (pin input line (at -11 5 0) (length 3) (name "~{SD}" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) - (pin power_in line (at -11 2 0) (length 3) (name "VDD" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) - (pin power_in line (at -11 -1 0) (length 3) (name "GND" (effects (font (size 1 1)))) (number "3" (effects (font (size 1 1))))) - (pin input line (at -11 -4 0) (length 3) (name "A+" (effects (font (size 1 1)))) (number "4" (effects (font (size 1 1))))) - (pin input line (at -11 -7 0) (length 3) (name "A-" (effects (font (size 1 1)))) (number "5" (effects (font (size 1 1))))) - (pin output line (at 11 2 180) (length 3) (name "VO+" (effects (font (size 1 1)))) (number "8" (effects (font (size 1 1))))) - (pin output line (at 11 -1 180) (length 3) (name "VO-" (effects (font (size 1 1)))) (number "7" (effects (font (size 1 1))))) - (pin power_in line (at 11 -4 180) (length 3) (name "PAD" (effects (font (size 1 1)))) (number "6" (effects (font (size 1 1))))) - ) - ) - - (symbol "baby_mobile:NMOS" (in_bom yes) (on_board yes) - (property "Reference" "Q" (at 3 0 0) (effects (font (size 1.27 1.27)))) - (property "Value" "AO3400A" (at 5 -2.5 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Package_TO_SOT_SMD:SOT-23" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (symbol "NMOS_0_1" - (polyline (pts (xy -0.5 0.5) (xy -0.5 -0.5)) (stroke (width 0.33) (type default)) (fill (type none))) - (polyline (pts (xy -0.5 -2) (xy -0.5 2)) (stroke (width 0.254) (type default)) (fill (type none))) - (polyline (pts (xy 0 -2.5) (xy 0 -1.5)) (stroke (width 0) (type default)) (fill (type none))) - (polyline (pts (xy 0 1.5) (xy 0 2.5)) (stroke (width 0) (type default)) (fill (type none))) - (polyline (pts (xy 0 0) (xy -1.5 0)) (stroke (width 0) (type default)) (fill (type none))) - ) - (symbol "NMOS_1_1" - (pin passive line (at 0 5 270) (length 2.5) (name "D" (effects (font (size 1 1)))) (number "3" (effects (font (size 1 1))))) - (pin input line (at -4 0 0) (length 2.5) (name "G" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) - (pin passive line (at 0 -5 90) (length 2.5) (name "S" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) - ) - ) - - (symbol "baby_mobile:Capacitor" (in_bom yes) (on_board yes) - (property "Reference" "C" (at 2 0 0) (effects (font (size 1.27 1.27)))) - (property "Value" "C" (at 2 -2 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (symbol "Capacitor_0_1" - (polyline (pts (xy -1.5 1) (xy 1.5 1)) (stroke (width 0.4) (type default)) (fill (type none))) - (polyline (pts (xy -1.5 -1) (xy 1.5 -1)) (stroke (width 0.4) (type default)) (fill (type none))) - ) - (symbol "Capacitor_1_1" - (pin passive line (at 0 3.5 270) (length 2.5) (name "1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) - (pin passive line (at 0 -3.5 90) (length 2.5) (name "2" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) - ) - ) - - (symbol "baby_mobile:Resistor" (in_bom yes) (on_board yes) - (property "Reference" "R" (at 2 0 0) (effects (font (size 1.27 1.27)))) - (property "Value" "R" (at 2 -2 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (symbol "Resistor_0_1" - (rectangle (start -1 2.5) (end 1 -2.5) (stroke (width 0.254) (type default)) (fill (type background))) - ) - (symbol "Resistor_1_1" - (pin passive line (at 0 5 270) (length 2.5) (name "1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) - (pin passive line (at 0 -5 90) (length 2.5) (name "2" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) - ) - ) - - (symbol "baby_mobile:Diode_Schottky" (in_bom yes) (on_board yes) - (property "Reference" "D" (at 2 0 0) (effects (font (size 1.27 1.27)))) - (property "Value" "SS14" (at 2 -2 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Diode_SMD:D_SMA" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (symbol "Diode_Schottky_0_1" - (polyline (pts (xy -1.5 1) (xy 0 -1) (xy 1.5 1) (xy -1.5 1)) (stroke (width 0.2) (type default)) (fill (type none))) - (polyline (pts (xy -1.5 -1) (xy 1.5 -1)) (stroke (width 0.3) (type default)) (fill (type none))) - ) - (symbol "Diode_Schottky_1_1" - (pin passive line (at 0 3.5 270) (length 2.5) (name "A" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) - (pin passive line (at 0 -3.5 90) (length 2.5) (name "K" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) - ) - ) - - (symbol "baby_mobile:Inductor" (in_bom yes) (on_board yes) - (property "Reference" "L" (at 2 0 0) (effects (font (size 1.27 1.27)))) - (property "Value" "L" (at 2 -2 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (symbol "Inductor_0_1" - (arc (start 0 2.5) (mid 0.75 1.875) (end 0 1.25) (stroke (width 0.254) (type default)) (fill (type none))) - (arc (start 0 1.25) (mid 0.75 0.625) (end 0 0) (stroke (width 0.254) (type default)) (fill (type none))) - (arc (start 0 0) (mid 0.75 -0.625) (end 0 -1.25) (stroke (width 0.254) (type default)) (fill (type none))) - (arc (start 0 -1.25) (mid 0.75 -1.875) (end 0 -2.5) (stroke (width 0.254) (type default)) (fill (type none))) - ) - (symbol "Inductor_1_1" - (pin passive line (at 0 5 270) (length 2.5) (name "1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) - (pin passive line (at 0 -5 90) (length 2.5) (name "2" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) - ) - ) - - (symbol "baby_mobile:Switch" (in_bom yes) (on_board yes) - (property "Reference" "SW" (at 0 3 0) (effects (font (size 1.27 1.27)))) - (property "Value" "SW" (at 0 -3 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (symbol "Switch_0_1" - (circle (center -2 0) (radius 0.4) (stroke (width 0) (type default)) (fill (type none))) - (circle (center 2 0) (radius 0.4) (stroke (width 0) (type default)) (fill (type none))) - (polyline (pts (xy -1.6 0) (xy 1.6 1)) (stroke (width 0.254) (type default)) (fill (type none))) - ) - (symbol "Switch_1_1" - (pin passive line (at -5 0 0) (length 3) (name "1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) - (pin passive line (at 5 0 180) (length 3) (name "2" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) - ) - ) - - (symbol "baby_mobile:Conn_2Pin" (in_bom yes) (on_board yes) - (property "Reference" "J" (at 0 4 0) (effects (font (size 1.27 1.27)))) - (property "Value" "Conn_2" (at 0 -4 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (symbol "Conn_2Pin_0_1" - (rectangle (start -2 3) (end 2 -3) (stroke (width 0.254) (type default)) (fill (type background))) - ) - (symbol "Conn_2Pin_1_1" - (pin passive line (at -5 1.5 0) (length 3) (name "1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) - (pin passive line (at -5 -1.5 0) (length 3) (name "2" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) - ) - ) - - (symbol "baby_mobile:Conn_3Pin" (in_bom yes) (on_board yes) - (property "Reference" "J" (at 0 5.5 0) (effects (font (size 1.27 1.27)))) - (property "Value" "Conn_3" (at 0 -5.5 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (symbol "Conn_3Pin_0_1" - (rectangle (start -2 4) (end 2 -4) (stroke (width 0.254) (type default)) (fill (type background))) - ) - (symbol "Conn_3Pin_1_1" - (pin passive line (at -5 2.5 0) (length 3) (name "1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) - (pin passive line (at -5 0 0) (length 3) (name "2" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) - (pin passive line (at -5 -2.5 0) (length 3) (name "3" (effects (font (size 1 1)))) (number "3" (effects (font (size 1 1))))) - ) - ) - - (symbol "baby_mobile:Conn_6Pin" (in_bom yes) (on_board yes) - (property "Reference" "J" (at 0 9 0) (effects (font (size 1.27 1.27)))) - (property "Value" "ISP_2x3" (at 0 -9 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (symbol "Conn_6Pin_0_1" - (rectangle (start -3 8) (end 3 -8) (stroke (width 0.254) (type default)) (fill (type background))) - ) - (symbol "Conn_6Pin_1_1" - (pin passive line (at -6 5 0) (length 3) (name "MISO" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) - (pin passive line (at 6 5 180) (length 3) (name "VCC" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) - (pin passive line (at -6 0 0) (length 3) (name "SCK" (effects (font (size 1 1)))) (number "3" (effects (font (size 1 1))))) - (pin passive line (at 6 0 180) (length 3) (name "MOSI" (effects (font (size 1 1)))) (number "4" (effects (font (size 1 1))))) - (pin passive line (at -6 -5 0) (length 3) (name "~{RST}" (effects (font (size 1 1)))) (number "5" (effects (font (size 1 1))))) - (pin passive line (at 6 -5 180) (length 3) (name "GND" (effects (font (size 1 1)))) (number "6" (effects (font (size 1 1))))) - ) - ) - - (symbol "baby_mobile:LED" (in_bom yes) (on_board yes) - (property "Reference" "D" (at 2 0 0) (effects (font (size 1.27 1.27)))) - (property "Value" "LED" (at 2 -2 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (symbol "LED_0_1" - (polyline (pts (xy -1.5 1) (xy 0 -1) (xy 1.5 1) (xy -1.5 1)) (stroke (width 0.2) (type default)) (fill (type none))) - (polyline (pts (xy -1.5 -1) (xy 1.5 -1)) (stroke (width 0.3) (type default)) (fill (type none))) - ) - (symbol "LED_1_1" - (pin passive line (at 0 3.5 270) (length 2.5) (name "A" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) - (pin passive line (at 0 -3.5 90) (length 2.5) (name "K" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) - ) - ) - - (symbol "baby_mobile:PWR_FLAG" (power) (in_bom no) (on_board no) - (property "Reference" "#FLG" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Value" "PWR_FLAG" (at 0 3 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (symbol "PWR_FLAG_0_1" - (polyline (pts (xy 0 0) (xy 0 1.5)) (stroke (width 0) (type default)) (fill (type none))) - (polyline (pts (xy -1 1.5) (xy 0 3) (xy 1 1.5) (xy -1 1.5)) (stroke (width 0) (type default)) (fill (type none))) - ) - (symbol "PWR_FLAG_1_1" - (pin power_out line (at 0 0 90) (length 0) (name "pwr" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) - ) - ) - ) - (symbol (lib_id "baby_mobile:Conn_2Pin") (at 25 35 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "507bdf9f-e516-4e7b-8916-4c751f1b84e2") - (property "Reference" "J1" (at 25 32 0) (effects (font (size 1.27 1.27)))) - (property "Value" "BATTERY" (at 25 38 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Connector_JST:JST_PH_S2B-PH-K_1x02_P2.00mm_Horizontal" (at 25 35 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 25 35 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:Capacitor") (at 55 35 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "c40c113d-1405-44ce-a1f0-58bef96d538e") - (property "Reference" "C1" (at 55 32 0) (effects (font (size 1.27 1.27)))) - (property "Value" "100uF" (at 55 38 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Capacitor_THT:CP_Radial_D5.0mm_P2.00mm" (at 55 35 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 55 35 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:Capacitor") (at 100 30 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "399c833b-8964-48dd-b796-3cb9e41ff4d0") - (property "Reference" "C2" (at 100 27 0) (effects (font (size 1.27 1.27)))) - (property "Value" "100nF" (at 100 33 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Capacitor_SMD:C_0805_2012Metric" (at 100 30 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 100 30 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:Capacitor") (at 115 30 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "da1e40d4-4aae-4393-8ac3-273b705cd8d2") - (property "Reference" "C3" (at 115 27 0) (effects (font (size 1.27 1.27)))) - (property "Value" "100nF" (at 115 33 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Capacitor_SMD:C_0805_2012Metric" (at 115 30 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 115 30 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:Switch") (at 40 25 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "d5f6e2c8-1f5a-4b82-abbb-cb3f97490465") - (property "Reference" "SW9" (at 40 22 0) (effects (font (size 1.27 1.27)))) - (property "Value" "PWR" (at 40 28 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Button_Switch_THT:SW_SPDT_CK-JS102011SAQN" (at 40 25 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 40 25 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:ATmega328P-AU") (at 130 90 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "45044e9c-b35e-4aac-8523-60d85a6a6df8") - (property "Reference" "U1" (at 130 87 0) (effects (font (size 1.27 1.27)))) - (property "Value" "ATmega328P-AU" (at 130 93 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Package_QFP:TQFP-32_7x7mm_P0.8mm" (at 130 90 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 130 90 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:Resistor") (at 95 55 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "94af8e3c-b3da-4777-8e91-865edfc76cdf") - (property "Reference" "R1" (at 95 52 0) (effects (font (size 1.27 1.27)))) - (property "Value" "10K" (at 95 58 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Resistor_SMD:R_0805_2012Metric" (at 95 55 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 95 55 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:Capacitor") (at 95 65 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "65aa9490-ed2d-43cc-bec1-e1f276413ef2") - (property "Reference" "C4" (at 95 62 0) (effects (font (size 1.27 1.27)))) - (property "Value" "100nF" (at 95 68 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Capacitor_SMD:C_0805_2012Metric" (at 95 65 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 95 65 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:W25Q128") (at 230 60 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "b5dc96e3-fbe8-4c5b-b1a7-82f3926f520f") - (property "Reference" "U2" (at 230 57 0) (effects (font (size 1.27 1.27)))) - (property "Value" "W25Q128JVSIQ" (at 230 63 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Package_SO:SOIC-8_3.9x4.9mm_P1.27mm" (at 230 60 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 230 60 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:Capacitor") (at 255 50 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "63c2829e-7fd6-485b-82f8-94ec57fe959b") - (property "Reference" "C5" (at 255 47 0) (effects (font (size 1.27 1.27)))) - (property "Value" "100nF" (at 255 53 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Capacitor_SMD:C_0805_2012Metric" (at 255 50 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 255 50 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:PAM8302A") (at 230 140 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "dc5d606b-6f45-42d0-82bb-b0db3a981adf") - (property "Reference" "U3" (at 230 137 0) (effects (font (size 1.27 1.27)))) - (property "Value" "PAM8302A" (at 230 143 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Package_SO:SOIC-8_3.9x4.9mm_P1.27mm" (at 230 140 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 230 140 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:Capacitor") (at 200 135 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "85967935-a5f6-4065-9ae7-b181b28d0674") - (property "Reference" "C6" (at 200 132 0) (effects (font (size 1.27 1.27)))) - (property "Value" "1uF" (at 200 138 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Capacitor_SMD:C_0805_2012Metric" (at 200 135 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 200 135 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:Resistor") (at 185 135 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "2d985162-8660-47cc-9982-688a70e5af66") - (property "Reference" "R2" (at 185 132 0) (effects (font (size 1.27 1.27)))) - (property "Value" "4.7K" (at 185 138 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Resistor_SMD:R_0805_2012Metric" (at 185 135 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 185 135 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:Capacitor") (at 192 145 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "136fb80a-2afa-44da-887f-5760ca0c20ee") - (property "Reference" "C7" (at 192 142 0) (effects (font (size 1.27 1.27)))) - (property "Value" "10nF" (at 192 148 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Capacitor_SMD:C_0805_2012Metric" (at 192 145 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 192 145 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:Capacitor") (at 255 130 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "47509d19-833e-498c-8131-5ad8bc4f9b89") - (property "Reference" "C8" (at 255 127 0) (effects (font (size 1.27 1.27)))) - (property "Value" "10uF" (at 255 133 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Capacitor_SMD:C_0805_2012Metric" (at 255 130 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 255 130 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:Conn_2Pin") (at 265 145 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "d84e0dcb-8d75-4de2-b76d-db6013404837") - (property "Reference" "J2" (at 265 142 0) (effects (font (size 1.27 1.27)))) - (property "Value" "SPEAKER" (at 265 148 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Connector_JST:JST_PH_S2B-PH-K_1x02_P2.00mm_Horizontal" (at 265 145 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 265 145 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:Resistor") (at 210 150 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "c73fafc0-ebff-46a7-b8a6-93719e4ba183") - (property "Reference" "R3" (at 210 147 0) (effects (font (size 1.27 1.27)))) - (property "Value" "100K" (at 210 153 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Resistor_SMD:R_0805_2012Metric" (at 210 150 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 210 150 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:NMOS") (at 140 190 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "f44467d7-d2d3-4056-b74e-d8e247ada0c0") - (property "Reference" "Q1" (at 140 187 0) (effects (font (size 1.27 1.27)))) - (property "Value" "AO3400A" (at 140 193 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Package_TO_SOT_SMD:SOT-23" (at 140 190 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 140 190 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:Resistor") (at 120 190 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "d2efdc5b-60e1-40ac-b81e-b671ae9e2524") - (property "Reference" "R4" (at 120 187 0) (effects (font (size 1.27 1.27)))) - (property "Value" "100R" (at 120 193 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Resistor_SMD:R_0805_2012Metric" (at 120 190 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 120 190 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:Resistor") (at 130 200 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "fa36bf14-db5f-4c2d-aa38-322990e1a079") - (property "Reference" "R5" (at 130 197 0) (effects (font (size 1.27 1.27)))) - (property "Value" "100K" (at 130 203 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Resistor_SMD:R_0805_2012Metric" (at 130 200 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 130 200 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:Diode_Schottky") (at 155 180 90) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "a86dfdae-f4a0-4d77-9501-410a463b4929") - (property "Reference" "D1" (at 155 177 0) (effects (font (size 1.27 1.27)))) - (property "Value" "SS14" (at 155 183 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Diode_SMD:D_SMA" (at 155 180 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 155 180 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:Conn_2Pin") (at 160 170 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "e215997e-3139-4cb2-903e-f84cabd0b1af") - (property "Reference" "J3" (at 160 167 0) (effects (font (size 1.27 1.27)))) - (property "Value" "MOTOR" (at 160 173 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Connector_JST:JST_PH_S2B-PH-K_1x02_P2.00mm_Horizontal" (at 160 170 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 160 170 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:Switch") (at 30 75 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "7f01bcc9-33e2-4fec-9df9-ee78a82cb270") - (property "Reference" "SW1" (at 30 72 0) (effects (font (size 1.27 1.27)))) - (property "Value" "BTN1" (at 30 78 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Button_Switch_SMD:SW_SPST_TL3342" (at 30 75 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 30 75 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:Switch") (at 30 90 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "bfa6ab0a-df05-4515-8d1f-72749aba4a20") - (property "Reference" "SW2" (at 30 87 0) (effects (font (size 1.27 1.27)))) - (property "Value" "BTN2" (at 30 93 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Button_Switch_SMD:SW_SPST_TL3342" (at 30 90 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 30 90 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:Switch") (at 30 105 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "1b1fc388-ea85-4a5c-bee5-7e769d4b59eb") - (property "Reference" "SW3" (at 30 102 0) (effects (font (size 1.27 1.27)))) - (property "Value" "BTN3" (at 30 108 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Button_Switch_SMD:SW_SPST_TL3342" (at 30 105 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 30 105 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:Switch") (at 30 120 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "bc5829d7-ff9c-4c0a-834e-e85b6795fb22") - (property "Reference" "SW4" (at 30 117 0) (effects (font (size 1.27 1.27)))) - (property "Value" "BTN4" (at 30 123 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Button_Switch_SMD:SW_SPST_TL3342" (at 30 120 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 30 120 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:Switch") (at 30 135 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "182c3254-622e-4fb9-a960-ce401433f071") - (property "Reference" "SW5" (at 30 132 0) (effects (font (size 1.27 1.27)))) - (property "Value" "BTN5" (at 30 138 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Button_Switch_SMD:SW_SPST_TL3342" (at 30 135 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 30 135 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:Switch") (at 30 150 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "86d0f6ec-c847-470d-9bbd-f4bed67fc489") - (property "Reference" "SW6" (at 30 147 0) (effects (font (size 1.27 1.27)))) - (property "Value" "BTN6" (at 30 153 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Button_Switch_SMD:SW_SPST_TL3342" (at 30 150 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 30 150 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:Switch") (at 30 165 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "cf404039-6a3b-4246-816c-1be4597bebb0") - (property "Reference" "SW7" (at 30 162 0) (effects (font (size 1.27 1.27)))) - (property "Value" "BTN7" (at 30 168 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Button_Switch_SMD:SW_SPST_TL3342" (at 30 165 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 30 165 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:Switch") (at 30 180 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "80093bcc-1f31-4639-8591-9f1cfa8e1721") - (property "Reference" "SW8" (at 30 177 0) (effects (font (size 1.27 1.27)))) - (property "Value" "BTN8" (at 30 183 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Button_Switch_SMD:SW_SPST_TL3342" (at 30 180 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 30 180 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:LED") (at 85 190 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "e0fae357-d301-48e8-a964-a410bbb95bc6") - (property "Reference" "D2" (at 85 187 0) (effects (font (size 1.27 1.27)))) - (property "Value" "LED" (at 85 193 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "LED_SMD:LED_0805_2012Metric" (at 85 190 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 85 190 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:Resistor") (at 75 190 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "898d416a-1773-4205-a6ee-11a04534c363") - (property "Reference" "R6" (at 75 187 0) (effects (font (size 1.27 1.27)))) - (property "Value" "1K" (at 75 193 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Resistor_SMD:R_0805_2012Metric" (at 75 190 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 75 190 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:Conn_6Pin") (at 250 200 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "049eaee8-ace8-4be4-8664-1f02e3371a2e") - (property "Reference" "J4" (at 250 197 0) (effects (font (size 1.27 1.27)))) - (property "Value" "ISP" (at 250 203 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Connector_PinHeader_2.54mm:PinHeader_2x03_P2.54mm_Vertical" (at 250 200 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 250 200 0) (effects (font (size 1.27 1.27)) hide)) - ) - (symbol (lib_id "baby_mobile:Conn_3Pin") (at 30 210 0) (unit 1) - (in_bom yes) (on_board yes) (dnp no) - (uuid "6e205180-7724-405f-af1d-daa148abacc5") - (property "Reference" "J5" (at 30 207 0) (effects (font (size 1.27 1.27)))) - (property "Value" "SERIAL" (at 30 213 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Connector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_Vertical" (at 30 210 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 30 210 0) (effects (font (size 1.27 1.27)) hide)) - ) - (label "VCC" (at 55 25 0) (effects (font (size 1.27 1.27))) (uuid "38d66dc5-0dfe-483d-b51e-2d579b758f33")) - (label "VCC" (at 100 25 0) (effects (font (size 1.27 1.27))) (uuid "56a7d1c9-361a-42f8-9d77-7cc94df15408")) - (label "VCC" (at 115 25 0) (effects (font (size 1.27 1.27))) (uuid "78fe02e6-db3b-4885-8a22-d0d962a13bd1")) - (label "VCC" (at 130 50 0) (effects (font (size 1.27 1.27))) (uuid "8dcc821a-8787-4ba3-aa6e-a13c6942949f")) - (label "VCC" (at 255 45 0) (effects (font (size 1.27 1.27))) (uuid "dc2b0694-b4c5-4e2f-a970-c86f81c186ed")) - (label "VCC" (at 255 125 0) (effects (font (size 1.27 1.27))) (uuid "1e7be094-6bef-468b-b0d8-960ef3ee34da")) - (label "VCC" (at 95 50 0) (effects (font (size 1.27 1.27))) (uuid "813d1f5e-21ee-46ad-90c9-d2746d49c93a")) - (label "VCC" (at 160 165 0) (effects (font (size 1.27 1.27))) (uuid "3cc3028b-6ef6-4394-b379-d6fddafb61c7")) - (label "GND" (at 55 45 0) (effects (font (size 1.27 1.27))) (uuid "e58d5e07-b8ad-408f-a3e2-23cba82e951c")) - (label "GND" (at 100 40 0) (effects (font (size 1.27 1.27))) (uuid "427f2a2e-c2c9-4e85-8dc5-6ac456496582")) - (label "GND" (at 115 40 0) (effects (font (size 1.27 1.27))) (uuid "c40ed645-0a77-432f-98e1-3022a591a6bf")) - (label "GND" (at 130 130 0) (effects (font (size 1.27 1.27))) (uuid "13423fca-5ee9-42db-97d7-8d291085433a")) - (label "GND" (at 255 70 0) (effects (font (size 1.27 1.27))) (uuid "f1680748-3b5e-4b5c-9231-f5b123334267")) - (label "GND" (at 255 155 0) (effects (font (size 1.27 1.27))) (uuid "3f2ad3e8-cab3-4661-8c6d-27a5c37248bd")) - (label "GND" (at 95 70 0) (effects (font (size 1.27 1.27))) (uuid "fdb07bc1-2a3f-4bfa-8e0d-44095ddb4eed")) - (label "GND" (at 140 205 0) (effects (font (size 1.27 1.27))) (uuid "a2e87db6-701b-4ee4-9680-ce3e641a1ce3")) - (label "GND" (at 192 155 0) (effects (font (size 1.27 1.27))) (uuid "2f5d05c3-2b85-442d-82e1-f9b8f73b99ae")) - (label "SPI_MOSI" (at 165 85 0) (effects (font (size 1.27 1.27))) (uuid "3c4184cd-6302-4f79-ad70-499253e6926a")) - (label "SPI_MOSI" (at 215 55 0) (effects (font (size 1.27 1.27))) (uuid "f6281dca-e340-4987-a951-2f82a1714181")) - (label "SPI_MISO" (at 165 90 0) (effects (font (size 1.27 1.27))) (uuid "15344a55-c345-4d4f-bc69-d1123a2c9edf")) - (label "SPI_MISO" (at 215 60 0) (effects (font (size 1.27 1.27))) (uuid "979ceaf3-85e4-449e-957c-41ef8f11c043")) - (label "SPI_SCK" (at 165 95 0) (effects (font (size 1.27 1.27))) (uuid "4382cc5e-6bd2-4b3c-a286-89e68a9bfe44")) - (label "SPI_SCK" (at 215 65 0) (effects (font (size 1.27 1.27))) (uuid "5a6dfb3a-06a4-49ca-aad3-f7193a293ce3")) - (label "FLASH_CS" (at 165 80 0) (effects (font (size 1.27 1.27))) (uuid "c791cf26-bc22-410d-aaea-c2eda0b338cd")) - (label "FLASH_CS" (at 215 50 0) (effects (font (size 1.27 1.27))) (uuid "ef59be0a-fc41-456f-947c-1692d138b101")) - (label "AUDIO_PWM" (at 165 100 0) (effects (font (size 1.27 1.27))) (uuid "29036b7e-9203-47e8-9d64-1f906a93ef48")) - (label "AUDIO_PWM" (at 175 135 0) (effects (font (size 1.27 1.27))) (uuid "44583660-84d0-446b-a09f-9b7c62d110a6")) - (label "AMP_SD" (at 165 105 0) (effects (font (size 1.27 1.27))) (uuid "52045a7c-f447-4d0c-a9eb-850e34f11964")) - (label "AMP_SD" (at 210 145 0) (effects (font (size 1.27 1.27))) (uuid "1bcd7182-a352-4545-afe0-2f863d13594c")) - (label "MOTOR_PWM" (at 165 110 0) (effects (font (size 1.27 1.27))) (uuid "6c11ecd3-674e-4579-b26f-fa7cc592b2ef")) - (label "MOTOR_PWM" (at 110 190 0) (effects (font (size 1.27 1.27))) (uuid "18a66086-7b01-4c86-904c-f721fc2edce7")) - (label "BTN1" (at 45 75 0) (effects (font (size 1.27 1.27))) (uuid "92101bd4-f77a-410a-ab6a-0e3d3d66bc02")) - (label "BTN1" (at 95 85 0) (effects (font (size 1.27 1.27))) (uuid "28383130-7933-45e2-bfed-0dd34ff8e876")) - (label "BTN2" (at 45 90 0) (effects (font (size 1.27 1.27))) (uuid "a2f3390b-61b3-4812-ada2-1f4246e4f0cb")) - (label "BTN2" (at 95 90 0) (effects (font (size 1.27 1.27))) (uuid "42b61c7b-b336-4758-b778-9b4ea4905074")) - (label "BTN3" (at 45 105 0) (effects (font (size 1.27 1.27))) (uuid "fe284da5-c9e9-48e5-a293-7bf5f6aa33c9")) - (label "BTN3" (at 95 95 0) (effects (font (size 1.27 1.27))) (uuid "46e2de5c-c19d-4699-8367-e91303e840d5")) - (label "BTN4" (at 45 120 0) (effects (font (size 1.27 1.27))) (uuid "1d9dff94-06c9-49c6-b8e0-66657dd4245a")) - (label "BTN4" (at 95 100 0) (effects (font (size 1.27 1.27))) (uuid "e53835b8-f6b2-40f7-9245-d0d67614ec45")) - (label "BTN5" (at 45 135 0) (effects (font (size 1.27 1.27))) (uuid "4322ba20-38b0-41cf-a3c4-8bf56908ce34")) - (label "BTN5" (at 95 105 0) (effects (font (size 1.27 1.27))) (uuid "a04ee831-82c5-48b5-85c1-9d7fb0a24e33")) - (label "BTN6" (at 45 150 0) (effects (font (size 1.27 1.27))) (uuid "f64f61ae-b22d-41a4-a8ea-770610aebd0a")) - (label "BTN6" (at 95 110 0) (effects (font (size 1.27 1.27))) (uuid "53e714b1-e914-4811-8290-a921f65cac0e")) - (label "BTN7" (at 45 165 0) (effects (font (size 1.27 1.27))) (uuid "ce9834a4-38a7-4ea9-931a-2f9919142d64")) - (label "BTN7" (at 95 115 0) (effects (font (size 1.27 1.27))) (uuid "ddf7162b-f974-4375-885a-f25f1b1d9f57")) - (label "BTN8" (at 45 180 0) (effects (font (size 1.27 1.27))) (uuid "783f1d6f-fe69-492a-aab0-a98b6ec4338b")) - (label "BTN8" (at 95 120 0) (effects (font (size 1.27 1.27))) (uuid "12159112-3e7e-478d-96a5-db94ad9ab8a7")) - (label "SPI_MOSI" (at 240 195 0) (effects (font (size 1.27 1.27))) (uuid "28dda728-344b-400c-81bf-085acc569b01")) - (label "SPI_MISO" (at 240 200 0) (effects (font (size 1.27 1.27))) (uuid "3c258f39-bf6c-4f9d-977a-ca79c60e541a")) - (label "SPI_SCK" (at 240 205 0) (effects (font (size 1.27 1.27))) (uuid "a7f8b6cd-ff0a-4f2e-95e2-c09c7380629b")) - (label "RESET" (at 240 210 0) (effects (font (size 1.27 1.27))) (uuid "8ca5b857-1e0a-4810-9169-7a53d9010e7a")) - (label "RESET" (at 95 60 0) (effects (font (size 1.27 1.27))) (uuid "892fcef9-51e4-47c6-95bc-23995df359e9")) - (label "TXD" (at 40 210 0) (effects (font (size 1.27 1.27))) (uuid "b7910a83-f672-4c68-89d5-a06db98757ec")) - (label "RXD" (at 40 215 0) (effects (font (size 1.27 1.27))) (uuid "db832982-7322-4447-8344-cc95d72ebb5b")) - (label "TXD" (at 95 75 0) (effects (font (size 1.27 1.27))) (uuid "16f4752d-6c95-4710-ba23-85842ce78a5d")) - (label "RXD" (at 95 80 0) (effects (font (size 1.27 1.27))) (uuid "e269931d-0da1-4020-9952-ef4385a672f7")) - (label "LED_OUT" (at 65 190 0) (effects (font (size 1.27 1.27))) (uuid "3cf2c0dd-1277-46aa-bbfa-0319ce140d17")) - (label "LED_OUT" (at 95 125 0) (effects (font (size 1.27 1.27))) (uuid "231cf2b7-4593-4067-9607-34041c287667")) - (text "POWER: 2xAA (1.8V-3.3V) → Long runtime design" (at 15 15 0) - (effects (font (size 1.5 1.5)) (justify left)) - (uuid "950687a6-9e66-444c-bf5d-ac1f097f704f") - ) - (text "MCU: ATmega328P-AU @ 8MHz internal osc, Arduino compatible" (at 15 18 0) - (effects (font (size 1.5 1.5)) (justify left)) - (uuid "f0cdcdd5-ae9a-4fac-b551-a92f7212bfdd") - ) - (text "FLASH: W25Q128 16MB = ~33 min @ 8kHz 8-bit PCM" (at 200 15 0) - (effects (font (size 1.5 1.5)) (justify left)) - (uuid "dd881348-3856-462b-bd58-72d20fb89ca3") - ) - (text "AMP: PAM8302A Class-D, 90% efficient, Vmin=2.0V" (at 200 18 0) - (effects (font (size 1.5 1.5)) (justify left)) - (uuid "7c7a46f6-98e4-4bf2-ae72-3ea92549e1d7") - ) - (text "BUTTONS: Internal pull-ups, active LOW, PCINT wake-from-sleep" (at 15 220 0) - (effects (font (size 1.5 1.5)) (justify left)) - (uuid "eca71b6b-2202-4712-8241-1daf4bd4d0b3") - ) - (text "MOTOR: AO3400A logic-level N-MOSFET, PWM speed control" (at 120 220 0) - (effects (font (size 1.5 1.5)) (justify left)) - (uuid "d36eb55c-80a1-4119-a4d5-92f77873caa6") - ) - (text "ESTIMATED RUNTIME: Audio+Motor ~23h, Audio only ~200h, Sleep ~years" (at 15 225 0) - (effects (font (size 1.5 1.5)) (justify left)) - (uuid "79709c38-5874-4567-856d-15479cbe33cd") - ) -) \ No newline at end of file diff --git a/baby_mobile_firmware.ino b/baby_mobile_firmware.ino deleted file mode 100644 index 1e746a0..0000000 --- a/baby_mobile_firmware.ino +++ /dev/null @@ -1,639 +0,0 @@ -/* - * Baby Mobile Audio Board — Firmware - * - * ATmega328P @ 8MHz internal oscillator - * Plays 8-bit unsigned PCM audio from W25Q128 SPI flash - * Controls DC motor via PWM - * 8 button inputs with sleep/wake support - * - * Board: ATmega328P, 8MHz internal, BOD 1.8V - * - * Pin mapping: - * PB1 (OC1A, pin 9) - Audio PWM output - * PB2 (pin 10) - Flash ~CS - * PB3 (pin 11) - SPI MOSI - * PB4 (pin 12) - SPI MISO - * PB5 (pin 13) - SPI SCK - * PD5 (OC0B, pin 5) - Motor PWM - * PC2 (A2) - Amp ~SD (HIGH=on, LOW=off) - * PC3 (A3) - Status LED - * PC0 (A0) - Button 1 - * PC1 (A1) - Button 2 - * PD2 (pin 2) - Button 3 (INT0) - * PD3 (pin 3) - Button 4 (INT1) - * PD4 (pin 4) - Button 5 - * PD6 (pin 6) - Button 6 - * PD7 (pin 7) - Button 7 - * PB0 (pin 8) - Button 8 - */ - -#include -#include -#include -#include - -// ---- Pin definitions ---- -#define PIN_AUDIO_PWM 9 // PB1 / OC1A -#define PIN_FLASH_CS 10 // PB2 -#define PIN_MOTOR_PWM 5 // PD5 / OC0B -#define PIN_AMP_SD A2 // PC2 - amp shutdown (active HIGH = enabled) -#define PIN_LED A3 // PC3 -#define PIN_BTN1 A0 // PC0 -#define PIN_BTN2 A1 // PC1 -#define PIN_BTN3 2 // PD2 / INT0 -#define PIN_BTN4 3 // PD3 / INT1 -#define PIN_BTN5 4 // PD4 -#define PIN_BTN6 6 // PD6 -#define PIN_BTN7 7 // PD7 -#define PIN_BTN8 8 // PB0 - -// ---- Audio config ---- -#define SAMPLE_RATE 8000 // Hz -#define FLASH_PAGE_SIZE 256 -#define FLASH_SECTOR 4096 -#define AUDIO_BUF_SIZE 256 // double buffer - -// ---- Flash commands (W25Q128) ---- -#define FLASH_CMD_READ 0x03 -#define FLASH_CMD_FAST_READ 0x0B -#define FLASH_CMD_WRITE_EN 0x06 -#define FLASH_CMD_PAGE_PROG 0x02 -#define FLASH_CMD_SECT_ERASE 0x20 -#define FLASH_CMD_CHIP_ERASE 0xC7 -#define FLASH_CMD_READ_SR1 0x05 -#define FLASH_CMD_JEDEC_ID 0x9F -#define FLASH_CMD_POWER_DOWN 0xB9 -#define FLASH_CMD_WAKE 0xAB - -// ---- Track table ---- -// First 4KB (sector 0) of flash stores a track index: -// Offset 0x000: uint8_t num_tracks -// Offset 0x004: uint32_t track_start[32] (byte address in flash) -// Offset 0x084: uint32_t track_length[32] (length in bytes = samples) -// Audio data begins at sector 1 (address 0x1000). - -#define TRACK_TABLE_ADDR 0x000000 -#define AUDIO_START_ADDR 0x001000 -#define MAX_TRACKS 32 - -// ---- State ---- -volatile bool g_playing = false; -volatile bool g_motorOn = false; -volatile bool g_wakeFlag = false; -volatile uint8_t g_buttonPressed = 0; - -uint8_t g_numTracks = 0; -uint32_t g_trackStart[MAX_TRACKS]; -uint32_t g_trackLen[MAX_TRACKS]; -uint8_t g_currentTrack = 0; -uint32_t g_playPos = 0; // current position in track (byte offset) -uint32_t g_playEnd = 0; // end position -uint8_t g_motorSpeed = 180; // PWM duty cycle (0-255) - -// Double buffer for audio DMA-style playback -uint8_t g_audioBuf[2][AUDIO_BUF_SIZE]; -volatile uint8_t g_activeBuf = 0; // buffer currently being played -volatile uint16_t g_bufPos = 0; // position in active buffer -volatile bool g_bufReady[2] = {false, false}; -uint32_t g_nextReadAddr = 0; - -// Auto-shutoff timer (milliseconds) -#define AUTO_OFF_MS (30UL * 60UL * 1000UL) // 30 minutes -unsigned long g_lastActivity = 0; - - -// ============================================================ -// FLASH FUNCTIONS -// ============================================================ - -void flashSelect() { digitalWrite(PIN_FLASH_CS, LOW); } -void flashDeselect() { digitalWrite(PIN_FLASH_CS, HIGH); } - -void flashWake() { - flashSelect(); - SPI.transfer(FLASH_CMD_WAKE); - flashDeselect(); - delayMicroseconds(5); -} - -void flashSleep() { - flashSelect(); - SPI.transfer(FLASH_CMD_POWER_DOWN); - flashDeselect(); -} - -uint32_t flashReadJEDEC() { - flashSelect(); - SPI.transfer(FLASH_CMD_JEDEC_ID); - uint32_t id = (uint32_t)SPI.transfer(0) << 16; - id |= (uint32_t)SPI.transfer(0) << 8; - id |= SPI.transfer(0); - flashDeselect(); - return id; -} - -void flashReadBytes(uint32_t addr, uint8_t *buf, uint16_t len) { - flashSelect(); - SPI.transfer(FLASH_CMD_READ); - SPI.transfer((addr >> 16) & 0xFF); - SPI.transfer((addr >> 8) & 0xFF); - SPI.transfer(addr & 0xFF); - for (uint16_t i = 0; i < len; i++) { - buf[i] = SPI.transfer(0); - } - flashDeselect(); -} - -void flashWaitBusy() { - flashSelect(); - SPI.transfer(FLASH_CMD_READ_SR1); - while (SPI.transfer(0) & 0x01) { /* spin */ } - flashDeselect(); -} - -void flashWriteEnable() { - flashSelect(); - SPI.transfer(FLASH_CMD_WRITE_EN); - flashDeselect(); -} - -void flashEraseSector(uint32_t addr) { - flashWriteEnable(); - flashSelect(); - SPI.transfer(FLASH_CMD_SECT_ERASE); - SPI.transfer((addr >> 16) & 0xFF); - SPI.transfer((addr >> 8) & 0xFF); - SPI.transfer(addr & 0xFF); - flashDeselect(); - flashWaitBusy(); -} - -void flashPageProgram(uint32_t addr, const uint8_t *data, uint16_t len) { - flashWriteEnable(); - flashSelect(); - SPI.transfer(FLASH_CMD_PAGE_PROG); - SPI.transfer((addr >> 16) & 0xFF); - SPI.transfer((addr >> 8) & 0xFF); - SPI.transfer(addr & 0xFF); - for (uint16_t i = 0; i < len; i++) { - SPI.transfer(data[i]); - } - flashDeselect(); - flashWaitBusy(); -} - - -// ============================================================ -// TRACK TABLE -// ============================================================ - -void loadTrackTable() { - uint8_t header[4]; - flashReadBytes(TRACK_TABLE_ADDR, header, 4); - g_numTracks = header[0]; - if (g_numTracks == 0 || g_numTracks == 0xFF || g_numTracks > MAX_TRACKS) { - g_numTracks = 0; - return; - } - - // Read start addresses - uint8_t buf[4]; - for (uint8_t i = 0; i < g_numTracks; i++) { - flashReadBytes(TRACK_TABLE_ADDR + 4 + i * 4, buf, 4); - g_trackStart[i] = ((uint32_t)buf[0] << 24) | ((uint32_t)buf[1] << 16) | - ((uint32_t)buf[2] << 8) | buf[3]; - } - // Read lengths - for (uint8_t i = 0; i < g_numTracks; i++) { - flashReadBytes(TRACK_TABLE_ADDR + 4 + MAX_TRACKS * 4 + i * 4, buf, 4); - g_trackLen[i] = ((uint32_t)buf[0] << 24) | ((uint32_t)buf[1] << 16) | - ((uint32_t)buf[2] << 8) | buf[3]; - } -} - - -// ============================================================ -// AUDIO PLAYBACK (Timer1 ISR) -// ============================================================ - -void audioInit() { - // Timer1: Fast PWM, 8-bit, TOP=255 - // At 8MHz clock: 8000000 / 256 = 31250 Hz PWM frequency - // Good enough — well above audible range - - // We use a separate Timer1 compare match for sample rate: - // Timer1 in Fast PWM mode for output, - // Timer2 for sample rate interrupt - - // Timer1: Fast PWM 8-bit on OC1A (PB1) - TCCR1A = _BV(COM1A1) | _BV(WGM10); // Clear on match, 8-bit fast PWM - TCCR1B = _BV(WGM12) | _BV(CS10); // No prescaler - OCR1A = 128; // 50% = silence for unsigned 8-bit - - // Timer2: CTC mode for sample rate interrupt - // 8MHz / 8 / 125 = 8000 Hz - TCCR2A = _BV(WGM21); // CTC mode - TCCR2B = _BV(CS21); // prescaler /8 - OCR2A = 124; // 8000000/8/(124+1) = 8000 Hz - TIMSK2 = 0; // interrupt disabled until playing -} - -void audioStart(uint8_t trackNum) { - if (trackNum >= g_numTracks) return; - - g_currentTrack = trackNum; - g_playPos = g_trackStart[trackNum]; - g_playEnd = g_playPos + g_trackLen[trackNum]; - - // Pre-fill both buffers - flashReadBytes(g_playPos, g_audioBuf[0], AUDIO_BUF_SIZE); - g_playPos += AUDIO_BUF_SIZE; - if (g_playPos < g_playEnd) { - flashReadBytes(g_playPos, g_audioBuf[1], AUDIO_BUF_SIZE); - g_playPos += AUDIO_BUF_SIZE; - } - - g_activeBuf = 0; - g_bufPos = 0; - g_bufReady[0] = true; - g_bufReady[1] = true; - g_nextReadAddr = g_playPos; - - // Enable amp - digitalWrite(PIN_AMP_SD, HIGH); - delay(10); // amp startup time - - g_playing = true; - TIMSK2 = _BV(OCIE2A); // enable sample rate interrupt -} - -void audioStop() { - TIMSK2 = 0; // disable interrupt - OCR1A = 128; // silence - g_playing = false; - - // Disable amp to save power - digitalWrite(PIN_AMP_SD, LOW); -} - -// Timer2 Compare Match A — fires at 8000 Hz -ISR(TIMER2_COMPA_vect) { - if (!g_playing) return; - - // Output sample to PWM - OCR1A = g_audioBuf[g_activeBuf][g_bufPos]; - g_bufPos++; - - if (g_bufPos >= AUDIO_BUF_SIZE) { - // Switch to other buffer - g_bufReady[g_activeBuf] = false; // mark for refill - g_activeBuf ^= 1; - g_bufPos = 0; - - if (!g_bufReady[g_activeBuf]) { - // Buffer underrun — stop playback - g_playing = false; - OCR1A = 128; - } - } -} - - -// ============================================================ -// MOTOR CONTROL -// ============================================================ - -void motorInit() { - pinMode(PIN_MOTOR_PWM, OUTPUT); - analogWrite(PIN_MOTOR_PWM, 0); // off -} - -void motorStart(uint8_t speed) { - g_motorSpeed = speed; - g_motorOn = true; - analogWrite(PIN_MOTOR_PWM, speed); -} - -void motorStop() { - g_motorOn = false; - analogWrite(PIN_MOTOR_PWM, 0); -} - - -// ============================================================ -// BUTTONS -// ============================================================ - -const uint8_t BTN_PINS[] = { - PIN_BTN1, PIN_BTN2, PIN_BTN3, PIN_BTN4, - PIN_BTN5, PIN_BTN6, PIN_BTN7, PIN_BTN8 -}; -#define NUM_BUTTONS 8 - -void buttonsInit() { - for (uint8_t i = 0; i < NUM_BUTTONS; i++) { - pinMode(BTN_PINS[i], INPUT_PULLUP); - } -} - -// Returns button number 1-8, or 0 if none pressed -uint8_t buttonRead() { - for (uint8_t i = 0; i < NUM_BUTTONS; i++) { - if (digitalRead(BTN_PINS[i]) == LOW) { - delay(20); // debounce - if (digitalRead(BTN_PINS[i]) == LOW) { - return i + 1; - } - } - } - return 0; -} - - -// ============================================================ -// SLEEP / WAKE -// ============================================================ - -// Pin change interrupts for wake-from-sleep -ISR(PCINT0_vect) { g_wakeFlag = true; } // PB0 (BTN8) -ISR(PCINT1_vect) { g_wakeFlag = true; } // PC0, PC1 (BTN1, BTN2) -ISR(PCINT2_vect) { g_wakeFlag = true; } // PD2-7 (BTN3-BTN7) -ISR(INT0_vect) { g_wakeFlag = true; } -ISR(INT1_vect) { g_wakeFlag = true; } - -void enterSleep() { - // Stop everything - audioStop(); - motorStop(); - flashSleep(); - digitalWrite(PIN_LED, LOW); - - // Enable pin change interrupts for wake - PCICR = _BV(PCIE0) | _BV(PCIE1) | _BV(PCIE2); - PCMSK0 = _BV(PCINT0); // PB0 - PCMSK1 = _BV(PCINT8) | _BV(PCINT9); // PC0, PC1 - PCMSK2 = _BV(PCINT18) | _BV(PCINT19) | _BV(PCINT20) | - _BV(PCINT22) | _BV(PCINT23); // PD2,3,4,6,7 - - // Also enable INT0/INT1 for PD2/PD3 - EICRA = 0; // LOW level trigger - EIMSK = _BV(INT0) | _BV(INT1); - - set_sleep_mode(SLEEP_MODE_PWR_DOWN); - sleep_enable(); - sei(); - sleep_cpu(); - - // --- ZZZ --- wakes up here --- - sleep_disable(); - - // Disable wake interrupts - PCICR = 0; - EIMSK = 0; - - // Wake flash - flashWake(); - - g_lastActivity = millis(); - g_wakeFlag = false; - - // Blink LED to indicate wake - digitalWrite(PIN_LED, HIGH); - delay(100); - digitalWrite(PIN_LED, LOW); -} - - -// ============================================================ -// SERIAL FLASH PROGRAMMER -// ============================================================ - -// Simple protocol for uploading audio over serial: -// 'I' → respond with flash JEDEC ID -// 'E' → erase entire flash chip -// 'W' addr(3 bytes) len(2 bytes) data... → write page -// 'R' addr(3 bytes) len(2 bytes) → read bytes back -// 'T' → read track table - -void handleSerial() { - if (!Serial.available()) return; - - uint8_t cmd = Serial.read(); - - switch (cmd) { - case 'I': { - uint32_t id = flashReadJEDEC(); - Serial.print("JEDEC: 0x"); - Serial.println(id, HEX); - break; - } - case 'E': { - Serial.println("Erasing flash..."); - flashWriteEnable(); - flashSelect(); - SPI.transfer(FLASH_CMD_CHIP_ERASE); - flashDeselect(); - flashWaitBusy(); // takes ~40 seconds for 16MB - Serial.println("Done"); - break; - } - case 'W': { - // Wait for address (3 bytes) and length (2 bytes) - while (Serial.available() < 5) {} - uint32_t addr = (uint32_t)Serial.read() << 16; - addr |= (uint32_t)Serial.read() << 8; - addr |= Serial.read(); - uint16_t len = (uint16_t)Serial.read() << 8; - len |= Serial.read(); - if (len > 256) len = 256; - - uint8_t buf[256]; - uint16_t received = 0; - while (received < len) { - if (Serial.available()) { - buf[received++] = Serial.read(); - } - } - flashPageProgram(addr, buf, len); - Serial.print("OK "); - Serial.println(addr, HEX); - break; - } - case 'R': { - while (Serial.available() < 5) {} - uint32_t addr = (uint32_t)Serial.read() << 16; - addr |= (uint32_t)Serial.read() << 8; - addr |= Serial.read(); - uint16_t len = (uint16_t)Serial.read() << 8; - len |= Serial.read(); - - uint8_t buf[256]; - while (len > 0) { - uint16_t chunk = (len > 256) ? 256 : len; - flashReadBytes(addr, buf, chunk); - Serial.write(buf, chunk); - addr += chunk; - len -= chunk; - } - break; - } - } -} - - -// ============================================================ -// MAIN -// ============================================================ - -void setup() { - // Disable unused peripherals for power saving - power_adc_disable(); // we don't use ADC - power_twi_disable(); // we don't use I2C - - // Pin setup - pinMode(PIN_FLASH_CS, OUTPUT); - pinMode(PIN_AMP_SD, OUTPUT); - pinMode(PIN_LED, OUTPUT); - - digitalWrite(PIN_FLASH_CS, HIGH); // deselect flash - digitalWrite(PIN_AMP_SD, LOW); // amp off - digitalWrite(PIN_LED, LOW); - - // Init peripherals - Serial.begin(9600); - SPI.begin(); - SPI.setClockDivider(SPI_CLOCK_DIV2); // 4MHz SPI (8MHz/2) - - buttonsInit(); - motorInit(); - audioInit(); - - // Init flash - flashWake(); - delay(1); - - uint32_t jedec = flashReadJEDEC(); - if (jedec == 0xEF4018) { - // W25Q128 detected - digitalWrite(PIN_LED, HIGH); - delay(200); - digitalWrite(PIN_LED, LOW); - } - - // Load track table - loadTrackTable(); - - g_lastActivity = millis(); - - Serial.print("Baby Mobile v1.0 — "); - Serial.print(g_numTracks); - Serial.println(" tracks loaded"); -} - -void loop() { - // ---- Handle serial commands (for programming) ---- - handleSerial(); - - // ---- Refill audio buffer in main loop ---- - if (g_playing) { - for (uint8_t b = 0; b < 2; b++) { - if (!g_bufReady[b] && g_nextReadAddr < g_playEnd) { - uint32_t remaining = g_playEnd - g_nextReadAddr; - uint16_t toRead = (remaining > AUDIO_BUF_SIZE) ? AUDIO_BUF_SIZE : remaining; - - flashReadBytes(g_nextReadAddr, g_audioBuf[b], toRead); - // Zero-pad if short - for (uint16_t i = toRead; i < AUDIO_BUF_SIZE; i++) { - g_audioBuf[b][i] = 128; // silence - } - g_nextReadAddr += toRead; - g_bufReady[b] = true; - } - } - - // Check if playback finished - if (!g_bufReady[0] && !g_bufReady[1]) { - audioStop(); - // Auto-advance to next track or loop - g_currentTrack = (g_currentTrack + 1) % g_numTracks; - audioStart(g_currentTrack); - } - } - - // ---- Read buttons ---- - uint8_t btn = buttonRead(); - if (btn > 0) { - g_lastActivity = millis(); - - switch (btn) { - case 1: // Play / Pause - if (g_playing) { - audioStop(); - } else { - audioStart(g_currentTrack); - } - break; - - case 2: // Next track - if (g_numTracks > 0) { - g_currentTrack = (g_currentTrack + 1) % g_numTracks; - if (g_playing) { - audioStop(); - audioStart(g_currentTrack); - } - } - break; - - case 3: // Previous track - if (g_numTracks > 0) { - g_currentTrack = (g_currentTrack == 0) ? g_numTracks - 1 : g_currentTrack - 1; - if (g_playing) { - audioStop(); - audioStart(g_currentTrack); - } - } - break; - - case 4: // Motor toggle - if (g_motorOn) { - motorStop(); - } else { - motorStart(g_motorSpeed); - } - break; - - case 5: // Motor speed up - if (g_motorSpeed < 235) g_motorSpeed += 20; - if (g_motorOn) analogWrite(PIN_MOTOR_PWM, g_motorSpeed); - break; - - case 6: // Motor speed down - if (g_motorSpeed > 80) g_motorSpeed -= 20; - if (g_motorOn) analogWrite(PIN_MOTOR_PWM, g_motorSpeed); - break; - - case 7: // Play all (music + motor) - motorStart(g_motorSpeed); - if (!g_playing) audioStart(0); - break; - - case 8: // Stop all - audioStop(); - motorStop(); - break; - } - - // Wait for button release - while (buttonRead() == btn) { delay(10); } - } - - // ---- Auto shutoff ---- - if (millis() - g_lastActivity > AUTO_OFF_MS) { - enterSleep(); - } - - // ---- Sleep if idle (no audio, no motor) ---- - if (!g_playing && !g_motorOn && (millis() - g_lastActivity > 60000)) { - enterSleep(); - } -} diff --git a/baby_mobile_v2.ino b/baby_mobile_v2.ino new file mode 100644 index 0000000..d990493 --- /dev/null +++ b/baby_mobile_v2.ino @@ -0,0 +1,945 @@ +/* + * Baby Mobile Audio Board v2 — nRF52840 Firmware + * + * Platform: Seeed XIAO nRF52840 (or MDBT50Q module) + * Framework: Adafruit nRF52 Arduino Core + * + * Features: + * - USB Mass Storage: drag-and-drop .raw audio files + * - BLE: wireless audio upload from phone/Web Bluetooth + * - 8-bit 8kHz PWM audio playback from IS25LP128F SPI flash + * - DC motor PWM speed control + * - 8 button inputs with debounce + * - Deep sleep with button wake (~10µA) + * - Auto-shutoff timer + * + * Audio format: unsigned 8-bit PCM, 8000 Hz, mono + * Convert: ffmpeg -i song.mp3 -ar 8000 -ac 1 -f u8 -acodec pcm_u8 song.raw + * + * Board setup in Arduino IDE: + * Board: "Seeed XIAO nRF52840" (or "Adafruit Feather nRF52840") + * Install: Seeed nRF52 Boards via Board Manager + * + * Wiring (XIAO pin names): + * D0 (P0.02) - Button 1 + * D1 (P0.03) - Button 2 + * D2 (P0.28) - Button 3 + * D3 (P0.29) - Button 4 + * D4 (P0.04) - Button 5 + * D5 (P0.05) - Button 6 + * D6 (P1.11) - Button 7 + * D7 (P1.12) - Button 8 + * D8 (P0.07) - SPI SCK → Flash pin 6 + * D9 (P0.06) - SPI MISO → Flash pin 2 + * D10 (P0.05) - SPI MOSI → Flash pin 5 + * A0 (P0.02) - Audio PWM output → R+C LPF → PAM8302A + * A1 (P0.03) - Amp ~SD (HIGH=on) + * A2 (P0.28) - Motor PWM → MOSFET gate + * A3 (P0.29) - LED output + * A4 (P0.04) - Flash ~CS + * A5 (P0.05) - (spare) + * + * NOTE: Pin assignments above are illustrative. Adjust to your actual + * XIAO pinout and PCB routing. The XIAO has 11 usable GPIOs on the + * edge pins plus additional pads on the bottom. + */ + +#include +#include +#include + +// ============================================================ +// PIN DEFINITIONS — adjust for your PCB +// ============================================================ + +// Using raw nRF52840 GPIO numbers for flexibility. +// Map these to your actual PCB connections. + +// Audio +#define PIN_AUDIO_PWM 13 // Any PWM-capable pin +#define PIN_AMP_SD 14 // PAM8302A shutdown (HIGH=enabled) + +// Motor +#define PIN_MOTOR_PWM 15 // PWM to MOSFET gate + +// SPI Flash +#define PIN_FLASH_CS 5 // Flash chip select +// SPI MOSI/MISO/SCK use default SPI pins + +// Buttons (directly to GPIO, active LOW with internal pull-up) +#define PIN_BTN1 2 +#define PIN_BTN2 3 +#define PIN_BTN3 4 +#define PIN_BTN4 28 +#define PIN_BTN5 29 +#define PIN_BTN6 30 +#define PIN_BTN7 31 +#define PIN_BTN8 12 + +// LED +#define PIN_LED 16 + +const uint8_t BTN_PINS[] = { + PIN_BTN1, PIN_BTN2, PIN_BTN3, PIN_BTN4, + PIN_BTN5, PIN_BTN6, PIN_BTN7, PIN_BTN8 +}; +#define NUM_BUTTONS 8 + +// ============================================================ +// FLASH CONSTANTS +// ============================================================ + +#define FLASH_SIZE (16UL * 1024UL * 1024UL) // 16MB +#define FLASH_SECTOR 4096 +#define FLASH_PAGE 256 +#define FLASH_BLOCK_64K (64UL * 1024UL) + +// IS25LP128F / W25Q128 compatible commands +#define CMD_READ 0x03 +#define CMD_FAST_READ 0x0B +#define CMD_WRITE_EN 0x06 +#define CMD_PAGE_PROG 0x02 +#define CMD_SECT_ERASE 0x20 +#define CMD_BLOCK_ERASE 0xD8 +#define CMD_CHIP_ERASE 0xC7 +#define CMD_READ_SR1 0x05 +#define CMD_JEDEC_ID 0x9F +#define CMD_POWER_DOWN 0xB9 +#define CMD_WAKE 0xAB + +// ============================================================ +// TRACK TABLE FORMAT +// ============================================================ +// Sector 0 (first 4KB) holds the track index: +// [0] uint8_t magic = 0xBB (indicates valid table) +// [1] uint8_t num_tracks +// [2..3] reserved +// [4..] Track entries, 12 bytes each: +// uint32_t start_addr (big-endian) +// uint32_t byte_length (big-endian) +// uint8_t sample_rate_khz (8 = 8kHz) +// uint8_t bits (8 = 8-bit unsigned) +// uint16_t reserved +// Audio data starts at AUDIO_START (sector 1 = 0x1000) + +#define TRACK_TABLE_ADDR 0x000000 +#define AUDIO_START_ADDR 0x001000 +#define TABLE_MAGIC 0xBB +#define MAX_TRACKS 32 +#define TRACK_ENTRY_SIZE 12 + +// ============================================================ +// AUDIO CONFIG +// ============================================================ + +#define SAMPLE_RATE 8000 +#define AUDIO_BUF_SIZE 512 // larger buffer = fewer SPI transactions +#define SILENCE 128 // 0x80 = center for unsigned 8-bit + +// ============================================================ +// USB MASS STORAGE +// ============================================================ + +Adafruit_USBD_MSC usb_msc; + +// Simple FAT12 filesystem on the SPI flash +// We present the entire 16MB flash as a USB drive. +// The host can write raw files; firmware scans for audio on boot. + +// MSC callbacks +int32_t msc_read_cb(uint32_t lba, void* buffer, uint32_t bufsize); +int32_t msc_write_cb(uint32_t lba, uint8_t* buffer, uint32_t bufsize); +void msc_flush_cb(void); +bool msc_start_stop_cb(uint8_t power_condition, bool start, bool load_eject); + +#define MSC_BLOCK_SIZE 512 +#define MSC_BLOCK_COUNT (FLASH_SIZE / MSC_BLOCK_SIZE) + +// ============================================================ +// BLE SERVICE +// ============================================================ + +BLEService audioSvc = BLEService("12340001-0000-1000-8000-00805f9b34fb"); +BLECharacteristic audioCmd = BLECharacteristic("12340002-0000-1000-8000-00805f9b34fb"); +BLECharacteristic audioData = BLECharacteristic("12340003-0000-1000-8000-00805f9b34fb"); +BLECharacteristic audioStat = BLECharacteristic("12340004-0000-1000-8000-00805f9b34fb"); + +// BLE upload state +volatile bool g_bleUploading = false; +volatile uint32_t g_bleWriteAddr = 0; +volatile uint32_t g_bleWriteLen = 0; + +// ============================================================ +// GLOBAL STATE +// ============================================================ + +volatile bool g_playing = false; +volatile bool g_motorOn = false; +uint8_t g_motorSpeed = 160; + +uint8_t g_numTracks = 0; +uint32_t g_trackStart[MAX_TRACKS]; +uint32_t g_trackLen[MAX_TRACKS]; +uint8_t g_currentTrack = 0; + +// Audio double-buffer +uint8_t g_audioBuf[2][AUDIO_BUF_SIZE]; +volatile uint8_t g_activeBuf = 0; +volatile uint16_t g_bufPos = 0; +volatile bool g_bufReady[2] = {false, false}; +uint32_t g_nextReadAddr = 0; +uint32_t g_playEnd = 0; + +// Timers +unsigned long g_lastActivity = 0; +#define AUTO_OFF_MS (30UL * 60UL * 1000UL) // 30 min auto-shutoff +#define IDLE_SLEEP_MS (60UL * 1000UL) // 1 min idle → sleep + +// USB connected flag +volatile bool g_usbConnected = false; + + +// ============================================================ +// SPI FLASH DRIVER +// ============================================================ + +SPISettings flashSPI(8000000, MSBFIRST, SPI_MODE0); // 8MHz + +void flashSelect() { digitalWrite(PIN_FLASH_CS, LOW); } +void flashDeselect() { digitalWrite(PIN_FLASH_CS, HIGH); } + +void flashWake() { + flashSelect(); + SPI.transfer(CMD_WAKE); + flashDeselect(); + delayMicroseconds(5); +} + +void flashSleep() { + flashSelect(); + SPI.transfer(CMD_POWER_DOWN); + flashDeselect(); +} + +uint32_t flashReadJEDEC() { + SPI.beginTransaction(flashSPI); + flashSelect(); + SPI.transfer(CMD_JEDEC_ID); + uint32_t id = (uint32_t)SPI.transfer(0) << 16; + id |= (uint32_t)SPI.transfer(0) << 8; + id |= SPI.transfer(0); + flashDeselect(); + SPI.endTransaction(); + return id; +} + +void flashReadBytes(uint32_t addr, uint8_t *buf, uint32_t len) { + SPI.beginTransaction(flashSPI); + flashSelect(); + SPI.transfer(CMD_READ); + SPI.transfer((addr >> 16) & 0xFF); + SPI.transfer((addr >> 8) & 0xFF); + SPI.transfer(addr & 0xFF); + for (uint32_t i = 0; i < len; i++) { + buf[i] = SPI.transfer(0); + } + flashDeselect(); + SPI.endTransaction(); +} + +void flashWaitBusy() { + SPI.beginTransaction(flashSPI); + flashSelect(); + SPI.transfer(CMD_READ_SR1); + while (SPI.transfer(0) & 0x01) { /* spin */ } + flashDeselect(); + SPI.endTransaction(); +} + +void flashWriteEnable() { + SPI.beginTransaction(flashSPI); + flashSelect(); + SPI.transfer(CMD_WRITE_EN); + flashDeselect(); + SPI.endTransaction(); +} + +void flashEraseSector(uint32_t addr) { + flashWriteEnable(); + SPI.beginTransaction(flashSPI); + flashSelect(); + SPI.transfer(CMD_SECT_ERASE); + SPI.transfer((addr >> 16) & 0xFF); + SPI.transfer((addr >> 8) & 0xFF); + SPI.transfer(addr & 0xFF); + flashDeselect(); + SPI.endTransaction(); + flashWaitBusy(); +} + +void flashEraseBlock64K(uint32_t addr) { + flashWriteEnable(); + SPI.beginTransaction(flashSPI); + flashSelect(); + SPI.transfer(CMD_BLOCK_ERASE); + SPI.transfer((addr >> 16) & 0xFF); + SPI.transfer((addr >> 8) & 0xFF); + SPI.transfer(addr & 0xFF); + flashDeselect(); + SPI.endTransaction(); + flashWaitBusy(); +} + +void flashPageProgram(uint32_t addr, const uint8_t *data, uint16_t len) { + flashWriteEnable(); + SPI.beginTransaction(flashSPI); + flashSelect(); + SPI.transfer(CMD_PAGE_PROG); + SPI.transfer((addr >> 16) & 0xFF); + SPI.transfer((addr >> 8) & 0xFF); + SPI.transfer(addr & 0xFF); + for (uint16_t i = 0; i < len; i++) { + SPI.transfer(data[i]); + } + flashDeselect(); + SPI.endTransaction(); + flashWaitBusy(); +} + + +// ============================================================ +// TRACK TABLE +// ============================================================ + +void loadTrackTable() { + uint8_t header[4]; + flashReadBytes(TRACK_TABLE_ADDR, header, 4); + + if (header[0] != TABLE_MAGIC) { + g_numTracks = 0; + Serial.println("No track table found (flash may be empty)"); + return; + } + + g_numTracks = header[1]; + if (g_numTracks > MAX_TRACKS) g_numTracks = MAX_TRACKS; + + uint8_t entry[TRACK_ENTRY_SIZE]; + for (uint8_t i = 0; i < g_numTracks; i++) { + flashReadBytes(TRACK_TABLE_ADDR + 4 + i * TRACK_ENTRY_SIZE, entry, TRACK_ENTRY_SIZE); + g_trackStart[i] = ((uint32_t)entry[0] << 24) | ((uint32_t)entry[1] << 16) | + ((uint32_t)entry[2] << 8) | entry[3]; + g_trackLen[i] = ((uint32_t)entry[4] << 24) | ((uint32_t)entry[5] << 16) | + ((uint32_t)entry[6] << 8) | entry[7]; + } + + Serial.print("Loaded "); + Serial.print(g_numTracks); + Serial.println(" tracks from flash"); + for (uint8_t i = 0; i < g_numTracks; i++) { + Serial.print(" Track "); + Serial.print(i + 1); + Serial.print(": addr=0x"); + Serial.print(g_trackStart[i], HEX); + Serial.print(", "); + Serial.print(g_trackLen[i] / SAMPLE_RATE); + Serial.println("s"); + } +} + +void writeTrackTable() { + // Erase sector 0 + flashEraseSector(0); + + // Build table in RAM + uint8_t table[4 + MAX_TRACKS * TRACK_ENTRY_SIZE]; + memset(table, 0xFF, sizeof(table)); + table[0] = TABLE_MAGIC; + table[1] = g_numTracks; + table[2] = 0; + table[3] = 0; + + for (uint8_t i = 0; i < g_numTracks; i++) { + uint8_t *e = &table[4 + i * TRACK_ENTRY_SIZE]; + e[0] = (g_trackStart[i] >> 24) & 0xFF; + e[1] = (g_trackStart[i] >> 16) & 0xFF; + e[2] = (g_trackStart[i] >> 8) & 0xFF; + e[3] = g_trackStart[i] & 0xFF; + e[4] = (g_trackLen[i] >> 24) & 0xFF; + e[5] = (g_trackLen[i] >> 16) & 0xFF; + e[6] = (g_trackLen[i] >> 8) & 0xFF; + e[7] = g_trackLen[i] & 0xFF; + e[8] = 8; // sample rate kHz + e[9] = 8; // bits + e[10] = 0; + e[11] = 0; + } + + // Write in pages + uint16_t total = 4 + g_numTracks * TRACK_ENTRY_SIZE; + for (uint16_t offset = 0; offset < total; offset += FLASH_PAGE) { + uint16_t chunk = min((uint16_t)FLASH_PAGE, (uint16_t)(total - offset)); + flashPageProgram(offset, &table[offset], chunk); + } +} + + +// ============================================================ +// USB MASS STORAGE CALLBACKS +// ============================================================ + +int32_t msc_read_cb(uint32_t lba, void* buffer, uint32_t bufsize) { + uint32_t addr = lba * MSC_BLOCK_SIZE; + flashReadBytes(addr, (uint8_t*)buffer, bufsize); + return bufsize; +} + +int32_t msc_write_cb(uint32_t lba, uint8_t* buffer, uint32_t bufsize) { + uint32_t addr = lba * MSC_BLOCK_SIZE; + + // Erase sector if we're at a sector boundary + if ((addr % FLASH_SECTOR) == 0) { + flashEraseSector(addr); + } + + // Write in page-sized chunks + uint32_t written = 0; + while (written < bufsize) { + uint16_t pageOffset = (addr + written) % FLASH_PAGE; + uint16_t chunk = min((uint16_t)(FLASH_PAGE - pageOffset), (uint16_t)(bufsize - written)); + flashPageProgram(addr + written, buffer + written, chunk); + written += chunk; + } + + return bufsize; +} + +void msc_flush_cb(void) { + // After USB write completes, reload the track table + // (host may have written a new FAT filesystem) + // We scan for audio data on eject instead +} + +bool msc_start_stop_cb(uint8_t power_condition, bool start, bool load_eject) { + if (!start && load_eject) { + // Host ejected the drive — rescan for tracks + Serial.println("USB ejected, rescanning tracks..."); + loadTrackTable(); + } + return true; +} + + +// ============================================================ +// BLE SETUP +// ============================================================ + +void ble_connect_cb(uint16_t conn_handle) { + Serial.println("BLE connected"); + g_lastActivity = millis(); +} + +void ble_disconnect_cb(uint16_t conn_handle, uint8_t reason) { + Serial.println("BLE disconnected"); + g_bleUploading = false; +} + +// BLE command characteristic: receives commands +// CMD 0x01 [num_tracks] [track_entries...] = write track table +// CMD 0x02 [addr_3bytes] = start writing audio at address +// CMD 0x03 = finish upload, reload tracks +// CMD 0x04 [track_num] = play track +// CMD 0x05 = stop playback +void audioCmd_write_cb(uint16_t conn_handle, BLECharacteristic* chr, + uint8_t* data, uint16_t len) { + if (len < 1) return; + g_lastActivity = millis(); + + switch (data[0]) { + case 0x01: // Write track table + if (len >= 2) { + g_numTracks = data[1]; + if (g_numTracks > MAX_TRACKS) g_numTracks = MAX_TRACKS; + // Parse track entries from data[2..] + for (uint8_t i = 0; i < g_numTracks && (2 + i * 8 + 7) < len; i++) { + uint8_t *e = &data[2 + i * 8]; + g_trackStart[i] = ((uint32_t)e[0] << 24) | ((uint32_t)e[1] << 16) | + ((uint32_t)e[2] << 8) | e[3]; + g_trackLen[i] = ((uint32_t)e[4] << 24) | ((uint32_t)e[5] << 16) | + ((uint32_t)e[6] << 8) | e[7]; + } + writeTrackTable(); + Serial.println("BLE: Track table updated"); + } + break; + + case 0x02: // Start audio write + if (len >= 4) { + g_bleWriteAddr = ((uint32_t)data[1] << 16) | ((uint32_t)data[2] << 8) | data[3]; + g_bleUploading = true; + // Erase 64K block at target + flashEraseBlock64K(g_bleWriteAddr & ~(FLASH_BLOCK_64K - 1)); + Serial.print("BLE: Start write at 0x"); + Serial.println(g_bleWriteAddr, HEX); + } + break; + + case 0x03: // Finish upload + g_bleUploading = false; + loadTrackTable(); + Serial.println("BLE: Upload complete"); + break; + + case 0x04: // Play track + if (len >= 2 && data[1] < g_numTracks) { + audioStart(data[1]); + } + break; + + case 0x05: // Stop + audioStop(); + motorStop(); + break; + } +} + +// BLE data characteristic: receives raw audio bytes for upload +void audioData_write_cb(uint16_t conn_handle, BLECharacteristic* chr, + uint8_t* data, uint16_t len) { + if (!g_bleUploading) return; + g_lastActivity = millis(); + + // Erase new sectors as we cross boundaries + uint32_t endAddr = g_bleWriteAddr + len; + uint32_t currentSector = g_bleWriteAddr / FLASH_SECTOR; + uint32_t endSector = (endAddr - 1) / FLASH_SECTOR; + for (uint32_t s = currentSector + 1; s <= endSector; s++) { + flashEraseSector(s * FLASH_SECTOR); + } + + // Write data page by page + uint16_t written = 0; + while (written < len) { + uint16_t pageOff = (g_bleWriteAddr + written) % FLASH_PAGE; + uint16_t chunk = min((uint16_t)(FLASH_PAGE - pageOff), (uint16_t)(len - written)); + flashPageProgram(g_bleWriteAddr + written, data + written, chunk); + written += chunk; + } + + g_bleWriteAddr += len; + g_bleWriteLen += len; + + // Update status characteristic with bytes written + uint8_t stat[4]; + stat[0] = (g_bleWriteLen >> 24) & 0xFF; + stat[1] = (g_bleWriteLen >> 16) & 0xFF; + stat[2] = (g_bleWriteLen >> 8) & 0xFF; + stat[3] = g_bleWriteLen & 0xFF; + audioStat.write(stat, 4); + audioStat.notify(stat, 4); +} + +void setupBLE() { + Bluefruit.begin(); + Bluefruit.setName("BabyMobile"); + Bluefruit.setTxPower(0); // 0 dBm — save power, short range is fine + Bluefruit.Periph.setConnectCallback(ble_connect_cb); + Bluefruit.Periph.setDisconnectCallback(ble_disconnect_cb); + + // Audio service + audioSvc.begin(); + + // Command characteristic (write) + audioCmd.setProperties(CHR_PROPS_WRITE); + audioCmd.setPermission(SECMODE_OPEN, SECMODE_OPEN); + audioCmd.setMaxLen(240); + audioCmd.setWriteCallback(audioCmd_write_cb); + audioCmd.begin(); + + // Data characteristic (write without response for speed) + audioData.setProperties(CHR_PROPS_WRITE_WO_RESP); + audioData.setPermission(SECMODE_OPEN, SECMODE_OPEN); + audioData.setMaxLen(240); + audioData.setWriteCallback(audioData_write_cb); + audioData.begin(); + + // Status characteristic (read + notify) + audioStat.setProperties(CHR_PROPS_READ | CHR_PROPS_NOTIFY); + audioStat.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS); + audioStat.setMaxLen(4); + audioStat.begin(); + + // Start advertising + Bluefruit.Advertising.addFlags(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE); + Bluefruit.Advertising.addTxPower(); + Bluefruit.Advertising.addService(audioSvc); + Bluefruit.Advertising.addName(); + Bluefruit.Advertising.restartOnDisconnect(true); + Bluefruit.Advertising.setInterval(160, 320); // 100-200ms + Bluefruit.Advertising.start(0); // advertise forever + + Serial.println("BLE advertising as 'BabyMobile'"); +} + + +// ============================================================ +// AUDIO PLAYBACK +// ============================================================ + +// nRF52840 has hardware PWM (up to 4 instances, 16MHz base clock) +// We use the nrf_pwm peripheral directly for audio output +// and a TIMER for the sample rate interrupt. + +// For Arduino compatibility, we use analogWrite for the PWM +// and a software timer for sample feeding. + +// Timer callback for audio sample rate +volatile bool g_timerFired = false; + +void timerCallback(void) { + if (!g_playing) return; + + // Output sample + analogWrite(PIN_AUDIO_PWM, g_audioBuf[g_activeBuf][g_bufPos]); + g_bufPos++; + + if (g_bufPos >= AUDIO_BUF_SIZE) { + g_bufReady[g_activeBuf] = false; + g_activeBuf ^= 1; + g_bufPos = 0; + + if (!g_bufReady[g_activeBuf]) { + // Buffer underrun + g_playing = false; + analogWrite(PIN_AUDIO_PWM, SILENCE); + } + } +} + +// Use nRF52 SoftwareTimer (built into Adafruit BSP) +SoftwareTimer audioTimer; + +void audioTimerHandler(TimerHandle_t xTimer) { + timerCallback(); +} + +void audioInit() { + pinMode(PIN_AUDIO_PWM, OUTPUT); + analogWrite(PIN_AUDIO_PWM, SILENCE); + analogWriteResolution(8); // 8-bit PWM + + // Create a FreeRTOS software timer at 8kHz + // Note: For better timing, use a hardware TIMER peripheral + // This works well enough for 8kHz audio + audioTimer.begin(1000 / 8, audioTimerHandler, true); // ~8kHz + // Better approach: use nrf_drv_timer for precise 125µs intervals +} + +void audioStart(uint8_t trackNum) { + if (trackNum >= g_numTracks) return; + + g_currentTrack = trackNum; + uint32_t start = g_trackStart[trackNum]; + g_playEnd = start + g_trackLen[trackNum]; + g_nextReadAddr = start; + + // Pre-fill both buffers + uint32_t toRead = min((uint32_t)AUDIO_BUF_SIZE, g_playEnd - g_nextReadAddr); + flashReadBytes(g_nextReadAddr, g_audioBuf[0], toRead); + g_nextReadAddr += toRead; + g_bufReady[0] = true; + + if (g_nextReadAddr < g_playEnd) { + toRead = min((uint32_t)AUDIO_BUF_SIZE, g_playEnd - g_nextReadAddr); + flashReadBytes(g_nextReadAddr, g_audioBuf[1], toRead); + g_nextReadAddr += toRead; + g_bufReady[1] = true; + } else { + memset(g_audioBuf[1], SILENCE, AUDIO_BUF_SIZE); + g_bufReady[1] = true; + } + + g_activeBuf = 0; + g_bufPos = 0; + + // Enable amplifier + digitalWrite(PIN_AMP_SD, HIGH); + delay(10); + + g_playing = true; + audioTimer.start(); + + Serial.print("Playing track "); + Serial.println(trackNum + 1); +} + +void audioStop() { + audioTimer.stop(); + g_playing = false; + analogWrite(PIN_AUDIO_PWM, SILENCE); + + // Disable amp + digitalWrite(PIN_AMP_SD, LOW); + + Serial.println("Playback stopped"); +} + + +// ============================================================ +// MOTOR +// ============================================================ + +void motorInit() { + pinMode(PIN_MOTOR_PWM, OUTPUT); + analogWrite(PIN_MOTOR_PWM, 0); +} + +void motorStart(uint8_t speed) { + g_motorSpeed = speed; + g_motorOn = true; + analogWrite(PIN_MOTOR_PWM, speed); +} + +void motorStop() { + g_motorOn = false; + analogWrite(PIN_MOTOR_PWM, 0); +} + + +// ============================================================ +// BUTTONS +// ============================================================ + +void buttonsInit() { + for (uint8_t i = 0; i < NUM_BUTTONS; i++) { + pinMode(BTN_PINS[i], INPUT_PULLUP); + } +} + +// Returns 1-8, or 0 if none pressed +uint8_t buttonRead() { + for (uint8_t i = 0; i < NUM_BUTTONS; i++) { + if (digitalRead(BTN_PINS[i]) == LOW) { + delay(20); // debounce + if (digitalRead(BTN_PINS[i]) == LOW) { + return i + 1; + } + } + } + return 0; +} + +void waitButtonRelease(uint8_t btn) { + while (buttonRead() == btn) { + delay(10); + } +} + + +// ============================================================ +// SLEEP / WAKE +// ============================================================ + +void enterDeepSleep() { + Serial.println("Entering deep sleep..."); + audioStop(); + motorStop(); + flashSleep(); + digitalWrite(PIN_LED, LOW); + + // Stop BLE advertising to save power + Bluefruit.Advertising.stop(); + + // Configure buttons as wake sources + // On nRF52840, any GPIO can wake from System OFF + // We use System ON sleep (RTOS idle) for quick wake + // For deepest sleep, use sd_power_system_off() + + // Use pin sense for wake + for (uint8_t i = 0; i < NUM_BUTTONS; i++) { + nrf_gpio_cfg_sense_input(BTN_PINS[i], + NRF_GPIO_PIN_PULLUP, + NRF_GPIO_PIN_SENSE_LOW); + } + + // System OFF — lowest power, wakes via GPIO sense or reset + sd_power_system_off(); + + // Execution stops here. Device resets on wake. + // (This line is never reached) +} + + +// ============================================================ +// SETUP +// ============================================================ + +void setup() { + // LED early — visual feedback + pinMode(PIN_LED, OUTPUT); + digitalWrite(PIN_LED, HIGH); + + Serial.begin(115200); + // Don't block on serial — may not be connected + delay(500); + + Serial.println("=== Baby Mobile v2 ==="); + Serial.println("nRF52840 + IS25LP128F + PAM8302A"); + + // Pin setup + pinMode(PIN_FLASH_CS, OUTPUT); + pinMode(PIN_AMP_SD, OUTPUT); + digitalWrite(PIN_FLASH_CS, HIGH); + digitalWrite(PIN_AMP_SD, LOW); + + // SPI + SPI.begin(); + + // Flash + flashWake(); + delay(1); + uint32_t jedec = flashReadJEDEC(); + Serial.print("Flash JEDEC: 0x"); + Serial.println(jedec, HEX); + + if (jedec == 0x9D6018 || jedec == 0x9D6017 || // IS25LP128F / IS25LP064 + jedec == 0xEF4018 || jedec == 0xEF4017) { // W25Q128 / W25Q064 + Serial.println("Flash detected OK"); + } else if (jedec == 0x000000 || jedec == 0xFFFFFF) { + Serial.println("WARNING: No flash detected! Check SPI wiring."); + } + + // Load tracks + loadTrackTable(); + + // Buttons + buttonsInit(); + + // Motor + motorInit(); + + // Audio + audioInit(); + + // USB Mass Storage + usb_msc.setID("BabyMobile", "Audio Drive", "2.0"); + usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb); + usb_msc.setStartStopCallback(msc_start_stop_cb); + usb_msc.setCapacity(MSC_BLOCK_COUNT, MSC_BLOCK_SIZE); + usb_msc.setReadOnly(false); + usb_msc.setUnitReady(true); + usb_msc.begin(); + + // BLE + setupBLE(); + + g_lastActivity = millis(); + + digitalWrite(PIN_LED, LOW); + Serial.println("Ready! Plug in USB to upload audio, or press a button."); +} + + +// ============================================================ +// MAIN LOOP +// ============================================================ + +void loop() { + // ---- Refill audio buffers ---- + if (g_playing) { + for (uint8_t b = 0; b < 2; b++) { + if (!g_bufReady[b] && g_nextReadAddr < g_playEnd) { + uint32_t remaining = g_playEnd - g_nextReadAddr; + uint32_t toRead = min((uint32_t)AUDIO_BUF_SIZE, remaining); + + flashReadBytes(g_nextReadAddr, g_audioBuf[b], toRead); + // Pad with silence + for (uint32_t i = toRead; i < AUDIO_BUF_SIZE; i++) { + g_audioBuf[b][i] = SILENCE; + } + g_nextReadAddr += toRead; + g_bufReady[b] = true; + } + } + + // Track finished? Auto-advance and loop + if (!g_bufReady[0] && !g_bufReady[1] && g_nextReadAddr >= g_playEnd) { + audioStop(); + if (g_numTracks > 0) { + g_currentTrack = (g_currentTrack + 1) % g_numTracks; + audioStart(g_currentTrack); + } + } + } + + // ---- Handle buttons ---- + uint8_t btn = buttonRead(); + if (btn > 0) { + g_lastActivity = millis(); + + switch (btn) { + case 1: // Play / Pause + if (g_playing) { + audioStop(); + } else if (g_numTracks > 0) { + audioStart(g_currentTrack); + } + break; + + case 2: // Next track + if (g_numTracks > 0) { + g_currentTrack = (g_currentTrack + 1) % g_numTracks; + if (g_playing) { audioStop(); audioStart(g_currentTrack); } + } + break; + + case 3: // Previous track + if (g_numTracks > 0) { + g_currentTrack = (g_currentTrack == 0) ? g_numTracks - 1 : g_currentTrack - 1; + if (g_playing) { audioStop(); audioStart(g_currentTrack); } + } + break; + + case 4: // Motor toggle + if (g_motorOn) motorStop(); else motorStart(g_motorSpeed); + break; + + case 5: // Motor faster + if (g_motorSpeed < 240) g_motorSpeed += 20; + if (g_motorOn) analogWrite(PIN_MOTOR_PWM, g_motorSpeed); + break; + + case 6: // Motor slower + if (g_motorSpeed > 60) g_motorSpeed -= 20; + if (g_motorOn) analogWrite(PIN_MOTOR_PWM, g_motorSpeed); + break; + + case 7: // Play all (music + motor) + motorStart(g_motorSpeed); + if (!g_playing && g_numTracks > 0) audioStart(0); + break; + + case 8: // Stop all + audioStop(); + motorStop(); + break; + } + + waitButtonRelease(btn); + } + + // ---- Auto shutoff ---- + if (millis() - g_lastActivity > AUTO_OFF_MS) { + enterDeepSleep(); + } + + // ---- Idle sleep (if nothing happening, no USB) ---- + if (!g_playing && !g_motorOn && !g_usbConnected && !g_bleUploading) { + if (millis() - g_lastActivity > IDLE_SLEEP_MS) { + enterDeepSleep(); + } + } + + // Small delay to prevent tight-looping + delay(1); +} diff --git a/flash_upload.py b/flash_upload.py index 1c670a1..2aa2723 100644 --- a/flash_upload.py +++ b/flash_upload.py @@ -1,16 +1,20 @@ #!/usr/bin/env python3 """ -flash_upload.py — Upload audio files to the Baby Mobile's W25Q128 flash. +flash_upload.py — Upload audio to Baby Mobile v2 via serial. + +This is a fallback for uploading audio if USB mass storage isn't working. +Normally you'd just drag files onto the USB drive. Usage: - python3 flash_upload.py /dev/ttyUSB0 song1.raw song2.raw song3.raw ... + python3 flash_upload.py /dev/ttyACM0 song1.mp3 song2.wav song3.raw -Audio files must be raw unsigned 8-bit PCM at 8000 Hz mono. -Convert with ffmpeg: - ffmpeg -i song.mp3 -ar 8000 -ac 1 -f u8 -acodec pcm_u8 song.raw +Audio files will be auto-converted to 8kHz/8-bit/unsigned PCM using ffmpeg. -The script writes a track table to sector 0, then audio data starting -at sector 1 (address 0x1000). +Track table format (v2): + [0] magic = 0xBB + [1] num_tracks + [2..3] reserved + [4..] 12-byte entries: start(4) + length(4) + rate_khz(1) + bits(1) + pad(2) """ import serial @@ -21,211 +25,172 @@ import os import subprocess import shutil -BAUD = 9600 +BAUD = 115200 PAGE_SIZE = 256 SECTOR_SIZE = 4096 AUDIO_START = 0x1000 MAX_TRACKS = 32 -FLASH_SIZE = 16 * 1024 * 1024 # 16MB +FLASH_SIZE = 16 * 1024 * 1024 +TABLE_MAGIC = 0xBB +ENTRY_SIZE = 12 def open_serial(port): ser = serial.Serial(port, BAUD, timeout=2) - time.sleep(2) # wait for Arduino reset - # Flush + time.sleep(2) ser.read(ser.in_waiting) return ser -def flash_identify(ser): - ser.write(b'I') - line = ser.readline().decode().strip() - print(f" {line}") - return line - - -def flash_erase(ser): - print(" Erasing entire flash (takes ~40 seconds)...") - ser.write(b'E') - line = ser.readline().decode().strip() - while "Done" not in line: - line = ser.readline().decode().strip() - if line: - print(f" {line}") - print(" Erase complete.") - - -def flash_write_page(ser, addr, data): - """Write up to 256 bytes to flash.""" - assert len(data) <= 256 - cmd = b'W' - cmd += struct.pack('>I', addr)[1:] # 3 bytes address - cmd += struct.pack('>H', len(data)) - ser.write(cmd) - ser.write(data) - resp = ser.readline().decode().strip() - return resp - - -def flash_write_data(ser, start_addr, data, label=""): - """Write arbitrary length data, page by page.""" - total = len(data) - written = 0 - addr = start_addr - - while written < total: - chunk = data[written:written + PAGE_SIZE] - # Pad last page - if len(chunk) < PAGE_SIZE: - chunk = chunk + b'\x80' * (PAGE_SIZE - len(chunk)) # 0x80 = silence - - flash_write_page(ser, addr, chunk) - written += PAGE_SIZE - addr += PAGE_SIZE - - pct = min(100, written * 100 // total) - print(f"\r Writing {label}: {pct}% ({written}/{total} bytes)", end="", flush=True) - - print() - return addr - - def convert_to_raw(input_path): - """Convert any audio file to 8kHz 8-bit unsigned PCM using ffmpeg.""" - raw_path = input_path + ".raw" - + """Convert any audio file to 8kHz 8-bit unsigned PCM.""" if input_path.endswith('.raw'): return input_path - + + raw_path = input_path + ".raw" if not shutil.which('ffmpeg'): - print(f"ERROR: ffmpeg not found. Please convert manually:") - print(f" ffmpeg -i {input_path} -ar 8000 -ac 1 -f u8 -acodec pcm_u8 {raw_path}") + print(f" ERROR: ffmpeg not found. Convert manually:") + print(f" ffmpeg -i {input_path} -ar 8000 -ac 1 -f u8 -acodec pcm_u8 {raw_path}") sys.exit(1) - - print(f" Converting {os.path.basename(input_path)} to 8kHz/8bit PCM...") - subprocess.run([ + + print(f" Converting {os.path.basename(input_path)}...") + result = subprocess.run([ 'ffmpeg', '-y', '-i', input_path, '-ar', '8000', '-ac', '1', '-f', 'u8', '-acodec', 'pcm_u8', raw_path ], capture_output=True) - + + if result.returncode != 0: + print(f" ERROR: ffmpeg failed: {result.stderr.decode()[-200:]}") + sys.exit(1) + return raw_path def build_track_table(tracks): - """Build the track index (stored in sector 0 of flash). - - Format: - byte 0: num_tracks (uint8) - bytes 1-3: padding - bytes 4+: track_start[MAX_TRACKS] as uint32 big-endian - then: track_length[MAX_TRACKS] as uint32 big-endian - """ - num = len(tracks) - table = struct.pack('B', num) + b'\x00' * 3 - - # Start addresses + """Build v2 track table.""" + table = bytearray() + table.append(TABLE_MAGIC) + table.append(len(tracks)) + table.extend(b'\x00\x00') # reserved + for start, length in tracks: - table += struct.pack('>I', start) - for _ in range(MAX_TRACKS - num): - table += struct.pack('>I', 0) - - # Lengths - for start, length in tracks: - table += struct.pack('>I', length) - for _ in range(MAX_TRACKS - num): - table += struct.pack('>I', 0) - - # Pad to sector size - table += b'\xFF' * (SECTOR_SIZE - len(table)) - return table + table.extend(struct.pack('>I', start)) + table.extend(struct.pack('>I', length)) + table.append(8) # sample rate kHz + table.append(8) # bits per sample + table.extend(b'\x00\x00') + + # Pad to page boundary + while len(table) % PAGE_SIZE != 0: + table.append(0xFF) + + return bytes(table) + + +def serial_cmd(ser, cmd): + """Send a single-char command and read response line.""" + ser.write(cmd.encode()) + return ser.readline().decode().strip() + + +def serial_write_page(ser, addr, data): + """Write up to 256 bytes via the serial 'W' command.""" + assert len(data) <= 256 + ser.write(b'W') + ser.write(struct.pack('>I', addr)[1:]) # 3-byte addr + ser.write(struct.pack('>H', len(data))) # 2-byte length + ser.write(data) + return ser.readline().decode().strip() + + +def serial_write_data(ser, start_addr, data, label=""): + """Write arbitrary-length data, page by page.""" + total = len(data) + written = 0 + addr = start_addr + + while written < total: + chunk = data[written:written + PAGE_SIZE] + if len(chunk) < PAGE_SIZE: + chunk = chunk + b'\x80' * (PAGE_SIZE - len(chunk)) + + serial_write_page(ser, addr, chunk) + written += PAGE_SIZE + addr += PAGE_SIZE + + pct = min(100, written * 100 // total) + print(f"\r Writing {label}: {pct}%", end="", flush=True) + + print() def main(): if len(sys.argv) < 3: - print("Usage: python3 flash_upload.py [audio_file ...]") - print() - print("Supported input formats: .raw (8kHz/8bit/unsigned), .mp3, .wav, .ogg, .flac") - print("Non-.raw files will be converted automatically using ffmpeg.") - print() - print("Example:") - print(" python3 flash_upload.py /dev/ttyUSB0 lullaby.mp3 twinkle.wav brahms.mp3") + print("Usage: python3 flash_upload.py [...]") + print(" Supported: .raw .mp3 .wav .ogg .flac .aac") sys.exit(1) - + port = sys.argv[1] audio_files = sys.argv[2:] - - if len(audio_files) > MAX_TRACKS: - print(f"ERROR: Maximum {MAX_TRACKS} tracks supported.") - sys.exit(1) - - # Convert files to raw PCM - print("=== Preparing audio files ===") + + # Convert + print("=== Preparing audio ===") raw_files = [] for f in audio_files: raw = convert_to_raw(f) size = os.path.getsize(raw) - duration = size / 8000 - print(f" {os.path.basename(f)}: {size} bytes ({duration:.1f} seconds)") + print(f" {os.path.basename(f)}: {size/1024:.0f} KB ({size/8000:.1f}s)") raw_files.append(raw) - - # Check total size - total_audio = sum(os.path.getsize(f) for f in raw_files) - available = FLASH_SIZE - AUDIO_START - if total_audio > available: - print(f"ERROR: Audio ({total_audio} bytes) exceeds flash capacity ({available} bytes)") - sys.exit(1) - - total_duration = total_audio / 8000 - print(f"\n Total: {total_audio} bytes ({total_duration:.1f} seconds / {total_duration/60:.1f} minutes)") - print(f" Flash usage: {(total_audio + AUDIO_START) * 100 // FLASH_SIZE}%") - + + total = sum(os.path.getsize(f) for f in raw_files) + print(f" Total: {total/1024:.0f} KB ({total/8000/60:.1f} min)") + # Connect print(f"\n=== Connecting to {port} ===") ser = open_serial(port) - flash_identify(ser) - + print(f" {serial_cmd(ser, 'I')}") + # Erase print("\n=== Erasing flash ===") - flash_erase(ser) - - # Write audio data and build track list + ser.write(b'E') + while True: + line = ser.readline().decode().strip() + if line: print(f" {line}") + if "Done" in line: break + + # Write tracks print("\n=== Writing audio ===") tracks = [] addr = AUDIO_START - - for i, raw_path in enumerate(raw_files): - with open(raw_path, 'rb') as f: + + for i, raw in enumerate(raw_files): + with open(raw, 'rb') as f: data = f.read() - - start = addr - length = len(data) - tracks.append((start, length)) - - name = os.path.basename(audio_files[i]) - addr = flash_write_data(ser, start, data, label=f"Track {i+1} ({name})") - - # Align to sector boundary for clean layout - if addr % SECTOR_SIZE != 0: + + tracks.append((addr, len(data))) + serial_write_data(ser, addr, data, label=f"Track {i+1}") + + addr += len(data) + # Align to sector + if addr % SECTOR_SIZE: addr = ((addr // SECTOR_SIZE) + 1) * SECTOR_SIZE - - # Write track table to sector 0 + + # Write track table print("\n=== Writing track table ===") table = build_track_table(tracks) - flash_write_data(ser, 0, table, label="Track table") - + serial_write_data(ser, 0, table, label="Track table") + # Summary - print("\n=== Upload complete! ===") - print(f" {len(tracks)} tracks written") - for i, (start, length) in enumerate(tracks): - print(f" Track {i+1}: addr=0x{start:06X}, {length} bytes ({length/8000:.1f}s)") - print(f"\n Reset the board to start playback.") - - # Cleanup temp files + print(f"\n=== Done! {len(tracks)} tracks uploaded ===") + for i, (s, l) in enumerate(tracks): + print(f" Track {i+1}: 0x{s:06X}, {l/8000:.1f}s") + + # Cleanup for raw, orig in zip(raw_files, audio_files): if raw != orig and os.path.exists(raw): os.remove(raw) - + ser.close() diff --git a/generate_kicad.py b/generate_kicad.py index 26b5d59..bcdc838 100644 --- a/generate_kicad.py +++ b/generate_kicad.py @@ -1,314 +1,123 @@ #!/usr/bin/env python3 """ -Generate KiCad 7 schematic and project files for Baby Mobile Audio Board. +Generate KiCad 7 schematic for Baby Mobile Audio Board v2. -Design: ATmega328P + W25Q128 SPI Flash + PAM8302A Class-D Amp + MOSFET motor driver -Power: 2x AA batteries (1.8V-3.3V), optimized for long runtime -Audio: 30+ min at 8kHz/8-bit mono via 16MB SPI flash +Design: MDBT50Q (nRF52840) + IS25LP128F SPI Flash + PAM8302A Class-D Amp +Power: 2xAA → TPS61220 boost → 3.3V, USB-C via MCP1700 LDO, diode OR-ing +Audio: 30+ min at 8kHz/8-bit mono via 16MB SPI flash +USB: Mass storage for drag-and-drop audio upload +BLE: Wireless audio transfer from phone + +FIX: Sub-symbol names (the _0_1, _1_1 variants) must NOT include the +library prefix. Only the outer symbol declaration gets "baby_mobile:". """ import uuid import json import os +LIB = "baby_mobile" + def uid(): return str(uuid.uuid4()) + # ============================================================ -# SCHEMATIC GENERATION +# SYMBOL HELPERS # ============================================================ -def generate_schematic(): - """Generate the complete .kicad_sch file.""" +def _sym_start(name, ref_prefix, default_value, footprint, extra_props=""): + """Outer symbol with library prefix.""" + return f""" + (symbol "{LIB}:{name}" (in_bom yes) (on_board yes) + (property "Reference" "{ref_prefix}" (at 0 1 0) (effects (font (size 1.27 1.27)))) + (property "Value" "{default_value}" (at 0 -1 0) (effects (font (size 1.27 1.27)))) + (property "Footprint" "{footprint}" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + {extra_props}""" - # We use net labels for connections instead of routing every wire. - # This keeps the schematic clean and KiCad resolves connectivity by label name. - - sch = [] - sch.append(f"""(kicad_sch (version 20230121) (generator "custom_generator") - (uuid "{uid()}") - (paper "A3") - - (title_block - (title "Baby Mobile Audio Board") - (date "2026-03-08") - (rev "1.0") - (comment 1 "ATmega328P + W25Q128 + PAM8302A") - (comment 2 "2xAA Battery Powered - Long Runtime Design") - (comment 3 "8-ohm 0.25W Speaker, DC Motor, 8 Buttons") - (comment 4 "Arduino Compatible (8MHz Internal Osc)") - ) -""") - - # ---- LIB_SYMBOLS ---- - sch.append(" (lib_symbols") - sch.append(_sym_atmega328p()) - sch.append(_sym_w25q128()) - sch.append(_sym_pam8302a()) - sch.append(_sym_nmos()) - sch.append(_sym_capacitor()) - sch.append(_sym_resistor()) - sch.append(_sym_diode_schottky()) - sch.append(_sym_inductor()) - sch.append(_sym_switch()) - sch.append(_sym_conn2()) - sch.append(_sym_conn3()) - sch.append(_sym_conn6()) - sch.append(_sym_led()) - sch.append(_sym_pwr_flag()) - sch.append(" )") # end lib_symbols - - # ---- COMPONENT INSTANCES ---- - # Layout regions (KiCad uses mm, origin top-left): - # Power supply section: x=30, y=30 - # MCU (ATmega328P): x=130, y=90 - # SPI Flash (W25Q128): x=230, y=60 - # Audio section (PAM8302A): x=230, y=140 - # Motor driver: x=130, y=190 - # Buttons (8x): x=30, y=80-180 - # ISP Header: x=230, y=200 - # Serial Header: x=30, y=200 - - # ---- POWER SUPPLY SECTION ---- - # Battery connector J1 - sch.append(_instance("baby_mobile:Conn_2Pin", "J1", "BATTERY", "Connector_JST:JST_PH_S2B-PH-K_1x02_P2.00mm_Horizontal", - 25, 35, 0)) - # Main decoupling C1: 100uF electrolytic - sch.append(_instance("baby_mobile:Capacitor", "C1", "100uF", "Capacitor_THT:CP_Radial_D5.0mm_P2.00mm", - 55, 35, 0)) - # Decoupling C2: 100nF ceramic near MCU VCC - sch.append(_instance("baby_mobile:Capacitor", "C2", "100nF", "Capacitor_SMD:C_0805_2012Metric", - 100, 30, 0)) - # Decoupling C3: 100nF ceramic near MCU AVCC - sch.append(_instance("baby_mobile:Capacitor", "C3", "100nF", "Capacitor_SMD:C_0805_2012Metric", - 115, 30, 0)) - # Power switch SW_PWR - sch.append(_instance("baby_mobile:Switch", "SW9", "PWR", "Button_Switch_THT:SW_SPDT_CK-JS102011SAQN", - 40, 25, 0)) - - # ---- MCU: ATmega328P-AU ---- - sch.append(_instance("baby_mobile:ATmega328P-AU", "U1", "ATmega328P-AU", "Package_QFP:TQFP-32_7x7mm_P0.8mm", - 130, 90, 0)) - # Reset pullup R_RST: 10K - sch.append(_instance("baby_mobile:Resistor", "R1", "10K", "Resistor_SMD:R_0805_2012Metric", - 95, 55, 0)) - # Reset capacitor C_RST: 100nF - sch.append(_instance("baby_mobile:Capacitor", "C4", "100nF", "Capacitor_SMD:C_0805_2012Metric", - 95, 65, 0)) - - # ---- SPI FLASH: W25Q128JVSIQ ---- - sch.append(_instance("baby_mobile:W25Q128", "U2", "W25Q128JVSIQ", "Package_SO:SOIC-8_3.9x4.9mm_P1.27mm", - 230, 60, 0)) - # Flash decoupling C5: 100nF - sch.append(_instance("baby_mobile:Capacitor", "C5", "100nF", "Capacitor_SMD:C_0805_2012Metric", - 255, 50, 0)) - - # ---- AUDIO AMP: PAM8302A ---- - sch.append(_instance("baby_mobile:PAM8302A", "U3", "PAM8302A", "Package_SO:SOIC-8_3.9x4.9mm_P1.27mm", - 230, 140, 0)) - # Input coupling cap C6: 1uF - sch.append(_instance("baby_mobile:Capacitor", "C6", "1uF", "Capacitor_SMD:C_0805_2012Metric", - 200, 135, 0)) - # RC low-pass filter on PWM: R_LPF + C_LPF - # f_c = 1/(2*pi*R*C) ~ 3.4kHz with 4.7K + 10nF - sch.append(_instance("baby_mobile:Resistor", "R2", "4.7K", "Resistor_SMD:R_0805_2012Metric", - 185, 135, 0)) - sch.append(_instance("baby_mobile:Capacitor", "C7", "10nF", "Capacitor_SMD:C_0805_2012Metric", - 192, 145, 0)) - # Amp supply bypass C8: 10uF - sch.append(_instance("baby_mobile:Capacitor", "C8", "10uF", "Capacitor_SMD:C_0805_2012Metric", - 255, 130, 0)) - # Speaker connector J2 - sch.append(_instance("baby_mobile:Conn_2Pin", "J2", "SPEAKER", "Connector_JST:JST_PH_S2B-PH-K_1x02_P2.00mm_Horizontal", - 265, 145, 0)) - # Shutdown pulldown R_SD: 100K (default ON, MCU can shut down) - sch.append(_instance("baby_mobile:Resistor", "R3", "100K", "Resistor_SMD:R_0805_2012Metric", - 210, 150, 0)) - - # ---- MOTOR DRIVER ---- - # N-ch MOSFET Q1 - sch.append(_instance("baby_mobile:NMOS", "Q1", "AO3400A", "Package_TO_SOT_SMD:SOT-23", - 140, 190, 0)) - # Gate resistor R_GATE: 100 ohm - sch.append(_instance("baby_mobile:Resistor", "R4", "100R", "Resistor_SMD:R_0805_2012Metric", - 120, 190, 0)) - # Gate pulldown R_GPD: 100K - sch.append(_instance("baby_mobile:Resistor", "R5", "100K", "Resistor_SMD:R_0805_2012Metric", - 130, 200, 0)) - # Flyback diode D1 - sch.append(_instance("baby_mobile:Diode_Schottky", "D1", "SS14", "Diode_SMD:D_SMA", - 155, 180, 90)) - # Motor connector J3 - sch.append(_instance("baby_mobile:Conn_2Pin", "J3", "MOTOR", "Connector_JST:JST_PH_S2B-PH-K_1x02_P2.00mm_Horizontal", - 160, 170, 0)) - - # ---- 8 BUTTONS ---- - button_pins = ["BTN1", "BTN2", "BTN3", "BTN4", "BTN5", "BTN6", "BTN7", "BTN8"] - for i, name in enumerate(button_pins): - y = 75 + i * 15 - sch.append(_instance("baby_mobile:Switch", f"SW{i+1}", name, "Button_Switch_SMD:SW_SPST_TL3342", - 30, y, 0)) - - # ---- STATUS LED ---- - sch.append(_instance("baby_mobile:LED", "D2", "LED", "LED_SMD:LED_0805_2012Metric", - 85, 190, 0)) - sch.append(_instance("baby_mobile:Resistor", "R6", "1K", "Resistor_SMD:R_0805_2012Metric", - 75, 190, 0)) - - # ---- ISP HEADER (2x3) ---- - sch.append(_instance("baby_mobile:Conn_6Pin", "J4", "ISP", "Connector_PinHeader_2.54mm:PinHeader_2x03_P2.54mm_Vertical", - 250, 200, 0)) - - # ---- SERIAL HEADER (3-pin: GND, TX, RX) ---- - sch.append(_instance("baby_mobile:Conn_3Pin", "J5", "SERIAL", "Connector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_Vertical", - 30, 210, 0)) - - # ---- NET LABELS ---- - # Power nets - net_labels = [ - # Power distribution - ("VCC", 55, 25), ("VCC", 100, 25), ("VCC", 115, 25), - ("VCC", 130, 50), ("VCC", 255, 45), ("VCC", 255, 125), - ("VCC", 95, 50), ("VCC", 160, 165), - ("GND", 55, 45), ("GND", 100, 40), ("GND", 115, 40), - ("GND", 130, 130), ("GND", 255, 70), ("GND", 255, 155), - ("GND", 95, 70), ("GND", 140, 205), ("GND", 192, 155), - - # SPI bus - ("SPI_MOSI", 165, 85), ("SPI_MOSI", 215, 55), - ("SPI_MISO", 165, 90), ("SPI_MISO", 215, 60), - ("SPI_SCK", 165, 95), ("SPI_SCK", 215, 65), - ("FLASH_CS", 165, 80), ("FLASH_CS", 215, 50), - - # Audio - ("AUDIO_PWM", 165, 100), ("AUDIO_PWM", 175, 135), - ("AMP_SD", 165, 105), ("AMP_SD", 210, 145), - - # Motor - ("MOTOR_PWM", 165, 110), ("MOTOR_PWM", 110, 190), - - # Buttons (directly named for MCU pins mapping) - ("BTN1", 45, 75), ("BTN1", 95, 85), - ("BTN2", 45, 90), ("BTN2", 95, 90), - ("BTN3", 45, 105), ("BTN3", 95, 95), - ("BTN4", 45, 120), ("BTN4", 95, 100), - ("BTN5", 45, 135), ("BTN5", 95, 105), - ("BTN6", 45, 150), ("BTN6", 95, 110), - ("BTN7", 45, 165), ("BTN7", 95, 115), - ("BTN8", 45, 180), ("BTN8", 95, 120), - - # ISP - ("SPI_MOSI", 240, 195), ("SPI_MISO", 240, 200), - ("SPI_SCK", 240, 205), ("RESET", 240, 210), - ("RESET", 95, 60), - - # Serial - ("TXD", 40, 210), ("RXD", 40, 215), - ("TXD", 95, 75), ("RXD", 95, 80), - - # LED - ("LED_OUT", 65, 190), ("LED_OUT", 95, 125), - ] - - for name, x, y in net_labels: - sch.append(f""" (label "{name}" (at {x} {y} 0) (effects (font (size 1.27 1.27))) (uuid "{uid()}"))""") - - # ---- TEXT NOTES ---- - notes = [ - (15, 15, "POWER: 2xAA (1.8V-3.3V) → Long runtime design"), - (15, 18, "MCU: ATmega328P-AU @ 8MHz internal osc, Arduino compatible"), - (200, 15, "FLASH: W25Q128 16MB = ~33 min @ 8kHz 8-bit PCM"), - (200, 18, "AMP: PAM8302A Class-D, 90% efficient, Vmin=2.0V"), - (15, 220, "BUTTONS: Internal pull-ups, active LOW, PCINT wake-from-sleep"), - (120, 220, "MOTOR: AO3400A logic-level N-MOSFET, PWM speed control"), - (15, 225, "ESTIMATED RUNTIME: Audio+Motor ~23h, Audio only ~200h, Sleep ~years"), - ] - for x, y, text in notes: - sch.append(f""" (text "{text}" (at {x} {y} 0) - (effects (font (size 1.5 1.5)) (justify left)) - (uuid "{uid()}") - )""") - - sch.append(")") # end kicad_sch - return "\n".join(sch) +def _unit(name, unit_id): + """Inner sub-symbol WITHOUT library prefix — this was the bug.""" + return f""" (symbol "{name}_{unit_id}" """ # ============================================================ # SYMBOL DEFINITIONS # ============================================================ -def _sym_atmega328p(): - return f""" - (symbol "baby_mobile:ATmega328P-AU" (in_bom yes) (on_board yes) - (property "Reference" "U" (at 0 26 0) (effects (font (size 1.27 1.27)))) - (property "Value" "ATmega328P-AU" (at 0 24 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Package_QFP:TQFP-32_7x7mm_P0.8mm" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (symbol "ATmega328P-AU_0_1" - (rectangle (start -17 23) (end 17 -23) (stroke (width 0.254) (type default)) (fill (type background))) +def sym_mdbt50q(): + """MDBT50Q-P nRF52840 BLE module, 32 pins exposed.""" + s = _sym_start("MDBT50Q", "U", "MDBT50Q-P1MV2", + "RF_Module:Raytac_MDBT50Q", + "") + s += f""" + (symbol "MDBT50Q_0_1" + (rectangle (start -20 30) (end 20 -30) (stroke (width 0.254) (type default)) (fill (type background))) ) - (symbol "ATmega328P-AU_1_1" - (pin power_in line (at -7 -26 90) (length 3) (name "GND" (effects (font (size 1 1)))) (number "3" (effects (font (size 1 1))))) - (pin power_in line (at -5 -26 90) (length 3) (name "GND2" (effects (font (size 1 1)))) (number "5" (effects (font (size 1 1))))) - (pin power_in line (at -3 26 270) (length 3) (name "VCC" (effects (font (size 1 1)))) (number "4" (effects (font (size 1 1))))) - (pin power_in line (at -1 26 270) (length 3) (name "AVCC" (effects (font (size 1 1)))) (number "6" (effects (font (size 1 1))))) - (pin passive line (at 1 26 270) (length 3) (name "AREF" (effects (font (size 1 1)))) (number "21" (effects (font (size 1 1))))) - (pin bidirectional line (at -20 15 0) (length 3) (name "PD0/RXD" (effects (font (size 1 1)))) (number "30" (effects (font (size 1 1))))) - (pin bidirectional line (at -20 12.5 0) (length 3) (name "PD1/TXD" (effects (font (size 1 1)))) (number "31" (effects (font (size 1 1))))) - (pin bidirectional line (at -20 10 0) (length 3) (name "PD2/INT0" (effects (font (size 1 1)))) (number "32" (effects (font (size 1 1))))) - (pin bidirectional line (at -20 7.5 0) (length 3) (name "PD3/INT1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) - (pin bidirectional line (at -20 5 0) (length 3) (name "PD4" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) - (pin bidirectional line (at -20 2.5 0) (length 3) (name "PD5/OC0B" (effects (font (size 1 1)))) (number "9" (effects (font (size 1 1))))) - (pin bidirectional line (at -20 0 0) (length 3) (name "PD6/OC0A" (effects (font (size 1 1)))) (number "10" (effects (font (size 1 1))))) - (pin bidirectional line (at -20 -2.5 0) (length 3) (name "PD7" (effects (font (size 1 1)))) (number "11" (effects (font (size 1 1))))) - (pin bidirectional line (at 20 15 180) (length 3) (name "PB0" (effects (font (size 1 1)))) (number "12" (effects (font (size 1 1))))) - (pin bidirectional line (at 20 12.5 180) (length 3) (name "PB1/OC1A" (effects (font (size 1 1)))) (number "13" (effects (font (size 1 1))))) - (pin bidirectional line (at 20 10 180) (length 3) (name "PB2/SS" (effects (font (size 1 1)))) (number "14" (effects (font (size 1 1))))) - (pin bidirectional line (at 20 7.5 180) (length 3) (name "PB3/MOSI" (effects (font (size 1 1)))) (number "15" (effects (font (size 1 1))))) - (pin bidirectional line (at 20 5 180) (length 3) (name "PB4/MISO" (effects (font (size 1 1)))) (number "16" (effects (font (size 1 1))))) - (pin bidirectional line (at 20 2.5 180) (length 3) (name "PB5/SCK" (effects (font (size 1 1)))) (number "17" (effects (font (size 1 1))))) - (pin bidirectional line (at 20 -2.5 180) (length 3) (name "PC0/ADC0" (effects (font (size 1 1)))) (number "23" (effects (font (size 1 1))))) - (pin bidirectional line (at 20 -5 180) (length 3) (name "PC1/ADC1" (effects (font (size 1 1)))) (number "24" (effects (font (size 1 1))))) - (pin bidirectional line (at 20 -7.5 180) (length 3) (name "PC2/ADC2" (effects (font (size 1 1)))) (number "25" (effects (font (size 1 1))))) - (pin bidirectional line (at 20 -10 180) (length 3) (name "PC3/ADC3" (effects (font (size 1 1)))) (number "26" (effects (font (size 1 1))))) - (pin bidirectional line (at 20 -12.5 180) (length 3) (name "PC4/SDA" (effects (font (size 1 1)))) (number "27" (effects (font (size 1 1))))) - (pin bidirectional line (at 20 -15 180) (length 3) (name "PC5/SCL" (effects (font (size 1 1)))) (number "28" (effects (font (size 1 1))))) - (pin input line (at -20 -10 0) (length 3) (name "~{{RESET}}" (effects (font (size 1 1)))) (number "29" (effects (font (size 1 1))))) - (pin input line (at -20 -15 0) (length 3) (name "XTAL1" (effects (font (size 1 1)))) (number "7" (effects (font (size 1 1))))) - (pin output line (at -20 -17.5 0) (length 3) (name "XTAL2" (effects (font (size 1 1)))) (number "8" (effects (font (size 1 1))))) + (symbol "MDBT50Q_1_1" + (pin power_in line (at -5 -33 90) (length 3) (name "GND" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) + (pin power_in line (at -5 33 270) (length 3) (name "VCC" (effects (font (size 1 1)))) (number "32" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 20 0) (length 3) (name "P0.00/XL1" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 17.5 0) (length 3) (name "P0.01/XL2" (effects (font (size 1 1)))) (number "3" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 15 0) (length 3) (name "P0.02/AIN0" (effects (font (size 1 1)))) (number "4" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 12.5 0) (length 3) (name "P0.03/AIN1" (effects (font (size 1 1)))) (number "5" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 10 0) (length 3) (name "P0.04/AIN2" (effects (font (size 1 1)))) (number "6" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 7.5 0) (length 3) (name "P0.05/AIN3" (effects (font (size 1 1)))) (number "7" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 5 0) (length 3) (name "P0.06" (effects (font (size 1 1)))) (number "8" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 2.5 0) (length 3) (name "P0.07" (effects (font (size 1 1)))) (number "9" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 0 0) (length 3) (name "P0.08" (effects (font (size 1 1)))) (number "10" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 -2.5 0) (length 3) (name "P0.09/NFC1" (effects (font (size 1 1)))) (number "11" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 -5 0) (length 3) (name "P0.10/NFC2" (effects (font (size 1 1)))) (number "12" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 -7.5 0) (length 3) (name "P0.11" (effects (font (size 1 1)))) (number "13" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 -10 0) (length 3) (name "P0.12" (effects (font (size 1 1)))) (number "14" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 -12.5 0) (length 3) (name "P0.13" (effects (font (size 1 1)))) (number "15" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 -15 0) (length 3) (name "P0.14" (effects (font (size 1 1)))) (number "16" (effects (font (size 1 1))))) + (pin bidirectional line (at -23 -17.5 0) (length 3) (name "P0.15" (effects (font (size 1 1)))) (number "17" (effects (font (size 1 1))))) + (pin bidirectional line (at 23 20 180) (length 3) (name "P0.16" (effects (font (size 1 1)))) (number "18" (effects (font (size 1 1))))) + (pin bidirectional line (at 23 17.5 180) (length 3) (name "P0.17" (effects (font (size 1 1)))) (number "19" (effects (font (size 1 1))))) + (pin bidirectional line (at 23 15 180) (length 3) (name "P0.18/~{{RESET}}" (effects (font (size 1 1)))) (number "20" (effects (font (size 1 1))))) + (pin bidirectional line (at 23 12.5 180) (length 3) (name "P0.19" (effects (font (size 1 1)))) (number "21" (effects (font (size 1 1))))) + (pin bidirectional line (at 23 10 180) (length 3) (name "P0.20" (effects (font (size 1 1)))) (number "22" (effects (font (size 1 1))))) + (pin bidirectional line (at 23 7.5 180) (length 3) (name "P0.21" (effects (font (size 1 1)))) (number "23" (effects (font (size 1 1))))) + (pin bidirectional line (at 23 5 180) (length 3) (name "P0.22" (effects (font (size 1 1)))) (number "24" (effects (font (size 1 1))))) + (pin bidirectional line (at 23 2.5 180) (length 3) (name "P0.23" (effects (font (size 1 1)))) (number "25" (effects (font (size 1 1))))) + (pin bidirectional line (at 23 0 180) (length 3) (name "P0.24" (effects (font (size 1 1)))) (number "26" (effects (font (size 1 1))))) + (pin bidirectional line (at 23 -2.5 180) (length 3) (name "P1.00" (effects (font (size 1 1)))) (number "27" (effects (font (size 1 1))))) + (pin bidirectional line (at 23 -5 180) (length 3) (name "D-" (effects (font (size 1 1)))) (number "28" (effects (font (size 1 1))))) + (pin bidirectional line (at 23 -7.5 180) (length 3) (name "D+" (effects (font (size 1 1)))) (number "29" (effects (font (size 1 1))))) + (pin bidirectional line (at 23 -10 180) (length 3) (name "P0.25" (effects (font (size 1 1)))) (number "30" (effects (font (size 1 1))))) + (pin bidirectional line (at 23 -12.5 180) (length 3) (name "P0.26" (effects (font (size 1 1)))) (number "31" (effects (font (size 1 1))))) + (pin input line (at 23 -17.5 180) (length 3) (name "SWDIO" (effects (font (size 1 1)))) (number "33" (effects (font (size 1 1))))) + (pin input line (at 23 -20 180) (length 3) (name "SWDCLK" (effects (font (size 1 1)))) (number "34" (effects (font (size 1 1))))) ) )""" + return s -def _sym_w25q128(): - return f""" - (symbol "baby_mobile:W25Q128" (in_bom yes) (on_board yes) - (property "Reference" "U" (at 0 9 0) (effects (font (size 1.27 1.27)))) - (property "Value" "W25Q128JVSIQ" (at 0 7 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Package_SO:SOIC-8_3.9x4.9mm_P1.27mm" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (symbol "W25Q128_0_1" + +def sym_is25lp128f(): + s = _sym_start("IS25LP128F", "U", "IS25LP128F", "Package_SO:SOIC-8_3.9x4.9mm_P1.27mm") + s += f""" + (symbol "IS25LP128F_0_1" (rectangle (start -7 6) (end 7 -6) (stroke (width 0.254) (type default)) (fill (type background))) ) - (symbol "W25Q128_1_1" + (symbol "IS25LP128F_1_1" (pin input line (at -10 4 0) (length 3) (name "~{{CS}}" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) - (pin output line (at -10 1.5 0) (length 3) (name "DO/IO1" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) + (pin output line (at -10 1.5 0) (length 3) (name "SO/IO1" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) (pin input line (at -10 -1.5 0) (length 3) (name "~{{WP}}/IO2" (effects (font (size 1 1)))) (number "3" (effects (font (size 1 1))))) (pin power_in line (at -10 -4 0) (length 3) (name "GND" (effects (font (size 1 1)))) (number "4" (effects (font (size 1 1))))) - (pin input line (at 10 -4 180) (length 3) (name "DI/IO0" (effects (font (size 1 1)))) (number "5" (effects (font (size 1 1))))) - (pin input line (at 10 -1.5 180) (length 3) (name "CLK" (effects (font (size 1 1)))) (number "6" (effects (font (size 1 1))))) + (pin input line (at 10 -4 180) (length 3) (name "SI/IO0" (effects (font (size 1 1)))) (number "5" (effects (font (size 1 1))))) + (pin input line (at 10 -1.5 180) (length 3) (name "SCLK" (effects (font (size 1 1)))) (number "6" (effects (font (size 1 1))))) (pin input line (at 10 1.5 180) (length 3) (name "~{{HOLD}}/IO3" (effects (font (size 1 1)))) (number "7" (effects (font (size 1 1))))) (pin power_in line (at 10 4 180) (length 3) (name "VCC" (effects (font (size 1 1)))) (number "8" (effects (font (size 1 1))))) ) )""" + return s -def _sym_pam8302a(): - return f""" - (symbol "baby_mobile:PAM8302A" (in_bom yes) (on_board yes) - (property "Reference" "U" (at 0 11 0) (effects (font (size 1.27 1.27)))) - (property "Value" "PAM8302A" (at 0 9 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Package_SO:SOIC-8_3.9x4.9mm_P1.27mm" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + +def sym_pam8302a(): + s = _sym_start("PAM8302A", "U", "PAM8302A", "Package_SO:SOIC-8_3.9x4.9mm_P1.27mm") + s += f""" (symbol "PAM8302A_0_1" (rectangle (start -8 8) (end 8 -8) (stroke (width 0.254) (type default)) (fill (type background))) ) @@ -323,20 +132,97 @@ def _sym_pam8302a(): (pin power_in line (at 11 -4 180) (length 3) (name "PAD" (effects (font (size 1 1)))) (number "6" (effects (font (size 1 1))))) ) )""" + return s -def _sym_nmos(): - return f""" - (symbol "baby_mobile:NMOS" (in_bom yes) (on_board yes) - (property "Reference" "Q" (at 3 0 0) (effects (font (size 1.27 1.27)))) - (property "Value" "AO3400A" (at 5 -2.5 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Package_TO_SOT_SMD:SOT-23" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) + +def sym_tps61220(): + s = _sym_start("TPS61220", "U", "TPS61220DCK", "Package_TO_SOT_SMD:SOT-353_SC-70-5") + s += f""" + (symbol "TPS61220_0_1" + (rectangle (start -7 5) (end 7 -5) (stroke (width 0.254) (type default)) (fill (type background))) + ) + (symbol "TPS61220_1_1" + (pin power_in line (at -10 3 0) (length 3) (name "VIN" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) + (pin power_in line (at -10 -3 0) (length 3) (name "GND" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) + (pin input line (at 10 -3 180) (length 3) (name "EN" (effects (font (size 1 1)))) (number "3" (effects (font (size 1 1))))) + (pin power_out line (at 10 3 180) (length 3) (name "VOUT" (effects (font (size 1 1)))) (number "4" (effects (font (size 1 1))))) + (pin passive line (at 0 8 270) (length 3) (name "L" (effects (font (size 1 1)))) (number "5" (effects (font (size 1 1))))) + ) + )""" + return s + + +def sym_mcp1700(): + s = _sym_start("MCP1700", "U", "MCP1700-3302E", "Package_TO_SOT_SMD:SOT-23") + s += f""" + (symbol "MCP1700_0_1" + (rectangle (start -6 4) (end 6 -4) (stroke (width 0.254) (type default)) (fill (type background))) + ) + (symbol "MCP1700_1_1" + (pin power_in line (at -9 2 0) (length 3) (name "VIN" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) + (pin power_in line (at 0 -7 90) (length 3) (name "GND" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) + (pin power_out line (at 9 2 180) (length 3) (name "VOUT" (effects (font (size 1 1)))) (number "3" (effects (font (size 1 1))))) + ) + )""" + return s + + +def sym_generic_2pin(name, ref, value, fp): + """Generic 2-pin symbol for caps, resistors, diodes, connectors.""" + s = _sym_start(name, ref, value, fp) + s += f""" + (symbol "{name}_0_1" + (polyline (pts (xy -1.5 1) (xy 1.5 1)) (stroke (width 0.4) (type default)) (fill (type none))) + (polyline (pts (xy -1.5 -1) (xy 1.5 -1)) (stroke (width 0.4) (type default)) (fill (type none))) + ) + (symbol "{name}_1_1" + (pin passive line (at 0 3.5 270) (length 2.5) (name "1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) + (pin passive line (at 0 -3.5 90) (length 2.5) (name "2" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) + ) + )""" + return s + + +def sym_usb_c(): + s = _sym_start("USB_C", "J", "USB_C_Receptacle", "Connector_USB:USB_C_Receptacle_GCT_USB4085") + s += f""" + (symbol "USB_C_0_1" + (rectangle (start -6 8) (end 6 -8) (stroke (width 0.254) (type default)) (fill (type background))) + ) + (symbol "USB_C_1_1" + (pin power_in line (at -9 6 0) (length 3) (name "VBUS" (effects (font (size 1 1)))) (number "A4" (effects (font (size 1 1))))) + (pin passive line (at -9 3 0) (length 3) (name "CC1" (effects (font (size 1 1)))) (number "A5" (effects (font (size 1 1))))) + (pin passive line (at -9 0 0) (length 3) (name "CC2" (effects (font (size 1 1)))) (number "B5" (effects (font (size 1 1))))) + (pin bidirectional line (at -9 -3 0) (length 3) (name "D+" (effects (font (size 1 1)))) (number "A6" (effects (font (size 1 1))))) + (pin bidirectional line (at -9 -6 0) (length 3) (name "D-" (effects (font (size 1 1)))) (number "A7" (effects (font (size 1 1))))) + (pin power_in line (at 9 -6 180) (length 3) (name "GND" (effects (font (size 1 1)))) (number "A1" (effects (font (size 1 1))))) + (pin passive line (at 9 0 180) (length 3) (name "SHIELD" (effects (font (size 1 1)))) (number "S1" (effects (font (size 1 1))))) + ) + )""" + return s + + +def sym_switch(): + s = _sym_start("Switch", "SW", "SW", "Button_Switch_SMD:SW_SPST_TL3342") + s += f""" + (symbol "Switch_0_1" + (circle (center -2 0) (radius 0.4) (stroke (width 0) (type default)) (fill (type none))) + (circle (center 2 0) (radius 0.4) (stroke (width 0) (type default)) (fill (type none))) + (polyline (pts (xy -1.6 0) (xy 1.6 1)) (stroke (width 0.254) (type default)) (fill (type none))) + ) + (symbol "Switch_1_1" + (pin passive line (at -5 0 0) (length 3) (name "1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) + (pin passive line (at 5 0 180) (length 3) (name "2" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) + ) + )""" + return s + + +def sym_nmos(): + s = _sym_start("NMOS", "Q", "AO3400A", "Package_TO_SOT_SMD:SOT-23") + s += f""" (symbol "NMOS_0_1" - (polyline (pts (xy -0.5 0.5) (xy -0.5 -0.5)) (stroke (width 0.33) (type default)) (fill (type none))) - (polyline (pts (xy -0.5 -2) (xy -0.5 2)) (stroke (width 0.254) (type default)) (fill (type none))) - (polyline (pts (xy 0 -2.5) (xy 0 -1.5)) (stroke (width 0) (type default)) (fill (type none))) - (polyline (pts (xy 0 1.5) (xy 0 2.5)) (stroke (width 0) (type default)) (fill (type none))) - (polyline (pts (xy 0 0) (xy -1.5 0)) (stroke (width 0) (type default)) (fill (type none))) + (polyline (pts (xy -0.5 2) (xy -0.5 -2)) (stroke (width 0.254) (type default)) (fill (type none))) ) (symbol "NMOS_1_1" (pin passive line (at 0 5 270) (length 2.5) (name "D" (effects (font (size 1 1)))) (number "3" (effects (font (size 1 1))))) @@ -344,64 +230,12 @@ def _sym_nmos(): (pin passive line (at 0 -5 90) (length 2.5) (name "S" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) ) )""" + return s -def _sym_capacitor(): - return f""" - (symbol "baby_mobile:Capacitor" (in_bom yes) (on_board yes) - (property "Reference" "C" (at 2 0 0) (effects (font (size 1.27 1.27)))) - (property "Value" "C" (at 2 -2 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (symbol "Capacitor_0_1" - (polyline (pts (xy -1.5 1) (xy 1.5 1)) (stroke (width 0.4) (type default)) (fill (type none))) - (polyline (pts (xy -1.5 -1) (xy 1.5 -1)) (stroke (width 0.4) (type default)) (fill (type none))) - ) - (symbol "Capacitor_1_1" - (pin passive line (at 0 3.5 270) (length 2.5) (name "1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) - (pin passive line (at 0 -3.5 90) (length 2.5) (name "2" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) - ) - )""" -def _sym_resistor(): - return f""" - (symbol "baby_mobile:Resistor" (in_bom yes) (on_board yes) - (property "Reference" "R" (at 2 0 0) (effects (font (size 1.27 1.27)))) - (property "Value" "R" (at 2 -2 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (symbol "Resistor_0_1" - (rectangle (start -1 2.5) (end 1 -2.5) (stroke (width 0.254) (type default)) (fill (type background))) - ) - (symbol "Resistor_1_1" - (pin passive line (at 0 5 270) (length 2.5) (name "1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) - (pin passive line (at 0 -5 90) (length 2.5) (name "2" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) - ) - )""" - -def _sym_diode_schottky(): - return f""" - (symbol "baby_mobile:Diode_Schottky" (in_bom yes) (on_board yes) - (property "Reference" "D" (at 2 0 0) (effects (font (size 1.27 1.27)))) - (property "Value" "SS14" (at 2 -2 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "Diode_SMD:D_SMA" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (symbol "Diode_Schottky_0_1" - (polyline (pts (xy -1.5 1) (xy 0 -1) (xy 1.5 1) (xy -1.5 1)) (stroke (width 0.2) (type default)) (fill (type none))) - (polyline (pts (xy -1.5 -1) (xy 1.5 -1)) (stroke (width 0.3) (type default)) (fill (type none))) - ) - (symbol "Diode_Schottky_1_1" - (pin passive line (at 0 3.5 270) (length 2.5) (name "A" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) - (pin passive line (at 0 -3.5 90) (length 2.5) (name "K" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) - ) - )""" - -def _sym_inductor(): - return f""" - (symbol "baby_mobile:Inductor" (in_bom yes) (on_board yes) - (property "Reference" "L" (at 2 0 0) (effects (font (size 1.27 1.27)))) - (property "Value" "L" (at 2 -2 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) +def sym_inductor(): + s = _sym_start("Inductor", "L", "4.7uH", "Inductor_SMD:L_0805_2012Metric") + s += f""" (symbol "Inductor_0_1" (arc (start 0 2.5) (mid 0.75 1.875) (end 0 1.25) (stroke (width 0.254) (type default)) (fill (type none))) (arc (start 0 1.25) (mid 0.75 0.625) (end 0 0) (stroke (width 0.254) (type default)) (fill (type none))) @@ -413,181 +247,276 @@ def _sym_inductor(): (pin passive line (at 0 -5 90) (length 2.5) (name "2" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) ) )""" + return s -def _sym_switch(): - return f""" - (symbol "baby_mobile:Switch" (in_bom yes) (on_board yes) - (property "Reference" "SW" (at 0 3 0) (effects (font (size 1.27 1.27)))) - (property "Value" "SW" (at 0 -3 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (symbol "Switch_0_1" - (circle (center -2 0) (radius 0.4) (stroke (width 0) (type default)) (fill (type none))) - (circle (center 2 0) (radius 0.4) (stroke (width 0) (type default)) (fill (type none))) - (polyline (pts (xy -1.6 0) (xy 1.6 1)) (stroke (width 0.254) (type default)) (fill (type none))) - ) - (symbol "Switch_1_1" - (pin passive line (at -5 0 0) (length 3) (name "1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) - (pin passive line (at 5 0 180) (length 3) (name "2" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) - ) - )""" - -def _sym_conn2(): - return f""" - (symbol "baby_mobile:Conn_2Pin" (in_bom yes) (on_board yes) - (property "Reference" "J" (at 0 4 0) (effects (font (size 1.27 1.27)))) - (property "Value" "Conn_2" (at 0 -4 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (symbol "Conn_2Pin_0_1" - (rectangle (start -2 3) (end 2 -3) (stroke (width 0.254) (type default)) (fill (type background))) - ) - (symbol "Conn_2Pin_1_1" - (pin passive line (at -5 1.5 0) (length 3) (name "1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) - (pin passive line (at -5 -1.5 0) (length 3) (name "2" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) - ) - )""" - -def _sym_conn3(): - return f""" - (symbol "baby_mobile:Conn_3Pin" (in_bom yes) (on_board yes) - (property "Reference" "J" (at 0 5.5 0) (effects (font (size 1.27 1.27)))) - (property "Value" "Conn_3" (at 0 -5.5 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (symbol "Conn_3Pin_0_1" - (rectangle (start -2 4) (end 2 -4) (stroke (width 0.254) (type default)) (fill (type background))) - ) - (symbol "Conn_3Pin_1_1" - (pin passive line (at -5 2.5 0) (length 3) (name "1" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) - (pin passive line (at -5 0 0) (length 3) (name "2" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) - (pin passive line (at -5 -2.5 0) (length 3) (name "3" (effects (font (size 1 1)))) (number "3" (effects (font (size 1 1))))) - ) - )""" - -def _sym_conn6(): - return f""" - (symbol "baby_mobile:Conn_6Pin" (in_bom yes) (on_board yes) - (property "Reference" "J" (at 0 9 0) (effects (font (size 1.27 1.27)))) - (property "Value" "ISP_2x3" (at 0 -9 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (symbol "Conn_6Pin_0_1" - (rectangle (start -3 8) (end 3 -8) (stroke (width 0.254) (type default)) (fill (type background))) - ) - (symbol "Conn_6Pin_1_1" - (pin passive line (at -6 5 0) (length 3) (name "MISO" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) - (pin passive line (at 6 5 180) (length 3) (name "VCC" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) - (pin passive line (at -6 0 0) (length 3) (name "SCK" (effects (font (size 1 1)))) (number "3" (effects (font (size 1 1))))) - (pin passive line (at 6 0 180) (length 3) (name "MOSI" (effects (font (size 1 1)))) (number "4" (effects (font (size 1 1))))) - (pin passive line (at -6 -5 0) (length 3) (name "~{{RST}}" (effects (font (size 1 1)))) (number "5" (effects (font (size 1 1))))) - (pin passive line (at 6 -5 180) (length 3) (name "GND" (effects (font (size 1 1)))) (number "6" (effects (font (size 1 1))))) - ) - )""" - -def _sym_led(): - return f""" - (symbol "baby_mobile:LED" (in_bom yes) (on_board yes) - (property "Reference" "D" (at 2 0 0) (effects (font (size 1.27 1.27)))) - (property "Value" "LED" (at 2 -2 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (symbol "LED_0_1" - (polyline (pts (xy -1.5 1) (xy 0 -1) (xy 1.5 1) (xy -1.5 1)) (stroke (width 0.2) (type default)) (fill (type none))) - (polyline (pts (xy -1.5 -1) (xy 1.5 -1)) (stroke (width 0.3) (type default)) (fill (type none))) - ) - (symbol "LED_1_1" - (pin passive line (at 0 3.5 270) (length 2.5) (name "A" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) - (pin passive line (at 0 -3.5 90) (length 2.5) (name "K" (effects (font (size 1 1)))) (number "2" (effects (font (size 1 1))))) - ) - )""" - -def _sym_pwr_flag(): - return f""" - (symbol "baby_mobile:PWR_FLAG" (power) (in_bom no) (on_board no) - (property "Reference" "#FLG" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Value" "PWR_FLAG" (at 0 3 0) (effects (font (size 1.27 1.27)))) - (property "Footprint" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (property "Datasheet" "" (at 0 0 0) (effects (font (size 1.27 1.27)) hide)) - (symbol "PWR_FLAG_0_1" - (polyline (pts (xy 0 0) (xy 0 1.5)) (stroke (width 0) (type default)) (fill (type none))) - (polyline (pts (xy -1 1.5) (xy 0 3) (xy 1 1.5) (xy -1 1.5)) (stroke (width 0) (type default)) (fill (type none))) - ) - (symbol "PWR_FLAG_1_1" - (pin power_out line (at 0 0 90) (length 0) (name "pwr" (effects (font (size 1 1)))) (number "1" (effects (font (size 1 1))))) + +def sym_conn(name, ref, npins, fp): + s = _sym_start(name, ref, name, fp) + h = npins * 2.5 + 1 + s += f""" + (symbol "{name}_0_1" + (rectangle (start -3 {h}) (end 3 {-h}) (stroke (width 0.254) (type default)) (fill (type background))) ) + (symbol "{name}_1_1" +""" + for i in range(npins): + y = h - 2 - i * 2.5 + s += f""" (pin passive line (at -6 {y:.1f} 0) (length 3) (name "P{i+1}" (effects (font (size 1 1)))) (number "{i+1}" (effects (font (size 1 1))))) +""" + s += """ ) )""" + return s -def _instance(lib_id, ref, value, footprint, x, y, angle): - """Generate a component instance.""" - return f""" (symbol (lib_id "{lib_id}") (at {x} {y} {angle}) (unit 1) +# ============================================================ +# INSTANCE HELPER +# ============================================================ + +def _inst(lib_name, ref, value, footprint, x, y, angle=0): + return f""" (symbol (lib_id "{LIB}:{lib_name}") (at {x} {y} {angle}) (unit 1) (in_bom yes) (on_board yes) (dnp no) (uuid "{uid()}") - (property "Reference" "{ref}" (at {x} {y-3} 0) (effects (font (size 1.27 1.27)))) - (property "Value" "{value}" (at {x} {y+3} 0) (effects (font (size 1.27 1.27)))) + (property "Reference" "{ref}" (at {x+3} {y-3} 0) (effects (font (size 1.27 1.27)))) + (property "Value" "{value}" (at {x+3} {y+3} 0) (effects (font (size 1.27 1.27)))) (property "Footprint" "{footprint}" (at {x} {y} 0) (effects (font (size 1.27 1.27)) hide)) (property "Datasheet" "" (at {x} {y} 0) (effects (font (size 1.27 1.27)) hide)) )""" +# ============================================================ +# MAIN SCHEMATIC +# ============================================================ + +def generate_schematic(): + sch = [] + sch.append(f"""(kicad_sch (version 20230121) (generator "baby_mobile_gen_v2") + + (uuid "{uid()}") + (paper "A3") + + (title_block + (title "Baby Mobile Audio Board v2") + (date "2026-03-09") + (rev "2.0") + (comment 1 "MDBT50Q (nRF52840) + IS25LP128F + PAM8302A") + (comment 2 "2xAA Battery + USB-C, Diode OR, TPS61220 Boost") + (comment 3 "BLE + USB mass storage for audio upload") + (comment 4 "8-ohm 0.25W Speaker, DC Motor, 8 Buttons") + ) +""") + + # ---- LIB_SYMBOLS ---- + sch.append(" (lib_symbols") + sch.append(sym_mdbt50q()) + sch.append(sym_is25lp128f()) + sch.append(sym_pam8302a()) + sch.append(sym_tps61220()) + sch.append(sym_mcp1700()) + sch.append(sym_generic_2pin("Capacitor", "C", "C", "Capacitor_SMD:C_0805_2012Metric")) + sch.append(sym_generic_2pin("Resistor", "R", "R", "Resistor_SMD:R_0805_2012Metric")) + sch.append(sym_generic_2pin("Diode_Schottky", "D", "BAT54S", "Diode_SMD:D_SOT-23_ANK")) + sch.append(sym_generic_2pin("LED", "D", "LED", "LED_SMD:LED_0805_2012Metric")) + sch.append(sym_generic_2pin("Conn_2Pin", "J", "Conn_2", "Connector_JST:JST_PH_S2B-PH-K_1x02_P2.00mm_Horizontal")) + sch.append(sym_switch()) + sch.append(sym_nmos()) + sch.append(sym_inductor()) + sch.append(sym_usb_c()) + sch.append(sym_conn("SWD_Header", "J", 4, "Connector_PinHeader_2.54mm:PinHeader_1x04_P2.54mm_Vertical")) + sch.append(sym_conn("Serial_Header", "J", 3, "Connector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_Vertical")) + sch.append(" )") # end lib_symbols + + # ---- COMPONENT INSTANCES ---- + + # == POWER: Battery path == + sch.append(_inst("Conn_2Pin", "J1", "BATTERY", "Connector_JST:JST_PH_S2B-PH-K_1x02_P2.00mm_Horizontal", 20, 40)) + sch.append(_inst("Switch", "SW9", "PWR", "Button_Switch_THT:SW_SPDT_CK-JS102011SAQN", 38, 35)) + sch.append(_inst("Diode_Schottky", "D1", "BAT54S", "Diode_SMD:D_SOT-23_ANK", 55, 35)) # battery diode + sch.append(_inst("Capacitor", "C1", "100uF", "Capacitor_THT:CP_Radial_D5.0mm_P2.00mm", 48, 45)) + + # == POWER: Boost converter TPS61220 == + sch.append(_inst("TPS61220", "U4", "TPS61220DCK", "Package_TO_SOT_SMD:SOT-353_SC-70-5", 80, 40)) + sch.append(_inst("Inductor", "L1", "4.7uH", "Inductor_SMD:L_0805_2012Metric", 80, 28)) + sch.append(_inst("Capacitor", "C9", "10uF", "Capacitor_SMD:C_0805_2012Metric", 68, 45)) # boost input + sch.append(_inst("Capacitor", "C10", "10uF", "Capacitor_SMD:C_0805_2012Metric", 95, 45)) # boost output + + # == POWER: USB path == + sch.append(_inst("USB_C", "J6", "USB_C", "Connector_USB:USB_C_Receptacle_GCT_USB4085", 20, 80)) + sch.append(_inst("Resistor", "R7", "5.1K", "Resistor_SMD:R_0805_2012Metric", 38, 83)) # CC1 + sch.append(_inst("Resistor", "R8", "5.1K", "Resistor_SMD:R_0805_2012Metric", 38, 88)) # CC2 + sch.append(_inst("Diode_Schottky", "D3", "BAT54S", "Diode_SMD:D_SOT-23_ANK", 55, 74)) # USB diode + sch.append(_inst("MCP1700", "U5", "MCP1700-3302E", "Package_TO_SOT_SMD:SOT-23", 72, 74)) + sch.append(_inst("Capacitor", "C11", "1uF", "Capacitor_SMD:C_0805_2012Metric", 62, 82)) # LDO in + sch.append(_inst("Capacitor", "C12", "1uF", "Capacitor_SMD:C_0805_2012Metric", 82, 82)) # LDO out + + # == MCU: MDBT50Q (nRF52840 module) == + sch.append(_inst("MDBT50Q", "U1", "MDBT50Q-P1MV2", "RF_Module:Raytac_MDBT50Q", 160, 100)) + + # MCU decoupling + sch.append(_inst("Capacitor", "C2", "100nF", "Capacitor_SMD:C_0805_2012Metric", 135, 60)) + sch.append(_inst("Capacitor", "C3", "10uF", "Capacitor_SMD:C_0805_2012Metric", 128, 60)) + + # == SPI FLASH: IS25LP128F == + sch.append(_inst("IS25LP128F", "U2", "IS25LP128F", "Package_SO:SOIC-8_3.9x4.9mm_P1.27mm", 260, 60)) + sch.append(_inst("Capacitor", "C5", "100nF", "Capacitor_SMD:C_0805_2012Metric", 285, 50)) + + # == AUDIO AMP: PAM8302A == + sch.append(_inst("PAM8302A", "U3", "PAM8302A", "Package_SO:SOIC-8_3.9x4.9mm_P1.27mm", 260, 140)) + sch.append(_inst("Resistor", "R2", "4.7K", "Resistor_SMD:R_0805_2012Metric", 220, 135)) # LPF R + sch.append(_inst("Capacitor", "C7", "10nF", "Capacitor_SMD:C_0805_2012Metric", 230, 145)) # LPF C + sch.append(_inst("Capacitor", "C6", "1uF", "Capacitor_SMD:C_0805_2012Metric", 240, 135)) # coupling + sch.append(_inst("Capacitor", "C8", "10uF", "Capacitor_SMD:C_0805_2012Metric", 285, 130)) # amp bypass + sch.append(_inst("Resistor", "R3", "100K", "Resistor_SMD:R_0805_2012Metric", 240, 155)) # SD pulldown + sch.append(_inst("Conn_2Pin", "J2", "SPEAKER", "Connector_JST:JST_PH_S2B-PH-K_1x02_P2.00mm_Horizontal", 290, 145)) + + # == MOTOR DRIVER == + sch.append(_inst("NMOS", "Q1", "AO3400A", "Package_TO_SOT_SMD:SOT-23", 160, 200)) + sch.append(_inst("Resistor", "R4", "100R", "Resistor_SMD:R_0805_2012Metric", 140, 200)) + sch.append(_inst("Resistor", "R5", "100K", "Resistor_SMD:R_0805_2012Metric", 150, 212)) + sch.append(_inst("Diode_Schottky", "D4", "SS14", "Diode_SMD:D_SMA", 175, 190, 90)) + sch.append(_inst("Conn_2Pin", "J3", "MOTOR", "Connector_JST:JST_PH_S2B-PH-K_1x02_P2.00mm_Horizontal", 180, 180)) + + # == 8 BUTTONS == + for i in range(8): + y = 80 + i * 14 + sch.append(_inst("Switch", f"SW{i+1}", f"BTN{i+1}", "Button_Switch_SMD:SW_SPST_TL3342", 300, y)) + + # == STATUS LED == + sch.append(_inst("LED", "D2", "LED_GRN", "LED_SMD:LED_0805_2012Metric", 115, 200)) + sch.append(_inst("Resistor", "R6", "1K", "Resistor_SMD:R_0805_2012Metric", 105, 200)) + + # == HEADERS == + sch.append(_inst("SWD_Header", "J4", "SWD", "Connector_PinHeader_2.54mm:PinHeader_1x04_P2.54mm_Vertical", 200, 60)) + sch.append(_inst("Serial_Header", "J5", "SERIAL", "Connector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_Vertical", 200, 30)) + + # ---- NET LABELS ---- + labels = [ + # 3.3V rail (output of boost OR LDO) + ("3V3", 95, 37), ("3V3", 135, 55), ("3V3", 128, 55), + ("3V3", 285, 45), ("3V3", 285, 125), ("3V3", 155, 67), + ("3V3", 82, 72), ("3V3", 180, 175), + + # Battery rail (pre-boost) + ("VBAT", 48, 35), ("VBAT", 55, 30), + ("VBAT", 68, 37), + + # Boost input/output + ("VBOOST_IN", 65, 37), ("VBOOST_IN", 70, 37), + ("3V3", 90, 37), + + # USB VBUS + ("USB_VBUS", 29, 74), ("USB_VBUS", 55, 69), + ("USB_LDO_OUT", 81, 72), + + # GND everywhere + ("GND", 48, 55), ("GND", 68, 55), ("GND", 95, 55), + ("GND", 80, 50), ("GND", 155, 133), + ("GND", 260, 70), ("GND", 285, 55), ("GND", 285, 155), + ("GND", 160, 215), ("GND", 150, 218), + ("GND", 230, 155), ("GND", 240, 165), + ("GND", 62, 92), ("GND", 82, 92), ("GND", 72, 81), + ("GND", 38, 93), ("GND", 38, 98), + ("GND", 135, 65), ("GND", 128, 65), + + # USB data + ("USB_D+", 29, 77), ("USB_D+", 183, 92.5), + ("USB_D-", 29, 80), ("USB_D-", 183, 95), + + # USB CC (to pulldowns) + ("USB_CC1", 29, 83), ("USB_CC1", 38, 78), + ("USB_CC2", 29, 86), ("USB_CC2", 38, 83), + + # SPI bus + ("SPI_MOSI", 183, 87.5), ("SPI_MOSI", 250, 56), + ("SPI_MISO", 183, 85), ("SPI_MISO", 250, 61.5), + ("SPI_SCK", 183, 82.5), ("SPI_SCK", 270, 58.5), + ("FLASH_CS", 183, 80), ("FLASH_CS", 250, 64), + + # Audio + ("AUDIO_PWM", 183, 100), ("AUDIO_PWM", 210, 135), + ("AMP_SD", 183, 102.5), ("AMP_SD", 240, 150), + + # Motor + ("MOTOR_PWM", 137, 112.5), ("MOTOR_PWM", 130, 200), + + # Buttons (directly to GPIOs) + ("BTN1", 295, 80), ("BTN1", 137, 120), + ("BTN2", 295, 94), ("BTN2", 137, 117.5), + ("BTN3", 295, 108), ("BTN3", 137, 115), + ("BTN4", 295, 122), ("BTN4", 137, 112.5), + ("BTN5", 295, 136), ("BTN5", 137, 110), + ("BTN6", 295, 150), ("BTN6", 137, 107.5), + ("BTN7", 295, 164), ("BTN7", 137, 105), + ("BTN8", 295, 178), ("BTN8", 137, 102.5), + + # Button GND side + ("GND", 305, 80), ("GND", 305, 94), ("GND", 305, 108), ("GND", 305, 122), + ("GND", 305, 136), ("GND", 305, 150), ("GND", 305, 164), ("GND", 305, 178), + + # LED + ("LED_OUT", 95, 200), ("LED_OUT", 137, 100), + + # SWD header + ("SWDIO", 194, 55.5), ("SWDIO", 183, 82.5), + ("SWDCLK", 194, 58), ("SWDCLK", 183, 80), + ("3V3", 194, 53), ("GND", 194, 60.5), + + # Serial header + ("TXD", 194, 25.5), ("TXD", 137, 80), + ("RXD", 194, 28), ("RXD", 137, 82.5), + ("GND", 194, 30.5), + + # Flash WP and HOLD tied to VCC + ("3V3", 250, 58.5), ("3V3", 270, 61.5), + + # Boost EN tied to VIN (always on when battery present) + ("VBAT", 90, 43), + ] + + for name, x, y in labels: + sch.append(f""" (label "{name}" (at {x} {y} 0) (effects (font (size 1.27 1.27))) (uuid "{uid()}"))""") + + # ---- TEXT NOTES ---- + notes = [ + (10, 12, "POWER: 2xAA → BAT54S → TPS61220 boost → 3.3V (1.8-3.2V input)"), + (10, 15, "USB: VBUS → BAT54S → MCP1700 LDO → 3.3V (safe with any battery chemistry)"), + (10, 18, "MCU: MDBT50Q (nRF52840) — BLE 5.0, USB 2.0, 1.7-5.5V, UF2 bootloader"), + (10, 21, "FLASH: IS25LP128F 16MB (2.3-3.6V) = ~33 min @ 8kHz 8-bit PCM"), + (10, 24, "AMP: PAM8302A Class-D, 90% eff, Vmin=2.0V, shutdown pin for power save"), + (10, 27, "MOTOR: AO3400A logic-level N-MOSFET, PWM speed control"), + (10, 230, "USB-C: Drag-and-drop audio as mass storage device"), + (10, 233, "BLE: Wireless audio upload from phone (Web Bluetooth compatible)"), + (10, 236, "FIRMWARE: UF2 bootloader — update by drag-and-drop, no programmer needed"), + (10, 239, "RUNTIME: Audio+Motor ~25h, Audio only ~167h, Sleep ~years on 2xAA"), + ] + for x, y, text in notes: + sch.append(f""" (text "{text}" (at {x} {y} 0) + (effects (font (size 1.5 1.5)) (justify left)) + (uuid "{uid()}") + )""") + + sch.append(")") # end kicad_sch + return "\n".join(sch) + + # ============================================================ # PROJECT FILE # ============================================================ def generate_project(): return json.dumps({ - "meta": { - "filename": "baby-mobile.kicad_pro", - "version": 1 - }, + "meta": {"filename": "baby-mobile-v2.kicad_pro", "version": 1}, "board": { "design_settings": { - "defaults": { - "board_outline_line_width": 0.1, - "copper_line_width": 0.2, - "copper_text_size_h": 1.5, - "copper_text_size_v": 1.5, - "other_line_width": 0.15 - }, - "rules": { - "min_copper_edge_clearance": 0.3, - "min_hole_clearance": 0.25, - "min_track_width": 0.2, - "min_via_annular_width": 0.13, - "min_via_diameter": 0.6, - "solder_mask_to_copper_clearance": 0 - } - }, - "layer_presets": [] - }, - "libraries": { - "pinned_footprint_libs": [], - "pinned_symbol_libs": [] + "defaults": {"board_outline_line_width": 0.1, "copper_line_width": 0.2}, + "rules": {"min_copper_edge_clearance": 0.3, "min_track_width": 0.2, + "min_via_diameter": 0.6, "min_via_annular_width": 0.13} + } }, "net_settings": { - "classes": [{ - "bus_width": 12, - "clearance": 0.2, - "diff_pair_gap": 0.25, - "diff_pair_via_gap": 0.25, - "diff_pair_width": 0.2, - "line_style": 0, - "microvia_diameter": 0.3, - "microvia_drill": 0.1, - "name": "Default", - "pcb_color": "rgba(0, 0, 0, 0.000)", - "schematic_color": "rgba(0, 0, 0, 0.000)", - "track_width": 0.3, - "via_diameter": 0.6, - "via_drill": 0.3, - "wire_width": 6 - }] - }, - "schematic": { - "legacy_lib_dir": "", - "legacy_lib_list": [] + "classes": [{"name": "Default", "clearance": 0.2, "track_width": 0.3, + "via_diameter": 0.6, "via_drill": 0.3}] }, + "schematic": {"legacy_lib_dir": "", "legacy_lib_list": []}, "sheets": [["", ""]] }, indent=2) @@ -597,18 +526,28 @@ def generate_project(): # ============================================================ if __name__ == "__main__": - outdir = "/home/claude/baby-mobile-pcb" - - # Generate schematic + outdir = os.path.dirname(os.path.abspath(__file__)) + sch = generate_schematic() - with open(os.path.join(outdir, "baby-mobile.kicad_sch"), "w") as f: + sch_path = os.path.join(outdir, "baby-mobile-v2.kicad_sch") + with open(sch_path, "w") as f: f.write(sch) - print(f"Written: baby-mobile.kicad_sch ({len(sch)} bytes)") - - # Generate project file + print(f"Written: {sch_path} ({len(sch)} bytes)") + proj = generate_project() - with open(os.path.join(outdir, "baby-mobile.kicad_pro"), "w") as f: + proj_path = os.path.join(outdir, "baby-mobile-v2.kicad_pro") + with open(proj_path, "w") as f: f.write(proj) - print(f"Written: baby-mobile.kicad_pro ({len(proj)} bytes)") - - print("Done! Open baby-mobile.kicad_pro in KiCad 7+") + print(f"Written: {proj_path} ({len(proj)} bytes)") + + # Validate: check no sub-symbol has library prefix + import re + outer = re.findall(r'\(symbol "baby_mobile:[^"]+?"', sch) + inner_bad = re.findall(r'\(symbol "baby_mobile:[^"]+?_[01]_1"', sch) + print(f"\nValidation: {len(outer)} outer symbols, {len(inner_bad)} bad inner symbols") + if inner_bad: + print("ERROR: Found inner symbols with library prefix:") + for m in inner_bad: + print(f" {m}") + else: + print("OK: All inner sub-symbols correctly omit library prefix")