ESP32-S3 QEMU 无法稳定运行 PSRAM 配置:诊断与 QEMU 专用降级方案
ESP32-S3 QEMU 无法稳定运行 PSRAM 配置:诊断与 QEMU 专用降级方案
本文记录在 Windows + ESP-IDF v6.0.1 + Espressif QEMU 环境下,ESP32-S3 工程启用 Octal PSRAM 后无法在 QEMU 中稳定启动的问题,以及用于模拟器基础验证的处理方案。
本文方案的目标是让固件在 QEMU 中启动和运行基础功能,并不等价于验证真实硬件上的 PSRAM 功能。
1. 问题背景
许多 ESP32-S3 工程面向带 PSRAM 的真实开发板配置,例如:
CONFIG_SPIRAM=y
CONFIG_SPIRAM_MODE_OCT=y
CONFIG_SPIRAM_TYPE_AUTO=y
在真实硬件上,这类配置通常用于:
- 承载大块动态内存;
- Wi-Fi/LwIP 缓冲区;
- 图形或多媒体资源;
- WebAssembly runtime / 应用堆;
- 大型文件系统缓存。
在 ESP-WASMachine 中,WAMR runtime 的分配器也会根据 PSRAM 配置选择 heap capability:
#ifdef CONFIG_SPIRAM
uint32_t caps = MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT;
#else
uint32_t caps = MALLOC_CAP_8BIT;
#endif
因此在真实设备上,PSRAM 对较大的 WASM 运行负载非常重要。
但在 QEMU 中直接使用这套真实硬件配置,可能无法稳定启动。
2. 典型现象
执行:
idf.py qemu monitor
可能出现以下现象之一:
-
QEMU 刚启动便退出;
-
IDF monitor 显示:
[WinError 10054] 远程主机强迫关闭了一个现有的连接。 -
monitor 能连接,但没有任何 UART 启动日志;
-
前台启动 QEMU 时,bootloader 加载应用镜像后 QEMU 进程异常退出;
-
在启用 Octal PSRAM 时,QEMU 启动参数包含:
-global driver=ssi_psram,property=is_octal,value=true
这通常意味着 QEMU 对当前 ESP32-S3、IDF 和 Octal PSRAM 配置组合的模拟存在限制,而不是应用层业务代码必然有问题。
3. 不能简单靠 -m 增大内存解决
ESP32-S3 QEMU 常见参数:
-M esp32s3 -m 32M
这里的 -m 32M 用于模拟外部内存容量。
但如果固件配置为:
CONFIG_SPIRAM=n
ESP-IDF 不会初始化外部 RAM,也不会将它纳入可用 heap。因此即使把 QEMU 参数改为:
-m 64M
或:
-m 128M
应用也不会自动得到更多可用内存。
结论:
-m仅表示 QEMU 可模拟外部内存;CONFIG_SPIRAM=y才表示 IDF 将其当作 PSRAM 初始化和使用;- 如果 QEMU 无法正确模拟该 PSRAM 路径,单纯增大
-m没有帮助。
4. 推荐方案:建立 QEMU 专用 defaults
不要修改真实硬件默认配置。新增一份只供 QEMU 使用的配置,例如:
sdkconfig.defaults.qemu
建议内容:
# ESP32-S3 QEMU does not reliably emulate the Octal PSRAM used by the
# hardware configuration. Keep PSRAM disabled in the simulator-only build.
CONFIG_SPIRAM=n
# With PSRAM disabled, WAMR allocates executable AOT memory from internal RAM.
# ESP-IDF memory protection removes MALLOC_CAP_EXEC, so disable it for the
# simulator-only build.
CONFIG_ESP_SYSTEM_MEMPROT=n
其中两项分别解决不同问题。
4.1 禁用 PSRAM
CONFIG_SPIRAM=n
作用:
- 避开 QEMU 的 Octal PSRAM 模拟路径;
- 让 runtime 使用内部 DRAM;
- 适合执行小型测试程序和基本交互验证。
代价:
- 可用 heap 显著减少;
- 不适合大 WASM 应用;
- 不等价于真实板子的内存容量与内存分配行为。
4.2 禁用 IDF 内存保护
CONFIG_ESP_SYSTEM_MEMPROT=n
关闭 PSRAM 后,部分 WAMR AOT 内存映射代码会使用:
MALLOC_CAP_EXEC
但 IDF 6 启用内存保护时会移除这一 capability,典型编译错误:
error: 'MALLOC_CAP_EXEC' undeclared
HINT: MALLOC_CAP_EXEC capability cannot be used if
CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT or CONFIG_ESP_SYSTEM_MEMPROT_FEATURE is enabled.
因此,在 PSRAM 关闭的 QEMU 版本中,应关闭:
CONFIG_ESP_SYSTEM_MEMPROT=n
这是一项模拟器专用安全降级。真实硬件构建不应因为 QEMU 验证方便而关闭内存保护。
5. ESP-IDF 6 与 WAMR 的内存分配关系
WAMR 的 ESP-IDF 内存映射代码在不同配置下使用不同 capability。
启用外部双总线镜像/PSRAM 路径时,通常使用:
MALLOC_CAP_SPIRAM
关闭 PSRAM 后,则会使用:
MALLOC_CAP_EXEC
而 ESP-IDF 的内存布局在 CONFIG_ESP_SYSTEM_MEMPROT=y 时,不提供可执行 heap capability。
因此以下组合不可用:
CONFIG_SPIRAM=n
CONFIG_ESP_SYSTEM_MEMPROT=y
适用于 QEMU 基础验证的组合是:
CONFIG_SPIRAM=n
CONFIG_ESP_SYSTEM_MEMPROT=n
6. 推荐构建方式:使用独立构建目录
建议 QEMU 与真实硬件各自使用独立 build 目录:
build # 真实硬件配置
build-qemu # QEMU 专用配置
例如:
cd D:\code\your-project
idf.py -B build-qemu `
-DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.defaults.esp32s3;sdkconfig.defaults.qemu" `
set-target esp32s3
idf.py -B build-qemu build
验证最终配置:
Select-String -Path sdkconfig -Pattern "CONFIG_SPIRAM|CONFIG_ESP_SYSTEM_MEMPROT"
预期:
# CONFIG_SPIRAM is not set
# CONFIG_ESP_SYSTEM_MEMPROT is not set
sdkconfig位于项目根目录或由当前 SDKCONFIG 路径决定;如项目将其放在其他位置,请按实际路径检查。
7. 如何启动和观察 QEMU 日志
推荐以前台方式启动:
idf.py -B build-qemu qemu
它会将模拟 ESP32-S3 的 UART 直接连接到当前终端。
相比之下:
idf.py -B build-qemu qemu monitor
会使用 TCP 串口端口连接 IDF monitor。在某些 Windows QEMU 环境中,monitor 可以成功连接,但不一定稳定显示启动期 UART 日志。
因此排查 PSRAM 或启动问题时,优先用:
idf.py -B build-qemu qemu
可以直接观察:
- ROM 启动;
- bootloader;
- Flash 初始化;
- 内存初始化;
app_main();- panic/assert/backtrace。
8. 验证成功的标志
在关闭 PSRAM 的 QEMU 构建中,至少应能看到:
heap_init: Initializing. RAM available for dynamic allocation:
...
main_task: Calling app_main()
并且不应出现:
assert failed
Rebooting...
如果工程提供 shell,可进一步运行最小功能验证,例如:
WASMachine> iwasm wasm/hello_world.wasm
Hello World!
这说明固件、runtime 和基本应用流程可以在 QEMU 中工作。
9. 适用范围与限制
此 workaround 适合:
- CI 中的启动冒烟测试;
- QEMU 下的基础功能验证;
- Shell、文件系统、网络基础逻辑调试;
- 小型 WebAssembly 程序验证;
- 不依赖大块外部 RAM 的功能开发。
不适合将以下结论直接推导到真实硬件:
- PSRAM 容量是否足够;
- PSRAM 分配是否正确;
- PSRAM 性能;
- 大 WASM 模块加载能力;
- 多应用或高并发运行;
- 图形、音频、大缓存等高内存场景;
- 内存保护相关安全行为。
真实硬件仍应保留:
CONFIG_SPIRAM=y
CONFIG_SPIRAM_MODE_OCT=y
CONFIG_ESP_SYSTEM_MEMPROT=y
以及其对应的硬件 Flash 和 PSRAM 配置。
10. 总结
当 ESP32-S3 项目在 QEMU 中无法使用真实硬件的 Octal PSRAM 配置时,可采用专用模拟器配置:
CONFIG_SPIRAM=n
CONFIG_ESP_SYSTEM_MEMPROT=n
核心原则:
- 不修改真实硬件的默认配置;
- 使用
sdkconfig.defaults.qemu管理模拟器差异; - 使用独立的
build-qemu目录; - 前台运行
idf.py -B build-qemu qemu观察真实启动日志; - 将其定位为基础模拟验证方案,而非 PSRAM 功能验证方案。
浙公网安备 33010602011771号