Hacker News 中文摘要

RSS订阅

Show HN: Esp32sim – Run ESP32 firmware in the browser

esp32sim(esp32sim)是一款用 Rust 编写的 ESP32 芯片(ESP32)模拟器,对四款 ESP32 芯片(ESP32)做指令级模拟,覆盖乐鑫(Espressif)的两种 CPU 架构:ESP32 与 ESP32-S3(ESP32-S3)采用 Xtensa 架构(Xtensa),ESP32-C3(ESP32-C3)与 ESP32-C6(ESP32-C6)采用 RISC-V 架构(RISC-V)。它会启动真实的掩膜 ROM、真实的二级 bootloader 和未修改的应用镜像,无补丁固件与桩代码,且 SoC 建模足以端到端运行真实项目;无需云和账号,采用 MIT 许可。经典 ESP32 芯片(ESP32)还在双 LX6(LX6)核心上启动 ECO3 ROM,提供 GPIO、UART 与定时器,而 --board ttgo-tdisplay 会加入 LilyGO TTGO T-Display(LilyGO TTGO T-Display)的 ST7789(ST7789)与按键。

正文

esp32sim —— 一个用 Rust 编写的 ESP32 模拟器:Xtensa(ESP32、S3)和 RISC-V(C3、C6)

它对四款 ESP32 SoC 进行指令级模拟,覆盖 Espressif 的两种 CPU 架构。每一款都启动真实的 mask ROM、真实的第二阶段 bootloader 以及未修改的应用镜像,不需要打补丁的固件,也没有 stub 挡路;模拟器建模了足够的 SoC,能够端到端运行真实项目。无需云,无需账号。MIT 许可。

经典 ESP32 也在双 LX6 核上启动其 ECO3 ROM,支持 GPIO、UART 和定时器;--board ttgo-tdisplay 会增加 LilyGO TTGO T-Display 的 ST7789 和按钮。

| | ESP32-S3 | ESP32-C3 | ESP32-C6 | | --- | --- | --- | --- | | CPU | 2 × Xtensa LX7 @ 240 MHz | 1 × RISC-V RV32IMC @ 160 MHz | 1 × RISC-V RV32IMAC @ 160 MHz | | 命令 | esp32sim | esp32sim-c3 | esp32sim-c6 | | 核心 crate | xtensa-lx7 | riscv-rv32 | riscv-rv32(+ A 扩展) | | 报告的完整反汇编解码器检查 | 977 k 条指令,0 处不匹配 | 161 k 条指令,0 处不匹配 | 126 k 条指令,0 处不匹配 | | 启动流程 | ROM → bootloader → FreeRTOS → app | ROM → bootloader → FreeRTOS → app | ROM → bootloader → FreeRTOS → app | | 开发板 / 显示屏 | ST7735、ST7701S 480×480 + 触摸、WS2812、摄像头、音频 | 无——仅控制台 | ST7789 172×320(SPI+DMA)、WS2812、802.15.4 能量检测替代 | | WiFi | 虚拟 AP、WPA2、DHCP/DNS/NTP、NAT 到真实网络、HTTPS | 相同的虚拟 AP 和网络:扫描、WPA2、DHCP、NAT(一个 station) | 相同的虚拟 AP 和网络:扫描、WPA2、DHCP、NAT(一个 station,legacy 速率) | | 速度 | 块解释器 + AArch64 JIT,约 150–240 Minsn/s | 普通解释器(尚无块缓存或 JIT)——在 hello_world 上仍远高于实时 | 同解释器 | | 浏览器中 | 是(WebAssembly) | 是(WebAssembly) | 是(WebAssembly) | | 报告的真实硬件对比 | JTAG 跟踪,时序循环重新同步后 8000 步 | 控制台 diff,205/208 行相同 | 控制台 diff,203/204 行相同 | | 状态 | 成熟 | 草稿——见 docs/esp32c3.md | 草稿——见 docs/esp32c6.md |

上述完整反汇编和硬件计数描述的是早期的手工运行。CI 运行已签入的采样解码器语料和模拟器 golden 输出,不包含外部的完整反汇编测试。Xtensa objdump 测试排除 PIE 操作数比较。硬件跟踪比较会对窗口异常做归一化,并重新同步延迟循环,因此并非不间断的逐周期一致。参见测试范围、CI 工作流、Xtensa 解码器测试和硬件比较器。

大部分 SoC 是共享的:C3 原样复用 S3 的 UART、USB-Serial/JTAG、systimer、定时器组、GPIO、SPI flash 控制器、GDMA 以及 SHA/AES/RSA 模型,并加入自己的内存映射、缓存控制器和中断矩阵;C6 再次复用同样的模型,另有自己的内存映射、PLIC 前端、L1 缓存、PCR 和常开的 LP 模块。真正独立的只有 CPU crate。

无需安装即可在浏览器中试用:https://mikroverk.github.io/esp32sim/ —— S3 上的 Linux、带 SID 播放器的 Touch-LCD-4B 面板、pocket-tank LLM 水族箱,以及 C3 和 C6 演示。

  • esp32sim/
    • emu-core/:Bus 和 Core trait、Trap、ClockTree、AArch64 编码器——两个核心共享
    • esp-soc/:Machine:调度器、设备时间、控制台、脚本、Web UI、加载器、开发板——每种芯片一个机器;芯片插入自己的核心、总线和中断路由;每种芯片的虚拟 WiFi 接入点、其背后的网络以及 NAT
    • esp-periph/:各芯片共享的外设 IP(UART、systimer、TIMG、GPIO、SPIMEM、GDMA、crypto、I2S、RMT、I2C 等)、Device trait,以及挂载它们的 deviceset! 表
    • ESP32-S3(Xtensa LX7,双核)
      • xtensa-lx7/:解码器(采样 objdump 检查以及可选完整反汇编)、解释器(窗口寄存器、循环、XEA2 异常/中断、FPU、MAC16、booleans、PIE SIMD)、基本块解释器、AArch64 JIT、兼容 objdump 的反汇编器
      • esp32s3/:SoC + 开发板:内存映射、缓存 MMU、SPI flash/PSRAM、SHA/AES/RSA、RNG、systimer、定时器组、中断矩阵(每核)、GPIO、USB-CDC、UART、I2C、GDMA + I2S/LCDCAM、RMT TX、regi2c、RTC WDT、WiFi MAC;board/:atech14 / waveshare-cam / waveshare-lcd4b / waveshare-amoled18-v2 / none
      • cli/:命令行 esp32sim,支持每种芯片(--chip);esp32sim-c3 / esp32sim-c6 是别名二进制
    • ESP32-C3 与 ESP32-C6(RISC-V,单核)
      • riscv-rv32/:RV32IMAC 解码器(采样 objdump 检查)、解释器、反汇编器
      • esp32c3/:C3 SoC:内存映射、中断矩阵、缓存控制器、RNG;与 esp32s3 共享 IP 相同的外设模型
      • esp32c6/:C6 SoC:统一内存映射和 MMU、中断矩阵 + PLIC/INTPRI、L1 缓存、PCR、LP 模块(复位原因、软件复位、RTC 定时器)、ASSISTDEBUG、802.15.4 和 WiFi MAC
    • tests/:golden 输出回归测试及其 fixture(tests/README.md)
    • 共享
      • wasm/:C-ABI crate,在浏览器里把三个 Machine 包装进一个模块
      • web/:浏览器 UI(开发板绘图、控制台、音频、摄像头)+ 供 wasm 使用的 emu.js/worker.js
      • hw/:对真实开发板做 JTAG 差分测试的脚本,已抓取的 C3 和 C6 控制台
      • examples/:hello_world(IDF,S3、C3、C6)、waveshare-cam(自动运行脚本 + 照片)、wifi-station(S3)、c6-wifi-station(为 S3、C3、C6 构建;WiFi goldens 的固件)、c6-radio-dashboard(C6 板上的 WiFi + 802.15.4)
      • tools/:PIE 表生成器(来自 TRM)、bench.py(交错 A/B 基准测试)、wasm-build.sh(WebAssembly 模块)

开发板(ESP32-S3)

SoC 模型发出引脚级事件(GPIO 边沿、RMT 符号流、I2S 采样);BoardModel(esp-soc/src/board.rs)解释这些事件。--board atech14(默认)是 Atech 14 端口板,带 ST7735、WS2812 环、编码器和按钮;--board none 是裸模块——任意 ESP32-S3 固件,仅控制台;--board waveshare-lcd4b 是 Waveshare ESP32-S3-Touch-LCD-4B(通过 LCDCAM RGB 总线接 ST7701S 480×480,GT911 触摸、TCA9554、编解码器),运行带触摸的 esp32-screen LVGL 面板;--board waveshare-amoled18-v2 是 Waveshare ESP32-S3-Touch-AMOLED-1.8 V2(通过 QSPI 接 CO5300 368x448,CST820 触摸);--board waveshare-cam 是 Waveshare ESP32-S3-CAM-OV5640(CH32V003 IO 扩展器、通过 SCCB 的 OV5640、I2C0 上的 ES8311/ES7210 编解码器、I2S1 上的扬声器、LCDCAM DVP 端口上的 OV5640)——端到端运行 waveshare-autopling 固件(IDF 5.5,16 MB flash,8 MB octal PSRAM:--flash-mb 16 --psram-mb 8):摄像头帧来自 --cam-image 或浏览器(图片上传 / 摄像头)→ 在模拟的 PIE SIMD 单元上运行 esp-dl 行人检测器 → 在 ES8311 上发出 pling。参见 examples/waveshare-cam/。新增开发板 = 实现该 trait(gpio_changes、rmt_frame、i2c_devices、camera_frame 等)。

atech14 演示运行的 Pocket Synth 固件是它自己的项目:atech-firmware —— 一个 PlatformIO 构建的 SID 合成器和用于真实 .sid 曲子的 cRSID 播放器。本仓库携带它生成的构建镜像,位于 web/wasm/fw/public/。

  1. cargo build --release
  2. FW=web/wasm/fw/public(goldens 和网页运行的演示镜像)
  3. ./target/release/esp32sim --boot rom --bootloader $FW/atech-bootloader.bin --ptable $FW/atech-ptable.bin --app $FW/atech-firmware.bin --script $FW/atech-script1.txt --wav out.wav --tft-png tft.png --max-seconds 5

mask ROM ELF 从 ~/.espressif/tools/esp-rom-elfs/*/esp32s3_rev0_rom.elf 获取(随 ESP-IDF 提供)。没有 ESP-IDF 时,tools/fetch-demo-assets.sh --no-linux 会把 S3、C3 和 C6 的 ROM 放到 web/wasm/fw/:传入 --rom web/wasm/fw/esp32s3_rev0_rom.elf,或设置 ESP32SIM_ROM_DIR=web/wasm/fw 供测试使用。--boot app 跳过 ROM+bootloader,直接加载应用镜像。

一个普通的 ESP-IDF 项目,例如 examples/hello_world(用 idf.py set-target esp32s3 && idf.py build 构建的 IDF 5.5 入门示例):

  1. H=examples/hello_world/build
  2. ./target/release/esp32sim --board none --boot rom --console uart0 --bootloader $H/bootloader/bootloader.bin --ptable $H/partition_table/partition-table.bin --app $H/hello_world.bin --elf $H/hello_world.elf --elf $H/bootloader/bootloader.elf --max-seconds 26

它在 UART0 上打印 ROM banner、bootloader 和应用日志,输出 Hello world!、倒计时,然后像真实芯片一样通过 RTC 看门狗复位重启(rst:0xc (RTC_SW_CPU_RST)),比真实时间快约 30 倍。芯片复位(软件、RTC 看门狗)会以正确的复位原因从 ROM 重启机器;--no-reboot 则在第一次复位时停止。

运行 —— ESP32-C3

esp32sim-c3 在模拟的 RISC-V 核上运行未修改的 ESP-IDF 固件,从真实 mask ROM 经真实 bootloader 进入 FreeRTOS。参数与 esp32sim 相同(--trace、--break、--watch、--peek、--disasm、--log-periph),打印带符号的 RISC-V 助记符。

  1. H=examples/hello_world-c3/build
  2. ./target/release/esp32sim-c3 --boot rom --flash-mb 4 --bootloader $H/bootloader/bootloader.bin --ptable $H/partition_table/partition-table.bin --app $H/hello_world.bin --elf $H/hello_world.elf --max-seconds 26

它打印 ROM banner、bootloader 日志、Hello world! 以及复位,重复三次。与物理 C3 模块逐行核对:三个启动周期中 208 行控制台有 205 行相同——差异是 ROM 的 Saved PC: 行。--mac、--reset-cause 和 --strap 让运行采用某块开发板的身份,使对比有意义。WiFi station 模式支持开放和 WPA2 虚拟 AP,带 DHCP 和 NAT。无开发板;不支持 --boot app。参见 docs/esp32c3.md 了解可用功能、不可用功能,以及硬件发现的五个模拟器 bug。

运行 —— ESP32-C6

esp32sim-c6 是 ESP32-C6 上的同一前端:RV32IMAC、PLIC、统一内存映射。

  1. H=examples/hello_world-c6/build
  2. ./target/release/esp32sim-c6 --boot rom --flash-mb 4 --bootloader $H/bootloader/bootloader.bin --ptable $H/partition_table/partition-table.bin --app $H/hello_world.bin --elf $H/hello_world.elf --max-seconds 27

与 Waveshare ESP32-C6-LCD-1.47 核对:三个启动周期中 204 行控制台有 203 行相同,包括 esp_restart() 之后 ROM 的 Saved PC:;唯一差异是首次启动时的那一行。--board waveshare-c6-lcd147 增加该开发板——SPI2 上的 ST7789 和 GDMA、WS2812、BOOT 按钮——并且 C6 的 802.15.4 MAC 会应答能量扫描,因此开发板上的 LVGL 频谱扫描固件能端到端运行(examples/waveshare-c6-lcd147/)。该 MAC 还以空中时序发送和接收帧,--cooja 让 C6 成为 Cooja-NG 的外部节点,通过 NDJSON 精确锁步驱动(一个未修改的 Contiki-NG-on-IDF 镜像与模拟的 MSP430 节点交换广播)。WiFi 也可用:--wifi 挂载与 S3 相同的虚拟接入点(见下文 WiFi 部分)。参见 docs/esp32c6.md。

脚本(在模拟时间上的主机操作)

  1. 1.5 press btn1 150 —— GPIO17 拉低 150 ms
  2. 2.2 knob cw 2 —— CLK5/DT4 上两个正交档位
  3. 3.4 press btn2 120
  4. 4.0 serial {"action":"set_note","value":"9"} —— 进入 USB-CDC RX
  5. 5.0 stop

WiFi(ESP32-S3、C3、C6 和经典 ESP32)

--wifi ssid=NAME[,psk=PASS,chan=N,bssid=..] 挂载一个虚拟接入点,未修改的 Espressif WiFi blob 会与之关联——扫描、认证、关联,带密码时还有 WPA2-PSK 四次握手——以及其背后的虚拟网络(DHCP、ARP、ICMP、DNS、基于主机时钟的 SNTP)。--net nat(默认)通过普通主机套接字中继客体的 TCP 和 UDP,因此固件能访问真实网络;--net none 拒绝访问。无需改固件,无需 root,无需 tun 设备。

  1. ./target/release/esp32sim --board waveshare-lcd4b --boot rom --flash-mb 16 --psram-mb 8 --bootloader $P/bootloader/bootloader.bin --ptable $P/partition_table/partition-table.bin --app $P/energy_panel.bin --console usb --wifi "ssid=home,psk=secret" --max-seconds 45

它运行 esp32-screen 能源面板:加入网络、获取租约、同步时钟、通过 HTTPS 获取两天的电价,并轮询局域网上真实的 Home Assistant。docs/networking-howto.md 是操作指南(参数、调试、限制);docs/wifi-plan.md 和 docs/networking-plan.md 描述 MAC 模型和报文路径如何工作,docs/architecture.md 的 Networking 部分描述各芯片共享的层次。

ESP32-C6 通过自己的 MAC 模型加入同一个接入点和同一个网络(docs/wifi-c6-plan.md):一个 station,legacy 速率,无节能。examples/c6-wifi-station 是样本——扫描、加入、租约、五次 ping,以及状态显示在开发板屏幕上——并且每个 C6 射频运行都需要 --stub bb_init=0(PHY 的基带校准需要模拟硬件):

  1. B=examples/c6-wifi-station/build-emu
  2. ./target/release/esp32sim-c6 --boot rom --flash-mb 4 --board waveshare-c6-lcd147 --console usb --bootloader $B/bootloader/bootloader.bin --ptable $B/partition_table/partition-table.bin --app $B/c6_wifi_station.bin --elf $B/c6_wifi_station.elf --stub bb_init=0 --wifi ssid=esp32sim,psk=esp32sim-pass --max-seconds 14

ESP32-C3 也通过从 S3 派生的 MAC 模型加入同一个接入点。为每颗芯片构建、不带显示屏的同款 station 示例,已提交在 web/wasm/fw/public/ 下,作为 WiFi goldens 的输入(cli/tests/goldens.rs 中的 wifi_station_{s3,c3,c6}),因此无需本地构建即可运行:

  1. P=web/wasm/fw/public
  2. ./target/release/esp32sim-c3 --boot rom --flash-mb 4 --console usb --bootloader $P/c3-wifi-bootloader.bin --ptable $P/c3-wifi-ptable.bin --app $P/c3-wifi_station.bin --wifi ssid=esp32sim,psk=esp32sim-pass --max-seconds 14

examples/c6-radio-dashboard 在一个固件里同时运行 WiFi 和 802.15.4 能量扫描,各占一页。

浏览器中(WebAssembly)

  1. tools/wasm-build.sh(模块 -> web/wasm/esp32sim.wasm)
  2. tools/fetch-demo-assets.sh(mask ROM、xterm.js 和 Linux 镜像;--no-linux 跳过其 16 MB)
  3. python3 -m http.server -d web 8790(然后打开 http://127.0.0.1:8790/?wasm&fw=hello)

演示固件已提交;mask ROM、xterm.js 和 Linux 镜像未提交,而每个演示都从 ROM 启动,因此需先运行一次 fetch。它获取的是 Pages 站点所提供的相同文件。

同一个模拟器编译为 WebAssembly,在页面的 Web Worker 里运行:选择开发板,从磁盘加载 ROM ELF 和固件(或用 ?wasm&fw=<name> 加载托管 manifest),按下 Boot。helloworld、带 SID 播放器的 Touch-LCD-4B 面板、Atech 板、ESP32-C3 和 ESP32-C6 都能在 Chrome 中实时运行;没有 NAT(浏览器没有套接字)。S3 有自己的 WebAssembly JIT(热块和区域,WASM SIMD 上的 PIE)。参见 docs/wasm.md。在线地址:https://mikroverk.github.io/esp32sim/ —— ESP32-S3 上的 Linux 6.11(svermigo/Linux-on-esp32-S3,登录并在控制台输入)、带 SID 播放器的 Touch-LCD-4B 面板、Atech 板、pocket-tank(一个 4-bit transformer 在 Touch-AMOLED-1.8 上操控鱼),以及 ESP32-C3 和 C6 启动 helloworld;或从磁盘加载任意芯片的自己的固件(选择开发板,或 esp32c3 / esp32c6)。

调试

--trace [--trace-from N]、--break ADDR、--watch ADDR(字变化时停止)、--peek ADDR[,N]、--profile(pc 直方图)、--log-periph(每个未知寄存器的首次触碰)、--stop-after-exceptions N、--gram-png(原始 ST7735 GRAM)、--no-jit(解释执行而非运行原生代码——必须给出相同结果)。环境变量:ESP_EMU_DEBUG、ESP_EMU_DEBUG_SPI、ESP_EMU_DEBUG_USB、ESP_EMU_DEBUG_WIFI[_FRAMES]、ESP_EMU_DEBUG_NET、ESP_EMU_DEBUG_AES、ESP_EMU_DEBUG_SHA、ESP_EMU_DEBUG_RSA。

文档

来源

依据 ESP-IDF 寄存器头文件、随 ESP-IDF 提供的 Xtensa 核心配置、RISC-V 规范以及 C3 和 C6 技术参考手册编写,并结合观察到的固件行为。仅在确认指令语义时参考了 QEMU(未复制代码)。MIT。

与真实芯片的差分测试(hw/)

每颗芯片都通过不同方法与硬件核对:S3 用 JTAG 锁步(见下),C3 和 C6 通过对比抓取的控制台与运行相同二进制的模拟器(hw/c3-hello-world-real.txt,205/208 行相同——见 docs/esp32c3.md;hw/c6-hello-world-real.txt,203/204——见 docs/esp32c6.md)。这些对比各发现了五个模拟器 bug,包括一个设备命令竞争,以及一个在复位时未重启的周期计数器——这两者都是无开发板测试无法发现的。

ESP32-S3,JTAG 锁步

DIFF_DIR=hw/<board> FLASH_MB=8 hw/difftest.sh 3000 —— 脚本先通过 JTAG 读取所连芯片的 efuse/strap,然后在同一 flash dump(若存在则 flash-8M.bin)上让它和模拟器锁步单步执行。Atech 板,2026-08-25:从复位起 3000 步,0 处分歧。

任何通过 USB 连接的 ESP32-S3 开发板都可以(其内置 USB-Serial/JTAG 同时承载控制台和 JTAG)。流程全部脚本化:

  1. 一次性:用 esptool 把开发板的 bootloader/分区表/应用开头 dump 到 hw/flash-0-1M.bin
  2. hw/difftest.sh 8000 —— 复位后在芯片和模拟器上单步 8000 条指令并 diff
  3. hw/difftest-at.sh 403c8948 6000 —— 两者都运行到某个 PC(此处是第二阶段 bootloader 入口),然后单步 6000 并 diff

difftest*.sh 读取芯片的 efuse(hw/efuse.txt)、strapping 引脚和外设复位状态(hw/reset-regs.txt,在 reset halt 时通过 JTAG dump),并从相同的镜像和状态启动模拟器。hw/compare.py 逐条指令 diff pc a0..a15 ps windowbase,屏蔽 PS.INTLEVEL(单步时强制),隐藏窗口异常处理程序(调试器原子地单步跳过它们),并在 CCOUNT 定时的延迟循环上重新同步——因为每步耗时毫秒级时,这些循环迭代次数会不同。

目前结果:ROM 复位路径(8000 步)和 IDF 5.5 bootloader 的 3000+ 步运行,PC 零分歧;剩余的寄存器差异是依赖上一次启动的 RTC 域值。

实时开发板 UI(ESP32-S3)

  1. ./target/release/esp32sim --boot rom --bootloader … --ptable … --app … --web 8766
  2. 打开 http://127.0.0.1:8766/

--web PORT 实时运行模拟器并提供 web/run.html:14 端口板(旋钮 + LED 环、按钮、扬声器 VU、按其物理方向的 ST7735 以及一份可读副本)、USB-CDC 和 UART0 控制台、用于 SDK JSON 协议的 action box,以及通过 WebAudio 输出的音频。输入:点击按钮、在旋钮上滚轮/拖动/←→、点击帽子按下它。

性能 / 实时(ESP32-S3)

指令块被解码一次并放入缓存执行,然后编译为原生 AArch64 代码(--no-jit 回退到解释器,且必须给出相同结果);空闲核(waiti)被跳过,设备时间按计算出的定时器截止期限惰性投递,中断线仅在源变化时重新计算。参见 docs/speed-plan.md 了解每一步背后的测量。Pocket Synth 固件在空闲或播放音符时有余量地实时运行;唯一跟不上的地方是全屏重绘,此时核 1 100% 忙于 bit-bang SPI(每 20 ms 480 万条指令——需要 240 Minsn/s,M 系列 MacBook 上达到约 70 Minsn/s)。因此每次重绘带来约 0.3 s 延迟,UI 的自适应音频缓冲会吸收(在 underrun 时增长,最多 400 ms),随后 pacer 恢复;如果模拟器落后超过 0.5 s,它会重新同步而不是爆发。头部显示 real time、⚠ N s behind 和重新同步次数。

ESP_EMU_RT_LOG=1 会打印每个耗时 > 40 ms 的 20 ms 窗口,以及两个核的指令数和 PC。hw/wsdrive.py [port] [seconds] 无需浏览器即可驱动 UI 协议(按钮按下 + 旋钮转动),并报告推送间隔、延迟和已投递音频——用它来测量调度器的改动。

贡献

欢迎贡献。CONTRIBUTING.md 列出了拉取请求需要的检查(与 CI 运行的相同),以及测试、实验和证据的约定。

许可

esp32sim 以 MIT License 发布,版权归 Joakim Eriksson (@joakimeriksson)、Alice (@aliceisjustplaying) 和 Mattia Fiumara (@mfiumara) 所有。

第三方代码、数据和演示文件保留各自许可:

  • pocket-tank(mediacutlet/pocket-tank,MIT)。它的 bootloader、分区表和应用随 pocket-tank-LICENSE.txt 提交在 web/wasm/fw/public/ 下;其模型是拉取的。
  • MicroPython(micropython.org,MIT):T-Display 演示使用的官方 ESP32_GENERIC v1.29.0 镜像,由 tools/fetch-micropython.sh 拉取,未提交;演示的应用和文件系统位于 examples/ttgo-tdisplay,含 Russ Hughes 的 st7789py 驱动和字体(MIT),声明见 web/wasm/fw/public/tdisplay-NOTICE.txt。
  • Mask ROM ELF(espressif/esp-rom-elfs,Apache-2.0),拉取,未提交。
  • xterm.js(xtermjs/xterm.js,MIT),拉取,未提交。
  • Linux 镜像(svermigo/Linux-on-esp32-S3,GPL-3.0),拉取,未提交。
  • ESP-IDF ADC 校准数据(Espressif,Apache-2.0):曲线拟合系数和来自 #165 的 S3 ADC1 校准,现在合并在 esp-periph/src/sar_adc.rs 中;见 esp-periph/LICENSE-ADC。

评论

讨论整体偏正面,多数人认为在浏览器里仿真 ESP32 既酷又有实用价值,尤其看好它能让前后端与 CI/CD 直接运行真实固件。分歧主要集中在两点:它与已发展多年的 Wokwi 等方案相比是否有真正差异,以及项目页面文档信息密度过高、像 AI 生成内容一样让人读不下去。

认为在浏览器里运行真实 ESP32 固件比功能级模拟更有价值

  • 多位发言者认可项目,认为基于 ESP32 能在浏览器里做各种实验;更被看好的点是,它不像只模拟 BLE、Wi-Fi 或 API 指令的功能级模拟器那样仅用于过渡,而能让移动端、后端开发和 CI/CD 运行器都直接运行真实 ESP32 固件,从而不必等测试硬件。(认可度:较多人) > 它比只模拟 BLE、Wi-Fi 或 API 命令的功能级模拟器更进一步,能让移动端、后端和 CI/CD 都运行真实固件。(@raminf)

质疑它与 Wokwi 等已有模拟器相比缺乏明确差异

  • 有人提出 Wokwi.com 已经做了很多年,并且模拟了大量微控制器,因此想知道这个项目到底有何不同,隐含对项目是否重复已有方案的疑问。(认可度:少数人) > Wokwi 已经做了很多年,而且支持大量微控制器,这个和它有什么不同?(@turbine401)

认为项目文档像 AI 生成的冗长内容,阅读体验很差

  • 有发言者表示本来想上手尝试,但被页面里巨大且格式糟糕的段落劝退:格式、方括号、语义化标点、命令行参数、元器件型号等密集混排,信息过载,连专家年轻读者也会觉得吃力;建议作者重新考虑呈现方式。(认可度:少数人) > 那些又长又乱、像 AI 生成内容的段落,密集混排格式、方括号、语义化标点、命令行参数和元器件编号,连专家年轻读者都会觉得吃力。(@dofm)

有价值的补充

  • 已有开发者在浏览器里用 WebAssembly 运行真实 ESP32 飞控 C 代码,做出可模拟飞行的无人机模拟器;其飞控由真实 ESP32 代码驱动,并且代码能直接刷进真实板子(@mrtksn)。