Minimal reproduction of a bug where a TinyGo sketch that writes to
machine.Serial produces no output on /dev/cu.usbmodem* when flashed
to a Seeed XIAO ESP32-C3 on macOS, while functionally-identical Arduino
and MicroPython sketches on the same board and cable work fine.
| Component | Version |
|---|---|
| Hardware | Seeed XIAO ESP32-C3 |
| Host | macOS 15.7.4, Apple Silicon (M1) |
| Go | 1.26.5 darwin/arm64 |
| TinyGo | 0.41.1 (also tested 0.41.0 — same silent behavior) |
| arduino-cli | 1.5.1 |
| esp32:esp32 core | 3.3.11 |
| MicroPython | v1.28.0 (2026-04-06) ESP32_GENERIC_C3 |
| mpremote | 1.28.0 |
brew install tinygo arduino-cli
arduino-cli config init
arduino-cli config add board_manager.additional_urls \
https://espressif.github.io/arduino-esp32/package_esp32_index.json
arduino-cli core update-index
arduino-cli core install esp32:esp32Plug the XIAO ESP32-C3 into USB. Confirm the port appears:
ls /dev/cu.usbmodem*make flash-arduino
make monitorExpected AND actual output:
tick 0
tick 1
tick 2
...
make flash-tinygo
make monitorExpected output:
boot
tick 0
tick 1
tick 2
...
Actual output: nothing — silent for the full 15-second monitor window.
Extra prereqs:
pip install mpremote # or: brew install mpremoteDownload the ESP32_GENERIC_C3 firmware .bin from
https://micropython.org/download/ESP32_GENERIC_C3/ and drop it into
micropython/firmware/. Then:
make flash-micropython-firmware # one-time: erase + install MicroPython
make flash-micropython # upload micropython/main.py and reset
make monitorExpected AND actual output (the board's REPL auto-runs main.py at boot):
boot
tick 0
tick 1
tick 2
...
Same board, same cable, same /dev/cu.usbmodem* — MicroPython prints
immediately, so USB-CDC on this hardware/host works and the silence is
isolated to TinyGo.
- Flash completes successfully in both cases (esptool verify passes; MD5 matches).
- USB-CDC is enabled in both cases:
- Arduino: the default XIAO_ESP32C3 board profile has
USBMode=hwcdc, CDCOnBoot=cdc. - TinyGo:
"serial": "usb"is set intargets/esp32c3.json, inherited byxiao-esp32c3.json.machine.Serialmaps to USB-CDC.
- Arduino: the default XIAO_ESP32C3 board profile has
- The failure also reproduces with TinyGo's own
src/examples/echo/echo.gosketch — not specific to the code in this repro. - Physical USB unplug/replug (including switching USB ports on the Mac) does not recover output for the TinyGo case.
- Both TinyGo 0.41.0 and 0.41.1 are silent. Older TinyGo (0.40.x)
cannot be tested against Go 1.26 (
cannot compile with Go toolchain version go1.26). - The chip itself is fine: switching to the Arduino sketch on the same
cable/port/board prints as expected within seconds of
make flash-arduino. - MicroPython v1.28.0 (
ESP32_GENERIC_C3) also printstick Ncorrectly over the same USB-CDC endpoint — two independent stacks (Arduino, MicroPython) work; only TinyGo is silent.
Both sketches do the same thing — print tick N over serial once per second.
arduino/arduino.ino— 8 lines of C++.tinygo/main.go— modeled after$(brew --prefix tinygo)/src/examples/echo/echo.go.micropython/main.py— sametick Nloop in Python (second control).
.
├── Makefile Targets: flash-arduino / flash-tinygo / flash-micropython[-firmware] / monitor / clean
├── README.md This file
├── arduino/
│ └── arduino.ino Arduino sketch (control)
├── tinygo/
│ ├── go.mod
│ └── main.go TinyGo sketch (bug)
└── micropython/
├── main.py MicroPython sketch (second control)
└── firmware/ Drop ESP32_GENERIC_C3 .bin here (gitignored)