This commit is contained in:
zyphlar
2026-07-04 03:28:11 -07:00
parent e681a74534
commit 5a18a689e0
9 changed files with 2561 additions and 2233 deletions
+182 -231
View File
@@ -1,278 +1,229 @@
# Baby Mobile Audio Board — Design Document # Baby Mobile Audio Board v2 — Design Document
## Overview ## Overview
Drop-in replacement board for a baby crib mobile. Plays custom audio from Drop-in replacement for baby crib mobile electronics. Custom audio from
SPI flash memory, drives a DC motor, handles 8 button inputs, and runs SPI flash, DC motor control, 8 buttons, and long runtime on 2×AA batteries.
for days on two AA batteries. No programmer needed — upload audio via USB drag-and-drop or Bluetooth.
**Key design decisions for long battery life:** ## Architecture
- SPI flash instead of microSD (4mA vs 30100mA 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 2×AA (1.8-3.2V) → SW9 → D1(BAT54S) → TPS61220 boost → 3.3V ──┐
VCC → C1(100µF) → GND bulk decoupling ├── MDBT50Q
VCC → C2(100nF) → GND MCU VCC decoupling USB-C VBUS (5V) → D3(BAT54S) → MCP1700 LDO → 3.3V ────────────┘ (nRF52840)
VCC → C3(100nF) → GND MCU AVCC decoupling
VCC → C5(100nF) → GND Flash decoupling ┌────────────── SPI ── IS25LP128F (16MB flash, 2.3-3.6V) │
VCC → C8(10µF) → GND Amp supply bypass │ ┌───────── 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) │
└────┴───┴─┴─┴──────────────────────────────────────────────────┘
``` ```
### MCU: U1 — ATmega328P-AU (TQFP-32) ## Power Design — Diode OR-ing (Safe for ALL Battery Types)
| MCU Pin | Port | Function | Connected To | ```
|---------|----------|---------------|---------------------------| BAT54S TPS61220
| 30 | PD0/RXD | Serial RX | J5 pin 3 (SERIAL header) | 2×AA ──SW9──┤►├──────┐ ┌─ VIN VOUT ─── 3.3V rail
| 31 | PD1/TXD | Serial TX | J5 pin 2 (SERIAL header) | ├── node ┤
| 32 | PD2/INT0 | Button 3 | SW3 → GND (active LOW) | USB VBUS ───┤►├── LDO ┘ └─ EN GND ─── GND
| 1 | PD3/INT1 | Button 4 | SW4 → GND (active LOW) | BAT54S MCP1700 L ─── L1(4.7µH)
| 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) | **Why this is safe:** The Schottky diodes only pass current in one direction.
| 11 | PD7 | Button 7 | SW7 → GND (active LOW) | When USB provides 3.3V via the LDO, the boost converter stops switching and
| 12 | PB0 | Button 8 | SW8 → GND (active LOW) | the battery diode is reverse-biased. Zero current flows into the batteries
| 13 | PB1/OC1A | Audio PWM | R2(4.7K) → C7(10nF) → U3 | regardless of chemistry (alkaline, NiMH, lithium).
| 14 | PB2/SS | Flash ~CS | U2 pin 1 |
| 15 | PB3/MOSI | SPI MOSI | U2 pin 5, J4 MOSI | **Diode drop:** BAT54S drops ~0.25V. TPS61220 accepts inputs down to 0.7V.
| 16 | PB4/MISO | SPI MISO | U2 pin 2, J4 MISO | Depleted 2×AA = 1.8V → boost sees 1.55V → still operational.
| 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 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 | | Pin | Name | Connected To |
|-----|-----------|-----------------| |-----|-----------|-------------------|
| 1 | ~CS | PB2 (FLASH_CS) | | 1 | ~CS | P0.12 (FLASH_CS) |
| 2 | DO (MISO) | PB4 (SPI_MISO) | | 2 | SO (MISO) | P0.14 (SPI_MISO) |
| 3 | ~WP | VCC (tie high) | | 3 | ~WP | 3V3 (tie high) |
| 4 | GND | GND | | 4 | GND | GND |
| 5 | DI (MOSI) | PB3 (SPI_MOSI) | | 5 | SI (MOSI) | P0.13 (SPI_MOSI) |
| 6 | CLK | PB5 (SPI_SCK) | | 6 | SCLK | P0.15 (SPI_SCK) |
| 7 | ~HOLD | VCC (tie high) | | 7 | ~HOLD | 3V3 (tie high) |
| 8 | VCC | VCC | | 8 | VCC | 3V3 |
**Operating voltage: 2.3V3.6V** — works across entire boost output range.
### Audio Amplifier: U3 — PAM8302AASCR (SOIC-8) ## Audio Signal Path
| Pin | Name | Connected To |
|-----|------|-------------------------------------------|
| 1 | ~SD | PC2 (AMP_SD) + R3(100K) pulldown to GND |
| 2 | VDD | VCC + C8(10µF) bypass |
| 3 | GND | GND |
| 4 | A+ | Audio signal from RC filter |
| 5 | A- | GND (single-ended input) |
| 6 | PAD | GND (thermal pad) |
| 7 | VO- | Speaker - |
| 8 | VO+ | Speaker + |
**Audio signal path:**
```
PB1 (OC1A PWM) → R2 (4.7KΩ) → node → C6 (1µF coupling) → U3 A+ (pin 4)
|
C7 (10nF) → GND
RC low-pass filter: fc = 1/(2π × 4700 × 10e-9) ≈ 3.4 kHz
This removes the PWM carrier while passing audio baseband.
```
**Shutdown control:**
- R3 (100K) pulls ~SD LOW by default = amplifier OFF
- MCU drives PC2 HIGH to enable amplifier
- Saves ~2mA quiescent current when not playing
### Motor Driver
``` ```
PD5 (OC0B) → R4 (100Ω gate resistor) → Q1 Gate P0.11 (PWM) → R2(4.7K) → node → C6(1µF coupling) → PAM8302A A+
|
R5 (100K) → GND (pulldown, ensures OFF at boot) C7(10nF) → GND
Q1: AO3400A N-ch MOSFET (SOT-23) RC LPF cutoff: 1/(2π × 4700 × 10e-9) ≈ 3.4 kHz
Drain → Motor terminal 1
Source → GND
(Motor terminal 2 → VCC)
D1: SS14 Schottky flyback diode across motor (Cathode → VCC, Anode → Drain)
``` ```
**Motor specs:**
- PWM on Timer0 (OC0B) for variable speed
- AO3400A: Vgs(th) = 0.65V typ, fully enhanced at 1.8V → works at depleted AA voltage
- R4 limits gate ringing; R5 ensures MOSFET OFF during MCU reset/programming
## USB-C Wiring
### Button Matrix
All 8 buttons connect between their MCU pin and GND (active LOW).
MCU internal pull-ups enabled (~3050KΩ). 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 USB-C Pin → Board
SCK 3 4 MOSI ────────────────────
~RST 5 6 GND VBUS (5V) → D3 anode → MCP1700 VIN
``` GND → GND
D+ → nRF52840 D+ (pin 29)
**J5 — Serial (1×3, for bootloader programming / debug):** D- → nRF52840 D- (pin 28)
``` CC1 → R7(5.1K) → GND
GND 1 CC2 → R8(5.1K) → GND
TXD 2 (MCU TX out)
RXD 3 (MCU RX in)
``` ```
## Bill of Materials ## Bill of Materials
| Ref | Value/Part | Package | Qty | ~Cost | Notes | | Ref | Part | Package | Qty | ~Cost |
|------|------------------|-------------------|-----|--------|-------------------------------| |--------|----------------------|---------------|-----|--------|
| U1 | ATmega328P-AU | TQFP-32 | 1 | $2.50 | Pre-burn Arduino bootloader | | U1 | MDBT50Q-P1MV2 | Module | 1 | $6.00 |
| U2 | W25Q128JVSIQ | SOIC-8 | 1 | $1.20 | 16MB, 33min @ 8kHz/8bit | | U2 | IS25LP128F-JBLE | SOIC-8 | 1 | $2.00 |
| U3 | PAM8302AASCR | SOIC-8 | 1 | $0.80 | 2.5W class-D, Vmin=2.0V | | U3 | PAM8302AASCR | SOIC-8 | 1 | $0.80 |
| Q1 | AO3400A | SOT-23 | 1 | $0.15 | Logic-level N-ch MOSFET | | U4 | TPS61220DCKR | SC-70-5 | 1 | $0.80 |
| D1 | SS14 | SMA | 1 | $0.10 | Motor flyback protection | | U5 | MCP1700-3302E/TT | SOT-23 | 1 | $0.20 |
| D2 | LED (green) | 0805 | 1 | $0.05 | Status indicator | | Q1 | AO3400A | SOT-23 | 1 | $0.15 |
| R1 | 10KΩ | 0805 | 1 | $0.01 | Reset pull-up | | D1 | BAT54S | SOT-23 | 1 | $0.05 |
| R2 | 4.7KΩ | 0805 | 1 | $0.01 | Audio LPF resistor | | D3 | BAT54S | SOT-23 | 1 | $0.05 |
| R3 | 100KΩ | 0805 | 1 | $0.01 | Amp shutdown pull-down | | D4 | SS14 | SMA | 1 | $0.10 |
| R4 | 100Ω | 0805 | 1 | $0.01 | MOSFET gate resistor | | D2 | LED green | 0805 | 1 | $0.05 |
| R5 | 100KΩ | 0805 | 1 | $0.01 | MOSFET gate pull-down | | L1 | 4.7µH inductor | 0805 | 1 | $0.15 |
| R6 | 1KΩ | 0805 | 1 | $0.01 | LED current limit | | R2 | 4.7KΩ | 0805 | 1 | $0.01 |
| C1 | 100µF/10V | Radial 5mm | 1 | $0.15 | Bulk power decoupling | | R3 | 100 | 0805 | 1 | $0.01 |
| C2 | 100nF | 0805 | 1 | $0.01 | MCU VCC bypass | | R4 | 100Ω | 0805 | 1 | $0.01 |
| C3 | 100nF | 0805 | 1 | $0.01 | MCU AVCC/AREF bypass | | R5 | 100 | 0805 | 1 | $0.01 |
| C4 | 100nF | 0805 | 1 | $0.01 | Reset noise filter | | R6 | 1 | 0805 | 1 | $0.01 |
| C5 | 100nF | 0805 | 1 | $0.01 | Flash bypass | | R7,R8 | 5.1KΩ | 0805 | 2 | $0.02 |
| C6 | 1µF | 0805 | 1 | $0.02 | Audio AC coupling | | C1 | 100µF/10V | Radial 5mm | 1 | $0.15 |
| C7 | 10nF | 0805 | 1 | $0.01 | Audio LPF capacitor | | C2 | 100nF | 0805 | 1 | $0.01 |
| C8 | 10µF | 0805 | 1 | $0.05 | Amp supply bypass | | C3 | 10µF | 0805 | 1 | $0.05 |
| SW1-8| Tactile switch | 6mm SMD | 8 | $0.80 | Or reuse existing buttons | | C5 | 100nF | 0805 | 1 | $0.01 |
| SW9 | SPDT slide | THT | 1 | $0.20 | Power switch | | C6 | 1µF | 0805 | 1 | $0.02 |
| J1 | JST-PH 2-pin | THT | 1 | $0.15 | Battery connector | | C7 | 10nF | 0805 | 1 | $0.01 |
| J2 | JST-PH 2-pin | THT | 1 | $0.15 | Speaker connector | | C8 | 10µF | 0805 | 1 | $0.05 |
| J3 | JST-PH 2-pin | THT | 1 | $0.15 | Motor connector | | C9,C10 | 10µF | 0805 | 2 | $0.10 |
| J4 | 2×3 pin header | 2.54mm | 1 | $0.10 | ISP programming | | C11,C12| 1µF | 0805 | 2 | $0.04 |
| J5 | 1×3 pin header | 2.54mm | 1 | $0.05 | Serial debug | | SW1-8 | Tactile switch | 6mm SMD | 8 | $0.80 |
| | AA battery holder| 2×AA | 1 | $0.50 | Reuse existing | | SW9 | SPDT slide | THT | 1 | $0.20 |
| | | | | | | | J1 | JST-PH 2-pin | THT | 1 | $0.15 |
| | **TOTAL** | | |**~$7** | | | 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 ## 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 | **Estimated runtimes on 2×AA alkaline (2500 mAh usable with boost):**
|--------------------|--------|--------|--------|--------|---------|
| Playing + spinning | 4 mA | 4 mA | 3 mA | 80 mA | ~91 mA |
| Playing only | 4 mA | 4 mA | 3 mA | 0 | ~11 mA |
| Idle (awake) | 4 mA | 0.001 | 0.001 | 0 | ~4 mA |
| Deep sleep | 0.0001 | 0.001 | 0.001 | 0 | <0.01mA |
### Estimated runtime on 2× AA Alkaline (2500 mAh): | Mode | Runtime |
|------------------|--------------|
| Mode | Current | Runtime | | Audio + Motor | ~22 hours |
|--------------------|---------|-------------| | Audio only | ~104 hours |
| Audio + Motor | 91 mA | ~27 hours | | BLE standby | ~149 days |
| Audio only | 11 mA | ~227 hours | | Deep sleep | ~28 years |
| Sleep | <10 µA | ~28 years | | 30 min/day use | **~44 days** |
With typical use of 30 min/day (motor + audio), batteries last roughly **54 days**.
With 1 hour/day, roughly **27 days** — well within AA change interval for a toy.
## PCB Layout Guidelines ## 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:** **Recommended for beginners: Seeed XIAO nRF52840.** It plugs into standard
1. Place C2 and C3 as close to U1 pins 4/6 as physically possible 2.54mm headers like an Arduino Nano. USB-C and UF2 bootloader are built in,
2. Place C5 directly adjacent to U2 pin 8 so you never need a programmer. Just drag-and-drop firmware and audio files.
3. Keep SPI traces short and parallel-routed
4. Audio RC filter (R2, C7) close to U3 input
5. Wide traces for motor path (VCC → motor → Q1 drain): 0.5mm minimum
6. Ground pour on bottom layer
7. Thermal relief on U3 pad (pin 6) connected to ground pour
8. Keep battery/motor power traces away from audio section
**Recommended trace widths:** **If using a XIAO or Feather:** you can skip the TPS61220 boost converter,
- Power (VCC, GND, motor): 0.5mm+ MCP1700 LDO, USB-C connector, and CC resistors from the BOM. The dev board
- Signal (SPI, buttons): 0.25mm handles all of that. Feed the boost converter's 3.3V output to the board's
- Audio: 0.25mm (keep short, away from digital noise) 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 ### Upload Audio (USB)
Burn the Arduino bootloader for "ATmega328P 8MHz internal" using the ISP 1. Plug USB-C cable into board
header (J4) and an Arduino-as-ISP or USBasp programmer. 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: ### Upload Audio (Bluetooth)
- Board: "ATmega328P" 1. Open Web Bluetooth page on phone (no app install)
- Clock: "Internal 8 MHz" 2. Connect to "BabyMobile" device
- BOD: "BOD 1.8V" (for low-voltage operation) 3. Select audio files → transfer
4. ~15 min for 30 minutes of audio at BLE speeds
### Loading audio onto W25Q128 ### Update Firmware
Use the serial header (J5) with a USB-serial adapter. The firmware 1. Double-tap reset button (or hold BTN1+BTN2 on power-on)
includes a serial protocol to receive audio data and write it to flash. 2. Board appears as UF2 drive
Alternatively, program the flash chip directly with a CH341A SPI 3. Drag .uf2 firmware file onto drive
programmer before soldering (~$3 on Amazon). 4. Board reboots with new firmware
### Audio format ### No-Programmer Setup
Raw unsigned 8-bit PCM, 8000 Hz sample rate, mono. The MDBT50Q ships with the nRF52840 bootloader ROM. Flash the Adafruit
Convert with ffmpeg: 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
ffmpeg -i input.mp3 -ar 8000 -ac 1 -f u8 -acodec pcm_u8 output.raw are drag-and-drop over USB. The SWD header is only needed once.
```
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)
+41
View File
@@ -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": [
[
"",
""
]
]
}
+815
View File
@@ -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")
)
)
-61
View File
@@ -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": [
[
"",
""
]
]
}
-628
View File
@@ -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")
)
)
-639
View File
@@ -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 <avr/sleep.h>
#include <avr/power.h>
#include <avr/interrupt.h>
#include <SPI.h>
// ---- 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();
}
}
+945
View File
@@ -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 <SPI.h>
#include <Adafruit_TinyUSB.h>
#include <bluefruit.h>
// ============================================================
// 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);
}
+102 -137
View File
@@ -1,16 +1,20 @@
#!/usr/bin/env python3 #!/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: 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. Audio files will be auto-converted to 8kHz/8-bit/unsigned PCM using ffmpeg.
Convert with ffmpeg:
ffmpeg -i song.mp3 -ar 8000 -ac 1 -f u8 -acodec pcm_u8 song.raw
The script writes a track table to sector 0, then audio data starting Track table format (v2):
at sector 1 (address 0x1000). [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 import serial
@@ -21,207 +25,168 @@ import os
import subprocess import subprocess
import shutil import shutil
BAUD = 9600 BAUD = 115200
PAGE_SIZE = 256 PAGE_SIZE = 256
SECTOR_SIZE = 4096 SECTOR_SIZE = 4096
AUDIO_START = 0x1000 AUDIO_START = 0x1000
MAX_TRACKS = 32 MAX_TRACKS = 32
FLASH_SIZE = 16 * 1024 * 1024 # 16MB FLASH_SIZE = 16 * 1024 * 1024
TABLE_MAGIC = 0xBB
ENTRY_SIZE = 12
def open_serial(port): def open_serial(port):
ser = serial.Serial(port, BAUD, timeout=2) ser = serial.Serial(port, BAUD, timeout=2)
time.sleep(2) # wait for Arduino reset time.sleep(2)
# Flush
ser.read(ser.in_waiting) ser.read(ser.in_waiting)
return ser return ser
def flash_identify(ser): def convert_to_raw(input_path):
ser.write(b'I') """Convert any audio file to 8kHz 8-bit unsigned PCM."""
line = ser.readline().decode().strip() if input_path.endswith('.raw'):
print(f" {line}") return input_path
return line
raw_path = input_path + ".raw"
if not shutil.which('ffmpeg'):
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)}...")
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 flash_erase(ser): def build_track_table(tracks):
print(" Erasing entire flash (takes ~40 seconds)...") """Build v2 track table."""
ser.write(b'E') table = bytearray()
line = ser.readline().decode().strip() table.append(TABLE_MAGIC)
while "Done" not in line: table.append(len(tracks))
line = ser.readline().decode().strip() table.extend(b'\x00\x00') # reserved
if line:
print(f" {line}") for start, length in tracks:
print(" Erase complete.") 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 flash_write_page(ser, addr, data): def serial_cmd(ser, cmd):
"""Write up to 256 bytes to flash.""" """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 assert len(data) <= 256
cmd = b'W' ser.write(b'W')
cmd += struct.pack('>I', addr)[1:] # 3 bytes address ser.write(struct.pack('>I', addr)[1:]) # 3-byte addr
cmd += struct.pack('>H', len(data)) ser.write(struct.pack('>H', len(data))) # 2-byte length
ser.write(cmd)
ser.write(data) ser.write(data)
resp = ser.readline().decode().strip() return ser.readline().decode().strip()
return resp
def flash_write_data(ser, start_addr, data, label=""): def serial_write_data(ser, start_addr, data, label=""):
"""Write arbitrary length data, page by page.""" """Write arbitrary-length data, page by page."""
total = len(data) total = len(data)
written = 0 written = 0
addr = start_addr addr = start_addr
while written < total: while written < total:
chunk = data[written:written + PAGE_SIZE] chunk = data[written:written + PAGE_SIZE]
# Pad last page
if len(chunk) < PAGE_SIZE: if len(chunk) < PAGE_SIZE:
chunk = chunk + b'\x80' * (PAGE_SIZE - len(chunk)) # 0x80 = silence chunk = chunk + b'\x80' * (PAGE_SIZE - len(chunk))
flash_write_page(ser, addr, chunk) serial_write_page(ser, addr, chunk)
written += PAGE_SIZE written += PAGE_SIZE
addr += PAGE_SIZE addr += PAGE_SIZE
pct = min(100, written * 100 // total) pct = min(100, written * 100 // total)
print(f"\r Writing {label}: {pct}% ({written}/{total} bytes)", end="", flush=True) print(f"\r Writing {label}: {pct}%", end="", flush=True)
print() 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"
if input_path.endswith('.raw'):
return input_path
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}")
sys.exit(1)
print(f" Converting {os.path.basename(input_path)} to 8kHz/8bit PCM...")
subprocess.run([
'ffmpeg', '-y', '-i', input_path,
'-ar', '8000', '-ac', '1', '-f', 'u8', '-acodec', 'pcm_u8',
raw_path
], capture_output=True)
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
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
def main(): def main():
if len(sys.argv) < 3: if len(sys.argv) < 3:
print("Usage: python3 flash_upload.py <serial_port> <audio_file> [audio_file ...]") print("Usage: python3 flash_upload.py <port> <audio_file> [...]")
print() print(" Supported: .raw .mp3 .wav .ogg .flac .aac")
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")
sys.exit(1) sys.exit(1)
port = sys.argv[1] port = sys.argv[1]
audio_files = sys.argv[2:] audio_files = sys.argv[2:]
if len(audio_files) > MAX_TRACKS: # Convert
print(f"ERROR: Maximum {MAX_TRACKS} tracks supported.") print("=== Preparing audio ===")
sys.exit(1)
# Convert files to raw PCM
print("=== Preparing audio files ===")
raw_files = [] raw_files = []
for f in audio_files: for f in audio_files:
raw = convert_to_raw(f) raw = convert_to_raw(f)
size = os.path.getsize(raw) size = os.path.getsize(raw)
duration = size / 8000 print(f" {os.path.basename(f)}: {size/1024:.0f} KB ({size/8000:.1f}s)")
print(f" {os.path.basename(f)}: {size} bytes ({duration:.1f} seconds)")
raw_files.append(raw) raw_files.append(raw)
# Check total size total = sum(os.path.getsize(f) for f in raw_files)
total_audio = sum(os.path.getsize(f) for f in raw_files) print(f" Total: {total/1024:.0f} KB ({total/8000/60:.1f} min)")
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}%")
# Connect # Connect
print(f"\n=== Connecting to {port} ===") print(f"\n=== Connecting to {port} ===")
ser = open_serial(port) ser = open_serial(port)
flash_identify(ser) print(f" {serial_cmd(ser, 'I')}")
# Erase # Erase
print("\n=== Erasing flash ===") print("\n=== Erasing flash ===")
flash_erase(ser) ser.write(b'E')
while True:
line = ser.readline().decode().strip()
if line: print(f" {line}")
if "Done" in line: break
# Write audio data and build track list # Write tracks
print("\n=== Writing audio ===") print("\n=== Writing audio ===")
tracks = [] tracks = []
addr = AUDIO_START addr = AUDIO_START
for i, raw_path in enumerate(raw_files): for i, raw in enumerate(raw_files):
with open(raw_path, 'rb') as f: with open(raw, 'rb') as f:
data = f.read() data = f.read()
start = addr tracks.append((addr, len(data)))
length = len(data) serial_write_data(ser, addr, data, label=f"Track {i+1}")
tracks.append((start, length))
name = os.path.basename(audio_files[i]) addr += len(data)
addr = flash_write_data(ser, start, data, label=f"Track {i+1} ({name})") # Align to sector
if addr % SECTOR_SIZE:
# Align to sector boundary for clean layout
if addr % SECTOR_SIZE != 0:
addr = ((addr // SECTOR_SIZE) + 1) * SECTOR_SIZE addr = ((addr // SECTOR_SIZE) + 1) * SECTOR_SIZE
# Write track table to sector 0 # Write track table
print("\n=== Writing track table ===") print("\n=== Writing track table ===")
table = build_track_table(tracks) table = build_track_table(tracks)
flash_write_data(ser, 0, table, label="Track table") serial_write_data(ser, 0, table, label="Track table")
# Summary # Summary
print("\n=== Upload complete! ===") print(f"\n=== Done! {len(tracks)} tracks uploaded ===")
print(f" {len(tracks)} tracks written") for i, (s, l) in enumerate(tracks):
for i, (start, length) in enumerate(tracks): print(f" Track {i+1}: 0x{s:06X}, {l/8000:.1f}s")
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 # Cleanup
for raw, orig in zip(raw_files, audio_files): for raw, orig in zip(raw_files, audio_files):
if raw != orig and os.path.exists(raw): if raw != orig and os.path.exists(raw):
os.remove(raw) os.remove(raw)
+439 -500
View File
File diff suppressed because it is too large Load Diff