Connecting To The Internet With Pico W

Download as pdf or txt
Download as pdf or txt
You are on page 1of 30

Connecting to the Internet with Raspberry Pi Pico W

Colophon
Copyright © 2022 Raspberry Pi Ltd

The documentation of the RP2040 microcontroller is licensed under a Creative Commons Attribution-NoDerivatives 4.0
International (CC BY-ND).

build-date: 2022-11-30
build-version: 3a2defe-clean

About the SDK

Throughout the text "the SDK" refers to our Raspberry Pi Pico SDK. More details about the SDK can be
found in the Raspberry Pi Pico C/C++ SDK book. Source code included in the documentation is
Copyright © 2020-2022 Raspberry Pi Ltd (formerly Raspberry Pi (Trading) Ltd.) and licensed under the 3-
Clause BSD license.

Legal disclaimer notice


TECHNICAL AND RELIABILITY DATA FOR RASPBERRY PI PRODUCTS (INCLUDING DATASHEETS) AS MODIFIED FROM
TIME TO TIME (“RESOURCES”) ARE PROVIDED BY RASPBERRY PI LTD (“RPL”) "AS IS" AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW IN NO
EVENT SHALL RPL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
THE USE OF THE RESOURCES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

RPL reserves the right to make any enhancements, improvements, corrections or any other modifications to the
RESOURCES or any products described in them at any time and without further notice.

The RESOURCES are intended for skilled users with suitable levels of design knowledge. Users are solely responsible for
their selection and use of the RESOURCES and any application of the products described in them. User agrees to
indemnify and hold RPL harmless against all liabilities, costs, damages or other losses arising out of their use of the
RESOURCES.

RPL grants users permission to use the RESOURCES solely in conjunction with the Raspberry Pi products. All other use
of the RESOURCES is prohibited. No licence is granted to any other RPL or other third party intellectual property right.

HIGH RISK ACTIVITIES. Raspberry Pi products are not designed, manufactured or intended for use in hazardous
environments requiring fail safe performance, such as in the operation of nuclear facilities, aircraft navigation or
communication systems, air traffic control, weapons systems or safety-critical applications (including life support
systems and other medical devices), in which the failure of the products could lead directly to death, personal injury or
severe physical or environmental damage (“High Risk Activities”). RPL specifically disclaims any express or implied
warranty of fitness for High Risk Activities and accepts no liability for use or inclusions of Raspberry Pi products in High
Risk Activities.

Raspberry Pi products are provided subject to RPL’s Standard Terms. RPL’s provision of the RESOURCES does not
expand or otherwise modify RPL’s Standard Terms including but not limited to the disclaimers and warranties
expressed in them.

Legal disclaimer notice 1


Connecting to the Internet with Raspberry Pi Pico W

Table of contents
Colophon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Legal disclaimer notice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1. About Raspberry Pi Pico W . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2. Getting on the internet with the C SDK. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.1. Installing the SDK and examples. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.2. Building an SDK example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.3. Creating your own project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.3.1. Going further. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.4. Which hardware am I running on?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
3. Getting on the internet with MicroPython . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.1. Getting MicroPython for Raspberry Pi Pico W . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.2. Installing MicroPython on Raspberry Pi Pico W . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.3. Connecting from a Raspberry Pi over USB. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
3.3.1. Using an integrated development environment (IDE) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.3.2. Remote access via serial port . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.4. The on-board LED . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.5. Installing modules. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.6. Connecting to a wireless network. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.6.1. Connection status codes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.6.2. Setting the country. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.6.3. Power-saving mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.7. The MAC address . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.8. Making HTTP requests. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.8.1. HTTP with sockets. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
3.8.2. HTTP with urequests. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.8.3. Ensuring robust connections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
3.9. Building HTTP servers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3.9.1. A simple server for static pages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.9.2. Controlling an LED via a web server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.9.3. An asynchronous web server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3.10. Running iperf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3.11. Which hardware am I running on? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
Appendix A: Building MicroPython from source. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Appendix B: Documentation release history . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

Table of contents 2
Connecting to the Internet with Raspberry Pi Pico W

Chapter 1. About Raspberry Pi Pico


W
Raspberry Pi Pico W is a microcontroller board based on the Raspberry Pi RP2040 microcontroller chip.

Figure 1. The
Raspberry Pi Pico W
Rev3 board.

Raspberry Pi Pico W has been designed to be a low cost yet flexible development platform for RP2040, with the addition
of a 2.4GHz wireless interface and the following key features:

• RP2040 microcontroller with 2MB of external flash


• On board 2.4GHz wireless (802.11n) interface
• Micro-USB port for power and data (and for reprogramming the flash)
• 40-pin 21mm×51mm 'DIP' style 1mm thick PCB with 0.1 inch through-hole pins also with edge castellations
◦ Exposes 26 multi-function 3.3V general purpose I/O (GPIO)
◦ 23 GPIO are digital-only, with 3 more which also support ADC
◦ Can be surface-mounted as a module
Apart from the addition of wireless networking, Raspberry Pi Pico W is very similar to Raspberry Pi Pico and, like all
RP2040-based boards, shares the same development environment. If you have not previously used an RP2040-based
board you can get started by reading Getting started with Raspberry Pi Pico if you’re intending to use our C SDK, or
Raspberry Pi Pico Python SDK if you’re thinking about using MicroPython.

 NOTE

Full details of the Raspberry Pi Pico W can be found in the Raspberry Pi Pico W Datasheet.

Chapter 1. About Raspberry Pi Pico W 3


Connecting to the Internet with Raspberry Pi Pico W

Chapter 2. Getting on the internet


with the C SDK
Wireless support for Raspberry Pi Pico W has been added to the C/C++ SDK.

 NOTE

If you have not previously used an RP2040-based board you can get started by reading Getting started with
Raspberry Pi Pico, while further details about the SDK along with API-level documentation can be found in the
Raspberry Pi Pico C/C++ SDK book.

2.1. Installing the SDK and examples


For full instructions on how to get started with the SDK see the Getting started with Raspberry Pi Pico book.

$ git clone https://github.com/raspberrypi/pico-sdk.git --branch master


$ cd pico-sdk
$ git submodule update --init
$ cd ..
$ git clone https://github.com/raspberrypi/pico-examples.git --branch master

 WARNING

If you have not initialised the tinyusb submodule in your pico-sdk checkout, then USB CDC serial, and other USB
functions and example code, will not work as the SDK will contain no USB functionality. Similarly, if you have not
initialised the cyw43-driver and lwip submodules in your checkout, then network-related functionality will not be
enabled.

2.2. Building an SDK example


Building the SDK examples, and other wireless code, requires you to specify your network SSID and password, like this:

$ cd pico-examples
$ mkdir build
$ cd build
$ export PICO_SDK_PATH=../../pico-sdk
$ cmake -DPICO_BOARD=pico_w -DWIFI_SSID="Your Network" -DWIFI_PASSWORD="Your Password" ..
Using PICO_SDK_PATH from environment ('../../pico-sdk')
PICO_SDK_PATH is /home/pi/pico/pico-sdk
.
.
.
-- Build files have been written to: /home/pi/pico/pico-examples/build
$

2.1. Installing the SDK and examples 4


Connecting to the Internet with Raspberry Pi Pico W

 NOTE

The command line flags -DWIFI_SSID="Your Network" -DWIFI_PASSWORD="Your Password" are used by the pico-examples to
set the SSID and password to the call to cyw43_arch_wifi_connect_xxx() to connect to your wireless network.

To then build a basic example for Raspberry Pi Pico W that will scan for nearby wireless networks, you can do:

$ cd pico_w/wifi_scan
$ make
PICO_SDK_PATH is /home/pi/pico-sdk
PICO platform is rp2040.
Build type is Release
PICO target board is pico_w.
.
.
.
[100%] Built target picow_scan_test_background
$

Along with other targets, we have now built a binary called picow_scan_test_background.uf2, which can be dragged onto
the RP2040 USB mass storage device

This binary will scan for wireless networks using the Raspberry Pi Pico W’s wireless chip.

The fastest method to load software onto a RP2040-based board for the first time is by mounting it as a USB mass
storage device. Doing this allows you to drag a file onto the board to program the flash. Go ahead and connect the
Raspberry Pi Pico W to your Raspberry Pi using a micro-USB cable, making sure that you hold down the BOOTSEL
button as you do so, to force it into USB mass storage mode.

If you are running the Raspberry Pi Desktop the Raspberry Pi Pico W should automatically mount as a USB mass
storage device. From here, you can drag-and-drop the UF2 file onto the mass storage device. RP2040 will reboot,
unmounting itself as a mass storage device, and start to run the flashed code.

By default the code will report its results via serial UART.

 IMPORTANT

The default UART pins are configured on a per-board basis using board configuration files. The default Raspberry Pi
Pico W UART TX pin (out from Pico W) is pin GP0, and the UART RX pin (in to Pico W) is pin GP1.

To see the text, you will need to enable UART serial communications on the Raspberry Pi host. To do so, run raspi-
config:

$ sudo raspi-config

and go to Interfacing Options → Serial and select "No" when asked "Would you like a login shell to be accessible over
serial?", then "Yes" when asked "Would you like the serial port hardware to be enabled?" You should see something like
Figure 2.

2.2. Building an SDK example 5


Connecting to the Internet with Raspberry Pi Pico W

Figure 2. Enabling a
serial UART using
raspi-config on
the Raspberry Pi.

Leaving raspi-config you should choose "Yes" and reboot your Raspberry Pi to enable the serial port.

You should then wire the Raspberry Pi and the Raspberry Pi Pico W together with the following mapping:

Raspberry Pi Raspberry Pi Pico W

GND (Pin 14) GND (Pin 3)

GPIO15 (UART_RX0, Pin 10) GP0 (UART0_TX, Pin 1)

GPIO14 (UART_TX0, Pin 8) GP1 (UART0_RX, Pin 2)

See Figure 3.

Figure 3. A Raspberry
Pi 4 and the Raspberry
Pi Pico with UART0
connected together.

Once the two boards are wired together you should install minicom if you have not already done so:

$ sudo apt install minicom

and open the serial port:

2.2. Building an SDK example 6


Connecting to the Internet with Raspberry Pi Pico W

$ minicom -b 115200 -o -D /dev/serial0

You should see the results of our wireless scanning being printed to the console, see Figure 4.

 TIP

To exit minicom, use CTRL-A followed by X.

Figure 4. Results of
our wireless scanning
in the console

2.3. Creating your own project


Go ahead and create a directory to house your test project sitting alongside the pico-sdk directory,

$ ls -la
total 16
drwxr-xr-x 7 aa staff 224 6 Apr 10:41 ./
drwx------@ 27 aa staff 864 6 Apr 10:41 ../
drwxr-xr-x 10 aa staff 320 6 Apr 09:29 pico-examples/
drwxr-xr-x 13 aa staff 416 6 Apr 09:22 pico-sdk/
$ mkdir test
$ cd test

and then create a test.c file in the directory,

1 #include <stdio.h>
2
3 #include "pico/stdlib.h"
4 #include "pico/cyw43_arch.h"
5
6 char ssid[] = "A Network";①
7 char pass[] = "A Password";②
8
9 int main() {
10 stdio_init_all();

2.3. Creating your own project 7


Connecting to the Internet with Raspberry Pi Pico W

11
12 if (cyw43_arch_init_with_country(CYW43_COUNTRY_UK)) {
13 printf("failed to initialise\n");
14 return 1;
15 }
16 printf("initialised\n");
17
18 cyw43_arch_enable_sta_mode();
19
20 if (cyw43_arch_wifi_connect_timeout_ms(ssid, pass, CYW43_AUTH_WPA2_AES_PSK, 10000)) {
21 printf("failed to connect\n");
22 return 1;
23 }
24 printf("connected\n");
25 }

1. Replace A Network with the SSID name of your wireless network.

2. Replace A Password with the password for your wireless network.

along with a CMakeLists.txt file,

cmake_minimum_required(VERSION 3.13)

include(pico_sdk_import.cmake)

project(test_project C CXX ASM)


set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
pico_sdk_init()

add_executable(test
test.c
)

pico_enable_stdio_usb(test 1)
pico_enable_stdio_uart(test 1)

pico_add_extra_outputs(test)

target_include_directories(test PRIVATE ${CMAKE_CURRENT_LIST_DIR} )

target_link_libraries(test pico_cyw43_arch_lwip_threadsafe_background pico_stdlib)

Then copy the pico_sdk_import.cmake file from the external folder in your pico-sdk installation to your test project folder,

$ cp ../pico-sdk/external/pico_sdk_import.cmake .

along with the lwipopts.h file needed by the lwIP stack.

$ cp ../pico-examples/pico_w/lwipopts_examples_common.h lwipopts.h

You should now have something that looks like this,

2.3. Creating your own project 8


Connecting to the Internet with Raspberry Pi Pico W

$ ls -la
total 32
drwxr-xr-x 6 aa staff 192B 29 Jun 18:11 ./
drwxr-xr-x 7 aa staff 224B 29 Jun 16:57 ../
-rw-r--r--@ 1 aa staff 379B 29 Jun 18:10 CMakeLists.txt
-rw-rw-r--@ 1 aa staff 3.3K 15 Jun 00:34 lwipopts.h
-rw-rw-r--@ 1 aa staff 3.1K 15 Jun 00:34 pico_sdk_import.cmake
-rw-r--r--@ 1 aa staff 427B 29 Jun 17:03 test.c

and can build it as we did before with our previous example in the last section.

$ mkdir build
$ cd build
$ export PICO_SDK_PATH=../../pico-sdk
$ cmake -DPICO_BOARD=pico_w ..
$ make

Afterwards unplug your Raspberry Pi Pico W from your computer if it is plugged in already. Then push and hold the
BOOTSEL button while plugging it back into your computer. Then drag and drop the test.uf2 binary onto the RPI-RP2
mass storage volume which will mount on your desktop.

Open the serial port:

$ minicom -b 115200 -o -D /dev/serial0

and you should see the a message indicating that the Pico W has connected to your wireless network.

2.3.1. Going further


More information on the C SDK can be found in the Raspberry Pi Pico C/C++ SDK book. While information around lwIP
can be found on the project’s website. Example code can be found as part of the pico-examples Github repository.

2.4. Which hardware am I running on?


There is no direct method in the C SDK that can be called to allow software to discover whether it is running on a
Raspberry Pi Pico or a Pico W. However, it is possible to indirectly discover the type of underlying hardware. If the board
is powered via USB or VSYS, so 3v3_EN is not pulled low externally, with GPIO25 low, ADC3 will be around 0V for Raspberry
Pi Pico W and approximately 1/3 of VSYS for Raspberry Pi Pico.

Creating a test.c file,

1 #include <stdio.h>
2
3 #include "pico/stdlib.h"
4 #include "hardware/gpio.h"
5 #include "hardware/adc.h"
6
7 int main() {
8 stdio_init_all();
9
10 adc_init();
11 adc_gpio_init(29);

2.4. Which hardware am I running on? 9


Connecting to the Internet with Raspberry Pi Pico W

12 adc_select_input(3);
13 const float conversion_factor = 3.3f / (1 << 12);
14 uint16_t result = adc_read();
15 printf("ADC3 value: 0x%03x, voltage: %f V\n", result, result * conversion_factor);
16
17 gpio_init(25);
18 gpio_set_dir(25, GPIO_IN);
19 uint value = gpio_get(25);
20 printf("GP25 value: %i", value);
21 }

alongside the following CMakeLists.txt file,

cmake_minimum_required(VERSION 3.13)

include(pico_sdk_import.cmake)

project(test_project C CXX ASM)


set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
pico_sdk_init()

add_executable(test
test.c
)

target_link_libraries(test pico_stdlib hardware_adc hardware_gpio)

pico_enable_stdio_usb(test 1)
pico_enable_stdio_uart(test 1)

pico_add_extra_outputs(test)

in a project directory gives this for Raspberry Pi Pico W,

ADC3 value: 0x01c, voltage: 0.022559 V


GP25 value: 0

and this for an original Raspberry Pi Pico board,

ADC3 value: 0x2cd, voltage: 0.577661 V


GP25 value: 0

2.4. Which hardware am I running on? 10


Connecting to the Internet with Raspberry Pi Pico W

Chapter 3. Getting on the internet


with MicroPython
Wireless support for Raspberry Pi Pico W has been added to MicroPython. A pre-built binary, which can be downloaded
from the MicroPython section of the documentation website, should serve most use cases and comes with micropython-
lib pre-integrated into the binary.

 NOTE

If you have not previously used an RP2040-based board you can get started by reading Raspberry Pi Pico Python
SDK book.

3.1. Getting MicroPython for Raspberry Pi Pico W

Pre-built Binary

A pre-built binary of the latest MicroPython firmware is available from the MicroPython section of the
documentation.

The fastest way to get MicroPython is to download the pre-built release binary from the Documentation pages. If you
can’t or don’t want to use the pre-built release — for example, if you want to develop a C module for MicroPython — you
can follow the instructions in Appendix A> to get the source code for MicroPython, which you can use to build your own
MicroPython firmware binary.

3.2. Installing MicroPython on Raspberry Pi Pico W


Raspberry Pi Pico W has a BOOTSEL mode for programming firmware over the USB port. Holding the BOOTSEL button
when powering up your board will put it into a special mode where it appears as a USB mass storage device. First make
sure your Raspberry Pi Pico W is not plugged into any source of power: disconnect the micro USB cable if plugged in,
and disconnect any other wires that might be providing power to the board, e.g. through the VSYS or VBUS pin. Now
hold down the BOOTSEL button, and plug in the micro USB cable (which hopefully has its other end plugged into your
computer).

A drive called RPI-RP2 should pop up. Go ahead and drag the MicroPython firmware.uf2 file onto this drive. This
programs the MicroPython firmware onto the flash memory on your Raspberry Pi Pico W.

It should take a few seconds to program the UF2 file into the flash. The board will automatically reboot when finished,
causing the RPI-RP2 drive to disappear, and boot into MicroPython.

When MicroPython boots for the first time, it will sit and wait for you to connect and tell it what to do. You can load a .py
file from your computer onto the board, but a more immediate way to interact with it is through what is called the read-
evaluate-print loop, or REPL.

There are two ways to connect to this REPL; so you can communicate with the MicroPython firmware on your board
over USB, or over the UART serial port on Raspberry Pi Pico W GPIOs.

3.1. Getting MicroPython for Raspberry Pi Pico W 11


Connecting to the Internet with Raspberry Pi Pico W

 NOTE

The MicroPython port for RP2040 does not expose a REPL over a UART port by default, please see Raspberry Pi Pico
Python SDK for more details of how to configure MicroPython to allow you to connect to the REPL over UART.

3.3. Connecting from a Raspberry Pi over USB


The MicroPython firmware is equipped with a virtual USB serial port which is accessed through the micro USB
connector on Raspberry Pi Pico W. Your computer should notice this serial port and list it as a character device, most
likely /dev/ttyACM0.

 TIP

You can run ls /dev/tty* to list your serial ports. There may be quite a few, but MicroPython’s USB serial will start
with /dev/ttyACM. If in doubt, unplug the micro USB connector and see which one disappears. If you don’t see
anything, you can try rebooting your Raspberry Pi.

You can install minicom to access the serial port:

$ sudo apt install minicom

and then open it as such:

$ minicom -o -D /dev/ttyACM0

Where the -D /dev/ttyACM0 is pointing minicom at MicroPython’s USB serial port, and the -o flag essentially means "just do
it". There’s no need to worry about baud rate, since this is a virtual serial port.

Press the enter key a few times in the terminal where you opened minicom. You should see this:

>>>

This is a prompt. MicroPython wants you to type something in, and tell it what to do.

If you press CTRL-D on your keyboard whilst the minicom terminal is focused, you should see a message similar to this:

MPY: soft reboot


MicroPython v1.18-524-g22474d25d on 2022-05-25; Raspberry Pi Pico W with RP2040
Type "help()" for more information.
>>>

This key combination tells MicroPython to reboot. You can do this at any time. When it reboots, MicroPython will print
out a message saying exactly what firmware version it is running, and when it was built. Your version number will be
different from the one shown here.

3.3. Connecting from a Raspberry Pi over USB 12


Connecting to the Internet with Raspberry Pi Pico W

 NOTE

If you are working on an Apple Mac, so long as you’re using a recent version of macOS like Catalina, drivers should
already be loaded. Otherwise, see the manufacturers' website for FTDI Chip Drivers. Then you should use a Terminal
program to connect to Serial-over-USB (USB CDC). The serial port will show up as /dev/tty.usbmodem with a number
appended to the end.

If you don’t already have a Terminal program installed you can install minicom using Homebrew:

$ brew install minicom

and connect to the board as below.

$ minicom -b 115200 -o -D /dev/tty.usbmodem0000000000001

Other Terminal applications like CoolTerm or Serial can also be used.

3.3.1. Using an integrated development environment (IDE)


The MicroPython port to Raspberry Pi Pico W and other RP2040-based boards works with commonly-used development
environments. Thonny is the recommended editor. Thonny packages are available for Linux, MS Windows, and macOS.
After installation, using the Thonny development environment is the same across all three platforms. The latest release
of Thonny can be downloaded from thonny.org.

For full details on how to use the Thonny editor, see the section on using a development environment in the Raspberry
Pi Pico Python SDK book.

3.3.2. Remote access via serial port


It’s suggested you use the mpremote tool to access the device via the serial port.

$ pip install mpremote


$ mpremote connect list
/dev/cu.Bluetooth-Incoming-Port None 0000:0000 None None
/dev/cu.usbmodem22201 e660583883807e27 2e8a:0005 MicroPython Board in FS mode
$ mpremote connect port:/dev/cu.usbmodem22201
Connected to MicroPython at /dev/cu.usbmodem22201
Use Ctrl-] to exit this shell
>>>

With this you can run a script from your local machine directly on Raspberry Pi Pico W.

$ mpremote connect port:/dev/cu.usbmodem22201


$ mpremote run hello_world.py

3.3. Connecting from a Raspberry Pi over USB 13


Connecting to the Internet with Raspberry Pi Pico W

 NOTE

For more information on mpremote see the documentation.

3.4. The on-board LED


Unlike the original Raspberry Pi Pico, the on-board LED on Pico W is not connected to a pin on RP2040, but instead to a
GPIO pin on the wireless chip. MicroPython has been modified accordingly. This means that you can now do:

>>> import machine


>>> led = machine.Pin("LED", machine.Pin.OUT)
>>> led.off()
>>> led.on()

or even:

>>> led.toggle()

to change the current state. However, if you now look at the led object:

>>> led
Pin(WL_GPIO0, mode=OUT)
>>>

You can also do the following:

>>> led = machine.Pin("LED", machine.Pin.OUT, value=1)

which will configure the led object, associate it with the on-board LED and turn the LED on.

 NOTE

Full details of the Raspberry Pi Pico W can be found in the Raspberry Pi Pico W Datasheet. WL_GPIO1 is connected to
the PS/SYNC pin on the RT6154A to allow selection of different operating modes, while WL_GPIO2 can be used to
monitor USB VBUS.

3.5. Installing modules


You can use the upip tool to install modules that are not present in the default MicroPython installation.

>>> import upip


>>> upip.install("micropython-pystone_lowmem")
>>> import pystone_lowmem
>>> pystone_lowmem.main()
Pystone(1.2) time for 500 passes = 402ms

3.4. The on-board LED 14


Connecting to the Internet with Raspberry Pi Pico W

This machine benchmarks at 1243 pystones/second


>>>

3.6. Connecting to a wireless network


We’re using the network library to talk to the wireless hardware:

1 import network
2 import time
3
4 wlan = network.WLAN(network.STA_IF)
5 wlan.active(True)
6 wlan.connect('Wireless Network', 'The Password')
7
8 while not wlan.isconnected() and wlan.status() >= 0:
9 print("Waiting to connect:")
10 time.sleep(1)
11
12 print(wlan.ifconfig())

although more correctly, you should wait for the connection to succeed or fail in your code, and handle any connection
errors that might occur.

1 import time
2 import network
3
4 ssid = 'Wireless Network'
5 password = 'The Password'
6
7 wlan = network.WLAN(network.STA_IF)
8 wlan.active(True)
9 wlan.connect(ssid, password)
10
11 # Wait for connect or fail
12 max_wait = 10
13 while max_wait > 0:
14 if wlan.status() < 0 or wlan.status() >= 3:
15 break
16 max_wait -= 1
17 print('waiting for connection...')
18 time.sleep(1)
19
20 # Handle connection error
21 if wlan.status() != 3:
22 raise RuntimeError('network connection failed')
23 else:
24 print('connected')
25 status = wlan.ifconfig()
26 print( 'ip = ' + status[0] )

You can also disconnect and then connect to a different wireless network.

3.6. Connecting to a wireless network 15


Connecting to the Internet with Raspberry Pi Pico W

1 # Connect to another network


2 wlan.disconnect();
3 wlan.connect('Other Network', 'The Other Password')

For more information on the network.WLAN library see the library documentation.

3.6.1. Connection status codes


The values returned by the wlan.status() call are defined in the CYW43 wireless driver, and are passed directly through
to user-code.

// Return value of cyw43_wifi_link_status


#define CYW43_LINK_DOWN (0)
#define CYW43_LINK_JOIN (1)
#define CYW43_LINK_NOIP (2)
#define CYW43_LINK_UP (3)
#define CYW43_LINK_FAIL (-1)
#define CYW43_LINK_NONET (-2)
#define CYW43_LINK_BADAUTH (-3)

3.6.2. Setting the country


By default, the country setting for the wireless network is unset. This means that the driver will use a default world-wide
safe setting, which may mean some channels are unavailable.

>>> import rp2


>>> rp2.country()
'\x00\x00'
>>>

This can cause problems on some wireless networks. If you find that your Raspberry Pi Pico W does not connect to your
wireless network you may want to try setting the country code, e.g.

>>> rp2.country('GB')

3.6.3. Power-saving mode


By default the wireless chip will active power-saving mode when it is idle, which might lead it to being less responsive. If
you are running a server or need more responsiveness, you can change this by toggling the power mode.

1 import network
2
3 wlan = network.WLAN(network.STA_IF)
4 wlan.active(True)
5 wlan.config(pm = 0xa11140)

3.6. Connecting to a wireless network 16


Connecting to the Internet with Raspberry Pi Pico W

3.7. The MAC address


The MAC is stored in the wireless chip OTP.

1 import network
2 import ubinascii
3
4 wlan = network.WLAN(network.STA_IF)
5 wlan.active(True)
6 mac = ubinascii.hexlify(network.WLAN().config('mac'),':').decode()
7 print(mac)
8
9 # Other things you can query
10 print(wlan.config('channel'))
11 print(wlan.config('essid'))
12 print(wlan.config('txpower'))

 NOTE

We have to set the wireless active (which loads the firmware) before we can get the MAC address.

3.8. Making HTTP requests


You can take a low-level approach to HTTP requests using raw sockets, or a high-level approach using the urequests
library.

3.8.1. HTTP with sockets

1 # Connect to network
2 import network
3
4 wlan = network.WLAN(network.STA_IF)
5 wlan.active(True)
6 wlan.connect('Wireless Network', 'The Password')
7
8 # Should be connected and have an IP address
9 wlan.status() # 3 == success
10 wlan.ifconfig()
11
12 # Get IP address for google.com
13 import socket
14 ai = socket.getaddrinfo("google.com", 80)
15 addr = ai[0][-1]
16
17 # Create a socket and make a HTTP request
18 s = socket.socket()
19 s.connect(addr)
20 s.send(b"GET / HTTP/1.0\r\n\r\n")
21
22 # Print the response
23 print(s.recv(512))

3.7. The MAC address 17


Connecting to the Internet with Raspberry Pi Pico W

3.8.2. HTTP with urequests


It is much simpler to use the urequests library to make an HTTP connection.

1 # Connect to network
2 import network
3 wlan = network.WLAN(network.STA_IF)
4 wlan.active(True)
5 wlan.connect('Wireless Network', 'The Password')
6
7 # Make GET request
8 import urequests
9 r = urequests.get("http://www.google.com")
10 print(r.content)
11 r.close()

Support has been added for redirects.

1 import urequests
2 r = urequests.get("http://www.raspberrypi.com")
3 print(r.status_code) # redirects to https
4 r.close()

 NOTE

HTTPS works, but you should be aware that SSL verification is currently disabled.

The urequests libary comes with limited JSON support.

>>> r = urequests.get("http://date.jsontest.com")
>>> r.json()
{'milliseconds_since_epoch': 1652188199441, 'date': '05-10-2022', 'time': '01:09:59 PM'}
>>>>

For more information on urequests see the library documentation.

 IMPORTANT

You must close the returned response object after making a request using the urequests library using
response.close(). If you do not, the object will not be garbage-collected, and if the request is being made inside a loop
this will quickly lead to a crash.

3.8.3. Ensuring robust connections


This partial example illustrates a more robust approach to connecting to a network using urequests.

1 import time
2 import network
3 import urequests as requests
4
5 ssid = 'A Network'

3.8. Making HTTP requests 18


Connecting to the Internet with Raspberry Pi Pico W

6 password = 'The Password'


7
8 wlan = network.WLAN(network.STA_IF)
9 wlan.active(True)
10 wlan.connect(ssid, password)
11
12 # Wait for connect or fail
13 max_wait = 10
14 while max_wait > 0:
15 if wlan.status() < 0 or wlan.status() >= 3:
16 break
17 max_wait -= 1
18 print('waiting for connection...')
19 time.sleep(1)
20
21 # Handle connection error
22 if wlan.status() != 3:
23 raise RuntimeError('network connection failed')
24 else:
25 print('connected')
26 status = wlan.ifconfig()
27 print( 'ip = ' + status[0] )
28
29 while True:
30
31 # Do things here, perhaps measure something using a sensor?
32
33 # ...and then define the headers and payloads
34 headers = ...
35 payload = ...
36
37 # Then send it in a try/except block
38 try:
39 print("sending...")
40 response = requests.post("A REMOTE END POINT", headers=headers, data=payload)
41 print("sent (" + str(response.status_code) + "), status = " + str(wlan.status()) )
42 response.close()
43 except:
44 print("could not connect (status =" + str(wlan.status()) + ")")
45 if wlan.status() < 0 or wlan.status() >= 3:
46 print("trying to reconnect...")
47 wlan.disconnect()
48 wlan.connect(ssid, password)
49 if wlan.status() == 3:
50 print('connected')
51 else:
52 print('failed')
53
54 time.sleep(5)

Here we handle the possibility that we lose connection to our wireless network and then will seek to reconnect.

3.9. Building HTTP servers


You can build synchronous or asynchronous web servers.

3.9. Building HTTP servers 19


Connecting to the Internet with Raspberry Pi Pico W

3.9.1. A simple server for static pages


You can use the socket library to build a simple web server.

1 import network
2 import socket
3 import time
4
5 from machine import Pin
6
7 led = Pin(15, Pin.OUT)
8
9 ssid = 'A Network'
10 password = 'A Password'
11
12 wlan = network.WLAN(network.STA_IF)
13 wlan.active(True)
14 wlan.connect(ssid, password)
15
16 html = """<!DOCTYPE html>
17 <html>
18 <head> <title>Pico W</title> </head>
19 <body> <h1>Pico W</h1>
20 <p>Hello World</p>
21 </body>
22 </html>
23 """
24
25 # Wait for connect or fail
26 max_wait = 10
27 while max_wait > 0:
28 if wlan.status() < 0 or wlan.status() >= 3:
29 break
30 max_wait -= 1
31 print('waiting for connection...')
32 time.sleep(1)
33
34 # Handle connection error
35 if wlan.status() != 3:
36 raise RuntimeError('network connection failed')
37 else:
38 print('connected')
39 status = wlan.ifconfig()
40 print( 'ip = ' + status[0] )
41
42 # Open socket
43 addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
44
45 s = socket.socket()
46 s.bind(addr)
47 s.listen(1)
48
49 print('listening on', addr)
50
51 # Listen for connections
52 while True:
53 try:
54 cl, addr = s.accept()
55 print('client connected from', addr)
56 cl_file = cl.makefile('rwb', 0)
57 while True:
58 line = cl_file.readline()

3.9. Building HTTP servers 20


Connecting to the Internet with Raspberry Pi Pico W

59 if not line or line == b'\r\n':


60 break
61 response = html
62 cl.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
63 cl.send(response)
64 cl.close()
65
66 except OSError as e:
67 cl.close()
68 print('connection closed')

 NOTE

This example is synchronous, for more robust request handling you should implement the server to handle requests
asynchronously.

3.9.2. Controlling an LED via a web server


Going further, we can implement a RESTful web server that will allow us to control an LED.

Figure 5. The
Raspberry Pi Pico W
with an LED on GP15.

Connecting an LED to GP15 we can turn the LED on and off by using HTTP GET. We can do this by going to
http://192.168.1.X/light/on to turn the LED on, and http://192.168.1.X/light/off to turn the LED off, in our web browser;
where 192.168.1.X is the IP address of our Pico W, which will be printed in the console after it connects to the network.

1 import network
2 import socket
3 import time
4
5 from machine import Pin
6
7 led = Pin(15, Pin.OUT)
8
9 ssid = 'A Network'
10 password = 'A Password'
11
12 wlan = network.WLAN(network.STA_IF)
13 wlan.active(True)

3.9. Building HTTP servers 21


Connecting to the Internet with Raspberry Pi Pico W

14 wlan.connect(ssid, password)
15
16 html = """<!DOCTYPE html>
17 <html>
18 <head> <title>Pico W</title> </head>
19 <body> <h1>Pico W</h1>
20 <p>%s</p>
21 </body>
22 </html>
23 """
24
25 # Wait for connect or fail
26 max_wait = 10
27 while max_wait > 0:
28 if wlan.status() < 0 or wlan.status() >= 3:
29 break
30 max_wait -= 1
31 print('waiting for connection...')
32 time.sleep(1)
33
34 # Handle connection error
35 if wlan.status() != 3:
36 raise RuntimeError('network connection failed')
37 else:
38 print('connected')
39 status = wlan.ifconfig()
40 print( 'ip = ' + status[0] )
41
42 # Open socket
43 addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
44
45 s = socket.socket()
46 s.bind(addr)
47 s.listen(1)
48
49 print('listening on', addr)
50
51 # Listen for connections
52 while True:
53 try:
54 cl, addr = s.accept()
55 print('client connected from', addr)
56 request = cl.recv(1024)
57 print(request)
58
59 request = str(request)
60 led_on = request.find('/light/on')
61 led_off = request.find('/light/off')
62 print( 'led on = ' + str(led_on))
63 print( 'led off = ' + str(led_off))
64
65 if led_on == 6:
66 print("led on")
67 led.value(1)
68 stateis = "LED is ON"
69
70 if led_off == 6:
71 print("led off")
72 led.value(0)
73 stateis = "LED is OFF"
74
75 response = html % stateis
76

3.9. Building HTTP servers 22


Connecting to the Internet with Raspberry Pi Pico W

77 cl.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')


78 cl.send(response)
79 cl.close()
80
81 except OSError as e:
82 cl.close()
83 print('connection closed')

Running the code, we can see the response in our browser.

Figure 6. What we see


in our web browser
when connecting to
our Pico W web server

3.9.3. An asynchronous web server


We can use the uasyncio module to implement the same server, but in this case it will handle HTTP requests
asynchronously rather than blocking.

1 import network
2 import socket
3 import time
4
5 from machine import Pin
6 import uasyncio as asyncio
7
8 led = Pin(15, Pin.OUT)
9 onboard = Pin("LED", Pin.OUT, value=0)
10
11 ssid = 'A Network'
12 password = 'A Password'
13
14 html = """<!DOCTYPE html>
15 <html>
16 <head> <title>Pico W</title> </head>
17 <body> <h1>Pico W</h1>
18 <p>%s</p>
19 </body>
20 </html>
21 """
22
23 wlan = network.WLAN(network.STA_IF)
24

3.9. Building HTTP servers 23


Connecting to the Internet with Raspberry Pi Pico W

25 def connect_to_network():
26 wlan.active(True)
27 wlan.config(pm = 0xa11140) # Disable power-save mode
28 wlan.connect(ssid, password)
29
30 max_wait = 10
31 while max_wait > 0:
32 if wlan.status() < 0 or wlan.status() >= 3:
33 break
34 max_wait -= 1
35 print('waiting for connection...')
36 time.sleep(1)
37
38 if wlan.status() != 3:
39 raise RuntimeError('network connection failed')
40 else:
41 print('connected')
42 status = wlan.ifconfig()
43 print('ip = ' + status[0])
44
45 async def serve_client(reader, writer):
46 print("Client connected")
47 request_line = await reader.readline()
48 print("Request:", request_line)
49 # We are not interested in HTTP request headers, skip them
50 while await reader.readline() != b"\r\n":
51 pass
52
53 request = str(request_line)
54 led_on = request.find('/light/on')
55 led_off = request.find('/light/off')
56 print( 'led on = ' + str(led_on))
57 print( 'led off = ' + str(led_off))
58
59 stateis = ""
60 if led_on == 6:
61 print("led on")
62 led.value(1)
63 stateis = "LED is ON"
64
65 if led_off == 6:
66 print("led off")
67 led.value(0)
68 stateis = "LED is OFF"
69
70 response = html % stateis
71 writer.write('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
72 writer.write(response)
73
74 await writer.drain()
75 await writer.wait_closed()
76 print("Client disconnected")
77
78 async def main():
79 print('Connecting to Network...')
80 connect_to_network()
81
82 print('Setting up webserver...')
83 asyncio.create_task(asyncio.start_server(serve_client, "0.0.0.0", 80))
84 while True:
85 onboard.on()
86 print("heartbeat")
87 await asyncio.sleep(0.25)

3.9. Building HTTP servers 24


Connecting to the Internet with Raspberry Pi Pico W

88 onboard.off()
89 await asyncio.sleep(5)
90
91 try:
92 asyncio.run(main())
93 finally:
94 asyncio.new_event_loop()

3.10. Running iperf


You can install iperf using the upip tool:

>>> import network


>>> wlan = network.WLAN(network.STA_IF)
>>> wlan.active(True)
>>> wlan.connect('Wireless Network', 'The Password')
>>> import upip
>>> upip.install("uiperf3")

and start an iperf3 client.

 NOTE

The iperf server should be running on another machine.

>>> import uiperf3


>>> uiperf3.client('10.3.15.xx)

CLIENT MODE: TCP sending


Connecting to ('10.3.15.234', 5201)
Interval Transfer Bitrate
0.00-1.00 sec 48.4 KBytes 397 Kbits/sec
1.00-2.00 sec 48.4 KBytes 397 Kbits/sec
2.00-3.00 sec 80.5 KBytes 659 Kbits/sec
3.00-4.00 sec 100 KBytes 819 Kbits/sec
4.00-5.00 sec 103 KBytes 845 Kbits/sec
5.00-6.00 sec 22.7 KBytes 186 Kbits/sec
6.00-7.00 sec 0.00 Bytes 0.00 bits/sec
7.00-8.00 sec 0.00 Bytes 0.00 bits/sec
8.00-9.00 sec 45.3 KBytes 371 Kbits/sec
9.00-10.00 sec 89.1 KBytes 729 Kbits/sec
10.00-10.01 sec 0.00 Bytes 0.00 bits/sec
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
0.00-10.01 sec 538 KBytes 440 Kbits/sec sender
>>>

3.11. Which hardware am I running on?


There is no direct method for software written in MicroPython to discover whether it is running on a Raspberry Pi Pico or
a Pico W by looking at the hardware. However, you can tell indirectly by looking to see if network functionality is
included in your particular MicroPython firmware:

3.10. Running iperf 25


Connecting to the Internet with Raspberry Pi Pico W

1 import network
2 if hasattr(network, "WLAN"):
3 # the board has WLAN capabilities

Alternatively, you can inspect the MicroPython firmware version to check whether it was compiled for Raspberry Pi Pico
or for Pico W using the sys module.

>>> import sys


>> sys.implementation
(name='micropython', version=(1, 19, 1), _machine='Raspberry Pi Pico W with RP2040', _mpy=4102)

So if 'Pico W' in sys.implementation._machine can be used to detect whether your firmware was compiled for Pico W.

3.11. Which hardware am I running on? 26


Connecting to the Internet with Raspberry Pi Pico W

Appendix A: Building MicroPython


from source
Before you can proceed with building a MicroPython UF2 for Raspberry Pi Pico W from source, you should install the
normal dependencies to build MicroPython. See Section 1.3 of the Raspberry Pi Pico Python SDK book for full details.

Afterwards you should clone the micropython and micropython-lib repositories.

$ mkdir pico_w
$ cd pico_w
$ git clone https://github.com/micropython/micropython.git --branch master
$ git clone https://github.com/micropython/micropython-lib.git --branch master

 NOTE

Putting micropython-lib side-by-side with your MicroPython checkout will mean that it is automatically pulled into
your MicroPython build, and libraries in micropython-lib will be "pre-added" to the list of modules available by default
on your Pico W device.

Then build MicroPython:

$ cd micropython
$ make -C ports/rp2 BOARD=PICO_W submodules
$ make -C mpy-cross
$ cd ports/rp2
$ make BOARD=PICO_W

If everything went well, there will be a new directory called build-PICO_W (that’s ports/rp2/build-PICO_W relative to the top-
level micropython directory), which contains the new firmware binaries. Drag and drop the firmware.uf2 onto the RPI-RP2
drive that pops up once your Raspberry Pi Pico W is in BOOTSEL mode.

Appendix A: Building MicroPython from source 27


Connecting to the Internet with Raspberry Pi Pico W

Appendix B: Documentation release


history
Table 1.
Release Date Description
Documentation
release history
1.0 30 Jun 2022 • Initial release
Pico and Pico W databooks combined into a unified release history

2.0 01 Dec 2022 • Minor updates and corrections


• Added RP2040 availability information
• Added RP2040 storage conditions and thermal characteristics
• Replace SDK library documentation with links to the online
version

• Updated Picoprobe build and usage instructions

The latest release can be found at https://datasheets.raspberrypi.com/picow/connecting-to-the-internet-with-pico-


w.pdf.

Appendix B: Documentation release history 28

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy