Начало работы с беспроводным модулем на плате Raspberry Pi Pico W

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. Так что здесь ничего не изменилось.

Вот вывод из журнала ядра для справки:

[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 или загрузим его напрямую следующим образом:

wget https://micropython.org/download/rp2-pico-w/rp2-pico-w-latest.uf2

Как только мы загрузим его, просто скопируйте rp2-pico-w-latest.uf2 на диск RPI-RP2…

… и скоро диск исчезнет, ​​а Raspberry Pi Pico W теперь будет отображаться как последовательное устройство:

[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 и т. д.):

$ bt -l
 port |  age (sec) | device     | driver           | description          
------+------------+------------+------------------+----------------------
 *  0 |        132 | ttyACM0    | cdc_acm          | Board CDC

Если мы подключимся к последовательному устройству, мы сможем войти в интерфейс REPL, где мы можем ввести несколько команд, чтобы вывести список точек доступа 2,4 ГГц:

$ 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:

sudo apt install python3-tk
pip3 install thonny

Мы можем запустить предыдущую программу MicroPython в Thonny IDE без каких-либо проблем после перехода в «Выполнить» — > «Выбрать интерпретатор» и выбрать «MicroPython (Raspberry Pi Pico)».

Давайте подключимся к CNX_Software_Xiaomi SSID с помощью следующей программы:

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-адрес, и мы можем успешно пропинговать его:

$ 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:

$ 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).
...

Прошивка поставляется с безопасными глобальными настройками, но вы можете включить дополнительные каналы, настроив страну:

import rp2
rp2.country('TH')

Это будет особенно полезно, если ваша плата не может подключиться к маршрутизатору из-за недоступных каналов.

Типичным вариантом использования платы этого типа является наличие веб-интерфейса для управления светодиодами или GPIO. Давайте запустим веб-сервер для управления пользовательским светодиодом на плате:

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:

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')

Код довольно короткий, потому что мы пропустили обработку ошибок для соединения. Во всяком случае, вот результат теста производительности сети:

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 и подключиться с телефона:

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:

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:

$ 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:

**
 * 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:

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 и пароль, чтобы они соответствовали тем, которые есть в вашей сети. Вот вывод команды для справки:

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:

cd pico_w/wifi_scan
make -j8

Вывод довольно длинный, но должен начинаться и заканчиваться следующим образом:

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, который мы будем использовать для копирования на плату:

$ 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 нашего маршрутизатора:

$ 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 :

#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 :

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)


А также потребуется скопировать некоторые дополнительные файлы в ваш рабочий каталог:

cp ../../../pico-sdk/external/pico_sdk_import.cmake .
cp ../lwipopts_examples_common.h lwipopts.h

Теперь у вас должно быть четыре файла в папке:

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

Теперь мы можем построить программу, как мы делали это раньше:

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

Если на этапе cmake возникла какая-либо проблема, просто исправьте файл CMakeLists.txt и удалите все файлы в папке сборки перед повторным запуском команды cmake.

Поскольку мы находимся в Таиланде, мы сначала предположили, что подойдет CYW43_COUNTRY_TH. Но, увы, это не верно!:

/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. Вот выдержка:

...
#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:

ls -l *.uf2
-rw-rw-r-- 1 jaufranc jaufranc 638976 Jul  3 14:00 wifi_connect.uf2

Давайте прошьем его на плату обычным способом и посмотрим, действительно ли мы сможем подключиться к роутеру:

$ 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 и соберем образец:

make -j8

В этом случае у нас есть два файла UF2:

$ 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:

  1. PICO_CYW43_ARCH_POLL = 1 — если вы используете pico_cyw43_arch_poll, то вы должны периодически проводить опрос из вашего основного цикла (не из таймера), чтобы проверить наличие драйвера WiFi или работу LwIP, которую необходимо выполнить.
  2. PICO_CYW43_ARCH_POLL != 1 — если вы не используете pico_cyw43_arch_poll, то работа драйвера WiFI и lwIP осуществляется через прерывание в фоновом режиме. Этот сон всего лишь пример некоторых (блокирующих).

Это всего лишь два разных метода программирования для выполнения программы с использованием опроса или прерывания. Последний обычно более эффективен, но более сложен. Мы просто скопируем picow_iperf_server_background.uf2 на плату для тестирования. Обратите внимание, что реализация основана на iperf2, а не на iperf3, как в примере с MicroPython. Сервер iperf работает на Raspberry Pi Pico W:

$ 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 на ноутбуке:

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:

Completed iperf transfer of 9 MBytes @ 8.1 Mbits/sec
Total iperf megabytes since start 9 Mbytes

Если вы хотите запустить пример iperf в качестве клиента на Pico W, вам нужно будет добавить следующие две строки:

#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:

    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…

    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 на плату, как обычно. Вот вывод из терминала:

$ 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:

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.

Оригинал статьи вы можете прочитать здесь.

5 1 vote
Article Rating
Подписаться
Уведомление о
guest

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.

1 Комментарий
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
CrazyIT
4 месяцев назад

Это всё можно сделать на плате за $2.