# ESP32-PICO-D4 (M5Stack Atom Lite) Port — Design Spec > **Goal:** Port the Sylvia Touch Relay project from ESP32-S3-Pico (Atom VoiceS3R) to ESP32-PICO-D4 (Atom Lite), update the Android app for CDC-class USB detection, compile, bundle, and deploy via ADB wireless. ## Current State The project targets the M5Stack Atom VoiceS3R with ESP32-S3-PICO-1-N8R8 (8MB Flash, 8MB PSRAM). The Android app filters USB devices by Espressif vendor ID (`0x303A`) for key exchange and firmware flashing. The `esp32-flash-lib` handles DTR/RTS via the `SerialTransport` interface implemented by `UsbSerialTransport`. ## Target Hardware M5Stack Atom Lite with ESP32-PICO-D4: - 4MB Flash (no PSRAM) - FTDI FT2232C/D USB-to-UART bridge (VID `0x0403`) — appears as `/dev/ttyUSB0` - SK6812 addressable RGB LED on GPIO27 - Relay on GPIO32 (G32) - Touch sensor on GPIO33 (G33) — open-drain type, needs pullup ## Design Decisions ### 1. Side Branch & Git Worktree Create branch `esp32picod4` via git worktree at `.worktrees/esp32picod4` to isolate the port from the main S3 variant. ### 2. Firmware (`platformio.ini` + `src/main.cpp`) **New PlatformIO environment `m5stack-atom`:** | Setting | Old (S3) | New (PICO-D4) | Reason | |---------|----------|---------------|--------| | `board` | `esp32-s3-devkitc-1` | `m5stack-atom` | PlatformIO board ID for M5Stack Atom Lite | | `board_build.arduino.memory_type` | `qio_opi` | removed | Not needed for PICO-D4 | | `-DESP32S3` | present | `-DESP32` | Correct chip family | | `-DBOARD_HAS_PSRAM` | present | removed | Atom Lite has no PSRAM | | `-mfix-esp32-psram-cache-issue` | present | removed | Only needed with PSRAM | | `-DARDUINO_USB_CDC_ON_BOOT=1` | present | removed | No native USB on PICO-D4 | | `-DARDUINO_USB_MODE=1` | present | removed | No native USB | | `upload_port` | `/dev/ttyACM0` | `/dev/ttyUSB0` | FTDI serial device | | `lib_deps` | (empty) | `fastled/FastLED@^3.7` | SK6812 Neopixel library | **Pin definitions:** | Constant | Old | New | Notes | |----------|-----|-----|-------| | `SENSOR_PIN` | 38 | 33 | G33, open-drain, `INPUT_PULLUP` unchanged | | `RELAY_PIN` | 1 | 32 | G32 | | `LED_PIN` | 27 | 27 | SK6812 Neopixel — replaces `digitalWrite` with FastLED API | **BLE device name:** `"SyldaServer"` (was `"AtomS3R-Relay"`) **Serial banner:** `"Atom Lite BLE Relay"` (was `"Atom VoiceS3R BLE Relay"`) **LED code change:** Replace `digitalWrite(LED_PIN, HIGH/LOW)` with FastLED: - Include `FastLED.h` - Define `#define NUM_LEDS 1` - `CRGB leds[NUM_LEDS]` - `FastLED.addLeds(leds, NUM_LEDS)` in setup - Startup blink: 3x green (`leds[0] = CRGB::Green; FastLED.show()`) No other firmware logic changes — HMAC key exchange, BLE relay control, touch sensor logic remain identical. ### 3. Android USB Detection **Problem:** The Atom Lite's FTDI bridge presents VID `0x0403`, not Espressif's `0x303A`. The app currently filters on VID and won't detect the device. **Solution:** Replace VID (`0x303A`) filtering with CDC-ACM class filtering (interface class `0x0A`). **Changes in `UsbUtils.kt`:** - Add `hasCdcDataInterface(device: UsbDevice): Boolean` — iterates interfaces, returns true if any has `interfaceClass == 0x0A` **Changes in `SettingsActivity.kt`:** - Remove `ESP_VENDOR_ID` constant - Replace all `device?.vendorId == ESP_VENDOR_ID` checks with `UsbUtils.hasCdcDataInterface(device)` This detects all CDC-ACM serial devices including: - FTDI FT2232C/D (Atom Lite) - CP210x (some Atom Lite revisions) - ESP32-S3 native USB (current hardware) - CH340/CH9102 (other Atom variants) ### 4. DTR/RTS — No Changes Needed **Research findings:** The `esp32-flash-lib`'s `EspFlasherProtocol.enterBootLoader()` implements the standard DTR/RTS download-mode sequence: ``` setControlLines(true, false) // DTR=High → EN released, RTS=Low → GPIO0=Low (download mode) delayMS(100) setControlLines(false, true) // DTR=Low → reset pulse via capacitor, RTS=High → GPIO0=High delayMS(100) setControlLines(true, false) // DTR=High → release reset, RTS=Low → GPIO0=Low → boot in download mode ``` The `UsbSerialTransport.setControlLines()` implementation sends `CDC_SET_CONTROL_LINE_STATE` control transfers with correct DTR/RTS bit flags. This works for FTDI, CP2104, and native USB CDC-ACM. The `SettingsActivity.setupCdcControl()` sets DTR|RTS both HIGH for normal serial operation (key exchange), which is correct for all bridge types. **Verdict: No changes to `EspFlasher.kt`, `UsbSerialTransport.kt`, or key exchange logic.** ### 5. Build, Bundle & Deploy 1. `pio run -e m5stack-atom` to compile firmware 2. `tools/copy_firmware.sh` to copy binaries to `android/app/src/main/assets/firmware/` (environment dir is now `m5stack-atom`) 3. `./gradlew assembleDebug` in `android/` to build APK 4. ADB wireless to connect phone (`adb-wireless` skill) 5. `adb install -r app-debug.apk` to deploy ## Files Changed | File | Change | |------|--------| | `platformio.ini` | New environment `m5stack-atom` replacing S3 config | | `src/main.cpp` | New pin definitions, BLE name, FastLED LED code | | `android/.../UsbUtils.kt` | Add `hasCdcDataInterface()` | | `android/.../SettingsActivity.kt` | VID filter → CDC class filter | | `tools/copy_firmware.sh` | Environment name `m5stack-atoms3r` → `m5stack-atom` | ## Files Not Changed | File | Reason | |------|--------| | `EspFlasher.kt` | DTR/RTS handled by library | | `UsbSerialTransport.kt` | Correct implementation | | `MainActivity.kt` | No BLE changes beyond device name (auto-discovered) | | `PrefsHelper.kt` | No changes | | `AndroidManifest.xml` | No changes | | `build.gradle` | No dependency changes |