# Print and Play Atlas — Build & Flash Guide

**Target hardware:** Waveshare ESP32-S3 Mini (ESP32-S3FH4R2)
**Firmware version:** v5.19.1
**Board variant:** `ATLAS_BOARD_S3` (set in source)

Copyright (c) 2026 Print and Play Creative Manufacturing
162 Locke Street South, Hamilton, Ontario, Canada
https://printandplay.ca

This guide covers everything needed to flash and assemble one Atlas unit.
Time estimate: ~45 min per unit once you've done the first one.

---

## Bill of Materials (per unit)

| Component | Quantity | Notes |
|---|---|---|
| Waveshare ESP32-S3 Mini | 1 | ESP32-S3FH4R2, 4MB flash, 2MB PSRAM |
| 1.3" SH1106 OLED, I²C, 128×64 | 1 | Address 0x3C |
| KY-040 rotary encoder | 1 | With press-to-click switch |
| WS2812B LED strip | 3 LEDs | Or single LEDs wired in series |
| 1S Li-ion 18650 OR LiPo pouch | 1 | 800–2000 mAh, with built-in protection |
| TP4056 charging module | 1 | Blue board with DW01 + FS8205A protection ICs |
| 100 kΩ resistors | 2 | For battery voltage divider |
| 470 Ω resistor (optional) | 1 | In-line on LED data line for noise immunity |
| Hookup wire / WAGO connectors | as needed | For tidy joints |
| USB-C cable | 1 | For programming and charging |
| 3D-printed enclosure | 1 | Per your design |

---

## Pin Wiring (Waveshare ESP32-S3 Mini)

All pins documented in source under `#ifdef ATLAS_BOARD_S3`.

| Function | S3 GPIO | Connect to |
|---|---|---|
| OLED SDA | GPIO 8 | OLED SDA pin |
| OLED SCL | GPIO 9 | OLED SCL pin |
| OLED VCC | 3V3 | OLED VCC pin |
| OLED GND | GND | OLED GND pin |
| Encoder CLK | GPIO 4 | KY-040 CLK |
| Encoder DT | GPIO 5 | KY-040 DT |
| Encoder SW | GPIO 6 | KY-040 SW (press button) |
| Encoder + | 3V3 | KY-040 + |
| Encoder GND | GND | KY-040 GND |
| LED data | GPIO 10 | WS2812 DIN |
| LED 5V | 5V | WS2812 5V |
| LED GND | GND | WS2812 GND |
| Battery sense | GPIO 1 | Voltage divider midpoint |

### Battery wiring

```
TP4056 B+ ────[ 100k ]──┬──[ 100k ]──── GND
                        │
                        └──> S3 GPIO 1 (battery sense)

TP4056 B+   ──> Battery RED wire (positive)
TP4056 B-   ──> Battery BLACK wire (negative)
TP4056 OUT+ ──> Waveshare S3 Mini 5V pin
TP4056 OUT- ──> Waveshare S3 Mini GND
```

**CRITICAL: verify battery polarity with multimeter before connecting.**
Reverse polarity into a TP4056 destroys the chip instantly. Red = positive,
Black = negative on every battery this firmware supports.

### Optional: 470 Ω resistor on LED data line

Place a 470 Ω resistor in series between GPIO 10 and the WS2812 DIN pin.
This dampens reflections on the data line and prevents corrupted color
data on longer runs. Not strictly required for 3 LEDs sitting near the
board, but cheap insurance.

---

## Arduino IDE Setup

### Install board support

1. Open Arduino IDE
2. Tools → Board → Boards Manager
3. Search "esp32" → install **"esp32 by Espressif Systems"** (latest stable)

### Install required libraries

Sketch → Include Library → Manage Libraries, install:

- **Adafruit GFX Library**
- **Adafruit SH110X**
- **Adafruit BusIO** (auto-installed as dependency)
- **ESP32Encoder** by Kevin Harrington (madhephaestus)
- **FastLED**

### Board settings (Tools menu)

| Setting | Value |
|---|---|
| Board | **ESP32S3 Dev Module** |
| USB CDC On Boot | **Enabled** |
| CPU Frequency | 240 MHz |
| Flash Mode | QIO |
| Flash Size | **4 MB (32Mb)** |
| Partition Scheme | **Huge APP (3MB No OTA/1MB SPIFFS)** |
| PSRAM | **OPI PSRAM** |
| Upload Speed | 921600 |
| USB Mode | Hardware CDC and JTAG |

**The "Huge APP" partition is non-negotiable.** Default 4MB partition gives
only ~1.4MB for the app, and Atlas is right at that line. Wrong scheme =
"sketch too big" error at flash time.

**The "ESP32S3 Dev Module" board selection is non-negotiable.** Selecting
"ESP32 Dev Module" while flashing the S3 produces FastLED pin-validity
errors (static_assert failed: invalid pin) that look like hardware faults
but are board-selection issues.

---

## Flashing

1. Plug the Waveshare S3 Mini into your computer with USB-C
2. Tools → Port → select the new COM/tty port that appeared
3. Open `atlas_v5_19_1.ino`
4. Verify the source has `#define ATLAS_BOARD_S3` uncommented (line ~1455)
5. Click Upload

If upload fails with "no serial data received":
- Hold BOOT button on the board while pressing RESET, release RESET, then BOOT
- Try a different USB-C cable (some are charge-only)
- Lower upload speed to 460800

After successful flash, the board reboots and Atlas runs immediately.
The OLED should show the boot splash within 2 seconds.

---

## Initial Smoke Test

After first flash, verify each subsystem before assembly:

1. **Boot message** — open Serial Monitor at 115200 baud, hit reset; should
   see `Print and Play Atlas v5.19.1` print
2. **OLED** — boot splash visible, then face mode loads
3. **Encoder rotation** — turn the dial; menu items should highlight in
   sequence
4. **Encoder direction** — CW should move "back/up", CCW "forward/down"
   (if reversed, swap CLK and DT wires physically)
5. **Encoder click** — short press = enter mode, long press = back to menu
6. **LEDs** — enter Flashlight mode from menu; on White effect all 3 LEDs
   should light bright white
7. **Battery sense** — go to About → Battery; should show a voltage between
   3.0–4.2 V if cell is connected, or "not connected" if divider unwired
8. **Plug detection** — plug/unplug USB while watching About → Battery;
   should flip between "on USB" and "on battery" (may take ~20s after a
   state change as the trend ring fills)

If any step fails, check the wiring against the pin table above.

---

## Per-Unit Calibration

None required. The firmware self-calibrates the battery reading via the
1:1 voltage divider math.

---

## Operating Characteristics

- **Boot time**: ~1.5 sec from power-on to face animation
- **Active current (typical)**: ~80 mA
- **Active current (LEDs full white)**: ~250 mA
- **Idle current (face dim)**: ~40 mA
- **Expected runtime on 1000 mAh battery (typical use)**: ~10 hours
- **Expected runtime on 2000 mAh battery (typical use)**: ~20 hours
- **Charge time on TP4056 (1000 mAh, default 1A rate)**: ~1 hour
- **Charge time on TP4056 (2000 mAh, default 1A rate)**: ~2 hours

---

## Battery Compatibility

The firmware works with any **1S 3.7V Li-ion or LiPo cell** (3.0–4.2V range).
Common options:

| Battery type | Form factor | Capacity range | Notes |
|---|---|---|---|
| 18650 cell | Cylindrical 65×18mm | 2000–3500 mAh | Cheapest per mAh, requires holder |
| LiPo pouch | Flat, various sizes | 500–3000 mAh | Slimmer enclosures, JST connector |
| Round LiPo | Coin-shape | 100–500 mAh | For tiny enclosures, short runtime |

**Always use cells with built-in protection PCBs** (most LiPo pouches and
quality 18650s have them). The TP4056 module's protection (DW01 + FS8205A)
is a backup, not a primary safety net.

---

## Troubleshooting

**OLED stays black after boot:**
- Check SDA/SCL not swapped
- Confirm 3.3V power to OLED, not 5V
- Try address 0x3D instead of 0x3C if OLED has ADDR jumper soldered
  differently (modify SCREEN_ADDR in source)

**Encoder turns but nothing happens:**
- CLK and DT may be swapped — try swapping wires (most common cause)
- Some KY-040 modules need external pullups on CLK/DT — internal
  pullups in firmware should handle this on the S3, but if not,
  add 10kΩ pullups from CLK and DT to 3.3V

**Encoder direction reversed:**
- Different KY-040 clones wire A/B in opposite phase
- Quickest fix: swap the wires going to GPIO 4 and GPIO 5 physically

**LEDs not lighting:**
- Confirm board selected is "ESP32S3 Dev Module" (NOT "ESP32 Dev Module")
  — wrong board causes silent pin remapping
- Confirm LED_PIN is GPIO 10 in source (line ~1429)
- Check WS2812 strip arrows: data flows in arrow direction; your wire
  goes to the side WITHOUT the arrow pointing at it
- Verify common ground between LED strip GND and S3 Mini GND
- Try the 470Ω in-line resistor if data line is corrupted

**LEDs flicker or wrong colors:**
- WS2812 timing-sensitive; ensure GPIO 10 isn't being shared with
  another peripheral
- Check 5V supply has enough current capacity for LED count

**"Not connected" battery message persists:**
- Check both 100kΩ resistors actually soldered
- Verify GPIO 1 connection at the divider midpoint
- Check TP4056 OUT+ has voltage (battery side reading correct)

**Plug detection doesn't flip when USB plugged in:**
- This is partly expected — the firmware infers plug state from voltage
  trend over ~20s, so wait that long
- Voltage > 4.15V triggers immediate "on USB" detection
- Below that, the trend ring needs to see voltage rising before flipping

**Random reboots under load:**
- Power supply insufficient; check USB-C cable can deliver 1A+
- Lower LED brightness in firmware (LED master brightness in
  flashlight mode is user-adjustable in-mode)

---

## Updating Firmware

When new versions are released:

1. Pull the latest `atlas_vX.Y.Z.ino` file
2. Verify `#define ATLAS_BOARD_S3` is uncommented at top of file
3. Confirm Tools → Board is "ESP32S3 Dev Module"
4. Flash with same Arduino IDE settings as above

User-facing settings (favorite mode, name, etc.) are not preserved
across flashes since Atlas doesn't persist state to flash. Each unit
boots fresh into Atlas mode.

---

## Version History

- **v5.19.1** — Quotes author-aware shuffle; Pip Check action removed;
  racing oil-slick now a temporary slow; splash-skip goes to menu;
  battery percent recalibrated (3.0V=0%, 3.8V=100%) with menu % readout
- **v5.19.0** — Bug-fix + polish batch (12 fixes): skippable splash,
  trivia dedup root-fix + explanation spacing, stopwatch 99:59 freeze +
  persistence, quote sequence buffer, flashlight single-LED low mode,
  math overflow fix, snake border, racing lane-line + sprite fixes,
  Pip crush renderer fix
- **v5.18.8** — Companion tooling: flash_atlas.bat, flash_atlas.py,
  and ATLAS_AI_DEV_PRIMER.md added (no firmware code changes)
- **v5.18.7** — Stack dial direction reverted (rotation stays CW)
- **v5.18.6** — Compile-error fix: 66 trivia entries had a malformed
  trailing comma from v5.18.4 rewrites; all 1043 entries now correct
- **v5.18.5** — Stack portrait rotation flipped from CCW to CW
  (now user holds Atlas tilted CCW to read Stack); dial direction
  flipped accordingly
- **v5.18.4** — Major trivia quality pass: eliminated 72 ambiguous
  "Both"/"All these" answer options; lengthened 96 terse questions
- **v5.18.3** — Bingo line celebration animation; stronger same-card
  duplicate prevention; About updated to May 2026
- **v5.18.2** — Pet adult now renders as Movie robot for polished
  walk/stand/dance/turn animations
- **v5.18.1** — Polish pass: pet adult uses Movie robot visual style;
  trivia disambiguation (4 ambiguous questions fixed); trivia session
  persistence across menu trips; Morse silly messages replaced with
  useful ones
- **v5.18.0** — SHIPPING BUILD. NOUNS pool restored to 755 (was 485
  after grammar cleanup); 270 new singular nouns in BMO/cottagecore
  voice. Pre-existing duplicates and cross-pool collisions cleaned up.
- **v5.17.3** — Grammar pass: NOUNS pool cleaned of plural items,
  smart a/an handling extended to adjectives, About hardware line
  updated to LiPo
- **v5.17.2** — Documentation pass: file header refreshed, copyright
  updated to "Print and Play Creative Manufacturing 2026", Arduino
  IDE settings documented inline, build guide synced
- **v5.17.1** — LED pin moved from GPIO 7 to GPIO 10 (more resilient
  against board-selection mistakes)
- **v5.17.0** — Dual-board support (ATLAS_BOARD_CLASSIC / ATLAS_BOARD_S3)
- **v5.16.6** — Battery: single source of truth for "connected" check
- **v5.16.5** — Pip rebuild printer cropped to left half
- **v5.16.4** — Trivia: 96-slot recent-question ring, no repeats
  within or between cards
- **v5.16.3** — "Card Lost" two-line big text rendering
- **v5.16.2** — "BLOCKED" → "Card Lost"
- **v5.16.1** — 479 trivia questions rephrased to natural form
- **v5.16.0** — Battery: voltage display + plug-in inference
  (replaces inaccurate percentage gauge)

---

Copyright (c) 2026 Print and Play Creative Manufacturing
