A minimal experimental implementation of debugpy for MicroPython, enabling remote debugging with VS Code and other Debug Adapter Protocol (DAP) compatible debuggers.
import debugpy
# Start listening for debugger connections
host, port = debugpy.listen() # Default: 127.0.0.1:5678
print(f"Debugger listening on {host}:{port}")
# Enable debugging for current thread
debugpy.debug_this_thread()
# Your code here...
def my_function():
x = 10
y = 20
result = x + y # Set breakpoint here in VS Code
return result
result = my_function()
print(f"Result: {result}")
Create a .vscode/launch.json
file in your project:
{
"version": "0.2.0",
"configurations": [
{
"name": "Attach to MicroPython",
"type": "python",
"request": "attach",
"connect": {
"host": "127.0.0.1",
"port": 5678
},
"pathMappings": [
{
"localRoot": "${workspaceFolder}",
"remoteRoot": "."
}
],
"justMyCode": false
}
]
}
- Run your MicroPython script with debugpy
- In VS Code, press
F5
or use "Run and Debug" to attach - Set breakpoints and debug as usual
Build MicroPython Unix port with debugging support:
cd ports/unix
make CFLAGS_EXTRA="-DMICROPY_PY_SYS_SETTRACE=1"
To be reviewed - The firmware version and build configuration need verification
Flash custom firmware with debugging enabled:
# Erase flash
esptool --chip esp32 --port /dev/ttyUSB0 erase_flash
# Flash firmware
esptool.py --chip esp32 --port /dev/ttyUSB0 -b 921600 write_flash --flash_mode keep --flash_size detect --compress 0x1000 firmware/build-ESP32_GENERIC/firmware.bin
To be reviewed - Version information needs verification The firmware includes:
- MicroPython v1.26.0-preview.272.ga7c7a75eef.dirty
MICROPY_PY_SYS_SETTRACE = 1
MICROPY_PY_SYS_SETTRACE_SAVE_NAMES = 1
- Breakpoints: Set and manage breakpoints in your code
- Step Operations: Step over/into/out of functions
- Stack Inspection: View call stack and frame information
- Variable Inspection: To be reviewed - Contradictory statements about variable support
- Expression Evaluation: Evaluate expressions in the current context
- Pause/Continue: Control execution flow
- Unix Port: Full debugging support for development
- ESP32: Remote debugging over WiFi
- VS Code Integration: Semi-Complete DAP protocol support
Start listening for debugger connections.
- Parameters:
port
(int),host
(str) - Returns: Tuple of (host, port) actually used
Enable debugging for the current thread by installing the trace function.
Trigger a manual breakpoint that will pause execution if a debugger is attached.
Wait for the debugger client to connect and initialize.
Check if a debugger client is currently connected.
- Returns: Boolean indicating connection status
Disconnect from the debugger client and clean up resources.
# Start MicroPython with your script
firmware/unix_debug_enabled/micropython test_vscode.py
# Connect VS Code debugger to 127.0.0.1:5678
For detailed protocol analysis:
# Terminal 1: Start your MicroPython script
firmware/unix_debug_enabled/micropython test_vscode.py
# Terminal 2: Start DAP monitor
python3 python-ecosys/debugpy/dap_monitor.py
# VS Code: Connect to port 5679 instead of 5678
The monitor shows all DAP message exchanges:
[DAP] RECV: request initialize (seq=1)
[DAP] args: {...}
[DAP] SEND: response initialize (req_seq=1, success=True)
The workspace includes several predefined tasks for different scenarios:
flowchart LR
subgraph VS Code Launch Configs
l_unix_file["Unix: Current File"]
l_unix_module["Unix: Module"]
l_esp32_module["ESP32: Module"]
l_unix_monitor["Unix + DAP Monitor"]
end
subgraph Tasks
mp_unix_file["Run Current File"]
mp_unix_launcher["Run start_debugpy.py"]
mp_esp32_upload["Upload & Run ESP32"]
DAP_monitor["DAP Protocol Monitor"]
end
l_unix_file --> mp_unix_file
l_unix_module --> mp_unix_launcher
l_esp32_module --> mp_esp32_upload
l_unix_monitor --> DAP_monitor
- Connection Failures: Ensure MicroPython is listening before connecting VS Code
- Breakpoint Issues: Check that
sys.settrace
support is enabled in firmware - Variable Inspection: To be reviewed - Behavior depends on configuration flags that may be inconsistent
Enable VS Code's DAP logging:
- Open VS Code settings (Ctrl+,)
- Search for
debug.console.verbosity
- Set to
verbose
- Set
debug.allowBreakpointsEverywhere
totrue
A successful debug session follows this sequence:
initialize
→ capabilities responseinitialized
eventsetBreakpoints
→ verified breakpointsconfigurationDone
→ readyattach
→ connected- On breakpoint:
stopped
event stackTrace
→ frame informationscopes
→ variable scopes
- Public API (
public_api.py
): User-facing functions - Debug Session (
debug_session.py
): DAP protocol handler - PDB Adapter (
pdb_adapter.py
): Trace system bridge - Messaging (
messaging.py
): JSON/DAP messages - Constants (
constants.py
): Protocol definitions
The implementation includes advanced local variable introspection through MicroPython's enhanced sys.settrace()
functionality:
frame.f_locals
provides access to local variables- Memory-safe with GC lock checking
- Fallback to generic names (
local_01
,local_02
) when needed
When variable name preservation is enabled:
- Actual variable names are preserved in bytecode
- Variables appear with real names:
{'foo': 'hello', 'bar': 123}
- Reverse slot assignment ensures correct variable-to-slot mapping
To enable debugging features, ensure the following flags are set:
make -C ports/unix CFLAGS_EXTRA="-DMICROPY_PY_SYS_SETTRACE=1 -DMICROPY_PY_SYS_SETTRACE_SAVE_NAMES=1"
// Required for basic debugging
#define MICROPY_PY_SYS_SETTRACE (1)
// Enhanced variable name preservation (method 1 - [PR#4](https://github.com/andrewleech/micropython/pull/4))
#define MICROPY_PY_SYS_SETTRACE_SAVE_NAMES (1)
// Alternative broader support (method 2 - [PR#5](https://github.com/andrewleech/micropython/pull/5))
#define MICROPY_SAVE_LOCAL_VARIABLE_NAMES (1)
- MicroPython: Built with
MICROPY_PY_SYS_SETTRACE=1
- Socket Support: For network communication
- JSON Support: For DAP message parsing
- Memory: Minimal overhead (~4 bytes per local variable mapping)
This is a minimal implementation with these current limitations:
-
Single-threaded debugging only
-
No conditional breakpoints
-
No function breakpoints
-
Limited nested object expansion
-
No step back functionality
-
No hot code reloading
-
Variable inspection support varies by configuration - may show generic names or real names
-
Maximum 32 local variables per stackFrame (configurable at compile time)
- MicroPython Unix port
- MicroPython ESP32 port
- VS Code with Python/debugpy extension
- CPython 3.x (for comparison)
- Works with or without variable name preservation
- Progressive enhancement as more features are enabled
- Existing code continues to work without modification
This implementation provides a foundation for MicroPython debugging. Contributions welcome for:
- Conditional breakpoint support
- Enhanced variable inspection
- Multi-threading support
- Performance optimizations
- Additional DAP protocol features
- More hardware platform support
Note:
- Contributions for features should go directly to the MicroPython and micropython-lib repositories (or existing PRs)
- If you have samle configurations or tests or additional firmwares, they are welcome here
MIT License - see the MicroPython project license for details.