Сегодня я хотел бы рассмотреть новый камень (в данный момент не очень) камень от создателей Raspberry Pi - RP2040. Это 2-х ядерный микроконтроллер на 2-х ядрах Cortex-M0+ с максимальной частотой 133MHz, 264kB SRAM и отсутствующей внутренней flash памяти, зато возможность подключения до 16mb внешней. Звучит достаточно неплохо с учетом того что STM32 сейчас практически не достать, но все ли хорошо с поддержкой? Сегодня попробуем выяснить.

Для начала предлагаю взглянуть на то что нам предлагает производитель:

  • Dual ARM Cortex-M0+ @ 133MHz
  • 264kB on-chip SRAM in six independent banks
  • Support for up to 16MB of off-chip Flash memory via dedicated QSPI bus
  • DMA controller
  • Fully-connected AHB crossbar
  • Interpolator and integer divider peripherals
  • On-chip programmable LDO to generate core voltage
  • 2 on-chip PLLs to generate USB and core clocks
  • 30 GPIO pins, 4 of which can be used as analogue inputs
  • 2 UARTs
  • 2 SPI controllers
  • 2 I2C controllers
  • 16 PWM channels
  • USB 1.1 controller and PHY, with host and device support
  • 8 PIO state machines

Не очень густо, однако имеются модули PIO, по сути мини fpga висящая на GPIO, что в теории должно позволить создавать свои периферийные блоки.

Работать мы будем с Raspberry Pi Pico, платой которою предлагает для работы производитель.

Pico-Pinout

Для начала попробуем помигать диодом, для чего код нужно собрать, а потом загрузить на контроллер. Для разработки производитель предлагает много вариантов это и С/C++ и MicroPython и arduino. Однако мы рассматриваем этот контроллер как вариант в прод, поэтому нас интересует только первый вариант. Для программирования на C/C++ существует SDK, который базируется на системе сборки Cmake, что как по мне достаточно хорошо.

Для того чтобы пользоваться этим SDK необходимо следующее:

1) Установить компилятор arm-none-eabi-gcc. Либо скачать отсюда, либо установить через apt, однако там может быть более старая версия:

sudo apt install cmake gcc-arm-none-eabi libnewlib-arm-none-eabi libstdc++-arm-none-eabi-newlib

Версия cmake не так важна, поэтому можно установить из репозиториев.

2) Скачиваем SDK и создаем проект:

mkdir led_test && cd led_test
git clone https://github.com/raspberrypi/pico-sdk
touch CMakeLists.txt main.c

3) Код для мигания диодом, пока не важно как это работает, естественно добавляем в main.c:

#include "pico/stdlib.h"

int main()
{
    const uint LED_PIN = 25;
    gpio_init(LED_PIN);
    gpio_set_dir(LED_PIN, GPIO_OUT);
    while (true)
    {
        gpio_put(LED_PIN, 1);
        sleep_ms(250);
        gpio_put(LED_PIN, 0);
        sleep_ms(250);
    }
}

4) Заполняем Cmake файл:

cmake_minimum_required(VERSION 3.13)
include(pico-sdk/pico_sdk_init.cmake)

set(PROJECT_NAME led_test)

project(${PROJECT_NAME})
pico_sdk_init()

add_executable(${PROJECT_NAME}
    main.c
)

target_link_libraries(${PROJECT_NAME} pico_stdlib)
#For create uf2 file.
pico_add_extra_outputs(${PROJECT_NAME})

5) Собираем проект:

mkdir build
cd build
cmake ..
make

После чего в папке build появится файл led_test.uf2. Теперь можно подключить платку USB кабилем к компьютером обязательно с надатой кнопкой BOOTSEL, посде чего в системе появится диск RPI-RP2, кидаем на него led_test.uf2 и диод начнет мигать. Удобно не правдали?

На самом деле НЕТ. Это фича работает благодаря тому что одно из 2х ядер работает как рограмматор. Т.е. не доступно для использования. Также используя данную фичу, код на контроллере нельзя отлаживать. Поэтому наш выбор это программатор. И тут мы сталкивается с целой кучей проблем.

В 99% статей которые можно найти в этих ваших тыртырнетах как программатор используется либо Raspberry PI (причем некотные предлагают не использовать ее как сервер для отладки а писать код под Pico прям на ней) либо другую плату Pico, установив на нее эту прошивку, примерно так:

pico_pico

Так-же есть совсем странный вариант, использование одного ядра как cmsis dap отладчик. А работает это так, нужно подключить pico к компьютеру с включеным бутлоадером (нажатой BOOTSEL), потом закинуть специальный бинарь который загрузится в ОЗУ, после чего он уже грузит код с флеш памяти.

IMG_5605

Эти варианты совершенно неприемлемы для комерческой разработки, поэтому необходимо искать другие варианты. Благо мы не одни такие и нашолся добрый человек который предложил комит, который добавляет поддержку Jlink. Однако это форк а значит придется собирать его из исходников:

git clone https://github.com/raspberrypi/openocd.git
cd openocd 
./bootstrap 
./configure --enable-picoprobe --enable-cmsis-dap
make -j$(nproc)
sudo make install

После чего необходимо подключить программатор:

  • Pico SWDIO в Jlink SWDIO, Pin 7
  • Pico SWCLK в Jlink SWCLK, Pin 9
  • Pico GND в Jlink GND
  • Pico 3V3(OUT), Pin 36 в Jlink VTref, Pin 1

После проверить что openocd нормально ее цепляет:

openocd -f interface/jlink.cfg -c "transport select swd" -c "adapter speed 6000" -f target/rp2040.cfg

После этого к данной плате можно подключится при помощи GDB:

$ arm-none-eabi-gdb
(gdb) target remote :3333
# тут диод погаснет
(gdb) continue
# тут сново начнет мигать
(gdb) quit

Если все прошло так как должно, значит все будет работать.

Отлаживать из консоли не очень удобно, лучше использовать для этого блокнот. Я предлагаю использовать VScode с расширением Cortex debug. Для этого нужно в папку нашего проекта добавить конфигурационный скрипт для openocd и конфигурацию для VScode:

mkdir .vscode && cd .vscode
touch launch.json tasks.json
cd .. && mkdir docs && cd docs
touch pico-jlink.cfg

pico-jlink.cfg - конфигурационный файл для OpenOCD:

source [find interface/jlink.cfg]
transport select swd
adapter speed 6000

source [find target/rp2040.cfg]

Для VScode необходимо описать задачи в tasks.json:

{
    "version": "2.0.0",
    "tasks": [
        {
            "type": "shell",
            "label": "cmake",
            "command": "cmake --build .",
            "options": {
                "cwd": "${workspaceFolder}/build"
            },
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "problemMatcher": {
                "base": "$gcc", 
                "fileLocation": ["relative", "${workspaceFolder}/build"]
            }
        }
    ]
}

Данная задача будет запускатся перед каждей сессией отладки. Также необходимо прописать параметры для Cortex debug launch.json:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "RP2030",
            "cwd": "${workspaceRoot}",
            "executable": "${command:cmake.launchTargetPath}",
            "request": "launch",
            "type": "cortex-debug",
            "servertype": "openocd",
            "preLaunchTask": "cmake",
            // Add you svd file
            "svdFile": "${workspaceRoot}/pico-sdk/src/rp2040/hardware_regs/rp2040.svd",
            // Set you programmer and trget controller
            "configFiles": [
                "docs/pico-jlink.cfg"
            ],

            "swoConfig": {
                "enabled": true,
                "cpuFrequency": 8000000,
                "swoFrequency": 2000000,
                "source": "probe",
                "decoders": [
                    {
                        "type": "console",
                        "label": "ITM",
                        "port": 0
                    }
                ]
            }
        }
    ]
}

После чего пререзапускае (или запускаем) VScode, и выбираем нужный компилятор - arm-none-eabi-gcc и запускаем отладку. И все должно заработать.

Далее можно поковырять Getting started и C/C++ SDK но об этом уже в следующих статьях.

Интересные ссылки

Previous Post