- PVSM.RU - https://www.pvsm.ru -

Настройка VSCode для отладки китайского RISC-V SoC

Я всей душой люблю малоизвестных производителей. Зачастую их продукты имеют фичи, недоступные у их более именитых конкурентов, по очень интересной цене (однажды меня очень выручило наличие встроенной в SoC полуамперной зарядки для аккумулятора и нескольких LDO, способных запитать всю периферию). Кроме того, сроки и условия поставки какого-нибудь Nanjing Qinheng Microelectronics [1] могут приятно удивить разработчиков, привыкших за последние два ковидных года к конскому ценнику и 52+ неделям доставки на ST, TI, Nordic и прочие привычные вещи. Логистика становится особенно приятной, если массовое производство планируется в Китае и на площадке присутствует ваша китайская команда, способная разрулить возникающие проблемы. Да и доставка из Шеньчженя в Шеньчжень проще и предсказуемей, чем со склада глобального дистрибьютора и растаможка в России.

Что готовим, шеф?

Вот такой зверь. Забудьте об Arduino-формате расположения пинов на отладках, здесь свой особый путь.
Вот такой зверь. Забудьте об Arduino-формате расположения пинов на отладках, здесь свой особый путь.

Незадолго до новогодних праздников мне в руки попал B91 Generic Starter Kit [2]. Отладка построена на базе TLSR9518A [3] - RISC-V SoC с поддержкой Bluetooth Classic, BLE, собственным AI-движком и кучей других плюшек, позволяющих сделать относительно сложное носимое устройство по достаточно низкой цене. На отладке распаян старший чип из линейки, ориентированный на задачи, связанные с аудио и одновременной поддержкой как классического Bluetooth, так и BLE, но в линейке есть и более простые устройства. В общем - идеальный кандидат на то, чтобы развеять тоску и отвлечь от тазика с оливье.
Telink раньше был известен в первую очередь благодаря сверхдешевым BLE-чипам, построенным на собственном ядре, но с недавнего времени в линейке появились и RISC-V.
На вики [4] вендора присутствуют ссылки на IDE, тулчейн и примеры кода. Если бы мы отлаживали что-то более распространенное в наших краях, то этого было бы достаточно, но здесь производитель приготовил несколько сюрпризов:

  • IDE только под винду, которой у меня нет (да и тысячи вендорских IDE на эклипсе уже набили оскомину. А после того, как WICED-Studio отказалась запускать отладку на CYW954907 пока я не уберу все брейкпойнты, я принял решение по возможности не использовать такие решения). Поэтому мы будем использовать связку CMake + VSCode.

  • Сервер, на котором хранятся IDE и тулчейн, находится где-то в тибетском монастыре, подключенном по dial-up'у, по крайней мере средняя скорость закачки в 10кб/с и более трех тысяч разрывов закачки намекают об этом.

  • Тулчейн неполный, мы можем собрать и зашить бинарь, но gdb-сервер не может стартовать из-за отсутствия одной из библиотек. Эти и другие проблемы мы попробуем решить.

Подготовка проекта и окружения

Я использовал в процессе Ubuntu 21.10, так что если вы работаете с другой ОС, то возможно придется немного скорректировать команды.

sudo apt update && sudo apt upgrade && sudo apt autoremove
sudo dpkg --add-architecture i386
sudo apt-get update
sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386
sudo apt install -y make cmake wget unzip libncurses5

Тулчейн

Его можно собрать самому по инструкции [5] или же скачать готовую сборку с гитхаба разработчиков ядра. У меня не получилось собрать его с ходу, а разбираться интереса не было. Поэтому, если кто укажет на причину - буду весьма благодарен.

Версия с Mculib

По умолчанию предлагается вендором.

wget https://github.com/andestech/Andes-Development-Kit/releases/download/ast-v3_2_3-release-linux/nds32le-elf-mculib-v5f.txz
mkdir toolchain
tar -xvf nds32le-elf-mculib-v5f.txz -C toolchain
rm nds32le-elf-mculib-v5f.txz

Версия с Newlib

https://github.com/andestech/Andes-Development-Kit/releases/download/ast-v3_2_3-release-linux/nds32le-elf-newlib-v5f.txz
mkdir toolchain
tar -xvf nds32le-elf-newlib-v5f.txz -C toolchain
rm nds32le-elf-newlib-v5f.txz

Инструменты отладки

В комплекте с девбордой идет JTAG-отладчик от вендора, но в принципе не должно возникнуть особых проблем с использованием других аппаратных средств, поддерживающих OpenOCD. Единственный нюанс - TLSR9518A, установленный на плате, предназначен исключительно для оценки и единственный из всей линейки не имеет встроенной FLASH-памяти.
Для работы с вендорским отладчиком потребуется утилита для прошивки внешней флешки и отладчик ICE, модифицированный OpenOCD.

wget https://github.com/andestech/Andes-Development-Kit/releases/download/ast-v3_2_3-release-linux/flash.zip
wget https://github.com/andestech/Andes-Development-Kit/releases/download/ast-v3_2_3-release-linux/ice.zip
unzip flash.zip -d toolchain
unzip ice.zip -d toolchain
rm -rf flash.zip ice.zip
cd toolchain/ice/
chmod +x ICEman.sh
./ICEman.sh

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

SDK

В том, что касается SDK, Telink придерживается подхода, похожего на тот, что использовали когда-то Nordic со свими SoftDevice - отдельный SDK под каждую задачу. Нужный вам можно найти на вики, а для примера я решил использовать Driver SDK, предназначенный для работы с периферией чипа. Стоит отметить, что Bluetooth SDK предполагает работу в суперцикле и не имеет ни малейшего намека на поддержку FreeRTOS, в отличие от Driver SDK. Представители вендора не дали прямого ответа, почему сделано именно так, но горячо уверили, что к осени SDK получит мощный апдейт. Заявлена поддержка Zephyr, но без BLE и, судя по треду [6], ситуация вряд ли улучшится в ближайшее время. Поэтому, если вы захотите начинать разработку следующего устройства на основе православного китайского чипа - имейте в виду такие особенности, они возникают достаточно часто.

wget http://wiki.telink-semi.cn/tools_and_sdk/Driver/B91_Driver_SDK.zip
mkdir driver_sdk
unzip B91_Driver_SDK.zip -d driver_sdk/
rm B91_Driver_SDK.zip

Сборка

Единственное, чего нам не хватает сейчас - инструкции по сборке. За основу я взял UART_DEMO [7], немного подправив его, чтобы сделать возможной out-of-tree сборку и отладку.

cmake_minimum_required(VERSION 3.0)

project(apptest)

enable_language(C ASM)

set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS)

set(RISCV_TOOLCHAIN ${CMAKE_CURRENT_LIST_DIR}/../toolchain/nds32le-elf-mculib-v5f/bin)
set(DRIVER_SDK ${CMAKE_CURRENT_LIST_DIR}/../driver_sdk/B91_Driver_Demo)

set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_C_COMPILER ${RISCV_TOOLCHAIN}/riscv32-elf-gcc)
set(CMAKE_CXX_COMPILER ${RISCV_TOOLCHAIN}/riscv32-elf-g++)
set(CMAKE_ASM_COMPILER ${RISCV_TOOLCHAIN}/riscv32-elf-gcc)

set(OBJCOPY ${RISCV_TOOLCHAIN}/riscv32-elf-objcopy)
set(OBJDUMP ${RISCV_TOOLCHAIN}/riscv32-elf-objdump)
set(NM ${RISCV_TOOLCHAIN}/riscv32-elf-nm)
set(READELF ${RISCV_TOOLCHAIN}/riscv32-elf-readelf)
set(SIZE ${RISCV_TOOLCHAIN}/riscv32-elf-size)

add_definitions(-DMCU_STARTUP_FLASH_B91=1)

add_compile_options(-Og -g3 -mcpu=d25f -mext-dsp -mabi=ilp32f -std=c99)
add_compile_options(-ffunction-sections -fdata-sections -fpack-struct -fshort-enums -flto)
add_compile_options(-fmessage-length=0 -fomit-frame-pointer -fno-strict-aliasing -fshort-wchar -fuse-ld=bfd)
add_compile_options(-Wall -Wno-nonnull-compare -Wextra -Wshadow -Werror -Wno-gnu-zero-variadic-macro-arguments)

set(CMAKE_EXE_LINKER_FLAGS "-Og -g3 -nostartfiles -static -T"${DRIVER_SDK}/link/flash_boot.link" -Wl,--gc-sections")

link_libraries(-lB91)

aux_source_directory(${DRIVER_SDK}/common SRCS_COMMON)
aux_source_directory(${DRIVER_SDK}/drivers/B91 SRCS_DRIVERS_B91)
aux_source_directory(${DRIVER_SDK}/vendor/common SRCS_VENDOR_COMMON)
aux_source_directory(${DRIVER_SDK}/vendor/UART_DEMO SRCS_APP)

set(SRCS
${SRCS_COMMON}
${SRCS_DRIVERS_B91}
${SRCS_VENDOR_COMMON}
${SRCS_APP}
${DRIVER_SDK}/boot/B91/cstartup_b91_flash.S)

include_directories(${CMAKE_CURRENT_LIST_DIR})
include_directories(${DRIVER_SDK})
include_directories(${DRIVER_SDK}/vendor/common)
include_directories(${DRIVER_SDK}/drivers/B91)
include_directories(${DRIVER_SDK}/common)

link_directories(${DRIVER_SDK}/drivers/B91)

add_executable(${PROJECT_NAME}.elf ${SRCS})

add_custom_target(BIN ALL
COMMAND ${OBJCOPY} -S -O binary ${PROJECT_NAME}.elf ${PROJECT_NAME}.bin
COMMAND ${SIZE} ${PROJECT_NAME}.elf
COMMAND ${OBJDUMP} -x -d -C ${PROJECT_NAME}.elf > objdump.txt
COMMAND ${NM} -n -l -C ${PROJECT_NAME}.elf > symbol.txt
COMMAND ${READELF} -a ${PROJECT_NAME}.elf > readelf.txt
DEPENDS ${PROJECT_NAME}.elf
)

Я поместил этот файл в директорию app, в которой планирую хранить и остальные исходники. Теперь можно запустить сборку.

cd app && mkdir build && cd build
cmake ..
make

Настройка VSCode

Для комфортной работы потребуется создать несколько файлов с настройками для VSCode: c_cpp_properties.json, launch.json, settings.json, tasks.json, каждый из которых отвечает за определенный функционал среды разработки. Для нас наиболее интересны настройки сборки и отладки.

Сборка (tasks.json)

Эти таски отвечают за сборку бинарника и его загрузку в чип. Задача ICEman отвечает за gdb-соединение и должна быть запущена в фоне всегда, когда идет отладка чипа или его прошивка. Здесь же можно настроить необходимые зависимости, например, собирать проект каждый раз перед прошивкой, если вы тоже иногда забываете это сделать.

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Build",
            "type": "shell",
            "command": "cmake -Bbuild && cd build && make",
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "options": {
                "cwd": "${workspaceRoot}/app/"
            },
            "problemMatcher": {
                "owner": "cpp",
                "fileLocation": ["relative", "${workspaceFolder}/build"],
                "pattern": {
                  "regexp": "^(.*):(\d+):(\d+):\s+(warning|error):\s+(.*)$",
                  "file": 1,
                  "line": 2,
                  "column": 3,
                  "severity": 4,
                  "message": 5
                }
            }
        },
        {
            "label": "ICEman",
            "type": "shell",
            "isBackground": true,
            "options": {
                "cwd": "${workspaceRoot}/toolchain/ice"
            },
            "command": "./ICEman -Z v5",
        },
        {
            "label": "flash",
            "type": "shell",
            "options": {
                "cwd": "${workspaceRoot}/toolchain/flash/bin"
            },
            "command": "./SPI_burn -i ./../../../app/build/apptest.bin -v",
            "dependsOn":["Build"],
        }
    ]
}

Отладка (launch.json)

Для отладки потребуется один из двух плагинов, Cortex-Debug [8] привычный для тех, кто уже использовал VSCode для отладки ARM-микроконтроллеров или Native Debug [9]. Большой разницы между ними нет, но Cortex-Debug позволяет несколько удобнее работать с Zephyr, FreeRTOS и выводить RTT-сообщения во встроенный терминал VSCode, поэтому я предпочитаю его. Настройки для обоих решений приведены ниже:

{
    "configurations": [
        {
            "type": "gdb",
            "name": "Native Debug",
            "request": "attach",
            "cwd": "${workspaceRoot}",
            "valuesFormatting": "parseText",
            "executable": "${workspaceRoot}/app/build/apptest.elf",
            "preLaunchTask": "ICEman",
            "target": ":1111",
            "remote": true,
            "gdbpath": "${workspaceRoot}/toolchain/nds32le-elf-mculib-v5f/bin/riscv32-elf-gdb",
            "autorun": [
                "reset-and-hold",
				"flushregs",
                "break main"
            ]
        },
        {
            "name": "Cortex-Debug",
            "cwd": "${workspaceRoot}",
            "executable": "./app/build/apptest.elf",
            "request": "launch",
            "type": "cortex-debug",
            "servertype": "external",
            "gdbTarget": "localhost:1111",
            "gdbPath": "${workspaceRoot}/toolchain/nds32le-elf-mculib-v5f/bin/riscv32-elf-gdb",
            "preLaunchTask": "ICEman",
            "runToEntryPoint": "main",
        }
    ]
}

Для использования Cortex-Debug потребуется добавить несколько строчек в настройки проекта settings.json

{
    "cortex-debug.openocdPath": "${workspaceRoot}/toolchain/ice/openocd",
    "cortex-debug.gdbPath": "${workspaceRoot}/toolchain/nds32le-elf-mculib-v5f/nds32le-elf-mculib-v5f/bin/riscv32-elf-gdb",
    "cmake.sourceDirectory": "${workspaceFolder}/app",
    "taskExplorer.enableMake": false,
    "search.exclude": {
        "**/build": true
      }
}

И подсказать IntelliSense, где лежат наши исходники и какие объявления мы хотим сделать при сборке. Для этих целей служит c_cpp_properties.json

{
    "configurations": [
        {
            "name": "Linux",
            "includePath": [
                "${workspaceFolder}/**",
                "${workspaceFolder}/app/**",
                "${workspaceFolder}/driver_sdk/**"                
            ],
            "defines": [
                "MCU_STARTUP_FLASH_B91=1",
                "DEBUG"
            ],
            "browse": {
                "limitSymbolsToIncludedHeaders": true,
                "databaseFilename": ""
            },
            
            "cStandard": "c11",
            "cppStandard": "c++17",
            "intelliSenseMode": "gcc-arm"
        }
    ],
    "version": 4
}

Заключение

В целом этого достаточно для комфортной разработки и отладки. Настройка автосборки для GIthub Actions не сильно отличается от тех шагов, что были проделаны выше, но на всякий случай оставлю рабочий пример [10] для другого не очень распространенного микроконтроллера. Посмотреть на проект целиком можно на гитхабе [11].

Автор: Егор Марков

Источник [12]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/programmirovanie-mikrokontrollerov/372302

Ссылки в тексте:

[1] Nanjing Qinheng Microelectronics: http://www.wch.cn/

[2] B91 Generic Starter Kit: http://wiki.telink-semi.cn/wiki/Hardware/B91_Generic_Starter_Kit_Hardware_Guide/

[3] TLSR9518A: http://wiki.telink-semi.cn/doc/ds/PB_TLSR9_Series_Product_Brief.pdf

[4] вики: http://wiki.telink-semi.cn/wiki/IDE-and-Tools/Compiler_Linux/

[5] инструкции: https://github.com/andestech/nds-gnu-toolchain

[6] треду: https://github.com/zephyrproject-rtos/zephyr/issues/34282

[7] UART_DEMO: http://wiki.telink-semi.cn/telink-document-package/CMakeLists.txt

[8] Cortex-Debug: https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug

[9] Native Debug: https://marketplace.visualstudio.com/items?itemName=webfreak.debug

[10] пример: https://github.com/aectaan/da1469x-cmake/blob/master/.github/workflows/da1469x.yml

[11] гитхабе: https://github.com/aectaan/Telink-TLSR9-CMake

[12] Источник: https://habr.com/ru/post/652471/?utm_source=habrahabr&utm_medium=rss&utm_campaign=652471