跳到正文
原文
Hacker News· joakimeriksson·· 22 天前精选AI 评分78

esp32sim:用 Rust 编写的 ESP32 模拟器,可在浏览器中运行未经修改的 ESP32 固件

Show HN: Esp32sim – Run ESP32 firmware in the browser

AI 摘要

Joakim Eriksson 等人发布 MIT 许可的 esp32sim,用 Rust 对 ESP32、S3、C3、C6 四款 SoC 做指令级模拟,可直接启动真实 mask ROM、二级引导程序和未经修改的应用镜像。

正文 · 中文整理稿

esp32sim — a smiling chip in an emulator window

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

对四款 ESP32 SoC 进行指令级模拟,覆盖乐鑫的两种 CPU 架构。 每一款都启动真实的 mask ROM、真实的二级引导程序和未经修改的应用程序 镜像——没有打补丁的固件,也没有挡路的桩——并且对 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(一个站点) 相同的虚拟 AP 和网络:扫描、WPA2、DHCP、NAT(一个站点,传统速率)
速度 块解释器 + AArch64 JIT,约 150–240 Minsn/s 纯解释器(尚无块缓存或 JIT)——在 hello_world 上仍远快于实时 相同的解释器
在浏览器中 是(WebAssembly) 是(WebAssembly) 是(WebAssembly)
报告的硬件对比 JTAG trace,在定时循环重新同步后 8000 步 控制台 diff,205/208 行相同 控制台 diff,203/204 行相同
状态 成熟 草稿——见 docs/esp32c3.md 草稿——见 docs/esp32c6.md

这些完整列表和硬件计数描述的是早期的人工运行。CI 运行的是已检入的 采样解码器语料和模拟器黄金输出;它不包含外部完整列表 测试。Xtensa objdump 测试不包含 PIE 操作数比较。硬件 trace 对比 会归一化窗口异常并重新同步延迟循环,因此并非不间断的 逐周期一致。见 测试范围、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/       the Bus and Core traits, Trap, ClockTree, AArch64 encoder — shared by both cores
  esp-soc/        Machine<S: Soc>: scheduler, device time, console, scripts, web UI, loaders, boards —
                  one machine for every chip; a chip plugs in its cores, bus and interrupt routing;
                  the virtual WiFi access point, the network behind it and the NAT, for every chip
  esp-periph/     the peripheral IP the chips share (UART, systimer, TIMG, GPIO, SPI_MEM, GDMA, crypto,
                  I2S, RMT, I2C, …), the Device trait, and the device_set! table that mounts them
  ── ESP32-S3 (Xtensa LX7, dual core) ──
  xtensa-lx7/     decoder (sampled objdump checks plus optional full listings), interpreter
                  (windowed regs, loops, XEA2 exceptions/interrupts, FPU, MAC16, booleans,
                  PIE SIMD), basic-block interpreter, AArch64 JIT, objdump-compatible disassembler
  esp32s3/        SoC + boards: memory map, cache MMU, SPI flash/PSRAM, SHA/AES/RSA, RNG,
                  systimer, timer groups, interrupt matrix (per core), GPIO, USB-CDC,
                  UARTs, I2C, GDMA + I2S/LCD_CAM, RMT TX, regi2c, RTC WDT, WiFi MAC;
                  board/: atech14 / waveshare-cam / waveshare-lcd4b / waveshare-amoled18-v2 / none
  cli/            the `esp32sim` command line, every chip (`--chip`); `esp32sim-c3` / `esp32sim-c6` are alias binaries
  ── ESP32-C3 and ESP32-C6 (RISC-V, single core) ──
  riscv-rv32/     RV32IMAC decoder (sampled objdump checks), interpreter, disassembler
  esp32c3/        the C3 SoC: memory map, interrupt matrix, cache controller, RNG;
                  peripheral models shared with esp32s3 where the IP is identical
  esp32c6/        the C6 SoC: unified memory map and MMU, interrupt matrix + PLIC/INTPRI, L1 cache,
                  PCR, the LP blocks (reset cause, software reset, RTC timer), ASSIST_DEBUG,
                  the 802.15.4 and WiFi MACs
  tests/          golden-output regression tests and their fixtures (tests/README.md)
  ── shared ──
  wasm/           C-ABI crate wrapping all three Machines for the browser in one module
  web/            browser UI (board drawing, console, audio, camera) + emu.js/worker.js for wasm
  hw/             JTAG differential-test scripts against a real board, captured C3 and C6 consoles
  examples/       hello_world (IDF, S3, C3 and C6), waveshare-cam (autopling run script + photo),
                  wifi-station (S3), c6-wifi-station (builds for the S3, C3 and C6; the WiFi goldens'
                  firmware), c6-radio-dashboard (WiFi + 802.15.4 on the C6 board)
  tools/          PIE table generator (TRM-derived); bench.py (interleaved A/B benchmark);
                  wasm-build.sh (the WebAssembly module)

开发板(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(ST7701S 480×480 通过 LCD_CAM RGB 总线,GT911 触摸,TCA9554,编解码器),运行带触摸的 esp32-screen LVGL 面板;--board waveshare-amoled18-v2 是 Waveshare ESP32-S3-Touch-AMOLED-1.8 V2(CO5300 368x448 通过 QSPI,CST820 触摸);--board waveshare-cam 是 Waveshare ESP32‑S3‑CAM‑OV5640(CH32V003 IO 扩展器,OV5640 通过 SCCB,ES8311/ES7210 编解码器在 I2C0 上,扬声器在 I2S1 上,OV5640 在 LCD_CAM DVP 端口上)——端到端运行 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 上发出提示音。参见 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/ 中携带它生成的已构建镜像。

cargo build --release
FW=web/wasm/fw/public                       # the demo images the goldens and the web page run
./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

掩码 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+引导加载程序并直接加载应用镜像。

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

H=examples/hello\_world/build
./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 横幅、引导加载程序和应用日志,Hello world!,倒计时,然后像真实芯片一样通过 RTC 看门狗重启(rst:0xc (RTC_SW_CPU_RST)),比实时快约 30 倍。芯片复位(软件、RTC 看门狗)会以正确的复位原因从 ROM 重新启动机器;--no-reboot 则在第一次复位时停止。

运行——ESP32-C3

esp32sim-c3 在模拟的 RISC-V 核心上运行未经修改的 ESP-IDF 固件,从真实掩码 ROM 经过真实引导加载程序进入 FreeRTOS。标志与 esp32sim 相同(--trace、--break、--watch、--peek、--disasm、--log-periph),打印带符号的 RISC-V 助记符。

H=examples/hello\_world-c3/build
./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 横幅、引导加载程序日志、Hello world! 和重启,重复三次。与物理 C3 模块逐行核对:在三个启动周期中,208 行控制台输出中有 205 行完全相同——差异在于 ROM 的 Saved PC: 行。--mac、--reset-cause 和 --strap 让一次运行采用板子的身份,从而使比较有意义。WiFi 站点模式支持开放和 WPA2 虚拟 AP,带 DHCP 和 NAT。无板子;--boot app 不支持。参见 docs/esp32c3.md 了解哪些可用、哪些不可用,以及硬件发现的五个模拟器 bug。

运行——ESP32-C6

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

H=examples/hello\_world-c6/build
./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 行完全一致,包括 ROM 在 esp_restart() 之后的 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 的外部 mote,通过 NDJSON 以精确的锁步方式驱动(一个未经修改的 Contiki-NG-on-IDF 镜像与模拟的 MSP430 节点交换广播)。WiFi 同样可用:--wifi 挂载与 S3 上相同的虚拟接入点(见下方 WiFi)。参见 docs/esp32c6.md。

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

1.5  press btn1 150                       # GPIO17 low for 150 ms
2.2  knob cw 2                            # two quadrature detents on CLK5/DT4
3.4  press btn2 120
4.0  serial {"action":"set_note","value":"9"}   # into USB-CDC RX
5.0  stop

WiFi(ESP32-S3、C3、C6 以及经典 ESP32)

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

./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):单个站点、传统速率、无省电模式。examples/c6-wifi-station 是示例——扫描、加入、获取租约、五次 ping,以及开发板屏幕上的状态——每次 C6 射频运行都需要 --stub bb_init=0(PHY 的基带校准需要模拟硬件):

B=examples/c6-wifi-station/build-emu
./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 模型加入同一个接入点。同一个站点示例在不带显示屏的情况下为每个芯片构建,已提交在 web/wasm/fw/public/ 下,作为 WiFi 黄金测试的输入(cli/tests/goldens.rs 中的 wifi_station_{s3,c3,c6}),因此无需本地构建即可运行:

P=web/wasm/fw/public
./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)

tools/wasm-build.sh                  # the module -> web/wasm/esp32sim.wasm
tools/fetch-demo-assets.sh           # mask ROMs, xterm.js and the Linux image (--no-linux skips its 16 MB)
python3 -m http.server -d web 8790   # then open http://127.0.0.1:8790/?wasm&fw=hello

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

同一个模拟器编译为 WebAssembly,在页面的 Web Worker 中运行:选择一块开发板,从磁盘加载 ROM ELF 和固件(或使用 ?wasm&fw=<name> 获取托管清单),然后按 Boot。hello_world、带 SID 播放器的 Touch-LCD-4B 面板、Atech 板、ESP32-C3 和 ESP32-C6 都能在 Chrome 中实时运行;没有 NAT(浏览器没有套接字)。S3 有自己的 WebAssembly JIT(热块和热区域,PIE 基于 WASM SIMD)。参见 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 位 transformer 在 Touch-AMOLED-1.8 上操控鱼),以及启动 hello_world 的 ESP32-C3 和 C6;或者从磁盘为任意芯片加载你自己的固件(选择开发板,或使用 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。

文档

  • docs/adding.md — 添加外设、带设备的开发板、CPU/芯片、观察器

docs/ — 架构、外设覆盖、开发板、CLI 参考、Web UI 协议、设计决策与注意事项、路线图、网络操作指南、WiFi 和 网络设计说明,以及 测试计划。

来源

根据 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 转储上对芯片和模拟器进行锁步单步执行(如果存在则使用 flash-8M.bin)。Atech 板,2026-08-25:从复位起 3000 步,0 次分歧。

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

# one-time: dump the board's bootloader/partition table/app start (esptool) into hw/flash-0-1M.bin
hw/difftest.sh 8000                 # reset → single-step 8000 instructions on the chip and in the emulator, diff
hw/difftest-at.sh 403c8948 6000     # run both to a PC (here the 2nd-stage bootloader entry), then step 6000 and diff

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

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

实时板卡 UI(ESP32-S3)

./target/release/esp32sim --boot rom --bootloader … --ptable … --app … --web 8766
# open http://127.0.0.1:8766/

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

性能 / 实时性(ESP32-S3)

指令块只解码一次并从缓存执行,然后编译为原生 AArch64 代码(--no-jit 回退到解释器且必须给出相同结果);空闲核心(waiti)被跳过,设备时间按计算出的定时器截止时间惰性交付,中断线仅在源发生变化时重新计算。每一步背后的测量数据见 docs/speed-plan.md。Pocket Synth 固件在空闲或演奏音符时都能以有余量的实时速度运行;唯一跟不上的是整屏重绘,此时核心 1 以 100% 占用进行 SPI 位操作(每 20 ms 4.8 M 条指令——需要 240 Minsn/s,在 M 系列 MacBook 上约达到 70 Minsn/s)。因此每次重绘会产生约 0.3 s 的延迟,由 UI 的自适应音频缓冲吸收(欠载时增长,最高 400 ms),之后由节拍器恢复;如果模拟器落后超过 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 许可证发布,版权归 Joakim Eriksson(@joakimeriksson)、Alice(@aliceisjustplaying)和(@mfiumara)Mattia Fiumara 所有。

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

  • pocket-tank(mediacutlet/pocket-tank,MIT)。其 bootloader、分区表和 app 提交在 web/wasm/fw/public/ 下,附带 pocket-tank-LICENSE.txt;其模型为获取所得。
  • MicroPython(micropython.org,MIT):T-Display 演示的官方 ESP32_GENERIC v1.29.0 镜像,由 tools/fetch-micropython.sh 获取,未提交;演示的 app 和文件系统位于 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。

来源:Hacker News · github.com

00