If you own a LilyGo T-Watch-S3 (2022 version) and you ever run the official “Factory Test” example from the LilyGo libraries… congratulations, you just discovered one of the most common (and frustrating) ESP32-S3 traps in 2025.

The Hardware & Software I Was Using

  • LilyGo T-Watch-S3 (2022) – ESP32-S3 with 16 MB flash + 8 MB PSRAM
  • Arduino IDE 1.8.19 (yes, the old one – this actually makes the problem worse)
  • ESP32 board package inside Arduino: the old LilyGo fork (esp-x32 2411)
  • TFT_eSPI + LilyGo libraries from their GitHub examples
  • Windows 10

What Happened – The Soft-Brick Explained

The factory demo sketch enables native USB (TinyUSB) on the ESP32-S3.
That instantly disables the normal USB-to-UART bridge (CP210x/CH910x) you had when the watch was new.
Result:

  • No more COM port when you plug it in
  • Windows shows “The last USB device you connected malfunctioned” or “Unknown device”
  • Arduino IDE can’t upload anything → you’re stuck
    Thousands of users think the watch is dead. It’s not – it’s just in native-USB purgatory.

The Recovery Path That Actually Worked (After Days1 of Pain)

  1. Force bootloader mode
  2. Hold the tiny BOOT button on the back → plug USB → keep holding for 10-12 seconds → release.
  3. Sometimes a COM port (COM10 in my case) appears for 20-30 seconds.Lower upload speed to 115200 (921600 almost always times out in this state).The magic half-step: manual erase via esptool
  4. This was the turning point. Even when Arduino kept failing, this command always connected and erased the flash:
  5. esptool.py --chip esp32s3 --port COM10 --baud 57600 erase_flash
  6. (At 57600 baud it finally worked without timeout. The erase takes ~90 seconds.)
  7. Immediate Arduino upload right after erase
  8. Board: LilyGo T-Watch-S3
  9. Erase All Flash: Enabled (first time only)
  10. Upload Speed: 115200
  11. Sketch: any tiny one, e.g.
    void setup() { Serial.begin(115200); } void loop() { Serial.println("I’m alive again!"); delay(1000); }

    The first upload often “drops” at 80-90 % with “Write timeout” – this is normal.
  12. The bootloader, partition table and most of the app were already written.
  13. One final normal upload (no erase this time)
  14. Hold BOOT → plug → hold 10 s → upload again.
  15. This time it finishes 100 % in ~3 seconds with “Hard resetting via RTS pin… Done”.

The Happy EndingAfter that second successful upload:

  • Normal COM port appears every single time I plug the watch in
  • No more boot button gymnastics
  • Uploads work at 921600 again
  • Serial Monitor shows my victory messages

TL;DR – The Exact Commands That Saved My Watch

:: 1. Get into bootloader (hold BOOT 10-12 s while plugging)
:: 2. Erase everything (this breaks the native-USB curse)
esptool.py --chip esp32s3 --port COM10 --baud 57600 erase_flash

:: 3. Immediately upload once with Arduino IDE (115200 baud, erase enabled)
:: 4. Upload a second time normally → done forever

If you ever see “device malfunctioned” on your T-Watch-S3 after running the factory example, don’t panic and don’t throw it away. Just follow the steps above – especially the low-baud esptool erase – and you’ll be back in business in under 10 minutes.Hope this saves someone else the 26+ hours of head-scratching I went through! 😅— Edu (November 2025)