First QEMU Session
QEMU emulation gives you a virtual ESP32 that behaves like a real device over a serial connection. The Espressif QEMU fork emulates the chip’s ROM bootloader, flash memory, eFuses, and GPIO strapping — enough for esptool to connect, flash firmware, and read back results. No USB cable, no devkit, no wiring.
Every tool in mcesptool that accepts a port parameter works with QEMU socket URIs (socket://localhost:PORT) exactly as it works with physical serial ports.
How it works
Section titled “How it works”When you start a QEMU instance, mcesptool launches the Espressif QEMU fork with a virtual flash image and exposes a TCP socket that speaks the ESP serial bootloader protocol. The returned socket://localhost:PORT URI is a drop-in replacement for /dev/ttyUSB0 in any tool invocation.
Two boot modes are available:
- download — the virtual chip starts in serial bootloader mode (GPIO straps held), ready for esptool commands like flash, read, and chip detect
- normal — the virtual chip boots from its flash image and runs whatever firmware is stored there
Prerequisites
Section titled “Prerequisites”QEMU binaries ship as part of the ESP-IDF toolchain. Install them with:
python3 $IDF_PATH/tools/idf_tools.py install qemu-xtensa qemu-riscv32After installation, activate the tools:
. $IDF_PATH/export.shmcesptool detects QEMU availability automatically at startup. If the binaries are on your PATH, QEMU tools are enabled with no additional configuration.
Walkthrough
Section titled “Walkthrough”-
Start a virtual device in download mode
Create an ESP32 instance with a blank 4 MB flash image, ready for esptool interaction:
esp_qemu_start(chip_type="esp32",flash_size_mb=4,boot_mode="download")The response includes the socket URI and instance ID you will use for subsequent commands:
{"success": true,"instance_id": "qemu-1","chip_type": "esp32","tcp_port": 5555,"socket_uri": "socket://localhost:5555","flash_image": "/path/to/flash_esp32_5555.bin","boot_mode": "download","pid": 12345} -
Detect the virtual chip
Use the socket URI with
esp_detect_chipjust as you would a USB port:esp_detect_chip(port="socket://localhost:5555",detailed=True)The virtual device reports as a real ESP32 with MAC address, flash size, and features. This confirms the QEMU instance is accepting esptool connections.
-
Flash firmware to the virtual device
Write a firmware binary using the same tool as physical hardware:
esp_flash_firmware(firmware_path="/path/to/my_app.bin",port="socket://localhost:5555",address="0x10000")For a complete firmware stack, use
esp_flash_multi:esp_flash_multi(port="socket://localhost:5555",files=[{"address": "0x1000", "path": "bootloader.bin"},{"address": "0x8000", "path": "partitions.bin"},{"address": "0x10000", "path": "my_app.bin"}]) -
Verify the flash contents
Confirm the write was successful:
esp_verify_flash(firmware_path="/path/to/my_app.bin",port="socket://localhost:5555",address="0x10000") -
Stop the instance
Shut down the download-mode instance. The flash image file is preserved on disk:
esp_qemu_stop(instance_id="qemu-1") -
Restart in normal boot mode
Boot the virtual device from flash to run your firmware. Point
flash_imageat the same file that was written to in the previous steps:esp_qemu_start(chip_type="esp32",flash_image="/path/to/flash_esp32_5555.bin",boot_mode="normal")The device now boots from flash and executes the firmware you flashed in step 3.
-
Clean up
When you are finished, stop all running instances:
esp_qemu_stop()Calling
esp_qemu_stopwith noinstance_idstops every running QEMU instance. Flash image files remain on disk for future sessions.
Supported chip types
Section titled “Supported chip types”| Chip | Architecture | QEMU Machine | Status |
|---|---|---|---|
| ESP32 | Xtensa | esp32 | Supported |
| ESP32-S3 | Xtensa | esp32s3 | Supported |
| ESP32-C3 | RISC-V | esp32c3 | Supported |
| ESP32-S2 | Xtensa | — | Not supported |
Managing multiple instances
Section titled “Managing multiple instances”mcesptool can run several QEMU instances in parallel, each on its own TCP port. Use esp_qemu_list to see all instances and their status:
esp_qemu_list(){ "success": true, "instances": [ { "instance_id": "qemu-1", "chip_type": "esp32", "tcp_port": 5555, "socket_uri": "socket://localhost:5555", "running": true, "uptime_seconds": 142.3 }, { "instance_id": "qemu-2", "chip_type": "esp32c3", "tcp_port": 5556, "socket_uri": "socket://localhost:5556", "running": true, "uptime_seconds": 87.1 } ], "total": 2, "running": 2, "max_instances": 4}For detailed status on a specific instance including PID, flash image path, and boot mode:
esp_qemu_status(instance_id="qemu-1")Next steps
Section titled “Next steps”- First Flash — the same workflow applied to physical hardware
- QEMU Manager Reference — full documentation for all QEMU tools
- Chip Control Reference — detection, scanning, and reset tools