5.5 KiB
ESP32-PICO-D4 (M5Stack Atom Lite) Port — Design Spec
Goal: Port the Sylvia Touch Relay project from ESP32-S3-Pico (Atom S3 Lite) 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 S3 Lite (ESP32-S3). 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: "SylDa_Server" (was "SyldaServer")
Serial banner: "Atom Lite BLE Relay" (was "SylDa 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<SK6812, LED_PIN, GRB>(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 hasinterfaceClass == 0x0A
Changes in SettingsActivity.kt:
- Remove
ESP_VENDOR_IDconstant - Replace all
device?.vendorId == ESP_VENDOR_IDchecks withUsbUtils.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
pio run -e m5stack-atomto compile firmwaretools/copy_firmware.shto copy binaries toandroid/app/src/main/assets/firmware/(environment dir is nowm5stack-atom)./gradlew assembleDebuginandroid/to build APK- ADB wireless to connect phone (
adb-wirelessskill) adb install -r app-debug.apkto 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 → s3lite-server |
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 |