Raspberry Pi Trading анонсировала плату Raspberry Pi Pico W, основанную на том же дизайне, что и оригинальная плата Raspberry Pi Pico с двухъядерным микроконтроллером Cortex-M0+ RP2040, но с добавлением беспроводного модуля с WiFi 4 и Bluetooth LE 5.2, хотя пока последний не включен на плате.
Компания прислала нам образец для обзора/оценки, и мы сосредоточимся на части WiFi, поскольку Raspberry Pi Pico W поддерживает те же SDK MicroPython и C/C++, что и плата Raspberry Pi Pico, а также дополнительные API для беспроводного подключения.
Распаковка Raspberry Pi Pico W
Плата, которую мы получили, была вырезана из катушки на 480 единиц, и мы также получили кабель micro USB к USB длиной один метр, который, вероятно, не должен быть включен по умолчанию для людей, заказывающих плату за 6 долларов.
Как и его предшественник, плата крошечная.
Распиновка такая же, как у первой платы RP2040, и четко обозначена на нижней стороне платы.
Подключение Raspberry Pi Pico W к компьютеру
Как только мы подключим плату к главному компьютеру, она должна появиться на вашем компьютере как диск RPI-RP2. Наш ноутбук работает под управлением Ubuntu 20.04, но результат будет таким же в Windows или macOS.
На диске есть два файла: INFO_UF2.txt с некоторой информацией о версии загрузчика UF2 и модели платы, и INDEX.HTM, который перенаправляет на документацию Pico на веб-сайте Raspberry Pi. Так что здесь ничего не изменилось.
Вот вывод из журнала ядра для справки:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
[31039.896573] usb 1-1: new full-speed USB device number 7 using xhci_hcd [31040.068190] usb 1-1: New USB device found, idVendor=2e8a, idProduct=0003, bcdDevice= 1.00 [31040.068198] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3 [31040.068201] usb 1-1: Product: RP2 Boot [31040.068203] usb 1-1: Manufacturer: Raspberry Pi [31040.068205] usb 1-1: SerialNumber: E0C9125B0D9B [31040.126291] usb-storage 1-1:1.0: USB Mass Storage device detected [31040.126674] scsi host2: usb-storage 1-1:1.0 [31040.126893] usbcore: registered new interface driver usb-storage [31040.134814] usbcore: registered new interface driver uas [31041.138666] scsi 2:0:0:0: Direct-Access RPI RP2 3 PQ: 0 ANSI: 2 [31041.139090] sd 2:0:0:0: Attached scsi generic sg2 type 0 [31041.139462] sd 2:0:0:0: [sdc] 262144 512-byte logical blocks: (134 MB/128 MiB) [31041.140240] sd 2:0:0:0: [sdc] Write Protect is off [31041.140242] sd 2:0:0:0: [sdc] Mode Sense: 03 00 00 00 [31041.142282] sd 2:0:0:0: [sdc] No Caching mode page found [31041.142290] sd 2:0:0:0: [sdc] Assuming drive cache: write through [31041.150224] sdc: sdc1 [31041.154246] sd 2:0:0:0: [sdc] Attached SCSI removable disk |
Wi-Fi с MicroPython
Raspberry Pi Pico и Pico W используют один и тот же загрузчик, но прошивки MicroPython отличаются, возможно, из-за небольших аппаратных различий (например, подключение пользовательского светодиода), а также потому, что не имеет смысла добавлять стек Wi-Fi в Raspberry Pi Pico и тратить драгоценное хранилище и память на микроконтроллере с ограниченными ресурсами.
Мы найдем нужный файл прошивки на веб-сайте Raspberry Pi или загрузим его напрямую следующим образом:
1 2 |
wget https://micropython.org/download/rp2-pico-w/rp2-pico-w-latest.uf2 |
Как только мы загрузим его, просто скопируйте rp2-pico-w-latest.uf2 на диск RPI-RP2…
… и скоро диск исчезнет, а Raspberry Pi Pico W теперь будет отображаться как последовательное устройство:
1 2 3 4 5 6 7 8 9 |
[31932.896450] usb 1-1: new full-speed USB device number 8 using xhci_hcd [31933.070029] usb 1-1: New USB device found, idVendor=2e8a, idProduct=0005, bcdDevice= 1.00 [31933.070039] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3 [31933.070043] usb 1-1: Product: Board in FS mode [31933.070046] usb 1-1: Manufacturer: MicroPython [31933.070049] usb 1-1: SerialNumber: e6614c311b939432 [31933.164647] cdc_acm 1-1:1.0: ttyACM0: USB ACM device [31933.164710] usbcore: registered new interface driver cdc_acm [31933.164714] cdc_acm: USB Abstract Control Model driver for USB modems and ISDN adapters |
Что мы также можем обнаружить в BootTerm (или других инструментах, таких как Putty, minicom, tio и т. д.):
1 2 3 4 |
$ bt -l port | age (sec) | device | driver | description ------+------------+------------+------------------+---------------------- * 0 | 132 | ttyACM0 | cdc_acm | Board CDC |
Если мы подключимся к последовательному устройству, мы сможем войти в интерфейс REPL, где мы можем ввести несколько команд, чтобы вывести список точек доступа 2,4 ГГц:
1 2 3 4 5 6 7 8 9 10 11 12 |
$ bt No port specified, using ttyACM0 (last registered). Use -l to list ports. Trying port ttyACM0... Connected to ttyACM0 at 115200 bps. Escape character is 'Ctrl-]'. Use escape followed by '?' for help. >>> import network >>> wlan = network.WLAN(network.STA_IF) >>> wlan.active(True) >>> print(wlan.scan()) [(b'CNX_Software_Xiaomi', b'<\xcdW\xf5\xaf\x92', 8, -24, 5, 5), (b'', b'B\xcdW\xf5\xaf\x92', 8, -26, 0, 2)] >>> |
Работает. Обнаружена только одна видимая точка доступа, потому что мы живем в сельской местности. Другое значение (“) предназначено для скрытого SSID, открытого на нашем маршрутизаторе Xiaomi. Согласно документации API MicroPython, пять других значений относятся к bssid, номеру канала, RSSI, режиму авторизации и скрытому статусу, но последние два числа находятся за пределами допустимого диапазона:
Существует пять значений безопасности:
- 0 – открыть
- 1 – WEP
- 2 – WPA-PSK
- 3 — WPA2-PSK
- 4 — WPA/WPA2-PSK
и два для скрытых:
- 0 — видимый
- 1 – скрытый
Чтобы пойти дальше, мы рассмотрим документацию «Подключение к Интернету» для платы. Самый простой способ обновить код — сначала установить редактор Thonny:
1 2 |
sudo apt install python3-tk pip3 install thonny |
Мы можем запустить предыдущую программу MicroPython в Thonny IDE без каких-либо проблем после перехода в «Выполнить» – > «Выбрать интерпретатор» и выбрать «MicroPython (Raspberry Pi Pico)».
Давайте подключимся к CNX_Software_Xiaomi SSID с помощью следующей программы:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
import time import network ssid = 'CNX_Software_Xiaomi' password = 'The Password' wlan = network.WLAN(network.STA_IF) wlan.active(True) wlan.connect(ssid, password) # Wait for connect or fail max_wait = 10 while max_wait > 0: if wlan.status() < 0 or wlan.status() >= 3: break max_wait -= 1 print('waiting for connection...') time.sleep(1) # Handle connection error if wlan.status() != 3: raise RuntimeError('network connection failed') else: print('connected') status = wlan.ifconfig() print( 'ip = ' + status[0] ) |
Наш Raspberry Pi Pico W получил IP-адрес, и мы можем успешно пропинговать его:
1 2 3 4 5 6 7 |
$ ping 192.168.31.120 PING 192.168.31.120 (192.168.31.120) 56(84) bytes of data. 64 bytes from 192.168.31.120: icmp_seq=1 ttl=255 time=187 ms 64 bytes from 192.168.31.120: icmp_seq=2 ttl=255 time=35.3 ms 64 bytes from 192.168.31.120: icmp_seq=3 ttl=255 time=54.1 ms 64 bytes from 192.168.31.120: icmp_seq=4 ttl=255 time=77.1 ms |
Для справки, в сети он отображается как PYPB:
1 2 3 4 5 6 |
$ nmap -sP 192.168.31.0/24 Starting Nmap 7.80 ( https://nmap.org ) at 2022-07-02 14:04 +07 ... Nmap scan report for PYBD (192.168.31.120) Host is up (0.026s latency). ... |
Прошивка поставляется с безопасными глобальными настройками, но вы можете включить дополнительные каналы, настроив страну:
1 2 |
import rp2 rp2.country('TH') |
Это будет особенно полезно, если ваша плата не может подключиться к маршрутизатору из-за недоступных каналов.
Типичным вариантом использования платы этого типа является наличие веб-интерфейса для управления светодиодами или GPIO. Давайте запустим веб-сервер для управления пользовательским светодиодом на плате:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
import network import socket import time from machine import Pin # Select the onboard LED led = machine.Pin("LED", machine.Pin.OUT) ssid = 'CNX_Software_Xiaomi' password = 'A Password' wlan = network.WLAN(network.STA_IF) wlan.active(True) wlan.connect(ssid, password) html = """<!DOCTYPE html> <html> <head> <title>CNX Software's Pico W </title> </head> <body> <h1>CNX Software's Pico W</h1> <p>%s</p> </body> </html> """ # Wait for connect or fail max_wait = 10 while max_wait > 0: if wlan.status() < 0 or wlan.status() >= 3: break max_wait -= 1 print('waiting for connection...') time.sleep(1) # Handle connection error if wlan.status() != 3: raise RuntimeError('network connection failed') else: print('connected') status = wlan.ifconfig() print( 'ip = ' + status[0] ) # Open socket addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1] s = socket.socket() s.bind(addr) s.listen(1) print('listening on', addr) # Listen for connections while True: try: cl, addr = s.accept() print('client connected from', addr) request = cl.recv(1024) print(request) request = str(request) led_on = request.find('/light/on') led_off = request.find('/light/off') print( 'led on = ' + str(led_on)) print( 'led off = ' + str(led_off)) if led_on == 6: print("led on") led.value(1) stateis = "LED is ON" if led_off == 6: print("led off") led.value(0) stateis = "LED is OFF" response = html % stateis cl.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n') cl.send(response) cl.close() except OSError as e: cl.close() print('connection closed') |
Код немного длинный, так как он также включает обработку ошибок. Он отлично работает, как вы можете видеть из короткого демо-видео ниже.
Код можно легко изменить для управления реле или GPIO.
Также можно установить и запустить популярный инструмент iperf3 на Raspberry Pi Pico W:
1 2 3 4 5 6 7 8 |
import network wlan = network.WLAN(network.STA_IF) wlan.active(True) wlan.connect('CNX_Software_Xiaomi', 'The Password') import upip upip.install("uiperf3") import uiperf3 uiperf3.client('192.168.31.48') |
Код довольно короткий, потому что мы пропустили обработку ошибок для соединения. Во всяком случае, вот результат теста производительности сети:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
Connecting to ('192.168.31.48', 5201) Interval Transfer Bitrate 0.00-1.00 sec 492 KBytes 4.03 Mbits/sec 1.00-2.00 sec 552 KBytes 4.51 Mbits/sec 2.00-3.00 sec 587 KBytes 4.80 Mbits/sec 3.00-4.00 sec 579 KBytes 4.74 Mbits/sec 4.00-5.00 sec 567 KBytes 4.65 Mbits/sec 5.00-6.00 sec 521 KBytes 4.26 Mbits/sec 6.00-7.00 sec 551 KBytes 4.51 Mbits/sec 7.00-8.00 sec 563 KBytes 4.61 Mbits/sec 8.00-9.00 sec 564 KBytes 4.61 Mbits/sec 9.00-10.00 sec 533 KBytes 4.38 Mbits/sec - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0.00-10.00 sec 5.38 MBytes 4.51 Mbits/sec sender 0.00-10.85 sec 5.38 MBytes 4.16 Mbits/sec receiver |
На наш взгляд, довольно медленно, хотя производительность не всегда является основным требованием для этого типа платформы. Это типично (для этого теста) для этого класса оборудования, поскольку, для справки, Дэмиен Джордж (главный разработчик MicroPython) протестировал его на плате Pyboard серии D и показал скорость около 7 Мбит/с.
Если в объявлении нам сказали, что Raspberry Pi Pico W также можно использовать в качестве точки доступа до четырех клиентов. Мы не нашли руководства по этому поводу в MicroPython, но есть инструкции для ESP8266 и ESP32, так что давайте попробуем настроить CNX-PICO SSID и подключиться с телефона:
1 2 3 4 5 6 7 |
import network ssid = 'CNX-PICO' password = 'cnx-review' ap = network.WLAN(network.AP_IF) ap.active(True) ap.config(essid=ssid, password=password) |
Хорошая новость заключается в том, что наш Raspberry Pi Pico W теперь действительно является точкой доступа, но менее хорошая новость заключается в том, что пользовательская конфигурация ssid не сработала, и вместо этого плата автоматически сгенерирует имя точки доступа (PICO349B) с открытой сетью. .
Таким образом, API должен быть другим, иначе пользовательские имена точек доступа пока не поддерживаются прошивкой Raspberry Pi Pico W MicroPython.
Использование WiFi на Raspberry Pi Pico W с программированием на C
Давайте попробуем воспроизвести приведенные выше примеры кода с помощью C/C++ SDK. Если вы еще этого не сделали, вам нужно настроить SDK, как мы это сделали для платы Raspberry Pi Pico, и получить образцы на компьютере с Linux или плате Raspberry Pi:
1 2 3 4 5 6 |
sudo apt install cmake gcc-arm-none-eabi libnewlib-arm-none-eabi build-essential git clone https://github.com/raspberrypi/pico-sdk cd pico-sdk git submodule update --init cd .. git clone -b master https://github.com/raspberrypi/pico-examples.git |
Теперь есть новый каталог для Pico W:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$ ls -l pico-examples/pico_w/ total 44 drwxrwxr-x 3 jaufranc jaufranc 4096 Jul 2 16:32 access_point drwxrwxr-x 2 jaufranc jaufranc 4096 Jul 2 16:32 blink -rw-rw-r-- 1 jaufranc jaufranc 985 Jul 2 16:32 CMakeLists.txt drwxrwxr-x 4 jaufranc jaufranc 4096 Jul 2 16:32 freertos drwxrwxr-x 2 jaufranc jaufranc 4096 Jul 2 16:32 iperf -rw-rw-r-- 1 jaufranc jaufranc 3417 Jul 2 16:32 lwipopts_examples_common.h drwxrwxr-x 2 jaufranc jaufranc 4096 Jul 2 16:32 ntp_client drwxrwxr-x 2 jaufranc jaufranc 4096 Jul 2 16:32 python_test_tcp drwxrwxr-x 2 jaufranc jaufranc 4096 Jul 2 16:32 tcp_client drwxrwxr-x 2 jaufranc jaufranc 4096 Jul 2 16:32 tcp_server drwxrwxr-x 2 jaufranc jaufranc 4096 Jul 2 16:32 wifi_scan |
Вот пример кода сканирования WiFi:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
** * Copyright (c) 2022 Raspberry Pi (Trading) Ltd. * * SPDX-License-Identifier: BSD-3-Clause */ #include <stdio.h> #include "pico/stdlib.h" #include "pico/cyw43_arch.h" static int scan_result(void *env, const cyw43_ev_scan_result_t *result) { if (result) { printf("ssid: %-32s rssi: %4d chan: %3d mac: %02x:%02x:%02x:%02x:%02x:%02x sec: %u\n", result->ssid, result->rssi, result->channel, result->bssid[0], result->bssid[1], result->bssid[2], result->bssid[3], result->bssid[4], result->bssid[5], result->auth_mode); } return 0; } #include "hardware/vreg.h" #include "hardware/clocks.h" int main() { stdio_init_all(); if (cyw43_arch_init()) { printf("failed to initialise\n"); return 1; } cyw43_arch_enable_sta_mode(); absolute_time_t scan_test = nil_time; bool scan_in_progress = false; while(true) { if (absolute_time_diff_us(get_absolute_time(), scan_test) < 0) { if (!scan_in_progress) { cyw43_wifi_scan_options_t scan_options = {0}; int err = cyw43_wifi_scan(&cyw43_state, &scan_options, NULL, scan_result); if (err == 0) { printf("\nPerforming wifi scan\n"); scan_in_progress = true; } else { printf("Failed to start scan: %d\n", err); scan_test = make_timeout_time_ms(10000); // wait 10s and scan again } } else if (!cyw43_wifi_scan_active(&cyw43_state)) { scan_test = make_timeout_time_ms(10000); // wait 10s and scan again scan_in_progress = false; } } // the following #ifdef is only here so this same example can be used in multiple modes; // you do not need it in your code #if PICO_CYW43_ARCH_POLL // if you are using pico_cyw43_arch_poll, then you must poll periodically from your // main loop (not from a timer) to check for WiFi driver or lwIP work that needs to be done. cyw43_arch_poll(); sleep_ms(1); #else // if you are not using pico_cyw43_arch_poll, then WiFI driver and lwIP work // is done via interrupt in the background. This sleep is just an example of some (blocking) // work you might be doing. sleep_ms(1000); #endif } cyw43_arch_deinit(); return 0; } |
Это немного сложнее, чем наш пример MicroPython выше. Давайте подготовим систему для сборки образцов C:
1 2 3 4 5 |
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" .. |
Вам нужно будет изменить SSID и пароль, чтобы они соответствовали тем, которые есть в вашей сети. Вот вывод команды для справки:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
Using PICO_SDK_PATH from environment ('../../pico-sdk') PICO_SDK_PATH is /home/jaufranc/edev/Raspberry-Pi-Pico-W/pico-sdk Defaulting PICO_PLATFORM to rp2040 since not specified. Defaulting PICO platform compiler to pico_arm_gcc since not specified. -- Defaulting build type to 'Release' since not specified. PICO compiler is pico_arm_gcc -- The C compiler identification is GNU 9.2.1 -- The CXX compiler identification is GNU 9.2.1 -- The ASM compiler identification is GNU -- Found assembler: /usr/bin/arm-none-eabi-gcc Build type is Release PICO target board is pico_w. Using CMake board configuration from /home/jaufranc/edev/Raspberry-Pi-Pico-W/pico-sdk/src/boards/pico_w.cmake Using board configuration from /home/jaufranc/edev/Raspberry-Pi-Pico-W/pico-sdk/src/boards/include/boards/pico_w.h -- Found Python3: /usr/bin/python3.8 (found version "3.8.10") found components: Interpreter TinyUSB available at /home/jaufranc/edev/Raspberry-Pi-Pico-W/pico-sdk/lib/tinyusb/src/portable/raspberrypi/rp2040; enabling build support for USB. cyw43-driver available at /home/jaufranc/edev/Raspberry-Pi-Pico-W/pico-sdk/lib/cyw43-driver lwIP available at /home/jaufranc/edev/Raspberry-Pi-Pico-W/pico-sdk/lib/lwip Enabling build support for Pico W wireless. Skipping tcp_client example as TEST_TCP_SERVER_IP is not defined Skipping Pico W FreeRTOS examples as FREERTOS_KERNEL_PATH not defined -- Configuring done -- Generating done -- Build files have been written to: /home/jaufranc/edev/Raspberry-Pi-Pico-W/pico-examples/build |
Теперь мы можем собрать пример wifi_scan:
1 2 |
cd pico_w/wifi_scan make -j8 |
Вывод довольно длинный, но должен начинаться и заканчиваться следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Scanning dependencies of target ELF2UF2Build [ 0%] Creating directories for 'ELF2UF2Build' [ 0%] No download step for 'ELF2UF2Build' [ 0%] No patch step for 'ELF2UF2Build' [ 0%] No update step for 'ELF2UF2Build' [ 0%] Performing configure step for 'ELF2UF2Build' -- The C compiler identification is GNU 9.4.0 -- The CXX compiler identification is GNU 9.4.0 -- Check for working C compiler: /usr/bin/cc -- Check for working C compiler: /usr/bin/cc -- works ... [100%] Building C object pico_w/wifi_scan/CMakeFiles/picow_wifi_scan_background.dir/home/jaufranc/edev/Raspberry-Pi-Pico-W/pico-sdk/lib/lwip/src/netif/ppp/polarssl/md5.c.obj [100%] Building C object pico_w/wifi_scan/CMakeFiles/picow_wifi_scan_background.dir/home/jaufranc/edev/Raspberry-Pi-Pico-W/pico-sdk/lib/lwip/src/netif/ppp/polarssl/sha1.c.obj [100%] Building C object pico_w/wifi_scan/CMakeFiles/picow_wifi_scan_background.dir/home/jaufranc/edev/Raspberry-Pi-Pico-W/pico-sdk/src/rp2_common/pico_lwip/nosys.c.obj [100%] Linking CXX executable picow_wifi_scan_background.elf [100%] Built target picow_wifi_scan_background |
Сборка сгенерирует кучу файлов, включая файл UF2, который мы будем использовать для копирования на плату:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
$ ls -l total 8560 drwxrwxr-x 4 jaufranc jaufranc 4096 Jul 2 16:48 CMakeFiles -rw-rw-r-- 1 jaufranc jaufranc 1027 Jul 2 16:48 cmake_install.cmake -rw-rw-r-- 1 jaufranc jaufranc 482519 Jul 2 16:48 Makefile -rwxrwxr-x 1 jaufranc jaufranc 306968 Jul 2 16:51 picow_wifi_scan_background.bin -rw-rw-r-- 1 jaufranc jaufranc 1499022 Jul 2 16:51 picow_wifi_scan_background.dis -rwxrwxr-x 1 jaufranc jaufranc 380952 Jul 2 16:51 picow_wifi_scan_background.elf -rw-rw-r-- 1 jaufranc jaufranc 452605 Jul 2 16:51 picow_wifi_scan_background.elf.map -rw-rw-r-- 1 jaufranc jaufranc 863499 Jul 2 16:51 picow_wifi_scan_background.hex -rw-rw-r-- 1 jaufranc jaufranc 614400 Jul 2 16:51 picow_wifi_scan_background.uf2 -rwxrwxr-x 1 jaufranc jaufranc 308304 Jul 2 16:51 picow_wifi_scan_poll.bin -rw-rw-r-- 1 jaufranc jaufranc 1490453 Jul 2 16:51 picow_wifi_scan_poll.dis -rwxrwxr-x 1 jaufranc jaufranc 418272 Jul 2 16:51 picow_wifi_scan_poll.elf -rw-rw-r-- 1 jaufranc jaufranc 437754 Jul 2 16:51 picow_wifi_scan_poll.elf.map -rw-rw-r-- 1 jaufranc jaufranc 867250 Jul 2 16:51 picow_wifi_scan_poll.hex -rw-rw-r-- 1 jaufranc jaufranc 616960 Jul 2 16:51 picow_wifi_scan_poll.uf2 |
Поскольку мы уже установили прошивку MicroPython на плату, нам нужно нажать кнопку BOOT и выключить и снова включить плату, чтобы перейти в режим запоминающего устройства, и скопировать файл picow_wifi_scan_poll.uf2 на диск RPI-RP2.
Диск будет перезагружен и программа запущена автоматически, но мы заметили, что плата больше не будет отображаться как последовательное устройство. Это потому, что нам нужно получить доступ к последовательной консоли через контакты UART Raspberry Pi Pico W с контактом 1 Tx, контактом 2 Rx и контактом 3 GND. Поэтому мы припаяли короткий разъем к соответствующим контактам на Raspberry Pi Pico W и использовали плату USB-TTL, подключенную к нашему ноутбуку, но если вы программируете плату Pico W с помощью Raspberry Pi SBC, вы можете вместо этого использовать UART из 40-контактного разъема GPIO
Теперь мы можем использовать BootTerm и видеть CNX_Software_Xiaomi SSID и правильно обнаруженный скрытый SSID нашего маршрутизатора:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$ bt -n 0 ports found, waiting for a new one... port | age (sec) | device | driver | description ------+------------+------------+------------------+---------------------- 0 | 0 | ttyUSB0 | ch341-uart | USB2.0-Serial Trying port ttyUSB0... Connected to ttyUSB0 at 115200 bps. Escape character is 'Ctrl-]'. Use escape followed by '?' for help. Performing wifi scan ssid: rssi: -35 chan: 8 mac: 42:cd:57:f5:af:92 sec: 0 ssid: CNX_Software_Xiaomi rssi: -36 chan: 8 mac: 3c:cd:57:f5:af:92 sec: 5 ssid: CNX_Software_Xiaomi rssi: -35 chan: 8 mac: 3c:cd:57:f5:af:92 sec: 5 ssid: CNX_Software_Xiaomi rssi: -33 chan: 8 mac: 3c:cd:57:f5:af:92 sec: 5 ssid: rssi: -34 chan: 8 mac: 42:cd:57:f5:af:92 sec: 0 |
Таким образом, сканирование работает (хотя оно показывает один и тот же SSID несколько раз), и теперь мы можем попытаться подключиться к нашему WiFi-маршрутизатору, используя следующий пример (из документации Pico W) в wifi_connect/wifi_connect.c :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#include <stdio.h> #include "pico/stdlib.h" #include "pico/cyw43_arch.h" char ssid[] = "CNX_Software_Xiaomi"; char pass[] = "A Password"; int main() { stdio_init_all(); if (cyw43_arch_init_with_country(CYW43_COUNTRY_UK)) { printf("failed to initialise\n"); return 1; } printf("initialised\n"); cyw43_arch_enable_sta_mode(); if (cyw43_arch_wifi_connect_timeout_ms(ssid, pass, CYW43_AUTH_WPA2_AES_PSK, 10000)) { printf("failed to connect\n"); return 1; } printf("connected\n"); } |
Просто убедитесь, что вы изменили значения ssid и pass, а также страну (CYW43_COUNTRY_??). Нам также понадобится файл CMakeLists.txt :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
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(wifi_connect wifi_connect.c ) pico_enable_stdio_usb(wifi_connect 1) pico_enable_stdio_uart(wifi_connect 1) pico_add_extra_outputs(wifi_connect) target_include_directories(wifi_connect PRIVATE ${CMAKE_CURRENT_LIST_DIR} ) target_link_libraries(wifi_connect pico_cyw43_arch_lwip_threadsafe_background pico_stdlib) |
А также потребуется скопировать некоторые дополнительные файлы в ваш рабочий каталог:
1 2 3 |
cp ../../../pico-sdk/external/pico_sdk_import.cmake . cp ../lwipopts_examples_common.h lwipopts.h |
Теперь у вас должно быть четыре файла в папке:
1 2 3 4 5 6 7 |
jaufranc@cnx-laptop-4:~/edev/Raspberry-Pi-Pico-W/pico-examples/pico_w/wifi_connect$ ls -l total 16 -rw-rw-r-- 1 jaufranc jaufranc 480 Jul 3 11:59 CMakeLists.txt -rw-rw-r-- 1 jaufranc jaufranc 3417 Jul 3 12:01 lwipopts.h -rw-rw-r-- 1 jaufranc jaufranc 3165 Jul 3 12:00 pico_sdk_import.cmake -rw-rw-r-- 1 jaufranc jaufranc 519 Jul 3 11:55 wifi_connect.c |
Теперь мы можем построить программу, как мы делали это раньше:
1 2 3 4 5 |
mkdir build cd build export PICO_SDK_PATH=../../../../pico-sdk/ cmake -DPICO_BOARD=pico_w .. make -j8 |
Если на этапе cmake возникла какая-либо проблема, просто исправьте файл CMakeLists.txt и удалите все файлы в папке сборки перед повторным запуском команды cmake.
Поскольку мы находимся в Таиланде, мы сначала предположили, что подойдет CYW43_COUNTRY_TH. Но, увы, это не верно!:
1 2 3 4 5 |
/home/jaufranc/edev/Raspberry-Pi-Pico-W/pico-examples/pico_w/wifi_connect/wifi_connect.c:11:36: error: 'CYW43_COUNTRY_TH' undeclared (first use in this function); did you mean 'CYW43_COUNTRY_UK'? 11 | if (cyw43_arch_init_with_country(CYW43_COUNTRY_TH)) { | ^~~~~~~~~~~~~~~~ | CYW43_COUNTRY_UK /home/jaufranc/edev/Raspberry-Pi-Pico-W/pico-examples/pico_w/wifi_connect/wifi_connect.c:11:36: note: each undeclared identifie |
Доступные страны можно найти в pico-sdk/lib/cyw43-driver/src/cyw43_country.h. Вот выдержка:
1 2 3 4 5 6 7 8 |
... #define CYW43_COUNTRY_SWITZERLAND CYW43_COUNTRY('C', 'H', 0) #define CYW43_COUNTRY_TAIWAN CYW43_COUNTRY('T', 'W', 0) #define CYW43_COUNTRY_THAILAND CYW43_COUNTRY('T', 'H', 0) #define CYW43_COUNTRY_TURKEY CYW43_COUNTRY('T', 'R', 0) #define CYW43_COUNTRY_UK CYW43_COUNTRY('G', 'B', 0) #define CYW43_COUNTRY_USA CYW43_COUNTRY('U', 'S', 0) |
Вместо этого нам стоит использовать CYW43_COUNTRY_THAILAND, и сборка может быть завершена. У нас есть необходимый файл UF2:
1 2 |
ls -l *.uf2 -rw-rw-r-- 1 jaufranc jaufranc 638976 Jul 3 14:00 wifi_connect.uf2 |
Давайте прошьем его на плату обычным способом и посмотрим, действительно ли мы сможем подключиться к роутеру:
1 2 3 4 5 6 7 8 9 |
$ bt -n 1 ports found, waiting for a new one... port | age (sec) | device | driver | description ------+------------+------------+------------------+---------------------- 1 | 0 | ttyACM0 | cdc_acm | Board CDC Trying port ttyACM0... Connected to ttyACM0 at 115200 bps. Escape character is 'Ctrl-]'. Use escape followed by '?' for help. connected |
Это мало о чем нам говорит, но, по крайней мере, программа работает без ошибок. Работа на C с Raspberry Pi Pico W потребует некоторой работы как с точки зрения изучения нового низкоуровневого API CYW43, библиотеки LWiP, так и с точки зрения работы с FreeRTOS для более сложных примеров.
Нет примера запуска веб-страницы для управления светодиодом, поэтому давайте рассмотрим пример iperf. Перейдем в папку /pico-examples/build/pico_w/iperf и соберем образец:
1 |
make -j8 |
В этом случае у нас есть два файла UF2:
1 2 3 |
$ ls -l *.uf2 -rw-rw-r-- 1 jaufranc jaufranc 629760 Jul 3 14:28 picow_iperf_server_background.uf2 -rw-rw-r-- 1 jaufranc jaufranc 632832 Jul 3 14:28 picow_iperf_server_poll.uf2 |
Если мы посмотрим на код, он выбирается через PICO_CYW43_ARCH_POLL:
- PICO_CYW43_ARCH_POLL = 1 — если вы используете pico_cyw43_arch_poll, то вы должны периодически проводить опрос из вашего основного цикла (не из таймера), чтобы проверить наличие драйвера WiFi или работу LwIP, которую необходимо выполнить.
- PICO_CYW43_ARCH_POLL != 1 — если вы не используете pico_cyw43_arch_poll, то работа драйвера WiFI и lwIP осуществляется через прерывание в фоновом режиме. Этот сон всего лишь пример некоторых (блокирующих).
Это всего лишь два разных метода программирования для выполнения программы с использованием опроса или прерывания. Последний обычно более эффективен, но более сложен. Мы просто скопируем picow_iperf_server_background.uf2 на плату для тестирования. Обратите внимание, что реализация основана на iperf2, а не на iperf3, как в примере с MicroPython. Сервер iperf работает на Raspberry Pi Pico W:
1 2 3 4 5 6 7 8 9 10 11 12 |
$ bt -n 1 ports found, waiting for a new one... port | age (sec) | device | driver | description ------+------------+------------+------------------+---------------------- 0 | 0 | ttyUSB0 | ch341-uart | USB2.0-Serial Trying port ttyUSB0... Connected to ttyUSB0 at 115200 bps. Escape character is 'Ctrl-]'. Use escape followed by '?' for help. Connecting to WiFi... Connected. Ready, running iperf server at 192.168.31.120 |
Запустим клиент iperf на ноутбуке:
1 2 3 4 5 6 7 8 |
jaufranc@cnx-laptop-4:~$ iperf -c 192.168.31.120 ------------------------------------------------------------ Client connecting to 192.168.31.120, TCP port 5001 TCP window size: 85.0 KByte (default) ------------------------------------------------------------ [ 3] local 192.168.31.48 port 50008 connected with 192.168.31.120 port 5001 [ ID] Interval Transfer Bandwidth [ 3] 0.0-10.0 sec 9.75 MBytes 8.15 Mbits/sec |
8 Мбит/с, что немного лучше, чем с MicroPython, но примерно на том же уровне. Результат также показан в последовательной консоли Pico W:
1 2 |
Completed iperf transfer of 9 MBytes @ 8.1 Mbits/sec Total iperf megabytes since start 9 Mbytes |
Если вы хотите запустить пример iperf в качестве клиента на Pico W, вам нужно будет добавить следующие две строки:
1 2 |
#define CLIENT_TEST 1 #define IPERF_SERVER_IP <IP_address of the server> |
«Руководство по началу работы» становится длинным и содержит немного больше деталей, чем мы изначально ожидали, поэтому мы пропустим эту часть.
Завершим руководство по WiFi демонстрацией точки доступа для Raspberry Pi Pico W. Прежде чем создавать пример, взглянем на код в pico-examples/pico_w/access_point/picow_access_point.c:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
const char *ap_name = "picow_test"; #if 1 const char *password = "password"; #else const char *password = NULL; #endif cyw43_arch_enable_ap_mode(ap_name, password, CYW43_AUTH_WPA2_AES_PSK); ip4_addr_t gw, mask; IP4_ADDR(&gw, 192, 168, 4, 1); IP4_ADDR(&mask, 255, 255, 255, 0); // Start the dhcp server dhcp_server_t dhcp_server; dhcp_server_init(&dhcp_server, &gw, &mask); |
Эта часть находится в функции main(). Мы видим, что по умолчанию SSID (точка доступа name0 — picow_test, пароль — password (с безопасностью WPA2), подсеть будет 192.168.4.0, и программа также запустит DHCP-сервер, чтобы клиент мог получить IP-адрес. адрес. Если вы установите пароль на NULL, это должна стать открытая сеть. Давайте изменим ap_name на picow_cnxsoft, а пароль на 123456…
1 2 3 4 5 6 |
const char *ap_name = "picow_cnxsoft"; #if 1 const char *password = "123465"; #else const char *password = NULL; #endif |
Создадим образец и скопируем picow_access_point_poll.uf2 или picow_access_point_background.uf2 на плату, как обычно. Вот вывод из терминала:
1 2 3 4 5 6 |
$ bt No port specified, using ttyUSB0 (last registered). Use -l to list ports. Trying port ttyUSB0... Connected to ttyUSB0 at 115200 bps. Escape character is 'Ctrl-]'. Use escape followed by '?' for help. Starting server on port 80 |
Сервер на порту 80 — это не веб-сервер, а базовый TCP-сервер, который, как мы полагаем, предназначен для работы с образцом TCP-клиента, установленным на другом Raspberry Pi Pico.
Тем не менее, нам удалось подключить наш телефон к точке доступа picow_cnxsoft…
а также ноутбук Ubuntu
Оба устройства также отображаются в последовательном терминале Raspberry Pi Pico W:
1 2 3 4 |
Starting server on port 80 DHCPS: client connected: MAC=bc:2e:f6:6a:71:64 IP=192.168.4.16 DHCPS: client connected: MAC=70:c9:4e:b7:84:77 IP=192.168.4.17 |
Документация Raspberry Pi Pico W довольно хороша для начала работы с WiFi, но не полная, так как, например, в настоящее время нет примера для настройки точки доступа в MicroPython и будьте готовы изучить код, например, нам пришлось заглянуть в код C/C++ SDK, а не в документацию, чтобы найти настройки страны. Большинству людей, вероятно, следует начать с MicroPython, так как, хотя C/C++ SDK более гибкий.
Выражаем свою благодарность источнику из которого взята и переведена статья, сайту cnx-software.com.
Оригинал статьи вы можете прочитать здесь.
Это всё можно сделать на плате за $2.