Метод работы с официальным плагином, описанный в предыдущей статье, на практике оказался не самым удобным. Поэтому сегодня мы разберем, как вручную настроить VS Code
для работы с контроллерами STM32
. Также рассмотрим основные принципы настройки VS Code
, которые могут быть полезны для работы в других аналогичных проектах.
Для начала я бы предложил разобраться с тем, почему я считаю, что плагин от производителя не подходит для работы. Я вижу следующие основные проблемы:
- Зависимость от IntelliSense, а значит невозможность использования VSCodium или Code - OSS (конечно, если соблюдать Terms of Use).
- Для работы используется CMake Tools, который создает бесполезное окно и, кроме того, автоматически запускает
cmake
при открытии любого проекта. Это расширение бесполезно и только мешает работе. - Плагин сам создает лишнее бесполезное окно, которое захламляет
VS Code
ненужными функциями. - Для работы обязательно использовать инструменты STM32CubeCLT, которые тоже зря засоряют систему, особенно если уже используется компилятор и утилиты из репозиториев. А главное, они лишают нас выбора: всегда нужно использовать именно ST-LINK server, а не OpenOCD или PyOCD (несмотря на поддержку в Cortex Debug).
В совокупности эти факторы приводят нас к решению о полном отказе от STM32 VS Code Extension.
Далее я думаю следует задаться вопросом: а что бы мы хотели от редактора кода в 21 веке? Я бы выделил три основных момента:
- Сборка
- Отладка
- Статический анализ
Далее рассмотрим, как VS Code
подразумевает решать каждую из этих задач. Однако для начала нужно создать проект. Для этого можно использовать инструкцию из прошлой статьи (Создание проекта -> Cube MX) или можно использовать любой другой конфиг и контроллер. Главное, чтобы проект был сгенерирован именно для CMake
.
Создание проекта
Далее создаем папку App
с тестовым кодом, ровно так, как описано в разделе Организация проекта на С
. Для проверки того, что всё работает корректно, можно собрать код с помощью консоли. Сделать это достаточно просто, находясь в папке с проектом:
mkdir build && cd build
cmake ..
cmake --build .
Для того чтобы это сработало, в системе должен быть установлен тулчейн arm-none-eabi-gcc
. Его можно установить через пакетный менеджер:
sudo pacman -S arm-none-eabi-gcc arm-none-eabi-newlib # Arch linux
sudo apt install arm-none-eabi-gcc # Debian based
Или можно скачать бинарные файлы непосредственно с сайта ARM.
Сборка
VS Code
предлагает механизм тасков для решения задач сборки или запуска чего-либо. По сути, таск — это просто обёртка над консольной командой, которую можно запустить из консоли или другими способами.
Другой способ запуска, в нашем случае, — это кнопки на статус-баре. Для их создания необходимо установить плагин Tasks.
Настройка статусов и команд осуществляется в файле .vscode/tasks.json
:
{
"version": "2.0.0",
"tasks": [
{
"label": "clean",
"group": "build",
"type": "shell",
"command": "rm -rf build",
"options": {
"statusbar": {
"color": "#ff8b8b",
"label": "$(clear-all) Clean",
"detail": "Clean ALL"
}
}
},
{
"label": "Configure_Debug",
"group": "build",
"type": "shell",
"command": "cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug",
"options": {
"cwd": "${workspaceFolder}",
"statusbar": {
"color": "#8bdeff",
"label": "$(gear) Debug",
"detail": "Cmake configure Debug"
}
}
},
{
"label": "Configure_RelWithDebInfo",
"group": "build",
"type": "shell",
"command": "cmake -S . -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo",
"options": {
"cwd": "${workspaceFolder}",
"statusbar": {
"color": "#8bdeff",
"label": "$(gear) RelWithDebInfo",
"detail": "Cmake configure RelWithDebInfo"
}
}
},
{
"label": "Configure_Release",
"group": "build",
"type": "shell",
"command": "cmake -S . -B build -DCMAKE_BUILD_TYPE=Release",
"options": {
"cwd": "${workspaceFolder}",
"statusbar": {
"color": "#8bdeff",
"label": "$(gear) Release",
"detail": "Cmake configure Release"
}
}
},
{
"label": "Configure_MinSizeRel",
"group": "build",
"type": "shell",
"command": "cmake -S . -B build -DCMAKE_BUILD_TYPE=MinSizeRel",
"options": {
"cwd": "${workspaceFolder}",
"statusbar": {
"color": "#8bdeff",
"label": "$(gear) MinSizeRel",
"detail": "Cmake configure MinSizeRel"
}
}
},
{
"label": "build",
"group": "build",
"type": "shell",
"command": "cmake --build build",
"options": {
"cwd": "${workspaceFolder}",
"statusbar": {
"color": "#8bff97",
"label": "$(code) Build",
"detail": "Build"
}
}
}
]
}
Данный конфиг создает кнопки (и разукрашивает) для каждого типа конфигурации, описанной в CMakePresets.json
, а также добавляет команды clean
и build
. Полагаю, что конфигурация и так достаточно понятна, и дополнительные объяснения излишни.
На самом деле, механизм тасков в VS Code
достаточно сложен и интересен. Например, можно создавать зависимые таски. Если для запуска вашего приложения требуется сервер, вы можете настроить его запуск перед приложением, сделать его зависимым и задать регулярное выражение для анализа логов. Это позволит останавливать процесс в случае возникновения ошибок. Однако обо всём этом как-нибудь в другой раз — для работы с STM32 такой функционал не является необходимым.
Отладка
VS Code
с помощью плагинов позволяет подключиться к GDB-серверу и, с помощью парсинга его вывода, реализовать управление отладкой прямо в редакторе. Для работы с C/C++ на микроконтроллерах подходят три решения:
- Cortex-Debug - Это самый популярный плагин для работы с архитектурой ARM. Мы остановимся именно на нём. Подробнее о работе с этим плагином можно почитать в прошлой статье, а здесь обсудим только его настройку.
- Официальный плагин от Microsoft — C/C++ for Visual Studio Code - Этот плагин можно использовать с микроконтроллерами, приложив немного больше усилий при настройке. Однако, мы откажемся от него по уже описанным выше причинам.
- Native Debug - Интересный плагин, который умеет работать как с
GDB
, так и сLLDB
. Его тоже можно настроить для работы с Cortex-контроллерами, но это несколько сложнее, чем в случае сCortex-Debug
, из-за большей универсальности. Мы остановимся на первом варианте, однако, вероятно, этот плагин понадобится в следующих статьях, если будет рассматриваться программирование RISC-V.
Для работы с Cortex-Debug
на компьютере должны быть установлены GDB
(подразумевается использование gdb-multiarch
, а не arm-none-eabi-gdb
), а так-же OpenOCD
:
sudo pacman -S openocd gdb # ARCH Linux
sudo apt install openocd gdb # Debian based
Как я писал выше, возможно использование PyOCD или J-Link server. Однако эти инструменты не будут рассмотрены в данной статье, так как OpenOCD
решает практически все задачи в контексте работы с STM32
.
Перед настройкой непосредственно VS Code
, лучше сначала убедиться в работоспособности OpenOCD
и GDB
в консоли. Для этого:
openocd -f interface/stlink.cfg -f target/stm32g4x.cfg
# Другой терминал
telnet localhost 4444
> reset halt
> flash write_image erase /home/zen/projects/stm32/vscode-cubemx-pro-guide/build/vscode-cubemx-pro-guide.hex
> reset
Для сборки HEX
, а не только ELF
нужно добавить строки в конец CMakeLists.txt
(описано в прошлой статье):
...
# Add custom commands to generate .bin and .hex files
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_OBJCOPY} -O binary $<TARGET_FILE:${CMAKE_PROJECT_NAME}> ${CMAKE_PROJECT_NAME}.bin
COMMAND ${CMAKE_OBJCOPY} -O ihex $<TARGET_FILE:${CMAKE_PROJECT_NAME}> ${CMAKE_PROJECT_NAME}.hex
COMMENT "Building ${CMAKE_PROJECT_NAME}.bin and ${CMAKE_PROJECT_NAME}.hex"
)
Также, в Arch Linux для работы telnet
необходимо установить пакет inetutils.
После этого плата должна быть прошита, и диод на ней должен замигать.
Далее можно проверить работоспособность GDB
сервера. Для этого нужно его запустить:
gdb
> target remote localhost:3333
> monitor reset halt
> monitor flash write_image erase /home/zen/projects/stm32/vscode-cubemx-pro-guide/build/vscode-cubemx-pro-guide.hex
> c
Для работы с GDB
необходимо, чтобы OpenOCD
был запущен. Вопрос отладки с использованием консольного GDB
(вероятно) будет рассмотрен в дальнейших статьях.
В VS Code
расширение Cortex-Debug
выполнит все эти действия автоматически без нашего участия. Для этого достаточно настроить файл .vscode/launch.json
:
{
"version": "0.2.0",
"configurations": [
{
"name": "STM32",
"cwd": "${workspaceRoot}",
"executable": "build/${workspaceFolderBasename}.elf",
"request": "launch",
"type": "cortex-debug",
"servertype": "openocd",
"preLaunchTask": "build",
"gdbPath": "gdb",
// Add you svd file
// "svdFile": "${workspaceRoot}/Docs/STM32F3x4.svd",
// Set you programmer and trget controller
"configFiles": [
"interface/stlink.cfg",
"target/stm32g4x.cfg"
],
// "runToEntryPoint": "main",
"showDevDebugOutput": "none",
"swoConfig": {
"enabled": true,
"swoFrequency": 2000000,
"cpuFrequency": 170000000,
"decoders": [
{
"port": 0,
"type": "console"
}
]
}
}
]
}
Важные моменты по данному конфигу:
servertype
— можно использовать не толькоopenocd
, но и другие значения, напримерpyocd
илиjlink
.preLaunchTask
— это тот самый таск, который мы настраивали в прошлом разделе.gdbPath
— путь доGDB
. Если используется системныйgdb-multiarch
, достаточно указать простоgdb
.svdFile
— путь до файла с описанием адресов регистров, что может быть полезно при отладке, так как делает их доступными для просмотра в отладчике. Такой файл можно взять на сайте ST. Например, для STM32G431 он доступен здесь (нужен файл STM32G4 System View Description).configFiles
— файлы конфигурации, определяющие отладчик и серию контроллера. Эти параметры передаются вOpenOCD
.runToEntryPoint
— останавливает выполнение в начале функцииmain
.swoConfig
— активирует консоль SWO. Для работы обязательно нужно указать правильную частоту процессора в параметреcpuFrequency
. Чтобы использоватьprintf()
с SWO, необходимо переопределить функцию_write()
:
// For use SWO
int _write(int file, char *ptr, int len) {
(void)file; // hack for fix warning - unused int file.
for (int i = 0; i < len; i++)
ITM_SendChar((*ptr++));
return len;
}
Подробнее про конфигурацию SWO можно посмотреть тут.
Статический анализ
В этом разделе я рассмотрю инструменты, которые помогают в написании кода, такие как сниппеты, линтеры, автодополнение, автоформатирование, подсветка и т.д. При использовании расширения от ST предполагается, что для этих целей используется C/C++ for Visual Studio Code. Однако, как уже не раз говорилось в этой статье, мы откажемся от него.
Этот функционал будет построен вокруг языкового сервера clangd и плагина clangd. Для работы этой системы clangd
должен быть установлен в системе:
sudo pacman -S clangd # ARCH Linux
sudo apt install clangd # Debian based
Данный языковой сервер использует список исходных файлов из compile_commands.json
для построения синтаксического дерева. CubeMX по умолчанию добавляет строку в CMakeLists.txt
, которая включает генерацию файла compile_commands.json
.
Однако, так как clangd
изначально заточен под работу с инструментарием clang
, для работы с gcc
нужно добавить некоторые дополнительные настройки. Дальнейшая настройка производится в файле .vscode/settings.json
:
{
"clangd.arguments": [
"--compile-commands-dir=build",
"--enable-config",
"--clang-tidy",
"-j=12",
"--completion-style=detailed",
"--suggest-missing-includes",
"--header-insertion-decorators",
"--background-index",
]
}
Однако, из-за особенностей парсинга параметров командной строки, необходимо использовать параметр --enable-config
и создать отдельный файл .clangd
в корне проекта с дополнительными опциями сборки:
CompileFlags:
Add:
- "-I/usr/arm-none-eabi/include"
- "-D__INT32_TYPE__=long"
- "-D__UINT32_TYPE__=unsigned long"
В файле .clangd
нужно указать инклуды от newlib
, а также переопределить тип long
. Это необходимо, так как его размерность отличается на 32-битных и 64-битных системах.
Из остальных параметров нужно поменять значение -j=12
на количество ядер вашего процессора. Остальное можно оставить без изменений. Описание доступных параметров можно получить с помощью команды:
clangd --help
После создания конфигурационных файлов перезапустите VS Code
. Во вкладке PROBLEMS
появятся все проблемы, выявленные статическим анализатором.
Это не единственный статический анализатор, который можно использовать. На самом деле, их достаточно много, но большинство из них являются платными. Для VS Code
существует плагин, который позволяет объединить несколько анализаторов, — C/C++ Advanced Lint.
Из поддерживаемых этим плагином инструментов нас интересует только CppCheck
благодаря его широким возможностям в бесплатной и открытой версии. Остальные анализаторы мы использовать не будем (но при желании вы можете попробовать их самостоятельно).
Настройка данного плагина также выполняется через файл .vscode/settings.json
:
...
// Advanced Lint
"c-cpp-flylint.clang.enable": false,
"c-cpp-flylint.flexelint.enable": false,
"c-cpp-flylint.cppcheck.enable": true,
"c-cpp-flylint.lizard.enable": false,
"c-cpp-flylint.flawfinder.enable": false,
"c-cpp-flylint.cppcheck.standard": [
"c11",
"c++20"
],
"c-cpp-flylint.cppcheck.severityLevels": {
"error": "Error",
"warning": "Warning",
"style": "Information",
"performance": "Information",
"portability": "Information",
"information": "Information"
},
"c-cpp-flylint.cppcheck.suppressions": [
"cstyleCast"
],
"c-cpp-flylint.cppcheck.extraArgs": [
"--cppcheck-build-dir=build",
"--platform=arm32-wchar_t2",
// "--addon=misra.py",
"--enable=all",
"--force",
"-j12",
"-D__GNUC__",
"-D__INT32_TYPE__=long",
"-D__UINT32_TYPE__=\"unsigned long\"",
"-I/usr/arm-none-eabi/include",
]
...
Анализатор clangd
отключен в этом конфиге, так как он уже работает в составе предыдущего плагина.
Для работы в системе должен быть установлен cppcheck
:
sudo pacman -S cppcheck # ARCH Linux
sudo apt install cppcheck # Debian based
Cppcheck
— это достаточно сложный и продвинутый статический анализатор с множеством опций. Подробнее о его использовании можно почитать здесь. В его функционале даже есть частичная поддержка MISRA C
в открытой версии. Однако, поскольку HAL не предполагает использование MISRA
, в моем конфиге данная опция не включена.
Дополнительные плагины для удобства работы
Для более удобной и эффективной работы стоит установить следующие плагины:
- Error Lens - Отображает ошибки и предупреждения прямо на строке с кодом, как это реализовано в Qt Creator.
- Better C++ Syntax - Улучшает подсветку синтаксиса для C/C++.
- C/C++ Snippets - Предоставляет полезные сниппеты для C/C++.
- Плагины для работы с CMake:
- CMake — добавляет базовую поддержку синтаксиса.
- cmake-format — добавляет автоформатирование. Для работы последнего в системе должен быть установлен
cmake-format
.
- Плагины для документации:
- Doxygen — добавляет поддержку синтаксиса
Doxygen
. - Doxygen Documentation Generator — автоматически генерирует описание функций на основе их объявлений.
- Doxygen — добавляет поддержку синтаксиса
- Подсветка специфических форматов:
- GNU Linker Map files — подсвечивает синтаксис
map
файлов. - LinkerScript — добавляет подсветку синтаксиса для
linker
скриптов.
- GNU Linker Map files — подсвечивает синтаксис
Регулярно проверяйте, нет ли новых интересных плагинов для работы с типами файлов, которые вы начали использовать. Возможно, кто-то уже решил вашу проблему с помощью плагина, что упростит вашу работу.
В итоге получаем:
Используемые плагины
- Tasks - кнопки тасков на статус баре.
- Cortex-Debug - плагин для отладки.
- Сlangd - плагин для работы с языковым сервером
clangd
. - C/C++ Advanced Lint - поддержка набора синтаксических анализаторов.
- Error Lens - отображение ошибок сразу в тексте программы.
- Better C++ Syntax - чуть лучшая подсветка синтаксиса.
- C/C++ Snippets - набор сниппетов.
- CMake - базовая поддержка
Cmake
. - Cmake-format - авто форматирование
cmake
скриптов. - Doxygen - поддержка синтаксиса
Doxygen
. - Doxygen Documentation Generator - генерация описания функции по его обьявлению.
- GNU Linker Map files - подсветка linker file.
- LinkerScript - подсветка linker script.
Так-же их можно автоматически добавить в систему создав файл extensions.json
в папке .vscode
:
{
"recommendations": [
"actboy168.tasks",
"marus25.cortex-debug",
"llvm-vs-code-extensions.vscode-clangd",
"jbenden.c-cpp-flylint",
"usernamehw.errorlens",
"jeff-hykin.better-cpp-syntax",
"hars.CppSnippets",
"twxs.cmake",
"cheshirekow.cmake-format",
"bbenoist.Doxygen",
"cschlosser.doxdocgen",
"trond-snekvik.gnu-mapfiles",
"ZixuanWang.linkerscript"
]
}
Ссылки
- Проект на гит с примером из статьи.
- Документация по vscode.