在传统的嵌入式开发中,我们往往需要依赖实体开发板、仿真器(ST-Link/J-Link)、各种驱动、复杂的 IDE(如 IAR、Keil),不仅环境搭建繁琐,还会受到硬件数量、条件、测试风险的限制。

但随着 Renode(Antmicro) 的成熟,现在我们终于可以:

  • 使用 VSCode + GCC 做现代化的编辑体验
  • 使用 Renode 模拟 **CPU + 外设 **
  • 使用 GDB Server 实现调试
  • 甚至可以在服务器(树莓派/OrangePi)上远程跑 Renode

过去几天,我一步步搭好了从 VSCode → Renode → GDB 的完整链路,并解决了一堆坑。 这篇文章记录完整的流程、关键配置、常见错误与解决方式。

📌 一、为什么选择 Renode + VSCode?

现代嵌入式开发已经从这样的方式:

❌ IAR + 实物板子 + 烧录器 + 串口线 + 硬件依赖 ❌ 调试断点和步进完全依赖物理板子 ❌ 一个芯片换平台就要重装一堆东西

逐渐走向:

✔ VSCode + GCC:轻量现代化开发体验 ✔ Renode:模拟 STM32/ESP32 等设备,包含 UART、SPI、I2C、GPIO、DMA ✔ GDB Remote:跨平台、可远程调试 ✔ 自动化、可脚本化

这套方式在国外公司非常常见,原因是:

  • 更高的开发效率
  • 测试可自动化
  • CI/CD 可跑仿真
  • 对硬件依赖更低

而在国内还不太普及,所以我自己实践后写下这篇文章,希望帮助更多人。

步骤:

  1. 安装Renode
  2. 配置Renode(编辑Renode的脚本)
  3. 配置VScode(.vscode/tasks.josn/.vscode/launch.josn)
  4. 测试

目标:

  1. 实现编写代码控制renode模拟外设工作
  2. 可以使用vscode配合renode对代码进行仿真

📌 二、安装 Renode

Renode 提供多个版本,你只需要选一个能跑的:

资源下载:[Renode的github仓库](renode/renode: Renode - Antmicro’s open source simulation and virtual development framework for complex embedded systems)

我的选择:


renode-latest.linux-portable-dotnet.tar.gz

理由:

  • 自带 dotnet runtime
  • 不依赖系统的 dotnet/mono
  • 可在 OrangePi / Raspberry Pi 上运行

解压后直接运行:


./renode

📌 三、配置Renode

写一个最基础的Renode.resc文件(STM32F103),这个Renode.resc相当于你要模拟MCU的配置表,Renode加载这个.resc,模拟出你想要的环境

这是我最终可运行的版本(可直接用):


using sysbus mach create "stm32f103" machine LoadPlatformDescription @platforms/cpus/stm32f103.repl # 加载固件,renode加载orangepi上.elf文件 machine LoadELF @/home/orangepi/object/renode_portable/firmware.elf # 打开 UART2 showAnalyzer sysbus.usart2 # 开 GDB 服务(端口 3333),让vscode可以使用GDB配合renode实现可视化debug machine StartGdbServer 3333 true start

你可以把它保存为:


run_stm32.resc

📌 四、VSCode 调试配置

配置launch.json,这是最关键的一步。

直接贴可运行版本(适用于 ARM Cortex-M3 / STM32F1):


{ "version": "0.2.0", "configurations": [ { "name": "Debug STM32F103 on Renode Remote", "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/build/firmware.elf", "cwd": "${workspaceFolder}", "miDebuggerPath": "arm-none-eabi-gdb", "miDebuggerServerAddress": "xxx.xxx.xxx.xxx:3333", "preLaunchTask": "Run Renode Remote", "stopAtEntry": true, "setupCommands": [ { "text": "set pagination off" }, { "text": "set confirm off" }, { "text": "set print pretty on" } ], /* On restart: pause, reload ELF, reset CPU (mimic your manual sequence) */ "postRemoteConnectCommands": [ { "text": "monitor machine Pause" }, { "text": "monitor sysbus LoadELF @/home/orangepi/object/renode_portable/firmware.elf" }, { "text": "monitor cpu Reset" } ], "externalConsole": false, "targetArchitecture": "arm" } ] }

核心点:


"miDebuggerPath": "arm-none-eabi-gdb", "miDebuggerServerAddress": "xxx.xxx.xxx.xxx:3333",

解释:

  • miDebuggerPath:本机要使用的 GDB(你电脑上安装的)
  • miDebuggerServerAddress:远端 Renode 的 GDB server 监听地址

"preLaunchTask": "Run Renode Remote",

VSCode 会先执行名称为 "Run Renode Remote" 的任务(在 tasks.json 里)。


"postRemoteConnectCommands": [ { "text": "monitor machine Pause" }, { "text": "monitor sysbus LoadELF @/home/orangepi/object/renode_portable/firmware.elf" }, { "text": "monitor cpu Reset" } ],

这是整个调试流程的灵魂。

逐句解释:

① 暂停仿真


monitor machine Pause

防止 Renode 继续运行旧固件。

② 在 Renode 内重新加载 ELF


monitor sysbus LoadELF @/home/orangepi/object/renode_portable/firmware.elf

原因:

  • VSCode 每次 build 完成本地有一个 ${workspaceFolder}/build/firmware.elf
  • 但是远程服务器上的 ELF 通常在另一个目录,比如 /home/orangepi/object/...
  • 重新加载 ELF 可以让 Renode 与最新符号一致

这是 “本地 build → scp → 远端自动加载” 的机制。

③ 重置 CPU(类似 reset halt)


monitor cpu Reset

相当于:

  • 程序从头开始运行
  • 下一步 VSCode 会停在 main()

这个序列相当于模拟 FreeRTOS 中的 debug reset。

Tasks.json配置

出了launch.json,还有tasks.json需要配置,配置如下:


{ "version": "2.0.0", "tasks": [ /* === 1. CMake Configure === */ { "label": "CMake Configure", "type": "shell", "command": "cmake", "args": [ "-S", "${workspaceFolder}", "-B", "${workspaceFolder}/build", "-DCMAKE_BUILD_TYPE=Debug" ], "problemMatcher": ["$gcc"] }, /* === 2. CMake Build === */ { "label": "CMake Build", "type": "shell", "command": "cmake", "args": [ "--build", "${workspaceFolder}/build", "--config", "Debug" ], "dependsOn": ["CMake Configure"], "problemMatcher": ["$gcc"] }, /* === 3. 上传 ELF === */ { "label": "Upload ELF", "type": "shell", "command": "scp", "args": [ "${workspaceFolder}/build/firmware.elf", "root@192.168.31.135:/home/orangepi/object/renode_portable/" ], "dependsOn": ["CMake Build"], "problemMatcher": [] }, /* === 4. 上传 RESC === */ { "label": "Upload RESC", "type": "shell", "command": "scp", "args": [ "${workspaceFolder}/renode/platform.resc", "root@xxx.xxx.xxx.xxx:/home/orangepi/object/renode_portable/" ], "problemMatcher": [] }, /* === 5. 关闭旧 Renode 实例 === */ { "label": "Close Renode Remote", "type": "shell", "command": "ssh", "args": [ "root@xxx.xxx.xxx.xxx", "pkill renode || true" ], "problemMatcher": [] }, /* === 6. 启动 Renode Remote(后台任务) === */ { "label": "Run Renode Remote", "type": "shell", "command": "ssh", "args": [ "root@xxx.xxx.xxx.xxx", "/home/orangepi/object/renode_portable/renode /home/orangepi/object/renode_portable/platform.resc" ], "dependsOn": [ "Upload ELF", "Upload RESC", "Close Renode Remote" ], "isBackground": true, "problemMatcher": { "owner": "Renode", "pattern": [ { "regexp": "^(?!.*)", "file": 0, "line": 0, "message": 0 } ], "background": { "activeOnStart": true, "beginsPattern": "Renode, version .*", "endsPattern": ".*Loaded SVD.*" } } } ] }

测试

使用vscode的一键debug,可以看到vscode正常和renode通讯,打断点和uart输出正常:

img

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐