Building Zephyr for the Raspberry Pi Pico2 W

The Raspberry Pi Pico2 W is the one with a microcontroller and Wi-Fi. When most people think of Raspberry Pi as a single-board computer running Linux, this model is a microcontroller with a slew of impressive peripherals. While the original Pico (based on the RP2040) has had Zephyr support for a long time, the Pico2 is build on an RP2350 and the W variant delivers Wi-Fi support which lands in Zephyr with the upcoming release of v4.3.0.

We love taking new IoT hardware for a spin on Golioth and couldn’t resist adding the Pico2 W to our list of “works with Golioth” boards. In fact, we like this one so much we’re planning to add it to our hardware-in-the-loop (HIL) rigs to test on the hardware with each PR and push to main.

State of Pico2 W Support in Zephyr

The RP2350 has had support in Zephyr for some time now, but the option of using the Wi-Fi–available thanks to the Infineon chip on the Pico2 W board–is brand new. For now, you’ll need to build on v4.3.0-rc2 to use the Wi-Fi.

Also of note is that the last stable release of OpenOCD (0.12.0 release January 2023) does not support the RP2350. Since this is the version included in the Zephyr skd-ng, you’ll need to build OpenOCD from source (or find a newer build) in order to flash/debug the Pico2 W.

I found that building OpenOCD was pretty straight-forward. Follow the compilation instructions on the README by running the following commands:

./bootstrap
./configure
make
sudo make install

I didn’t actually run the install command, instead pointing Zephyr’s west tool to the binary and the scripts directory. More on that later.

While there is a VScode plugin for working with the Pico2 in Zephyr, I have not tried it and am unable to report as to the state of OpenOCD with that approach.

Preparing Golioth for the Pico2 W Build

The latest release of the Golioth Firmware SDK (v0.21.1) supports Zephyr v4.2.1. Find the west.yml file and update the Zephyr version to v4.3.0-rc2, then run an update to pull in the new version:

west update

That Infineon module has some secret sauce that makes the Wi-Fi work. We need to pull in the binary blobs to take advantage of that. We can do this the easy way or the hard way. While the hard way is cooler, let’s start with the easy way:

west blobs fetch hal_infineon

That will take a few minutes as all available binary blobs from Infineon are downloaded. However, when bringing this board up I also discovered that the fetch command supports regex! Using this we can filter just for the blobs we need:

west blobs fetch hal_infineon --allow-regex='img/whd/resources/(firmware/COMPONENT_43439|clm/COMPONENT_43439/COMPONENT_MURATA-1YN)/*'

Building and Running Golioth Hello for the Pico2 W

As with most new things, I want to run hello world as a first test. With much trial and error I boiled the necessary configuration down as follows:

CONFIG_NETWORKING=y
CONFIG_TEST_RANDOM_GENERATOR=y

CONFIG_NET_DHCPV4=y

CONFIG_NET_IPV4=y
CONFIG_NET_IPV6=n

CONFIG_WIFI=y
CONFIG_WIFI_LOG_LEVEL_ERR=y
CONFIG_NET_L2_WIFI_SHELL=y
CONFIG_GOLIOTH_SAMPLE_WIFI=y

Enabling networking, DHCP, and IPv4 is pretty boilerplate for Zephyr. What’s not is turning on the test random number generator. While the RP2340 has a TRNG hardware peripheral (a great improvement over the RP2040 which did not), it is not yet supported in Zephyr.

Turning on Wi-Fi is expected. The Golioth sample Wi-Fi handles auto connection for the Golioth sample applications. You may also just use the Wi-Fi shell commands to set your SSID/PSK and connect to an AP if you prefer.

For the Golioth samples, the last piece of the puzzle is to add a storage partition. The vast majority of Zephyr boards I’ve worked with enable partitions by default in the board definition but the Pico2 is an outlier in a couple of ways I’ll discuss later. For now, add a board overlay to enable a storage partition.

/* Partitioning for the RP2350A-M33 board using 4M flash.
 */
#include <raspberrypi/partitions_4M_sysbuild.dtsi>

With this we can build and run the application:

west build -p -b rpi_pico2/rp2350a/m33/w examples/zephyr/hello
west flash

Oh no, it didn’t work!

Can't find target/rp2350.cfg
FATAL ERROR: command exited with status 1: /home/mike/zephyr-sdk-0.17.4/sysroots/x86_64-pokysdk-linux/usr/bin/openocd -s /home/mike/golioth-compile/golioth-firmware-sdk/zephyr/boards/raspberrypi/rpi_pico2/support -s /home/mike/zephyr-sdk-0.17.4/sysroots/x86_64-pokysdk-linux/usr/share/openocd/scripts -f /home/mike/golioth-compile/golioth-firmware-sdk/zephyr/boards/raspberrypi/rpi_pico2/support/openocd.cfg -c 'source [find interface/cmsis-dap.cfg]' -c 'source [find target/rp2350.cfg]' -c 'set_adapter_speed_if_not_set 5000' '-c init' '-c targets' -c 'reset init' -c 'flash write_image erase /home/mike/golioth-compile/golioth-firmware-sdk/modules/lib/golioth-firmware-sdk/build/zephyr/zephyr.hex' -c 'reset run' -c shutdown

As mentioned before, we are missing official support. Let’s build again and tell Zephyr where our custom OpenOCD is located:

west build -p -b rpi_pico2/rp2350a/m33/w examples/zephyr/hello -- -DOPENOCD=/home/mike/golioth-compile/openocd/src/openocd -DOPENOCD_DEFAULT_PATH=/home/mike/golioth-compile/openocd/tcl
west flash

This time we’re in business. Now it’s just a matter of creating some Golioth credentials using the web console, opening up a serial terminal, and provisioning the device:

wifi cred add -k 1 -s your_ssid -p your_wifi_password
settings set golioth/psk-id your-golioth-psk-id
settings set golioth/psk your-golioth-psk
kernel reboot

The three values for the Wi-Fi credentials are set using Zephyr’s built-in settings. The -k is encryption types, while -s and -p are SSID and PSK. From there, set your Golioth PSK-ID/PSK as normal and reboot the chip.

Sample Output

The entire process of provisioning and connecting to Golioth will look about like this:

[00:00:03.112,000] <inf> fs_nvs: 8 Sectors of 4096 bytes
[00:00:03.112,000] <inf> fs_nvs: alloc wra: 0, fe8
[00:00:03.112,000] <inf> fs_nvs: data wra: 0, 0
*** Booting Zephyr OS build v4.3.0-rc1 ***
*** Golioth Firmware SDK v0.21.1-24-g5d0365be5a81 ***
[00:00:03.113,000] <wrn> net_sock_tls: No entropy device on the system, TLS communication is insecure!
[00:00:03.113,000] <inf> golioth_settings_autoload: Initializing settings subsystem
[00:00:03.113,000] <inf> golioth_settings_autoload: Loading settings
[00:00:03.113,000] <dbg> hello_zephyr: main: start hello sample
[00:00:03.113,000] <inf> golioth_samples: Bringing up network interface
[00:00:03.113,000] <inf> golioth_samples: Waiting to obtain IP address
[00:00:03.113,000] <inf> golioth_wifi: Connecting to stored WiFi network
uart:~$ wifi cred add -k 1 -s golioth -p your-wifi-password
uart:~$ settings set golioth/psk-id rpi-pico2w@iot_fleet
Setting golioth/psk-id to rpi-pico2w@iot_fleet
Setting golioth/psk-id saved as rpi-pico2w@iot_fleet
uart:~$ settings set golioth/psk 840e6b5b64f23e0f2cd794051642c0aa
Setting golioth/psk to 840e6b5b64f23e0f2cd794051642c0aa
Setting golioth/psk saved as 840e6b5b64f23e0f2cd794051642c0aa
uart:~$ kernel reboot

[3067] WLAN MAC Address : 2C:CF:67:DF:09:D9

[3070] WLAN Firmware    : wl0: Jun  5 2024 06:33:59 version 7.95.88 (cf1d613 CY) FWID 01-7b7cf51a

[3079] WLAN CLM         : API: 12.2 Data: 9.10.39 Compiler: 1.29.4 ClmImport: 1.36.3 Creation: 2024-04-16 21:20:55

[3088] WHD VERSION      : 3.3.3.26653
[3091]  : WIFI5-v3.3.3
[3093]  : GCC 12.2
[3095]  : 2025-04-14 03:18:50 +0000

[00:00:03.112,000] <inf> fs_nvs: 8 Sectors of 4096 bytes
[00:00:03.112,000] <inf> fs_nvs: alloc wra: 0, fa0
[00:00:03.112,000] <inf> fs_nvs: data wra: 0, 13e
*** Booting Zephyr OS build v4.3.0-rc1 ***
*** Golioth Firmware SDK v0.21.1-24-g5d0365be5a81 ***
[00:00:03.113,000] <wrn> net_sock_tls: No entropy device on the system, TLS communication is insecure!
[00:00:03.113,000] <inf> golioth_settings_autoload: Initializing settings subsystem
[00:00:03.113,000] <inf> golioth_settings_autoload: Loading settings
[00:00:03.113,000] <dbg> hello_zephyr: main: start hello sample
[00:00:03.113,000] <inf> golioth_samples: Bringing up network interface
[00:00:03.113,000] <inf> golioth_samples: Waiting to obtain IP address
[00:00:03.113,000] <inf> golioth_wifi: Connecting to stored WiFi network
Connected
[00:00:06.024,000] <inf> net_wifi_mgmt: Connection requested
[00:00:06.612,000] <inf> net_dhcpv4: Received: 192.168.200.43
[00:00:06.613,000] <inf> golioth_mbox: Mbox created, bufsize: 1320, num_items: 10, item_size: 120
[00:00:06.839,000] <inf> golioth_coap_client_zephyr: Golioth CoAP client connected
[00:00:06.839,000] <inf> hello_zephyr: Sending hello! 0
[00:00:06.839,000] <inf> hello_zephyr: Golioth client connected
[00:00:06.839,000] <inf> golioth_coap_client_zephyr: Entering CoAP I/O loop
[00:00:11.839,000] <inf> hello_zephyr: Sending hello! 1
[00:00:16.839,000] <inf> hello_zephyr: Sending hello! 2
[00:00:21.839,000] <inf> hello_zephyr: Sending hello! 3

And when we look at the device logs on the Golioth cloud we see our hello world messages coming through from the Pico2 W!

Golioth web console showing log messages from a device: "Sending Hello! 0", etc.

Zephyr Gotchas with the Pico2 W

There are a number of gotchas to following along with the post so far. Zephyr supports a number of runners for flashing this board, including the UF2 bootloader. However, I’m using a programmer because I don’t want to push a button (and replug USB) to flash the chip.

That’s okay, because Zephyr doesn’t have USB-CDC support for this board either. This means you can’t get logs from the USB port. I’m using the Raspberry Pi Debug Probe because it takes care of a number of these issues: directly program the chip, use the built-in UART to connect to the chip’s console, and I’m using a hack to power the Pico from the debug probe (do so at your own peril).

Using this arrangement, I only need to plug USB into the debug program and I can flash, debug, and monitor serial output.

The final gotcha with this board is that the MCUboot support takes a much different approach than I’m used to. I mentioned above that the partition tables are not included in the build by default. Instead of simply using --sysbuild to indicate the build wants a bootloader, you must change the board name itself to use an additional qualifier: rpi_pico2/rp2350a/m33/w/mcuboot. This presents a minor annoyance when I added this to our GitHub CI, but otherwise it’s just a different approach from what I’m accustomed to and still works well.

Take Golioth for a Spin on your Pico2 W!

Official Golioth support for this board is coming soon. We can’t merge to main until Zephyr releases v4.3.0, expected this month. For now, check out my working branch and let us know how things go!

Mike Szczys
Mike Szczys
Mike is a Senior Firmware Engineer at Golioth. His deep love of microcontrollers began in the early 2000s, growing from the desire to make more of the BEAM robotics he was building. During his 12 years at Hackaday (eight of them as Editor in Chief), he had a front-row seat for the growth of the industry, and was active in developing a number of custom electronic conference badges. When he's not reading data sheets he's busy as an orchestra musician in Madison, Wisconsin.

Post Comments

No comments yet! Start the discussion at forum.golioth.io

More from this author

Related posts

spot_img

Latest posts

How to Convince Your Manager to Use Golioth (As an Engineer)

If you’ve ever built an IoT product from the ground up, you know how it starts. The first prototype is always easy: you wire...

The So What of IoT

Lately I've been thinking about what IoT really means. We talk a lot about devices, sensors, networks, and connectivity. But to me, those are...

Signed URLs on ESP32

This week we released v0.2.0 of signy, which expands support beyond Zephyr RTOS to Espressif's ESP-IDF. In addition to bringing signed URLs to more embedded devices, ESP-IDF support is particularly useful due to the framework's built-in OTA firmware update capabilities.

Want to stay up to date with the latest news?

Subscribe to our newsletter and get updates every 2 weeks. Follow the latest blogs and industry trends.