Zephyr quickstart#

This tutorial shows you how to set up a new C++-based Zephyr project that’s ready to use Pigweed. You’ll learn how to build and run the project’s app on native_sim as well as a physical Raspberry Pi Pico. The app uses pw_log and pw_string to log messages and Zephyr’s GPIO Driver API to blink an LED.

Editing the Zephyr quickstart project in VS Code

The project’s pw_ide integration provides code intelligence and easy target swapping in VS Code#

Prerequisites#

  • Disk space: After setting everything up, the project takes ~19GB of space. The project clones the Zephyr and Pigweed repos as well as their dependencies. It also downloads toolchains and sets up a hermetic development environment.

  • Operating systems: This tutorial has only been validated on Debian-based Linux and macOS. Windows support is a work in progress.

Setup#

  1. Complete Pigweed’s First-time setup process.

  2. Clone the starter repo.

    git clone --recursive \
      https://pigweed.googlesource.com/pigweed/quickstart/zephyr \
      zephyr-quickstart
    
    git clone --recursive \
      https://pigweed.googlesource.com/pigweed/quickstart/zephyr \
      zephyr-quickstart
    

    This command downloads the main Pigweed and main Zephyr repos as Git submodules.

  3. Change your working directory to the quickstart repo.

    cd zephyr-quickstart
    
    cd zephyr-quickstart
    
  4. Bootstrap the repo.

    source bootstrap.sh
    
    source bootstrap.sh
    

    Pigweed’s bootstrap workflow creates a hermetic development environment for you, including toolchain setup!

    Tip

    For subsequent development sessions, activate your development environment with the following command:

    source activate.sh
    
    source activate.sh
    

    The activate script is faster than the bootstrap script. You only need to run the bootstrap script after updating your Zephyr or Pigweed submodules.

  5. Initialize your West workspace using the manifest that came with the starter repo.

    west init -l manifest
    
  6. Update your West workspace.

    west update
    
  7. (Optional) Initialize pw_ide if you plan on working in VS Code. pw_ide provides code intelligence features and makes it easy to swap targets.

    pw ide sync
    

Build and run the app#

Native simulator#

  1. Build the quickstart app for native_sim and run it:

    export ZEPHYR_TOOLCHAIN_VARIANT=llvm &&
      west build -p -b native_sim app -t run
    

    You should see the app successfully build and then log messages to stdout:

    [00:00:00.000,000] <inf> pigweed:  Hello, world!
    [00:00:00.000,000] <inf> pigweed:  LED state: OFF
    [00:00:01.010,000] <inf> pigweed:  LED state: ON
    [00:00:02.020,000] <inf> pigweed:  LED state: OFF
    [00:00:03.030,000] <inf> pigweed:  LED state: ON
    [00:00:04.040,000] <inf> pigweed:  LED state: OFF
    

    Important

    When building for native_sim make sure that ZEPHYR_TOOLCHAIN_VARIANT is set to llvm. See fatal error: bits/c++config.h: No such file or directory.

  2. (Optional) Build and run an upstream Zephyr sample app:

    west build -p -b native_sim third_party/zephyr/samples/basic/blinky -t run
    

Raspberry Pi Pico#

  1. Build the quickstart app for Raspberry Pi Pico:

    export ZEPHYR_TOOLCHAIN_VARIANT=zephyr &&
      west build -p -b rpi_pico app
    

    Important

    When building for physical boards make sure that ZEPHYR_TOOLCHAIN_VARIANT is set to zephyr. See fatal error: bits/c++config.h: No such file or directory.

  2. Install the Pico SDK and picotool so that you can easily flash the quickstart app onto your Pico over USB without needing to manually put your Pico board into BOOTSEL mode:

    pw package install pico_sdk
    pw package install picotool
    
  3. Add the following rules to /etc/udev/rules.d/49-pico.rules or /usr/lib/udev/rules.d/49-pico.rules. Create the file if it doesn’t exist.

    # RaspberryPi Debug probe: https://github.com/raspberrypi/debugprobe
    SUBSYSTEMS=="usb", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="000c", MODE:="0666"
    KERNEL=="ttyACM*", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="000c", MODE:="0666"
    # RaspberryPi Legacy Picoprobe (early Debug probe version)
    SUBSYSTEMS=="usb", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="0004", MODE:="0666"
    KERNEL=="ttyACM*", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="0004", MODE:="0666"
    
    # RP2040 Bootloader mode
    SUBSYSTEMS=="usb", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="0003", MODE:="0666"
    KERNEL=="ttyACM*", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="0003", MODE:="0666"
    # RP2040 USB Serial
    SUBSYSTEMS=="usb", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="000a", MODE:="0666"
    KERNEL=="ttyACM*", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="000a", MODE:="0666"
    
    # RP2350 Bootloader mode
    SUBSYSTEMS=="usb", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="000f", MODE:="0666"
    KERNEL=="ttyACM*", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="000f", MODE:="0666"
    # RP2350 USB Serial
    SUBSYSTEMS=="usb", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="0009", MODE:="0666"
    KERNEL=="ttyACM*", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="0009", MODE:="0666"
    
  4. Apply the rules:

    sudo udevadm control --reload-rules
    sudo udevadm trigger
    
  5. Flash the app onto your board:

    picotool reboot -f -u &&
      sleep 3 &&
      picotool load -x ./build/zephyr/zephyr.elf
    

Troubleshooting#

fatal error: bits/c++config.h: No such file or directory#

If you see a compilation error about not being able to find <bits/c++config.h>, make sure that your ZEPHYR_TOOLCHAIN_VARIANT environment variable is correctly set:

  • Set it to llvm when building for native_sim.

  • Set it to zephyr when building for physical boards.

Here’s an example of the error:

...
[2/109] Generating include/generated/version.h
-- Zephyr version: 3.6.99 (~/zephyr-quickstart/third_party/zephyr), build: v3.6.0-1976-g8a88cd4805b0
[10/109] Building CXX object modules/pigweed/pw_string/CMakeFiles/pw_string.to_string.dir/type_to_string.cc.obj
FAILED: modules/pigweed/pw_string/CMakeFiles/pw_string.to_string.dir/type_to_string.cc.obj
ccache /usr/bin/g++
...
-c ~/zephyr-quickstart/third_party/pigweed/pw_string/type_to_string.cc
In file included from ~/zephyr-quickstart/third_party/pigweed/pw_string/public/pw_string/type_to_string.h:20,
                 from ~/zephyr-quickstart/third_party/pigweed/pw_string/type_to_string.cc:15:
/usr/include/c++/13/cstdint:38:10: fatal error: bits/c++config.h: No such file or directory
   38 | #include <bits/c++config.h>
      |          ^~~~~~~~~~~~~~~~~~
compilation terminated.
...
[12/109] Building CXX object modules/pigweed/pw_string/CMakeFiles/pw_string.builder.dir/string_builder.cc.obj
FAILED: modules/pigweed/pw_string/CMakeFiles/pw_string.builder.dir/string_builder.cc.obj
ccache /usr/bin/g++
...
-c ~/zephyr-quickstart/third_party/pigweed/pw_string/string_builder.cc
In file included from /usr/include/c++/13/algorithm:60,
                 from ~/zephyr-quickstart/third_party/pigweed/pw_string/public/pw_string/string_builder.h:21,
                 from ~/zephyr-quickstart/third_party/pigweed/pw_string/string_builder.cc:15:
/usr/include/c++/13/bits/stl_algobase.h:59:10: fatal error: bits/c++config.h: No such file or directory
   59 | #include <bits/c++config.h>
      |          ^~~~~~~~~~~~~~~~~~
compilation terminated.
[15/109] Building C object zephyr/CMakeFiles/offsets.dir/arch/posix/core/offsets/offsets.c.obj
ninja: build stopped: subcommand failed.
FATAL ERROR: command exited with status 1: ~/zephyr-quickstart/environment/cipd/packages/cmake/bin/cmake
  --build ~/zephyr-quickstart/build --target run