Developing in C on the RP2040: macOS

9 minute read

Updated: Feb 27, 2023: Where I install the tools and frameworks necessary to develop code in C on the RP2040 on a macOS platform.

Sources

Introduction

Just as I did for the Linux platform, in this entry I’ll work through the steps required to be successful with developing code in C for the RP2040 on the Mac. Updated: This entry has been tested on both an Intel 2018 MacBook Pro and a M1 2020 Mac Mini.

Chapter 1 Building the Toolset

Homebrew is a great way to have a Mac look like a Linux system. Brew uses similar commands and is able to install similar tools as a Linux system. To start, I recommend installing homebrew then using the following to install the tools you will need:

brew install cmake
brew install git
# Both Arm (M-variants) and Intel Mac may use this command
brew install gcc-arm-embedded
# various tools required for picotool etc, install as well
brew install libtool automake libusb wget pkg-config gcc texinfo

The application make might already be installed, however if it isn’t, you may use brew install make to install it as well.

Chapter 2. Get the SDK and examples

Let’s install the SDK and examples and test blink! Make sure you follow the structure laid out by the Guide. A base folder of pico with subfolders of pico-sdk and pico-examples.

cd Documents
mkdir pico
cd pico
git clone -b master https://github.com/raspberrypi/pico-sdk.git
cd pico-sdk
git submodule update --init
cd ..
git clone -b master https://github.com/raspberrypi/pico-examples.git
  • For the PICO_SDK_PATH: (copy the absolute path using pwd)
cd pico-sdk
pwd
/Users/username/Documents/pico/pico-sdk
export PICO_SDK_PATH=/Users/lkoepsel/Documents/pico/pico-sdk
# If you get "Compiler 'arm-none-eabi-gcc' not found...
export PICO_TOOLCHAIN_PATH=/Applications/ARM/bin
# continuing on with building of blink
cd pico-examples
mkdir build
cd build
cmake ..
cd blink
make -j4
# plugin Pico with BOOTSEL pressed down to get RPI-RP2
cp blink.uf2 /Volumes/RPI-RP2

Success! No surprise here.

Let’s follow a similar path for Hello_World.

  1. As before with Linux, use the UART version, not USB.
  2. I use the application Serial, its lovely. If you don’t want to pay for it, minicom is available for the Mac as well. Use “brew install minicom” to install and I used “minicom -b 115200 -D /dev/tty.usbserial-A10K59P8”. Your tty address will probably be different.

Success! Again, no surprise. So far, Linux and macOS are fairly similar.

Get picotool

There’s a tool which can help with both the documentation and file management process between the PC and the Pico called picotool. Its easy to build and use, I’ll use it for uploading the UF2 file to the pico. We’ll install it in the pico directory, alongside pico-sdk and pico-examples.

# move back to the root pico folder
cd ~/Documents/pico 
# clone the picotool repository
git clone https://github.com/raspberrypi/picotool.git --branch master
# create the tool
cd picotool
mkdir build
cd build
export PICO_SDK_PATH=/Users/lkoepsel/Documents/pico/pico-sdk
cmake ..
make -j4
# Add a symbolic link to run via PATH
cd ~/bin
ln -s Documents/pico/picotool/picotool picotool

Adding to pico-examples

It’s helpful to remain in the pico-examples directory when creating new programs. I believe successful programming needs to be muscle-memory, meaning the complile/link/load/upload step needs to be something you no longer think about, you simple execute commands.

To do this I created a new version of blink then determined the changes necessary to have it complete the process using the same commands we used on blink. I also used the picotool from above to manage the upload process.

Process for a new program in pico-examples

  1. Duplicate existing folder, such as blink to blink_array
  2. Change the name of the .c file from blink to blink_array
  3. In the local CMAKELists.txt file change all blink references to blink_array
  4. In CMAKELists at root, duplicate the single line for blink and change to blink_array:
# Add blink example
add_subdirectory(blink)

# Change blink references to blink_array
add_subdirectory(blink_array)
  1. Follow original instructions:
# assuming in folder pico/pico-examples/build/blink
cd ..
cmake ..
cd blink_array
make -j4
picotool load blink_array.uf2
  1. Once cmake has been run, you may simply use the following two commands in the local build directory. For example, blink_array would be (once in the build/blink_array directory):
# assuming in folder pico/pico-examples/build/blink_array
make -j4
picotool load blink_array.uf2

Chapter 5. Flash Programming with SWD

Let’s move on to where it begins to get tricky. macOS had some issues with openOCD and openOCD is required for communication using the SWD port.

# install the tools, confirmed on Intel Mac...
cd ~/pico
git clone https://github.com/raspberrypi/openocd.git --branch rp2040 --depth=1 
cd openocd
export PATH="/usr/local/opt/texinfo/bin:$PATH"
./bootstrap
./configure --disable-werror
make -j4
# confirm it starts, it will error out as a probe isn't connected
src/openocd
cd ~/bin
ln -s ~/Documents/pico/openocd/src/openocd openocd
# confirm it works from bin
openocd -h

Problems with Compiling OpenOCD on a M1 Mac (NEEDS TO BE CHECKED WITH NEW CODE)

I had the same issue as this one, namely a missing capstone.h file prevented the openocd from compiling on an M1 Mac. Following the solution was:

brew install open-ocd --only-dependencies
brew install automake
brew install autoconf pkg-config libtool texinfo wget gcc

cd ~/projects/pico
git clone https://github.com/raspberrypi/openocd.git --branch picoprobe --depth=1 --no-single-branch
cd openocd

export PATH="$(brew --prefix)/opt/texinfo/bin:$PATH"
./bootstrap
CAPSTONE_CFLAGS="-I$(brew --prefix)/include" \
  ./configure --prefix="$(brew --prefix)"  \
  --enable-picoprobe --disable-presto --disable-openjtag
make -j4

After that, openocd did compile. Many thanks to @idcrook.

Build and Flash PicoProbe

This has been confirmed on Intel Mac, yet to be confirmed on M1 Mac

cd ~/pico
git clone https://github.com/raspberrypi/picoprobe.git
cd picoprobe
git submodule update --init
export PICO_SDK_PATH=/Users/lkoepsel/Documents/pico/pico-sdk
mkdir build
cd build
cmake ..
make -j4

Getting OpenOCD to play nice

To test the picoprobe is connected to the target pico properly, I would recommend the following process:

1. Test the Serial connection

  1. Load the target pico with the hello_serial (pico-examples/hello_world/serial) example
  2. Start up a serial program such as Serial on the Mac and see if you get the following:
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
  1. Just to make sure, change the text and confirm again:
Hello, PicoProbe!
Hello, PicoProbe!
Hello, PicoProbe!
Hello, PicoProbe!
Hello, PicoProbe!

2. Test the openocd interface

Make sure you are in the openocd directory and run:

src/openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg -s tcl -c "adapter speed 5000"
Open On-Chip Debugger 0.11.0-g8e3c38f (2023-02-28-09:55)
Licensed under GNU GPL v2
For bug reports, read
  http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport "swd". To override use 'transport select <transport>'.
Info : Hardware thread awareness created
Info : Hardware thread awareness created
Info : RP2040 Flash Bank Command
adapter speed: 5000 kHz

Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : Using CMSIS-DAPv2 interface with VID:PID=0x2e8a:0x000c, serial=E6605481DB957836
Info : CMSIS-DAP: SWD  Supported
Info : CMSIS-DAP: FW Version = 2.0.0
Info : CMSIS-DAP: Interface Initialised (SWD)
Info : SWCLK/TCK = 0 SWDIO/TMS = 0 TDI = 0 TDO = 0 nTRST = 0 nRESET = 0
Info : CMSIS-DAP: Interface ready
Info : clock speed 5000 kHz
Info : SWD DPIDR 0x0bc12477
Info : SWD DLPIDR 0x00000001
Info : SWD DPIDR 0x0bc12477
Info : SWD DLPIDR 0x10000001
Info : rp2040.core0: hardware has 4 breakpoints, 2 watchpoints
Info : rp2040.core1: hardware has 4 breakpoints, 2 watchpoints
Info : starting gdb server for rp2040.core0 on 3333
Info : Listening on port 3333 for gdb connections

3. Test uploading a file

It took a bit of work to determine how to upload a file. The key elements to fixing is that the cfg file has changed to interface/cmsis-dap.cfg and the speed must be set using “-c adapter speed 5000”. There are two versions, the first, is my test while in the openocd folder, which isn’t practical, however, great for testing in this scenario. The second will be the version I use in the future, where I am in the build folder of the program under development.

# if calling from ~/Documents/pico/openocd
openocd -s ../tcl -f ./interface/cmsis-dap.cfg -f ./target/rp2040.cfg -c "adapter speed 5000" -c  "program /Users/lkoepsel/Documents/pico/pico-examples/build/hello_world/serial/hello_serial.elf verify reset exit"

# if calling from ~/Documents/pico/pico-examples/build/program-to-upload
openocd -s ~/Documents/pico/openocd/tcl/ -f ./interface/cmsis-dap.cfg -f ./target/rp2040.cfg -c "adapter speed 5000" -c  "program hello_timer.elf verify reset exit"

Going forward, I will be using a far more simple command (same as the one in Linux), to which I can make an alias:

export OPENOCD_TCL_PATH=/Users/lkoepsel/Documents/pico/openocd/tcl
openocd -s $OPENOCD_TCL_PATH -f ./interface/cmsis-dap.cfg -f ./target/rp2040.cfg -c "adapter speed 5000" -c  "program hello_timer.elf verify reset exit"

Running gdb

I used the homebrew install version of gdb as in “brew install gdb” it installed version 13.1 and it connected to the Pico combination fine:

# in openocd:
src/openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg -s tcl -c "adapter speed 5000"
Open On-Chip Debugger 0.11.0-g8e3c38f (2023-02-28-09:55)
Licensed under GNU GPL v2
For bug reports, read
  http://openocd.org/doc/doxygen/bugs.html
Info : auto-selecting first available session transport "swd". To override use 'transport select <transport>'.
Info : Hardware thread awareness created
Info : Hardware thread awareness created
Info : RP2040 Flash Bank Command
adapter speed: 5000 kHz

Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : Using CMSIS-DAPv2 interface with VID:PID=0x2e8a:0x000c, serial=E6605481DB957836
Info : CMSIS-DAP: SWD  Supported
Info : CMSIS-DAP: FW Version = 2.0.0
Info : CMSIS-DAP: Interface Initialised (SWD)
Info : SWCLK/TCK = 0 SWDIO/TMS = 0 TDI = 0 TDO = 0 nTRST = 0 nRESET = 0
Info : CMSIS-DAP: Interface ready
Info : clock speed 5000 kHz
Info : SWD DPIDR 0x0bc12477
Info : SWD DLPIDR 0x00000001
Info : SWD DPIDR 0x0bc12477
Info : SWD DLPIDR 0x10000001
Info : rp2040.core0: hardware has 4 breakpoints, 2 watchpoints
Info : rp2040.core1: hardware has 4 breakpoints, 2 watchpoints
Info : starting gdb server for rp2040.core0 on 3333
Info : Listening on port 3333 for gdb connections
Info : accepting 'gdb' connection on tcp/3333
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x00000178 msp: 0x20041f00
target halted due to debug-request, current mode: Thread
xPSR: 0x21000000 pc: 0x10000d42 msp: 0x20041fc0
Info : RP2040 B0 Flash Probe: 2097152 bytes @10000000, in 512 sectors

Info : New GDB Connection: 1, Target rp2040.core0, state: halted
Warn : Prefer GDB command "target extended-remote 3333" instead of "target remote 3333"
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x00000178 msp: 0x20041f00
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x00000178 msp: 0x20041f00
# in hello_serial window
gdb hello_serial.elf
GNU gdb (GDB) 13.1
Copyright (C) 2023 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-apple-darwin22.3.0".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from hello_serial.elf...
(No debugging symbols found in hello_serial.elf)
(gdb) target remote localhost:3333
Remote debugging using localhost:3333
warning: multi-threaded target stopped without sending a thread-id, using first non-exited thread
0x10000d42 in sleep_until ()
(gdb) c
Continuing.
^Ctarget halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x00000178 msp: 0x20041f00

Thread 1 received signal SIGINT, Interrupt.
0x10000d42 in sleep_until ()
(gdb) c
Continuing.
^Ctarget halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x00000178 msp: 0x20041f00

Thread 1 received signal SIGINT, Interrupt.
0x10000d42 in sleep_until ()
(gdb) q
A debugging session is active.

  Inferior 1 [Remote target] will be detached.

Quit anyway? (y or n) y
Detaching from program: /Users/lkoepsel/Documents/pico/pico-examples/build/hello_world/serial/hello_serial.elf, Remote target
Ending remote debugging.
[Inferior 1 (Remote target) detached]

Make sure you have done the following so gdb can find the symbols:

cd Documents/pico/pico-examples
cd build
cmake -DCMAKE_BUILD_TYPE=Debug ..
cd hello_world
make -j4

Be sure to setup .gdbinit, go here for instructions.

Comments powered by Talkyard.