本文记录在 Windows 环境中为ESP32-P4-Function-Ev-Board 1.6配置 Apache NuttX 开发环境并完成esp32p4-function-ev-board:nsh编译验证的完整过程。本次环境尽量复用机器上已有的 ESP32 / ESP-IDF 工具链只补齐 NuttX 编译过程中缺失的部分。0 开箱检查ESP32-P4-Function-Ev-Board 1.6包括一个开发板、摄像头和7寸触摸屏组装之后可以运行出厂程序确认开发板套件一切正常。1. 环境概况本次工作目录D:\esp32p4-nuttx已存在可复用工具ESP-IDF: D:\esp\master\esp-idf CMake: C:\Espressif\tools\cmake\4.0.3\bin\cmake.exe Ninja: C:\Espressif\tools\ninja\1.12.1\ninja.exe Python venv: C:\Espressif\tools\python\master\venv RISC-V GCC: C:\Espressif\tools\riscv32-esp-elf\esp-15.2.0_20251204\riscv32-esp-elf esptool: C:\Espressif\tools\python\master\venv\Scripts\esptool.exe Git Bash: C:\Program Files\Git\bin\bash.exe本次验证使用的版本riscv32-esp-elf-gcc 15.2.0 cmake 4.0.3 ninja 1.12.1 esptool 5.3.02. 获取 NuttX 和 apps 源码在工作目录中克隆 NuttX 主仓库和 apps 仓库cd D:\esp32p4-nuttx git clone--depth 1 https://github.com/apache/nuttx.git nuttx git clone--depth 1 https://github.com/apache/nuttx-apps.git apps本次验证时的提交nuttx: bdd68ed1 apps: 1d15c81ESP32-P4 相关板级目录位于nuttx\boards\risc-v\esp32p4其中 ESP32-P4-Eval-Board 对应的配置为esp32p4-function-ev-board:nsh3. 准备 MinGW / makeNuttX 的部分工具链流程依赖类 Unix 工具。Windows 下可以使用 MinGW64。如果系统中没有可用的 MinGW64可以从https://github.com/niXman/mingw-builds-binaries/releases下载解压本地安装包C:\Users\haili\Downloads\x86_64-16.1.0-release-win32-seh-msvcrt-rt_v14-rev1.7z本次解压到D:\esp32p4-nuttx\mingw64如果只使用 CMake Ninja 构建最终主要依赖的是mingw64\bin Git\usr\bin Git\bin4. 创建 Python 虚拟环境NuttX 的 Kconfig 解析需要kconfiglib。ESP-IDF 自带的 Python 环境中可能是 Espressif 定制版本解析 NuttX Kconfig 时可能报错因此建议单独创建 NuttX 专用 venvcd D:\esp32p4-nuttx python-m venv.venv.\.venv\Scripts\python.exe-m pip install kconfiglib14.1.0如果当前网络代理影响 pip可以临时清理代理环境变量$env:HTTP_PROXY$env:HTTPS_PROXY$env:ALL_PROXY5. 处理 RISC-V 工具链名称NuttX CMake 的 RISC-V 工具链逻辑会查找riscv64-unknown-elf-gcc但 ESP32-P4 实际可使用 Espressif 提供的riscv32-esp-elf-gccESP32-P4 使用rv32imac_zicsr_zifencei和ilp32目标参数因此可以复用riscv32-esp-elf工具链。本次做法是在工作区创建本地工具目录D:\esp32p4-nuttx\tools\bin然后把 Espressif 工具链中的可执行文件复制并重命名为 NuttX CMake 期望的前缀例如riscv32-esp-elf-gcc.exe - riscv64-unknown-elf-gcc.exe riscv32-esp-elf-g.exe - riscv64-unknown-elf-g.exe riscv32-esp-elf-ld.exe - riscv64-unknown-elf-ld.exe riscv32-esp-elf-ar.exe - riscv64-unknown-elf-ar.exe riscv32-esp-elf-objcopy.exe - riscv64-unknown-elf-objcopy.exe riscv32-esp-elf-objdump.exe - riscv64-unknown-elf-objdump.exe同时需要设置$env:GCC_EXEC_PREFIXC:\Espressif\tools\riscv32-esp-elf\esp-15.2.0_20251204\riscv32-esp-elf\libexec\gcc\否则重命名后的 GCC 可能找不到内部的cc1。6. 设置编译环境变量推荐准备一个环境脚本env-esp32p4-nuttx.ps1$Root$PSScriptRoot$toolPaths ((Join-Path$Root.venv\Scripts),C:\Espressif\tools\python\master\venv\Scripts,(Join-Path$Roottools\bin),(Join-Path$Rootmingw64\bin),C:\Espressif\tools\riscv32-esp-elf\esp-15.2.0_20251204\riscv32-esp-elf\bin,C:\Espressif\tools\cmake\4.0.3\bin,C:\Espressif\tools\ninja\1.12.1,C:\Program Files\Git\usr\bin,C:\Program Files\Git\bin)$existingToolPaths$toolPaths|Where-Object{Test-Path$_}$env:Path ($existingToolPaths-join;);$env:Path$env:GCC_EXEC_PREFIX C:\Espressif\tools\riscv32-esp-elf\esp-15.2.0_20251204\riscv32-esp-elf\libexec\gcc\Write-HostESP32-P4 NuttX environment ready at$Root加载环境cd D:\esp32p4-nuttx..\env-esp32p4-nuttx.ps1检查工具riscv64-unknown-elf-gcc--version cmake--version ninja--version esptool version7. 使用 CMake 配置 NuttX推荐使用 CMake Ninja而不是 Windows 下直接走传统 Makefile 流程。配置命令如下cmake -S D:\esp32p4-nuttx\nuttx -B D:\esp32p4-nuttx\build -G Ninja -DCMAKE_MAKE_PROGRAMC:\Espressif\tools\ninja\1.12.1\ninja.exe-DBOARD_CONFIGesp32p4-function-ev-board:nsh-DNUTTX_APPS_DIRD:\esp32p4-nuttx\apps-DPython3_EXECUTABLED:\esp32p4-nuttx\.venv\Scripts\python.exe-DEXTRA_FLAGS-stdgnu11其中BOARD_CONFIGesp32p4-function-ev-board:nsh表示为 ESP32-P4 Function EV Board 启用 NSH 示例配置。-DEXTRA_FLAGS-stdgnu11用于避免部分 ESP HAL / newlib 头文件在更新 C 标准下的兼容问题。8. 处理 ESP HAL stdatomic.h 兼容问题本次编译过程中遇到 ESP HAL 代码和当前工具链stdatomic.h宏定义不兼容的问题例如request for member __val in something not a structure or union以及field name not in record or union initializer原因是 ESP HAL 部分代码使用atomic_init、ATOMIC_VAR_INIT等宏但当前工具链的实现会把_Atomic标量按结构字段形式处理导致编译失败。解决方法是在 ESP HAL 的platform_include下放置一个兼容包装头build\arch\risc-v\src\common\espressif\esp-hal-3rdparty\nuttx\src\components\esp_libc\platform_include\stdatomic.h核心内容如下#pragmaonce#include_nextstdatomic.h#ifdefATOMIC_VAR_INIT#undefATOMIC_VAR_INIT#endif#defineATOMIC_VAR_INIT(val)(val)#ifdefatomic_init#undefatomic_init#endif#defineatomic_init(ptr,val)__atomic_store_n((ptr),(val),__ATOMIC_RELAXED)#ifdefatomic_store#undefatomic_store#endif#defineatomic_store(ptr,val)__atomic_store_n((ptr),(val),__ATOMIC_SEQ_CST)#ifdefatomic_load#undefatomic_load#endif#defineatomic_load(ptr)__atomic_load_n((ptr),__ATOMIC_SEQ_CST)#ifdefatomic_compare_exchange_strong#undefatomic_compare_exchange_strong#endif#defineatomic_compare_exchange_strong(ptr,expected,desired)\__atomic_compare_exchange_n((ptr),(expected),(desired),false,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST)#ifdefatomic_compare_exchange_weak#undefatomic_compare_exchange_weak#endif#defineatomic_compare_exchange_weak(ptr,expected,desired)\__atomic_compare_exchange_n((ptr),(expected),(desired),true,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST)#ifdefatomic_fetch_or#undefatomic_fetch_or#endif#defineatomic_fetch_or(ptr,val)__atomic_fetch_or((ptr),(val),__ATOMIC_SEQ_CST)#ifdefatomic_fetch_and#undefatomic_fetch_and#endif#defineatomic_fetch_and(ptr,val)__atomic_fetch_and((ptr),(val),__ATOMIC_SEQ_CST)#ifdefatomic_fetch_add#undefatomic_fetch_add#endif#defineatomic_fetch_add(ptr,val)__atomic_fetch_add((ptr),(val),__ATOMIC_SEQ_CST)#ifdefatomic_fetch_sub#undefatomic_fetch_sub#endif#defineatomic_fetch_sub(ptr,val)__atomic_fetch_sub((ptr),(val),__ATOMIC_SEQ_CST)如果另一个目录也存在 ESP libc 的platform_include也可以同步放置build\arch\risc-v\src\common\espressif\esp-hal-3rdparty\components\esp_libc\platform_include\stdatomic.h9. 处理 libgcc.a 依赖由于工具链可执行文件被重命名CMake / Ninja 可能把libgcc.a解析成当前构建目录下的相对依赖。可以直接复制一份Copy-Item-LiteralPathC:\Espressif\tools\riscv32-esp-elf\esp-15.2.0_20251204\riscv32-esp-elf\lib\gcc\riscv32-esp-elf\15.2.0\libgcc.a-DestinationD:\esp32p4-nuttx\build\libgcc.a10. 编译执行cmake--build D:\esp32p4-nuttx\build--parallel4如果 PATH 中没有esptool最后的elf2image会失败esptool.py elf2image failed需要确保以下路径在 PATH 中C:\Espressif\tools\python\master\venv\Scripts成功时会看到类似输出-- Generate NuttX image (esptool elf2image) esptool v5.3.0 Creating ESP32-P4 image... Image has only RAM segments visible. ROM segments are hidden and SHA256 digest is not appended. Merged 2 ELF sections. Successfully created ESP32-P4 image. -- Generated: nuttx.bin11. 编译产物本次编译完成后主要产物位于D:\esp32p4-nuttx\build产物如下nuttx 600788 bytes nuttx.bin 264856 bytes nuttx.hex 632951 bytes nuttx.map 1454116 bytes nuttx.manifest 22 bytes其中nuttx ELF 文件 nuttx.bin ESP32-P4 可用镜像 nuttx.hex Intel HEX 格式产物 nuttx.map 链接 map 文件12. 烧录和串口验证12.1 烧录地址本次配置使用的是 ESP32-P4 simple bootCONFIG_ESPRESSIF_SIMPLE_BOOTyNuttX 脚本中 ESP32-P4 simple boot 的应用偏移为0x2000因此烧录时需要把nuttx.bin写到0x2000。12.2 烧录 nsh 配置默认esp32p4-function-ev-board:nsh构建产物位于D:\esp32p4-nuttx\build\nuttx.bin以开发板枚举出的串口COM4为例烧录命令如下esptool--chip esp32p4-p COM4-b 460800write-flash-fs 4MB-fm dio-ff 80m 0x2000.\build\nuttx.bin本次实际烧录日志显示Connected to ESP32-P4 on COM4 Wrote 264856 bytes (133649 compressed) at 0x00002000 Hash of data verified. Hard resetting via RTS pin...这说明镜像已经正确写入 Flash。12.3 nsh 配置的控制台位置需要注意默认nsh配置的控制台不是 USB-Serial/JTAG 对应的COM4而是 UART0CONFIG_UART0_SERIAL_CONSOLEy CONFIG_UART0_TXPIN37 CONFIG_UART0_RXPIN38 CONFIG_UART0_BAUD115200 # CONFIG_ESPRESSIF_USBSERIAL is not set因此烧录默认nsh镜像后如果直接打开COM4看不到输出这是正常现象。需要使用 USB-TTL 转串口连接 UART0USB-TTL RX - ESP32-P4 GPIO37 / UART0 TX USB-TTL TX - ESP32-P4 GPIO38 / UART0 RX USB-TTL GND - ESP32-P4 GND串口参数115200 8N112.4 编译 USB 控制台版本如果希望直接通过烧录用的 USB 口查看 NSH可以改用板级配置esp32p4-function-ev-board:usbconsole推荐单独使用一个构建目录cmake-S D:\esp32p4-nuttx\nuttx-B D:\esp32p4-nuttx\build-usbconsole-G Ninja-DCMAKE_MAKE_PROGRAMC:\Espressif\tools\ninja\1.12.1\ninja.exe-DBOARD_CONFIGesp32p4-function-ev-board:usbconsole-DNUTTX_APPS_DIRD:\esp32p4-nuttx\apps-DPython3_EXECUTABLED:\esp32p4-nuttx\.venv\Scripts\python.exe-DEXTRA_FLAGS-stdgnu11注意PowerShell 中不要把路径字符串断行到中间否则 CMake 会把换行当成路径的一部分出现类似下面的错误Application directory D: \esp32p4-nuttx\apps is not found正确做法是整行复制命令或者只在参数之间换行。编译cmake--build D:\esp32p4-nuttx\build-usbconsole--parallel4本次usbconsole构建生成的主要产物为nuttx 442848 bytes nuttx.bin 225292 bytes nuttx.hex 430188 bytes nuttx.map 1227351 bytes其配置中启用了 USB 串口控制台CONFIG_ESPRESSIF_USBSERIALy CONFIG_SERIAL_CONSOLEy CONFIG_OTHER_SERIAL_CONSOLEy CONFIG_NSH_CONSOLEy12.5 烧录 usbconsole 配置烧录usbconsole版本esptool--chip esp32p4-p COM4-b 460800write-flash-fs 4MB-fm dio-ff 80m 0x2000.\build-usbconsole\nuttx.bin烧录完成后打开串口python-m serial.tools.miniterm COM4 115200如果没有立刻看到输出可以按一下开发板RESET或者在终端中敲几次回车。正常情况下会看到NuttShell (NSH) nsh可以执行nsh help nsh hello nsh ps本次usbconsole镜像的 Builtin Apps 包含dd dumpstack nsh sh hello其中hello是示例程序用于验证 NuttX 应用框架和 builtin app 机制是否正常。13. 一键构建脚本为了后续复用可以准备一个build-esp32p4-nuttx.ps1完成环境加载、首次 CMake 配置、兼容头写入、libgcc.a复制和构建powershell-ExecutionPolicy Bypass-File.\build-esp32p4-nuttx.ps1脚本核心流程1. 加载 env-esp32p4-nuttx.ps1 2. 如果 build.ninja 不存在则执行 CMake 配置 3. 写入 ESP HAL stdatomic.h 兼容头 4. 复制 libgcc.a 到 build 目录 5. 执行 cmake --build build --parallel 4 6. 整理 nuttx.manifest14. 常见问题14.1 kconfiglib 解析失败如果使用 ESP-IDF 自带 Python 环境可能遇到 NuttX Kconfig 解析失败。建议单独创建.venv并安装官方kconfiglib。python-m venv.venv.\.venv\Scripts\python.exe-m pip install kconfiglib14.1.014.2 CMake 找不到 RISC-V 编译器确认tools\bin中存在 NuttX 期望的工具名前缀riscv64-unknown-elf-gcc.exe riscv64-unknown-elf-objcopy.exe同时确认$env:GCC_EXEC_PREFIX已经指向 Espressif RISC-V GCC 的libexec\gcc\目录。14.3 esptool.py elf2image failed先检查esptool是否在 PATH 中where.exe esptool esptool version如果找不到把下面路径加入 PATHC:\Espressif\tools\python\master\venv\Scripts14.4 atomic_init / ATOMIC_VAR_INIT 编译失败这是 ESP HAL 与当前 RISC-V newlib / GCC 头文件组合下的兼容问题。可通过本文第 8 节中的stdatomic.h包装头解决。15. 总结Windows 下编译 ESP32-P4 的 NuttX 并不需要完全重新安装 ESP-IDF 工具链。关键点是1. 使用 NuttX apps 双仓库 2. 使用 esp32p4-function-ev-board:nsh 或 usbconsole 配置 3. 使用 CMake Ninja 4. 单独准备 NuttX Python venv 和 kconfiglib 5. 复用 Espressif riscv32-esp-elf 工具链 6. 处理工具链前缀、GCC_EXEC_PREFIX、libgcc.a 7. 确保 esptool 在 PATH 中并按 simple boot 地址 0x2000 烧录 8. 修正 ESP HAL stdatomic.h 兼容问题完成以上配置后Windows 下可以稳定生成nuttx nuttx.hex nuttx.bin nuttx.map其中nuttx.bin即为后续烧录 ESP32-P4-Eval-Board 的主要镜像文件。