Skip to content

Switch to Ninja and add README #53

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
218 changes: 218 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
# Pico-series microcontroller Command Line Setup

This script gives you an easy way to setup your Raspberry Pi to be able to build and run programs on your Pico-series microcontroller from the command line. Compatibility with any systems not running Raspberry Pi OS or Raspberry Pi OS Lite is not guaranteed or maintained.

To download & run this script, you can use the following commands:
```bash
wget https://raw.githubusercontent.com/raspberrypi/pico-setup/master/pico_setup.sh
chmod +x pico_setup.sh
./pico_setup.sh
```

For manual command line setup instructions for other operating systems, see [Basic Setup on Other Operating Systems](#basic-setup-on-other-operating-systems)

If you want to use a GUI instead of the command line, then see the [pico-vscode](https://github.com/raspberrypi/pico-vscode) extension instead of this script - this supports 64-bit Windows, MacOS, Raspberry Pi OS, and most common Linux distros. This is documented in the [Getting Started Guide](https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf).

## Compiling and running an example

After running the setup script, you'll want to run an example to check everything's working. First go into pico-examples:
```bash
cd pico/pico-examples
```

Depending on the board you're using (eg pico2), replace `build_pico` with the relevant build directory (eg `build_pico2`) in the following commands.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about this advice to create a board-specific build directory - IIRC we've never done that elsewhere in any of our other documentation?
(also, I suspect the vast majority of people will only have a single board and/or single type of board?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This recommendation was to follow how the script works (which uses board specific build directories), as then you can follow the instructions above exactly. Also, it avoids the need to say that you need to delete build directories when switching between Pico and Pico 2, but not Pico and Pico W


> If you're not using one of the default boards (pico, pico_w, pico2, or pico2_w), you'll need to create a new build directory for your board - you can do this with this command (replace `$board` with the board you are using):
> ```
> cmake -S . -B build_$board -GNinja -DPICO_BOARD=$board -DCMAKE_BUILD_TYPE=Debug
> ```

To build the blink example, run the following command:
```bash
cmake --build build_pico --target blink
```
This builds the specified target `blink` in the build folder `build_pico`

Then to run it, attach a Pico-series microcontroller in BOOTSEL mode, and run:
```bash
picotool load build_pico/blink/blink.uf2 -vx
```
This loads the file into Flash on the board, then verifies it was loaded correctly and reboots the board to execute it

You should now have a blinking LED on your board! For more info on the `picotool` command which is used to load and query binaries on the device, see its [README](https://github.com/raspberrypi/picotool?tab=readme-ov-file#readme)

## Console Input/Output

To view console output, you can either connect the UART output to a [Debug Probe](https://www.raspberrypi.com/documentation/microcontrollers/debug-probe.html#getting-started) (or similar) and use `stdio_uart` (see the hello_serial example), or you can use `stdio_usb` (see the hello_usb example).

First, build & run the example for your `stdio` choice on your Pico-series microcontroller with the same commands as before:
```bash
cmake --build build_pico --target hello_serial
picotool load build_pico/hello_world/serial/hello_serial.uf2 -vx
```

Then attach `minicom` to view the output:
```bash
minicom -b 115200 -D /dev/ttyACM0
```
The port number may be different, so also try `/dev/ttyACM1` etc - and on other OSes may be entirely different (eg `/dev/tty.usbmodem0001` on MacOS)

To exit minicom, type Ctrl+A then X

## Debugging with OpenOCD and GDB

To debug programs on the Pico-series microcontroller, you first need to attach a debugger such as the [Debug Probe](https://www.raspberrypi.com/documentation/microcontrollers/debug-probe.html#getting-started). Once that's done, you can attach OpenOCD to your Pico-series microcontroller with:
```bash
openocd -f interface/cmsis-dap.cfg -f target/rp2040.cfg -c "adapter speed 5000"
```

In a separate window, you can run GDB and connect to that OpenOCD server:
```bash
gdb -ex "target extended-remote localhost:3333"
```

Then in GDB, run the following (replacing blink.elf with the path to blink.elf if it's not in the current directory)
```console
file blink.elf
monitor reset init
load
continue
```

To exit GDB, use Ctrl+D twice. This will leave your Pico-series microcontroller in the halted state, so you will need to unplug and replug it to get it running again. To leave the device running, you can use:
```console
monitor reset run
```
before exiting to leave the Pico running the code.

### Useful GDB Commands
To configure the GDB layout, the following commands can be useful:
* `layout src` - displays the source code
* `layout split` - displays the source code and the assembly instructions
* `layout regs` - displays the current register contents

To step through code, you can use:
* `step` or `s` - step to the next line of code, and into any functions
* `next` or `n` - step to the next line of code, without stepping into functions
* `finish` or `fin` - step out of the current function

To step through assembly instructions, you can use:
* `stepi` or `si` - step to the next assembly instruction, and into any functions
* `nexti` or `ni` - step to the next assembly instruction, without stepping into functions

While stepping, you can just press enter again to repeat the previous command

To set breakpoints, use the `break` or `b` command plus the location of the breakpoint. The location can be:
* A function name - `break main`
* A line of code - `break 12`
* Either of those in a specific file - `break blink.c:48`, `break blink.c:main`
* A specific memory address - `break *0x10000ff2`

For more details on debugging with GDB, see the [GDB docs](https://sourceware.org/gdb/current/onlinedocs/gdb.html/)

## Multiple Terminals

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this really something we should include? won't most people just open multiple terminal instances?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given this script is to support Raspberry Pi OS Lite (as VS Code can be used everywhere else), I wanted to include how to have multiple terminals on that


When debugging or viewing serial output, you might want multiple programs open different terminals, as they all need to run at the same time.

On Raspberry Pi OS Lite, you can switch between different terminals with Alt+F1,F2,F3,F4 etc.

Alternatively you can use something like `screen` or `tmux` to allow you to open new terminals and detach from them - for example using `screen`:
* `screen -S minicom` - open a new terminal called `minicom`
* Ctrl+A then D - detach from the current terminal
* `screen -r minicom` - re-attach to an existing terminal called `minicom`
* `screen -ls` - list existing terminals

## Basic Setup on Other Operating Systems

### Prerequisites
#### Windows

If you're on Windows, it is **strongly recommended** to use [WSL2](https://learn.microsoft.com/en-us/windows/wsl/install) and then follow the [Linux instructions](#linux) inside that. You should also install [usbipd](https://github.com/dorssel/usbipd-win) to access USB devices inside WSL2 (see the docs there for instructions).

If you're not using WSL2, then you'll need to install the following tools:
* [Arm GNU Toolchain](https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads)
* Pick Windows -> AArch32 bare-metal target (arm-none-eabi) -> the .exe file
* [CMake](https://cmake.org/download/)
* [Microsoft Visual Studio](https://visualstudio.microsoft.com/downloads/)
* When running the installer, select Desktop Development with C++

Then follow the [manual setup instructions](#setup-sdk--picotool). You will need to run all commands from the "Developer PowerShell for VS ..." terminal, not your usual terminal. For the first cmake configuration in each project (eg `cmake ..`), you will need to replace `-GNinja` with `-G "NMake Makefiles"`, and anything with `sudo` needs to be run as administrator. Also, you should use as short a path as possible due to path length limits on Windows.

#### MacOS

Install [Homebrew](https://brew.sh/) and run these commands
```
xcode-select --install
brew install cmake ninja
brew install --cask gcc-arm-embedded
```

Then follow the [manual setup instructions](#setup-sdk--picotool).

#### Linux

If you have `apt`, then running the [pico_setup.sh](./pico_setup.sh) script should hopefully work for you, and you won't need to do any manual setup.

If it doesn't work, or you don't have `apt`, then you can manually install the `GIT_DEPS` (`git` & `git-lfs`) and `SDK_DEPS` (`cmake`, `gcc-arm-none-eabi`, `gcc`, `g++` & `ninja-build`) from the script. You may also need to install a cross-compiled `newlib` if it isn't included in `gcc-arm-none-eabi`, such as `libnewlib-arm-none-eabi` & `libstdc++-arm-none-eabi-newlib`. Once those are installed, follow the [manual setup instructions](#setup-sdk--picotool).

### Setup SDK & Picotool

#### SDK
Run this from the path you want to store the SDK:
```bash
git clone https://github.com/raspberrypi/pico-sdk.git
git -C pico-sdk submodule update --init
```

Then set `PICO_SDK_PATH` environment variable to that path - on MacOS or Linux, just add the following to your `.zshrc` (MacOS) or `.bashrc` file:
```bash
export PICO_SDK_PATH=/path/to/pico-sdk
```
then reload your terminal window.

On Windows, from an administrator PowerShell run:
```powershell
[System.Environment]::SetEnvironmentVariable('PICO_SDK_PATH','/path/to/pico-sdk', 'Machine')
```

#### Picotool
Run this from the path you want to store picotool:
```bash
git clone https://github.com/raspberrypi/picotool.git
```

Then install libusb
* On Windows, download and extract libUSB from here https://libusb.info/ (hover over Downloads, and click Latest Windows Binaries), and set LIBUSB_ROOT environment variable to the extracted directory.
* On MacOS `brew install libusb`
* On Linux `apt install libusb-1.0-0-dev`

Then build and install picotool using these commands
```bash
cd picotool
cmake -S . -B build
cmake --build build
sudo cmake --install .
```

To use picotool without sudo on Linux, you'll also need to install the picotool udev rules from the picotool/udev folder.

For more details on building & installing picotool, see its [README](https://github.com/raspberrypi/picotool?tab=readme-ov-file#readme)

### Test it's working with pico-examples
Clone pico-examples
```bash
git clone https://github.com/raspberrypi/pico-examples.git
cd pico-examples
```

Build them, replacing `$board` with the pico board you are using
```bash
cmake -S . -B build_$board =GNinja -DPICO_BOARD=$board -DCMAKE_BUILD_TYPE=Debug
cmake --build build
```

Put your board in BOOTSEL mode and use `picotool` to load the blink example:
```bash
picotool load build/blink/blink.uf2 -vx
```
You should now have a blinking LED on your board
22 changes: 7 additions & 15 deletions pico_setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ OUTDIR="$(pwd)/pico"

# Install dependencies
GIT_DEPS="git git-lfs"
SDK_DEPS="cmake gcc-arm-none-eabi gcc g++"
SDK_DEPS="cmake gcc-arm-none-eabi gcc g++ ninja-build"
OPENOCD_DEPS="gdb-multiarch automake autoconf build-essential texinfo libtool libftdi-dev libusb-1.0-0-dev libjim-dev pkg-config libgpiod-dev"
VSCODE_DEPS="code"
UART_DEPS="minicom"
Expand Down Expand Up @@ -102,23 +102,15 @@ do
cd $OUTDIR
done

# Build blink and hello world for pico and pico2
# Build blink and hello world for default boards
cd pico-examples
for board in pico pico2
for board in pico pico_w pico2 pico2_w
do
build_dir=build_$board
mkdir $build_dir
cd $build_dir
cmake ../ -DPICO_BOARD=$board -DCMAKE_BUILD_TYPE=Debug
for e in blink hello_world
do
echo "Building $e for $board"
cd $e
make -j$JNUM
cd ..
done

cd ..
cmake -S . -B $build_dir -GNinja -DPICO_BOARD=$board -DCMAKE_BUILD_TYPE=Debug
examples="blink hello_world"
echo "Building $examples for $board"
cmake --build $build_dir --target $examples
done

cd $OUTDIR
Expand Down