This is a library to write Nim code for Raspberry Pi Pico series and wraps Raspberry Pi Pico SDK.
By using this library with hidecmakelinker and write config.nims
, you can build your code with nim c blink.nim
and it doesn't require nimble.
You can wrap C libraries related to Raspberry Pi Pico on Nim module and use it without adding code to build tools.
- Nim 2.0.0
- hidecmakelinker
- CMake 3.13 or newer
- pathX
- Raspberry Pi Pico SDK
git clone https://github.com/raspberrypi/pico-sdk.git --branch master --depth 1 --recurse-submodules --shallow-submodules
- Build tools required by Raspberry Pi Pico SDK
- For more details: https://github.com/raspberrypi/pico-sdk
- Read Getting Started with the Raspberry Pi Pico-Series
- If you are Gentoo Linux user: https://wiki.gentoo.org/wiki/Crossdev
- Install binutils, gcc, new and gdb targets arm-none-eabi
- Build or install OpenOCD if you want to use Picoprobe or Raspberry Pi Debug Probe
- Read Appendix A: Debugprobe in Getting Started with the Raspberry Pi Pico-Series
- Install picotool if you use it.
Pico SDK use it to create UF2 file, hash and sign binaries.
If picotool is not installed, Pico SDK automatically download the source and build it.
But it takes long time, and it is cached only for one project and it is built again when you compile other projects.
If you installed picotool to a custom path, define
PicotoolDir
with the path to the directory containing picotool by adding-d:PicotoolDir=/path/to/picotool
to nim command line options orswitch("define", "PicotoolDir=/path/to/picotool")
toconfig.nims
. If you don't use picotool, definePicoNoPicotool
so that Pico SDK don't build picotool.
- For more details: https://github.com/raspberrypi/pico-sdk
Before installing picosdk4nim, make sure that build tools, CMake and Raspberry Pi Pico SDK are installed, and you can build example C code with CMakeLists.txt
in https://github.com/raspberrypi/pico-sdk/blob/master/README.md
Install using nimble:
$ nimble install https://github.com/demotomohiro/picosdk4nim
or install pathX and hidecmakelinker, and clone the project and set Nim import path so that you can import modules in src
directory:
$ git clone https://github.com/demotomohiro/picosdk4nim.git
Create config.nims
with following content:
switch("define", "release")
switch("mm", "arc") # use "arc", "orc" or "none"
switch("define", "checkAbi")
switch("define", "useMalloc")
switch("cpu", "arm")
switch("os", "any")
switch("threads", "off")
# If you use C++ backend:
# "quirk" works with C++ backend and produce smallest code, but you would better to learn how it works.
# See: https://nim-lang.org/araq/quirky_exceptions.html
# https://github.com/nim-lang/Nim/issues/10713
# "setjmp" works with C++ backend but produced code is larger than quirk. It needs `switch("define", "noCppExceptions")`.
# "cpp" is the default when compiling with C++ backend. It works but produces largest code. You might need to use this when using C++ libraries that throw C++ exceptions.
# "goto" might not work with C++ backend.
# See: https://github.com/nim-lang/Nim/issues/22686#issuecomment-1713374179
#switch("exceptions", "setjmp")
#switch("define", "noCppExceptions")
switch("gcc.linkerexe", "hidecmakelinker")
switch("gcc.cpp.linkerexe", "hidecmakelinker")
switch("gcc.exe", "void")
switch("gcc.cpp.exe", "void")
nimcacheDir().mkDir()
# If you want .uf2 file
switch("define", "PicoAddExtraOutput")
In main module, following code is needed:
import picosdk4nim
import hidecmakelinkerpkg/libconf
# Call this after importing all modules
writeHideCMakeToFile()
Then you can compile blink.nim
with following command:
$ nim c -d:PicoSDKPath=/path/to/pico-sdk/ blink.nim
You can put -d:PicoSDKPath=/path/to/pico-sdk/
option as switch("define", "/path/to/pico-sdk")
to config.nims
in any directories Nim searches for .nims
configuration files.
In default, output binary is compiled for Raspberry Pi Pico board.
If you want to run it on other boards with RP series micro controllers, set the board name to PicoBoard
build option.
For example:
# Build for Raspberry Pi Pico W
$ nim c -d:PicoBoard=pico_w blink.nim
# Build for Raspberry Pi Pico 2
$ nim c -d:PicoBoard=pico2 blink.nim
This is a list of board names
If you find the board name in the list, remove '.h' suffix and set it to PicoBoard
.
When you add or change PicoBoard or PicoPlatform build option, please clear the Nim cache directory before building.
-f
option doesn't works in this case because it doesn't delete CMake build directory in Nim cache directory.
If you didn't delete the Nim cache directory, you will get CMake error or C code are compiled with wrong compile options.
There several ways to loading a program to Pico to run and they are not different from programs compiled from C. See "Getting Started with the Raspberry Pi Pico-Series" in Raspberry Pi Pico SDK for more details.
- Build your code with
PicoAddExtraOutput
so that*.uf2
file is generated - Make sure Pico is disconnect from USB or other power source
- Hold down
BOOTSEL
button on Pico - Connect Pico's USB port to your PC
- Release
BOOTSEL
button on Pico - Pico should be recognized as USB storage on your PC
- Copy
*.uf2
file to the storage
Use another Pico as "Picoprobe" and wire it to main Pico. Use OpenOCD on your PC to load a program to Pico. You don't need to connect and disconnect Pico to USB port everytime you load updated program.
- Build your code so that
*.elf
file is generated - Build or install OpenOCD (Read "Appendix A: Debugprobe" in Getting Started with the Raspberry Pi Pico-Series)
- If you use a second Pico or Pico 2 instead of Debug Probe, install picoprobe (Read Appedix A again) to it
- Wire Picoprobe to another Pico (Read Appedix A again)
- Set environment variable
OPENOCD_PATH
to OpenOCD directory so that$OPENOCD_PATH/src/openocd
refersopenocd
executable - Run following command (replace
blink.elf
to your*.elf
file name):$ $OPENOCD_PATH/src/openocd -s $OPENOCD_PATH/tcl -f interface/cmsis-dap.cfg -c "adapter speed 5000" -f target/rp2040.cfg -c "program blink.elf verify reset exit"
Requires Picoprobe, OpenOCD and GDB. Loaded program will be lost when Pico lost power or reset.
- Build your code with
-d:PicoBinaryType=no_flash
- Install GDB (gdb-multiarch or arm-none-eabi-gdb)
- Build OpenOCD (Read Appendix A: Debugprobe in Getting Started with the Raspberry Pi Pico-Series)
- If you use a second Pico or Pico 2 instead of Debug Probe, install picoprobe (Read Appedix A again) to it
- Wire Picoprobe to another Pico (Read Appedix A again)
- Set environment variable
OPENOCD_PATH
to OpenOCD directory so that$OPENOCD_PATH/src/openocd
refersopenocd
executable - Run following command:
$ $OPENOCD_PATH/src/openocd -s $OPENOCD_PATH/tcl -f interface/cmsis-dap.cfg -c "adapter speed 5000" -f target/rp2040.cfg
- Open another terminal and run following command (replace
blink.elf
to your*.elf
file name):If you use Gentoo Linux:$ gdb-multiarch blink.elf
$ arm-none-eabi-gdb blink.elf
- Connect to OpenOCD on GDB
(gdb) target extended-remote localhost:3333
- Run following commands on GDB
(gdb) monitor reset init (gdb) load (gdb) continue
When you change your code and build a new program, press 'c' key with ctrl key on GDB and run following commands again
(gdb) monitor reset init
(gdb) load
(gdb) continue
You can define User-defined Commands using define
on GDB:
(gdb) define reload
>monitor reset init
>load
>continue
>end
This commands can be placed on GDB's initialization file.
There are build options on src/picosdk4nim.nim
. They can be set with compiler option like -d:option=value
or switch
proc like switch("define", "option=value")
on config.nims
file.
Some of build options are corresponding to CMake build configurations/functions of Raspberry Pi Pico-series C/C++ SDK. List of these options are explained in Chapter 6~7 on Raspberry Pi Pico-Series C/C++ SDK.