VSCode + Renode: Building a Modern Embedded Simulation Workflow
Source: Dev.to
Why Renode + VSCode?
Modern embedded development is moving away from:
- IAR + physical board + hardware programmer + serial cables
- Breakpoints and stepping limited to physical devices
- Reinstalling toolchains when switching MCU families
Towards:
- VSCode + GCC – lightweight, modern, cross‑platform
- Renode – full simulation of STM32 / ESP32 devices (UART, SPI, I2C, GPIO, DMA)
- GDB Remote Debugging – platform‑agnostic, can debug over a network
- Automation‑ready – suitable for CI/CD and reproducible testing
Benefits observed in many international companies
- Dramatically improves development efficiency
- Enables automated testing
- Allows CI pipelines to run MCU simulations
- Reduces dependency on physical hardware
Installing Renode
Renode provides several binary distributions. Choose the one that matches your platform.
- Repository:
- Example choice:
renode-latest.linux-portable-dotnet.tar.gz
Why this version?
- Bundles its own .NET runtime
- No need for a system‑installed
dotnet/mono - Runs directly on Orange Pi / Raspberry Pi
Installation steps
# Download the tarball, then extract
tar -xzf renode-latest.linux-portable-dotnet.tar.gz
cd renode
# Launch Renode
./renode
Renode Configuration
Create a minimal .resc script that describes the MCU and peripherals you want to simulate.
The example below targets an STM32F103.
using sysbus
mach create "stm32f103"
machine LoadPlatformDescription @platforms/cpus/stm32f103.repl
# Load the ELF firmware (adjust the path for your setup)
machine LoadELF @/home/orangepi/object/renode_portable/firmware.elf
# Enable UART2 analyzer
showAnalyzer sysbus.usart2
# Start GDB server on port 3333 (accessible from VSCode)
machine StartGdbServer 3333 true
start
Save this file as run_stm32.resc.
VSCode Debug Configuration
launch.json
{
"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" }
],
"postRemoteConnectCommands": [
{ "text": "monitor machine Pause" },
{ "text": "monitor sysbus LoadELF @/home/orangepi/object/renode_portable/firmware.elf" },
{ "text": "monitor cpu Reset" }
],
"externalConsole": false,
"targetArchitecture": "arm"
}
]
}
Key parameters
miDebuggerPath– path to the local GDB executable.miDebuggerServerAddress– remote Renode GDB endpoint.preLaunchTask– starts Renode on the remote machine before debugging.postRemoteConnectCommands– pauses the simulation, reloads the ELF, and resets the CPU to synchronize state.
tasks.json
{
"version": "2.0.0",
"tasks": [
{
"label": "CMake Configure",
"type": "shell",
"command": "cmake",
"args": [
"-S", "${workspaceFolder}",
"-B", "${workspaceFolder}/build",
"-DCMAKE_BUILD_TYPE=Debug"
]
},
{
"label": "CMake Build",
"type": "shell",
"command": "cmake",
"args": [
"--build", "${workspaceFolder}/build",
"--config", "Debug"
],
"dependsOn": ["CMake Configure"]
},
{
"label": "Run Renode Remote",
"type": "shell",
"command": "ssh",
"args": [
"orangepi@xxx.xxx.xxx.xxx",
"\"cd /home/orangepi/object/renode_portable && ./renode run_stm32.resc\""
],
"dependsOn": ["CMake Build"]
}
]
}
The task pipeline builds the firmware, copies the ELF and .resc script to the remote machine, starts Renode, and finally attaches the GDB debugger.
Testing
- Press F5 in VSCode.
- Renode boots on the remote board.
- The firmware loads automatically.
- UART output appears in the VSCode terminal, and breakpoints work as expected.
You now have a fully functional, modern embedded simulation workflow using VSCode, Renode, and GDB.