vak: (Default)
[personal profile] vak
Софт установили, начнём играться с платой. План будет следующий:
  1. Как загрузить прошивку в плату: два способа
  2. Blink: прошиваем через бутлоадер
  3. Прилаживаем адаптер picoprobe
  4. Hello_serial: прошиваем через picoprobe
  5. Подсоединяем консольный порт
  6. Сбрасываем плату из командной строки
  7. Подключаем отладчик

Два способа загрузить прошивку в плату

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

В каждой плате присутствует начальный загрузчик, который умеет загружать новую прошивку. Его можно активировать при включении. Если вынуть кабель USB из платы, нажать кнопку BOOTSEL и при нажатой кнопке вставить кабель, то загрузчик перейдёт в специальный режим, когда он прикидывается диском для компьютера. Диск имеет имя RPI-RP2. На нём находятся два файла с информацией о плате:
$ ls -l /Volumes/RPI-RP2
total 1
-rwxrwxrwx 1 vak staff 241 Sep 5 2008 INDEX.HTM
-rwxrwxrwx 1 vak staff 62 Sep 5 2008 INFO_UF2.TXT
$ cat /Volumes/RPI-RP2/INFO_UF2.TXT
UF2 Bootloader v3.0
Model: Raspberry Pi RP2
Board-ID: RPI-RP2
Но самое главное: если записать на этот диск файл в формате *.uf2, то он будет прошит в память процессора как программа для выполнения. Этот способ хорош тем, что не требует никаких дополнительных прибамбасов. Но нужно иметь возможность физически нажать кнопку на плате и передёрнуть питание.

Также в этот режиме можно пользоваться утилитой picotool. Она общается с бутлоадером через его протокол, и умеет много полезных вещей. Например, выдать подробную информацию о прошитой программе:
$ picotool info -a
Program Information
name: hello_serial
web site: https://github.com/raspberrypi/pico-examples/tree/HEAD/hello_world/serial
features: UART stdin / stdout
binary start: 0x10000000
binary end: 0x100053fc

Fixed Pin Information
0: UART0 TX
1: UART0 RX

Build Information
sdk version: 1.3.1
pico_board: pico
boot2_name: boot2_w25q080
build date: May 20 2022
build attributes: Debug

Device Information
flash size: 2048K
ROM version: 3
Есть и другой способ прошивки: через отладочный порт SWD. Это три контакта на торце платы, противоположном разъёму USB. Но требуется отдельный адаптер: про него я расскажу ниже. Также будет нужна утилита openocd.

Blink: прошиваем через бутлоадер

Опробуем прошивку через бутлоадер. Загрузим в плату пример blink: он мигает светодиодом. Его мы скомпилировали в прошлый раз:
$ cd ~/Project/Pico/pico-examples/build/blink
$ ls -l blink.uf2
-rw-r--r-- 1 vak staff 41984 May 21 00:39 blink.uf2
Определите, где у вас в файловой системе смонтировался диск платы Pico. У меня это /Volumes/RPI-RP2. Скопируйте бинарный файл программы (в формате uf2) на этот диск:
cp blink.uf2 /Volumes/RPI-RP2
Обратите внимание на светодиод на плате: он должен начать мигать. Диск при этом RPI-RP2 автоматически отмонтируется.

Чтобы повторить прошивку после изменения программы, надо опять вынуть кабель USB, нажать кнопку BOOTSEL и при нажатой кнопке вставить кабель.

Прилаживаем адаптер picoprobe

Дальнейшие шаги возможны, если у вас имеется не одна, а _две_ платы Raspberry Pico. Хитрость в том, что одну плату мы превратим в USB-адаптер для прошивки и отладки второй платы. Подробности смотрите в статье: Raspberry Pi Pico and RP2040 - C/C++ Part 2: Debugging with VS Code.

Польза от такого подхода тройная:
  • Можно прошивать плату без необходимости нажимать кнопку и передёргивать питание.
  • Можно отлаживать программу на плате с помощью отладчика GDB.
  • Можно подключаться к серийному порту UART0 платы.
Соедините платы следующим образом:


Можно просто припаять проводки, а можно обойтись макетной платой. У меня получилась такая конфигурация:



Теперь прошьём плату слева, которая станет адаптером отладки. Прошивку для неё (picoprobe) мы приготовили в предыдущий раз. Подключите кабель USB к левой плате, предварительно нажав кнопку BOOTSEL. После этого скопируйте на неё прошивку:
cd ~/Project/Pico/picoprobe/build
cp picoprobe.uf2 /Volumes/RPI-RP2
Светодиод должен загореться. Адаптер готов к работе. На вашем компьютере появится новый виртуальный последовательный порт. В моём случае это /dev/tty.usbmodem14301. Он нам будет нужен ниже.

Hello_serial: прошиваем через picoprobe

Теперь мы можем прошить вторую плату (справа) через наш свежеиспечённый адаптер. Возьмём другой пример, который выдаёт текстовое сообщение на серийный порт. Делается это таким образом:
cd ~/Project/Pico/pico-examples/build/hello_world/serial
openocd -f interface/picoprobe.cfg -f target/rp2040.cfg -c "program hello_serial.elf verify reset exit"
Процесс прошивки должен завершиться сообщениями:
** Programming Started **
Info : RP2040 B0 Flash Probe: 2097152 bytes @10000000, in 512 sectors
...
** Programming Finished **
** Verify Started **
...
** Verified OK **
** Resetting Target **
...
Заметьте: мы используем утилиту openocd, и прошиваем бинарный файл в формате elf (а не uf2, как с бутлоадером).

Командная строка слишком громоздкая получается, поэтому для себя я сварганил более удобный шелл-скрипт: pico-prog.

Подсоединяем консольный порт

Пример hello_serial, который мы прошили в плату, выдаёт сообщения в последовательный порт UART0, подсоединенный к контактам GP0 и GP1 на плате. Адаптер picoprobe даёт возможность подсоединиться к этому порту через USB. Нужен какой-то эмулятор терминала: я рекомендую minicom. Его можно установить на маке командой:
brew install minicom
На Линуксе
sudo apt-get install minicom
Подсоединяемся к серийному порту Pico:
minicom -D /dev/tty.usbmodem14301 -b 115200
В вашем случае имя устройства может быть другим. На Линуксе обычно /dev/ttyACM0. На экране должно повторяться сообщение:
Hello, world!
Hello, world!
Hello, world!
...

Сбрасываем плату из командной строки

Если есть необходимость сбросить программу на плате (послав виртуальный сигнал Reset), это можно сделать через адаптер отладки:
openocd -f interface/picoprobe.cfg -f target/rp2040.cfg -c init -c reset -c exit
Для удобства я засунул эту команду в шелл-скрипт: pico-reset.

Подключаем отладчик

Но конечно, самая мощная функция адаптера picoprobe - отладка через GDB. Методика отладки детально описана в документации Raspberry Pico, а здесь я покажу, как происходит подключение к плате.

В отдельном окошке запускаем openocd в режиме сервера. Он обеспечивает интерфейс между GDB и USB-адаптером picoprobe:
openocd -f interface/picoprobe.cfg -f target/rp2040.cfg
При вызове openocd выдаст сообщение:
Info : accepting 'gdb' connection on tcp/3333
То есть он принимает вызовы от отладчика GDB на локальном порту TCP с указанным номером.

При вызове отладчика нужно дать ему тот самый ELF-файл, который вы прошивали в плату:
$ gdb hello_serial.elf
GNU gdb (GDB) 12.1
...
Reading symbols from hello_serial.elf...
(gdb) target extended-remote :3333
Remote debugging using :3333
warning: multi-threaded target stopped without sending a thread-id, using first non-exited thread
time_reached (t=...) at pico-sdk/src/rp2_common/hardware_timer/include/hardware/timer.h:116
116     uint32_t hi_target = (uint32_t)(target << 32u);
(gdb) bt
#0  time_reached (t=...) at pico-sdk/src/rp2_common/hardware_timer/include/hardware/timer.h:116
#1  sleep_until (t=...) at pico-sdk/src/common/pico_time/time.c:361
#2  0x10000e78 in sleep_us (us=>optimized out<)
    at pico-sdk/src/common/pico_time/include/pico/time.h:102
#3  0x10000eb2 in sleep_ms (ms=ms@entry=1000) at pico-sdk/src/common/pico_time/time.c:393
#4  0x1000032a in main () at pico-examples/hello_world/serial/hello_serial.c:15
(gdb) i reg
r0             0xf480f             1001487
r1             0x1e8a44            2001476
r2             0x0                 0
r3             0xd0000128          -805306072
r4             0xf4239             999993
r5             0x0                 0
r6             0x1e8a4a            2001482
r7             0x0                 0
r8             0xffffffff          -1
r9             0xffffffff          -1
r10            0xffffffff          -1
r11            0xffffffff          -1
r12            0x20041f60          537141088
sp             0x20041fa8          0x20041fa8
lr             0x100010ab          268439723
pc             0x10000e0c          0x10000e0c >sleep_until+192<
xPSR           0x61000000          1627389952
msp            0x20041fa8          0x20041fa8
psp            0xfffffffc          0xfffffffc
primask        0x0                 0
basepri        0x0                 0
faultmask      0x0                 0
control        0x0                 0
(gdb) monitor resume
(gdb) _
Ну и так далее.

Мультиплатформенный отладчик на маке называется просто gdb, а на Линуксе gdb-multiarch. Устанавливается он, соответственно, на маке:
brew install gdb
На Линуксе:
sudo apt-get install gdb-multiarch
На этом подготовка инструментария для Pico закончена. В следующий раз займёмся изучением архитектуры процессора Cortext-M0+, в частности переключением контекста.

Date: 2022-05-23 11:42 (UTC)
From: [personal profile] ivanrubilo
Прикольно, но нахрен ещё minicom если есть уже screen по дефолту в макоси:
`screen /dev/tty.usbmodem14301 115200`

Date: 2022-05-24 01:11 (UTC)
ufm: (Default)
From: [personal profile] ufm
screen тем более есть в любом, по моему, линуксе.

Date: 2022-05-24 02:31 (UTC)
ufm: (Default)
From: [personal profile] ufm
Не буду спорить, так как не владею миникомом (пользовался им, по моему, пару раз всего, еще во времена Fido). Впрочем, как и screen в таком режиме. Как-то всю жизнь хватало cu :)