Setting Up Visual Studio Code to Compile and Debug C/C++ for BBC Micro:bit V2 on Raspberry Pi Using CODAL

by kevinjwalters in Circuits > Microcontrollers

87 Views, 2 Favorites, 0 Comments

Setting Up Visual Studio Code to Compile and Debug C/C++ for BBC Micro:bit V2 on Raspberry Pi Using CODAL

vsc-rasberrypi-compiledebug-microbit-title.jpg

This article shows how Microsoft's Visual Studio Code can be installed on a Raspberry Pi to cross-compile and remotely debug C/C++ programs on a microcontroller like the BBC micro:bit V2. A VNC client can be used from another computer to provide a graphical login to a headless Raspberry Pi over the network.

The micro:bit V2 sample programs using CODAL are used to demonstrate compiling and remote debugging. The Component Oriented Device Abstraction Layer (CODAL) is an evolution of the Device Abstraction Layer (DAL) runtime provided for the micro:bit V1. CODAL is a useful library providing fibers (user-level threads) and support for the micro:bit's many features. It is used by MicroPython for the micro:bit V2 and MakeCode.

Note: Visual Studio and Visual Studio Code (VS Code) are two different products despite sounding very similar.

Supplies

  1. Raspberry Pi.
  2. A suitable power supply for the Raspberry Pi.
  3. A heatsink for the Raspberry Pi, useful for Pi 4 and Pi 5.
  4. Minimum 16 GB microSD card and someway to insert this into another computer like a microSD USB adapter.
  5. A BBC micro:bit V2.

A Raspberry Pi 5 8GB with passive Edatec ED-PI5CASE-OB heatsink, a 128GB microSD card and a Raspberry Pi 15W USB-C Power Supply was used for this article. The 27W power supply is recommended for the Pi 5, the 15W one limits the USB peripheral powering to 600mA - this is fine for powering a micro:bit. Raspberry Pi: Heating and cooling Raspberry Pi 5 discusses the need for a heatsink for the Pi 5.

Internet searches suggest a Raspberry Pi 4 4GB is also a viable platform.

Installing Raspberry Pi OS Onto MicroSD Card

pi-imager-1.png
pi-imager-2.png
pi-imager-3.png
pi-imager-4.png

The Raspberry Pi imager program is the standard way to write an o/s image onto a microSD card from another computer. This can then be inserted into the (powered-off) Raspberry Pi.

  1. Insert the microSD card into the computer via an adapter if required.
  2. Select the appropriate Raspberry Pi hardware.
  3. Select the Raspberry Pi OS (64bit) (a port of Debian Bookwork with the Raspberry Pi Desktop (Recommended) (Raspberry Pi 3 and above are 64bit).
  4. Select device for the microSD card.
  5. Click NEXT and then EDIT SETTINGS for setup WiFi and to ensure ssh is enabled for remote access to a headless (no monitor attached) Raspberry Pi.
  6. Click on WRITE.
  7. Wait for it to finish.

Optional: Turning Off WiFi and Bluetooth

The Raspberry Pi will boot from the newly-imaged microSD card. It will use DHCP to pick up an IP address for WiFi and the ethernet, if connected.

If you are using a wired ethernet connection and want to turn off the radio devices, WiFi (and Bluetooth), this can be achieved by appending two lines to the [all] section in /boot/firmware/config.txt.

kevin@pi5:/boot $ cat config.txt
DO NOT EDIT THIS FILE

The file you are looking for has moved to /boot/firmware/config.txt

Not that one!

kevin@pi5:/boot $ cd firmware
kevin@pi5:/boot/firmware $ sudo ed config.txt # use your favourite editor
1247
/\[all\]
[all]
a
### Disable WiFi and Bluetooth
dtoverlay=disable-wifi
dtoverlay=disable-bt
.
w
1322

And then rebooting the Raspberry Pi.

$ sudo shutdown -r +1 'Reboot to apply WiFi/Bluetooth disable'

The -r option for the shutdown command will reboot the host. Using a time of +1 rather than now is a useful general precaution as it provides a short period to cancel the command and avoid a disaster if the user has got the wrong host.

The Raspberry Pi uses the same MAC address for its WiFi and ethernet. Some routers/switches may get briefly confused if they have seen two network connections from the Raspberry Pi and one of those is then disabled.

The ifconfig command can be used to verify which interfaces are UP and RUNNING.

Update Raspberry Pi OS

Some of the packages making up the Raspberry Pi OS are likely to have changed since the install image was created. These can be upgraded with two apt commands.

$ sudo apt update
$ sudo apt full-upgrade

This is likely to take 5-15 minutes and will ask the user to confirm actions.

Downloading a VNC Client - TigerVNC

vncviewer-1-43.png

A VNC client can be used for a graphical login to the Raspberry Pi over the network.

TigerVNC is a "high-performance, platform-neutral implementation of VNC (Virtual Network Computing), a client/server application that allows users to launch and interact with graphical applications on remote machines" based originally on TightVNC.

The GitHub releases page points to SourceForge for the actual downloads. There are many files to choose from, the naming scheme is explained at the bottom of the page, care is needed to select the correct one as they all sound very similar. The version 1.15.0 client for Windows (64 bit) is https://sourceforge.net/projects/tigervnc/files/stable/1.15.0/tigervnc64-1.15.0.exe/download.

Turning on the VNC Server

The Raspberry Pi OS switched from the X11 graphics server to Wayland at version 12 (bookworm) in June 2023. The realvnc service is still included but this is only applicable to X11. The wayvnc is the appropriate VNC service for Wayland. This can be enabled to start at boot time and started with the following commands.

$ sudo systemctl enable wayvnc
$ sudo systemctl start wayvnc

A basic check can be performed on the health of the service after it's started.

kevin@pi5:~ $ LC_CTYPE=C systemctl status wayvnc
* wayvnc.service - VNC Server
Loaded: loaded (/lib/systemd/system/wayvnc.service; enabled; preset: enabled)
Active: active (running) since Tue 2025-07-01 14:42:18 BST; 1h 21min ago
Docs: man:wayvnc
Main PID: 744 (sh)
Tasks: 6 (limit: 9578)
CPU: 2.846s
CGroup: /system.slice/wayvnc.service
|-744 /bin/sh /usr/sbin/wayvnc-run.sh
`-765 wayvnc --render-cursor --detached --config /etc/wayvnc/config --socket /tmp/wayvnc/wayvncctl.sock

Jul 01 14:42:14 pi5 systemd[1]: Starting wayvnc.service - VNC Server...
Jul 01 14:42:18 pi5 systemd[1]: Started wayvnc.service - VNC Server.

The sudo command isn't needed for status commands. The LC_CTYPE environment variable is set to limit the output to ASCII to ensure it renders on Instructables.

The network ports can be seen with lsof which may need sudo depending on how the executable file is installed. The ones marked LISTEN are the ones of interest. Port 5900 is the rfb service.

kevin@pi5:~ $ sudo lsof -n -itcp
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
cupsd 740 root 6u IPv6 5069 0t0 TCP [::1]:ipp (LISTEN)
cupsd 740 root 7u IPv4 5070 0t0 TCP 127.0.0.1:ipp (LISTEN)
wayvnc 765 vnc 8u IPv6 7580 0t0 TCP *:5900 (LISTEN)
wayvnc 765 vnc 12u IPv6 10605 0t0 TCP [fe80::8eaa:5c71:3283:3387]:5900->[fe80::8436:c8ca:21ab:bc2a]:51747 (ESTABLISHED)
sshd 782 root 3u IPv4 7326 0t0 TCP *:ssh (LISTEN)
sshd 782 root 4u IPv6 7328 0t0 TCP *:ssh (LISTEN)
sshd 2262 root 4u IPv4 18797 0t0 TCP 192.168.0.105:ssh->192.168.0.11:39886 (ESTABLISHED)
sshd 2268 kevin 4u IPv4 18797 0t0 TCP 192.168.0.105:ssh->192.168.0.11:39886 (ESTABLISHED)

The wayvnc server is only suitable at the moment for a single user Raspberry Pi setup.

Installing PyOCD

pyocd-0.png

The pyOCD: Installing on non-x86 platforms page states the pyocd python package cannot be installed with its normal set of dependencies due to cmsis-pack-manager being absent on the Raspberry Pi OS. These commands will install it (just for this user) omitting the absent package.

$ pip install pyocd --no-deps --user --break-system-packages
$ pip show pyocd | sed -n -e 's/^Requires://p' | tr ',' '\012' | fgrep -v cmsis-pack-manager > pyocd.deps.txt
$ pip install $(cat pyocd.deps.txt) --no-deps --user --break-system-packages

Any packages already present on the system will not be installed.

Additional Python packages

The sortedcontainers package is also required, this can easily be installed as part of the externally-managed python environment.

$ sudo apt install python3-sortedcontainers

pyocd in $PATH

Immediately after the installation, $PATH remains unchanged and will not include pyocd.

kevin@pi5:~ $ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games
kevin@pi5:~ $ type -path pyocd

If you logout and back in then $PATH will be magically include the newly created .local/bin directory in the home directory of the user. For a graphical login using VNC Logout is one of the four buttons that appear when Shutdown is selected from the menu.

kevin@pi5:~ $ echo $PATH
/home/kevin/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games
kevin@pi5:~ $ type -path pyocd
/home/kevin/.local/bin/pyocd

Check the version

This execution of pyocd is a useful basic check for errors particularly ones that indicate a missing library.

kevin@pi5:~ $ pyocd --version
0.36.0

Installing Visual Studio Code

vsc-on-pi.png

From https://code.visualstudio.com/docs/setup/raspberry-pi Microsoft reveal they are capable of supporting more than one operating system:

Although it's not officially supported, you can run Visual Studio Code on Raspberry Pi devices.

The installation is very simple with a single package.

$ sudo apt install code

Visual Studio Code can then be run by typing code in a terminal window or selecting it from the Programming menu.

Installing Packages for Building C++ for Various ARM Processors

cmake-gcc-gdb.png

CMake

CMake is a free, cross-platform, software development tool for building applications via compiler-independent instructions.
$ sudo apt install cmake

GCC Cross-Compiler

The GNU Arm Embedded Toolchain is a ready-to-use, open-source suite of tools for C, C++ and assembly programming. The GNU Arm Embedded Toolchain targets the 32-bit Arm Cortex-A, Arm Cortex-M, and Arm Cortex-R processor families.
$ sudo apt install gcc-arm-none-eabi binutils-arm-none-eabi

GDB

GDB is a source-level debugger, capable of breaking programs at any specific line, displaying variable values, and determining where errors occurred.
This package contains a version of GDB which supports multiple target architectures.
$ sudo apt install gdb-multiarch

Installing Cortex-Debug Extension in Visual Studio Code

cortex-debug-2.jpg
cortex-debug-3.jpg

Visual Studio Code is advertised as a code editor rather than a Integrated Development Environment (IDE). Its limited features can be considerably expanded with extensions. Cortex-Debug is "an extension to add debugging capabilities for ARM Cortex-M devices to Visual Studio Code."

From https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug

  1. Start Visual Studio Code.
  2. From Preferences / Extensions menu (or Ctrl+Shift+X),
  3. search for Cortex-Debug from marus25 and click on Install
  4. the Microsoft C/C++ Extension Pack can also be installed now or later when the first source file is opened.

Setting Up GDB Path for Cortex-Debug

cortex-debug-gdbsetup-1.jpg
cortex-debug-gdbsetup-2.jpg
cortex-debug-gdbsetup-3.jpg

The GDB binary for remote debugging on the Raspberry Pi is gdb-multiarch, not arm-none-eabi-gdb. This needs to be set in the configuration for the Cortex-Debug extension.

  1. From Preferences / Extensions menu (or Ctrl+Shift+X),
  2. search for Cortex-Debug and click on entry
  3. click on the settings icon in the Cortex-Debug (to the right of Uninstall button)
  4. click on Settings from the menu.
  5. scroll down to Cortex-debug: Gdb Path and click on Edit in settings.json for this entry, this will open up a file with a "" (empty string) value for the parameter.
  6. set the value to be "gdb-multiarch" and save the file.

The configuration file should look like this.

{
"cortex-debug.gdbPath": "gdb-multiarch",
}

This is discussed in a Raspberry Pi Forum thread and a StackOverflow question.

Download, Compile and Deploy Sample Code

vsc-cmake-build-1.jpg

Download

  1. Run Visual Studio Code.
  2. Click on the Source Code icon (Ctrl+Shift+G) on the left (Activity) bar and click on Clone Repository button, type https://github.com/lancaster-university/microbit-v2-samples.git into the box and then create a new directory called src to put it in. Click on Open when it gives you the option to open the folder.

Compile

  1. Click on the CMake icon on the left (Activity) bar, under PROJECT OUTLINE / codal there will be a CMAKELists.txt file, right click on this and select Build All Projects. This will produce a MICROBIT.hex file in the top level directory from source/main.cpp.

Command Line Deployment

This is a basic check to ensure the connectivity to the micro:bit is okay.

  1. Plugin the micro:bit. A dialogue box will appear, dismiss this by clicking Cancel.
  2. From a terminal window check the serial console has appeared and the MICROBIT drive has been mounted.
  3. Copy the src/MICROBIT.hex file to the MICROBIT drive. The amber light next to the micro:bit's USB connector will flash as the program is installed.
  4. The micro:bit will make a noise and a heart will appear on its display.
kevin@pi5:~ $ ls -l /dev/ttyACM*
crw-rw----+ 1 root plugdev 166, 0 Jul 1 22:54 /dev/ttyACM0
kevin@pi5:~ $ df | fgrep MICROBIT
/dev/sda 65532 132 65400 1% /media/kevin/MICROBIT


kevin@pi5:~ $ ls -l src/microbit-v2-samples/MICROBIT.hex
-rw-r--r-- 1 kevin kevin 914857 Jul 1 22:46 src/microbit-v2-samples/MICROBIT.hex
kevin@pi5:~ $ cp src/microbit-v2-samples/MICROBIT.hex /media/kevin/MICROBIT

Running Sample Code Under Debugger

Compiling and Debugging C++ for micro:bit in Visual Studio Code on Rapsberry Pi 5

The image of the monitor in the video isn't great due to aliasing effects from the camera used to record it but most of the text is legible. The 720 line resolution version may appear better.

  1. 00:00 TigerVNC is being used to connect to the Raspberry Pi 5, the BBC micro:bit has been left running a simple MicroPython program which illuminates a display row at brightness level of 5/9 and moves that every 5 seconds.
  2. 00:10 Run Visual Studio Code from the menu.
  3. 00:25 Open src/microbit-v2-samples folder.
  4. 00:41 Build the hex file.
  5. 01:12 Open src/microbit-v2-samples/sources/main.cpp file.
  6. 01:17 Set a breakpoint on the function call out_of_box_experience().
  7. 01:26 Start debugger - this sends the code to the micro:bit, at 01:29 the current program can be seen to stop.
  8. 02:09 Single step code.
  9. A mix of Step Over and Step Inside is used, the former will run all of a function without single-stepping each line in each called function.
  10. 02:43 Leave the while loop running, this will allow interrupts to be serviced and CODAL fibers to run.
  11. 02:52 Stop the debugger.

This is a very simple demonstration of a breakpoint and single-stepping. There are many panes on the left (VARIABLES, WATCH, CALL STACK, BREAKPOINTS, CORTEX LIVE WATCH, XPERIPHERALS) showing more functionality available.

The variable brightness LED matrix display provided by CODAL for the micro:bit is implemented with interrupts. The video demonstrates how interrupts are affected when the heart image is displayed and the program pauses - this must also pause interrupt servicing preventing the display image from being maintained correctly. This form of audio must also use hardware features and/or interrupts to produce the complete sound effect.

While breakpoints implemented in hardware can have no impact on the behaviour of the processor, many debugging features or actions will cause a change in timing which may unfortunately change the behaviour of the code.

A Look at the Debug Configuration Files

microbitv2samples-launchjson.jpg

The microbit-v2-samples repository includes a .vscode directory. This conveniently includes a launch.json file with three entries under configurations, the first one is the pyOCD one, shown below and above as a screenshot from Visual Studio Code.

{
"configurations": [
{
"name": "micro:bit PyOCD Cortex Debug",
"cwd": "${workspaceFolder}",
"executable": "build/MICROBIT",
"request": "launch",
"type": "cortex-debug",
"servertype": "pyocd",
"interface": "swd",
"device": "nrf52",
"targetId": "nrf52",
"svdFile": "libraries/codal-nrf52/nrfx/mdk/nrf52833.svd",
"preLaunchCommands": [
"load build/MICROBIT",
"enable breakpoint",
"monitor reset"
]
},

The executable here is not the hex file, it's the same code in an elf format executable.

This also sets the System View Description (SVD) file which provides information about the memory-mapped hardware for the Nordic nRF52833's internal peripherals.

A Look at Hardware Needed (or Not Needed)

three-hardware-debugers.jpg
microbit-two-mcu-debug-diagram.png

A microcontroller can be debugged via an SWD or JTAG interface. This needs to somehow be connected to a remote computer for remote debugging. This might be via a hardware probe, some low-end examples are listed below.

  1. Raspberry Pi Debug Probe (a Pi Pico can also be used with debugcode firmware)
  2. STLINK-V3MINIE
  3. J-Link EDU Mini (for for non-profit educational purposes only)

It could also be via an onboard probe which may just be another microcontroller acting as a USB interface and running some specialist firmware, some examples for hobbyist boards are listed below.

  1. BBC micro:bit (all of these run DAPLink firmware)
  2. V1: Freescale KL26
  3. V2.00: Freescale KL27
  4. V2.2x: Nordic nRF52820 (or nRF52833)
  5. Arduino UNO R4 WiFi: ESP32-S3

This explains how the micro:bit V2.21 used in this article can be debugged without any additional hardware.

Going Further

nrf528333-productspec-swddebugandtrace.png

You're now ready to write your own programs or debug existing ones.

Further reading on remote microcontroller debugging and Visual Studio Code:

  1. Raspberry Pi News: Visual Studio Code comes to Raspberry Pi (12-Feb-2021)
  2. Learn Embedded Systems: How to Debug the Raspberry Pi Pico Using Another Pico! - Picoprobe and VSCode Tutorial (YouTube)
  3. media.ccc.de (YouTube)
  4. 38C3 - Demystifying Common Microcontroller Debug Protocols
  5. Debugging Microcontrollers - talk by Niklas Hauser talk on remote debugging and graphical profiling with gdb and additional tools.
  6. Kevin Powell: How to get started with VS Code (YouTube)
  7. CODAL documentation
  8. Visual Micro: Debugging BBC Micro:Bit in Visual Studio with Arduino (YouTube)
  9. Arduino: Debugging Fundamentals - overview of many techniques for debugging including hardware for remote debugging.

Appendix A: Version Summary

These are the software versions used for this article.

  1. Raspberry Pi Imager: 1.9.4
  2. Rapsberry Pi OS: Raspberry Pi OS (64bit) (a port of Debian Bookwork with the Raspberry Pi Desktop (released 2025-05-13, uname -a output: Linux pi5 6.12.25+rpt-rpi-2712 #1 SMP PREEMPT Debian 1:6.12.25-1+rpt1 (2025-04-30) aarch64 GNU/Linux)
  3. TigerVNC client: v1.15.0
  4. Visual Studio Code: 1.101.2
  5. arm-none-eabi-g++: (15:12.2.rel1-1) 12.2.1 20221205
  6. gdb-multiarch: GNU gdb (Debian 13.1-3) 13.1
  7. pyOCD: 0.36.0
  8. Cortex-Debug: 1.12.1
  9. microbit-v2-samples: 0cb9cfe

The hardware was a Raspberry Pi 5 and a BBC micro:bit V2.21.