Developing on the RP2040 / Pi Pico with Docker and JLink

I love working with the Pi Pico / RP2040 microcontroller, but setting up the pico SDK can be a bit of a pain in the butt, especially while hopping across a few separate devices and operating systems (as I was for a while).

After a few years of messing around with it, I’ve settled on a reasonably painless solution for developing with the Pico that uses a custom-built docker container loaded with the pico SDK, arm-none-eabi compiler and debug tools, and the JLink debugger utility. With this setup, you can easily compile and debug programs for the Pi Pico / RP2040 by adding a single docker compose file to your project repo, mapping in the directories that you want to be bind mounted into your docker container, and setting up a VS Code .launch file to work with JLink.

Software and Hardware Requirements

You’ll need the following software installed on your computer:

This workflow is intended for use with a J-Link debugger, like the J-Link EDU, J-Link Base, and J-Link Plus. I personally use a J-Link Base, please let me know if there are any issues with other debuggers!

Installation

Docker Compose File (compose.yml)

Add the following code into a file called compose.yml in your project directory.

version: "3.2"
services:
  pico-docker:
    image: coolnamesalltaken/pico-docker:latest
    volumes:
      - type: bind
        source: . # Which directory from the host computer gets mounted to the container.
        target: /project_directory # Where the directory gets mounted in the Docker container.
      # You can bind additional project directories to the container with more - type: bind commands,
      # or create volumes that give the container its own storage.
    command: tail -f /dev/null # keep the container running forever

VS Code Configuration (launch.json)

This file is still somewhat a work in progress, but works well enough for me as it is. I do notice that I have to reset the device using the VS code debug buttons to get a firmware upload to complete properly, so there might still be some settings that I’m missing. Anyways, adding this file into your .vscode folder as launch.json will allow you to connect to your RP2040 from within the docker container, via an IP connection to the JLink GDB server running on your host machine (which in turn is connected to your JLink debugger via USB).

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Remote Debug",
            "type": "cortex-debug",
            "cwd": "${workspaceRoot}",
            "executable": "${command:cmake.launchTargetPath}",
            "request": "attach",
            "servertype": "external",
            "gdbPath": "arm-none-eabi-gdb",
            "gdbTarget": "host.docker.internal:2331",
            "showDevDebugOutput": "raw",
            "svdFile": "/usr/local/pico-sdk/src/rp2040/hardware_regs/rp2040.svd",
            "preRestartCommands": [
                "file ${command:cmake.launchTargetPath}",
                "load",
                "monitor reset"
            ],
            "device": "RP2040",
        }
    ]
}

J-Link GDB Server Settings

These are the settings I use for the J-Link GDB server that I run on my host computer.

Usage

When everything is set up and running, the development workflow looks like:

  1. Launch Docker Desktop on the host computer.
  2. Run docker compose up in your project directory where the docker compose file resides on your host computer.
  3. Launch VS Code on the host computer and attach a remote VS Code editor to the pico-docker container.
  4. Launch J-Link GDB Server on the host computer and connect to the RP2040 over USB.
  5. In the remote VS code editor, you can edit your code, compile and debug your code on the container with GNU gcc/g++/gdb, compile your code for the target with arm-none-eabi gcc/g++, and upload your code to the target via J-link using the launch.json file provided. Additional directories with libraries like googletest can be bind mounted to the docker container by editing compose.yml if you want to use unit tests!

Posted by jmcnelly

Leave a Reply