На хабре уже есть немало информации об отладке МК в VSCode на Linux (тыц, тыц), также было написано как настроить тулчейн для работы под Windows в QT Creator, Eclipse, etc.
Пришло и моё время написать похожую статью, но для VS Code и под Widnows.
Инициализация проекта будет проводиться с помощью STM32CubeMX. Сборкой будет управлять CMake с тулчейном stm32-cmake. В качестве компилятора используется ARM GNU Toolchain. Тестовым стендом является NUCLEO-F446ZE.
Источниками вдохновения послужили:
-
Репозиторий stm32-template
-
Видео EbeddedGeek
-
Видео Matej Blagšič
Предисловие окончено, приступаем к настройке.
Установка необходимых утилит
Для удобства установки будем пользоваться пакетным менеджером Scoop.
Для его установки достаточно прописать в powershell следующие команды:
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser; irm get.scoop.sh | iex
Добавим необходимые репозитории
scoop bucket add main scoop bucket add extras
И, наконец, сами программы:
scoop install meson scoop install ninja scoop install cmake scoop install llvm scoop install gcc-arm-none-eabi scoop install stlink scoop install openocd scoop install git
meson, ninja, cmake, llvm и gcc-arm-none-eabi используются для конфигурации и сборки проекта, stlink и openocd являются gdb-серверами, git необходим для подключения различных тулчейнов.
P.S.
Если у вас уже есть что-то из этого и вы можете вызвать его через консоль (т.е. программа добавлена в path) то советую либо убрать её из скрипта либо удалить у себя, и установить через scoop.
Настройка VS Code
Для работы потребуются установить в VS Code следующие расширения:
-
Также рекомендую Doxygen Documentation
Инициализация проекта
Открываем CubeMX и создаем проект для нашей платы. Всю периферию оставляем настроенной по умолчанию.
В параметрах проекта (Project Manajer) выбираем Make в качестве тулчейна
В параметрах генератора кода указываем подключение бибилотек только в виде ссылок
Настройка системы сборки
Открываем папку проекта в VS Code и вызываем терминал командой Ctr+~
Скачиваем stm32-cmake
git clone --recurse-submodules -j8 https://github.com/ObKo/stm32-cmake.git
Также потребуются файлы .clang-format
, .clang-tidy
, fetch_svd.cmake
, и CMakeLists.txt
из репозитория stm32-template. Для удоства клонируем его в соседнюю директорию.
git clone https://github.com/Dooez/stm32-template.git ../stm32-template
.clang-format
, .clang-tidy
необходимы LLVM, а fetch_svd.cmake
используется для поиска файла описания регистров конкретного микроконтроллера.
Отредактируем CMakeLists.txt
под наш проект.
Изменим переменную MCU на STM32F446ZE
set(MCU STM32F446ZE)
По умолчанию «кубик» инициализирует на плате NUCLEO-F446ZE USART3, USB_OTG_FS и несколько GPIO. Добавим библиотеки в проект, для этого необходимо для сборки прописать команду target_link_libraries
. Также добавим библиотеку CMSIS и, для уменьшения размеров прошивки, Newlib Nano и NoSys
target_link_libraries(${PROJECT_NAME} HAL::STM32::${MCU_FAMILY}::RCC HAL::STM32::${MCU_FAMILY}::GPIO HAL::STM32::${MCU_FAMILY}::UART HAL::STM32::${MCU_FAMILY}::CORTEX HAL::STM32::${MCU_FAMILY}::LL_USB HAL::STM32::${MCU_FAMILY}::PCD HAL::STM32::${MCU_FAMILY}::PCDEx CMSIS::STM32::${MCU_MODEL} STM32::Nano STM32::NoSys )
Чтобы CMake мог увидеть файлы, сгенерированные кубиком, необходимо добавить их в Include Path
и явно указать исполняемые c/cpp
файлы.
add_executable(${PROJECT_NAME} Core/Src/main.c Core/Src/stm32f4xx_it.c ) target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/Core/Inc ${CMAKE_CURRENT_SOURCE_DIR}/Core/Src )
main.c содержит, собственно, функцию main()
, а в stm32f4xx_it.c
находится функция, которая считает количество срабатываний SysTick
, без которой не будут работать такие функции как HAL_Delay()
Также для уменьшения размера исполняемого файла, добоавим следующие директивы компилятора:
target_compile_options(${PROJECT_NAME} PUBLIC -Os -fno-exceptions -fno-rtti)
Настройка проекта под VS Code
Нажимаем сочетание клавиш Ctrl+Shift+P
и в появившейся строке находим Preferences: Open Workspace Settings (JSON)
В создашемся файле .vscode/settings.json
указаны параметры для расширений и корректного отображения кода. Пишем:
{ "cmake.generator": "Ninja", "cmake.configureEnvironment": { "CMAKE_EXPORT_COMPILE_COMMANDS": "on" }, "C_Cpp.default.intelliSenseMode": "gcc-arm", "cortex-debug.gdbPath": "arm-none-eabi-gdb", "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools" }
Далее по тому же сочетанию находим Tasks: Configure Task и выбираем cmake build
В создашийся файл .vscode/tasks.json
добавляем задания для прошивки и очистки памяти микроконотроллера с помощью st-flash. Итоговый файл tasks.json
выглядит следующим образом:
{ "version": "2.0.0", "tasks": [ { "type": "cmake", "label": "CMake: build", "command": "build", "targets": [ "ALL_BUILD" ], "problemMatcher": [], "group": "build" }, { "type": "shell", "label": "flash", "command": "st-flash", "args": [ "--reset", "write", "${input:workspaceFolderForwardSlash}/build/${workspaceFolderBasename}.bin", "0x8000000" ], "options": { "cwd": "${workspaceFolder}/build" }, "dependsOn": "CMake: build", "problemMatcher": [], "group": { "kind": "build", "isDefault": true }, "detail": "Builds project and flashes firmware." }, { "type": "shell", "label": "erase", "command": "st-flash", "args": [ "--connect-under-reset", "erase" ], "detail": "mass erase of chip" } ], "inputs": [ { "id": "workspaceFolderForwardSlash", "type": "command", "command": "extension.commandvariable.transform", "args": { "text": "${workspaceFolder}", "find": "\\\\", "replace": "/", "flags": "g" } } ] }
Также при желании можно добавить команду для прошивки с помощью OpenOCD
Для STM32F4 она выглядит следующим образом
{ "type": "shell", "label": "flash-openocd", "command": "openocd -f interface/stlink.cfg -f target/stm32f4x.cfg -c 'program ${input:workspaceFolderForwardSlash}/build/${workspaceFolderBasename}.bin verify reset exit' ", "dependsOn": "CMake: build", "problemMatcher": [], "group": { "kind": "build", "isDefault": true }, "detail": "Builds project, connects to the openOCD server and flashes new firmware." }
Далее необходимо сконфигурировать расширение CMake для VS Code
Нажимаем сочетание клавиш Ctrl+Shift+P
и в появившейся строке находим CMake: Configure
и выбираем конфигурацию под arm-none-eabi
После конфигурации автоматически сгенерируется файл .vscode/launch.json
, рассмотрим его поподробнее:
{ "configurations" : [ { "cwd" : "${workspaceRoot}", "device" : "STM32F446ZE", "executable" : "${workspaceRoot}/build/${workspaceFolderBasename}.elf", "name" : "Cortex Debug (generated)", "preLaunchTask" : "CMake: build", "preRestartCommands" : [ "load", "enable breakpoint", "monitor reset" ], "request" : "launch", "runToEntryPoint" : "main", "servertype" : "stutil", "showDevDebugOutput" : "raw", "svdFile" : "${workspaceRoot}/build/_deps/st-svd-archive-src/STM32F4_svd_V1.8/STM32F446.svd", "type" : "cortex-debug" } ], "version" : "0.2.0" }
svdFile
– путь до файла, который необходим, чтобы просматривать регистры периферии МК
Картинка
"preLaunchTask": CMake: build
– компилирует проект перед прошивкой МК.
preRestartCommands
– отправляет команды через GDB при нажатии на кнопку перезапуска отладки
Скрипт fetch_svd.cmake
по умолчанию использует в качетсве GDB-сервера stutils. Примеры конфигурации под OpenOCD и JLink можно посмотреть на вики cortex-debug в приложенных ссылках.
Переходим к коду (наконец-то)
Не мудрствуя лукаво, пойдём мигать светодиодом. (и ещё немного поиграемся с выделением памяти). Изменим main()
следующим образом
#include "stdlib.h" uint8_t* data; int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART3_UART_Init(); /* USER CODE BEGIN 2 */ data = new uint8_t[16]; uint8_t const_data[16]; for(int i = 0; i < 16; i++){ data[i] = i+1; const_data[i] = i+1; } /* USER CODE END 2 */ /* Infinite loop */ while (1) { HAL_GPIO_TogglePin(LD3_GPIO_Port, LD3_Pin); HAL_Delay(50); } }
Компиляция проекта осуществляется нажатием клавиши F7
либо сочетанием Ctrl+Shift+B
. Так как ранее мы в launch.json указали сборку перед прошивкой, то нам будет достаточно нажать F5
и перейти сразу к отладке. Рассмотрим интерфейс:
Первая кнопка осуществляет программный сброс (software reset) устройства
Вторая запускает код (горячая клавиша F5
)
Третья, четвёртая и пятая – «шаг» вперёд к следующей функции, «шаг» вперёд к следующей инструкции (т.е. с погружением) и выполнение код до выхода из функции.
Шестая клавиша осуществляет пересборку проекта и перезапуск прошивки.
А седьмая останавливает отладку.
Окно слева содержит следующие разделы:
-
Cortex Registers – регистры процессора
-
Cortex Peripherals – регистры периферии (например, там можно смотреть и изменять состоянием регистров GPIO и мигать светодиодом с помощью мышки, хехе)
-
Breakpoints – список выставленных прерываний. Отмечу, что у разных микроконтроллеров и отладчиков допустимо различное число брейкпоинтов (Например, у ST-Link V2.1 их всего 6)
-
В CallStack можно посмотреть очередь вызова (вплоть до main, что логично)
-
Раздел Variables позволяет просматривать как локально объявленные переменные, так и глобальные, например
uwTick
, показывающую количество милисекунд от момента запуска МК -
В Memory View можно посмотреть в любой доступный раздел памяти МК
Рассмотрим возможности Watch Window (и заодно сравним его с Keil MDK)
Массив const_data
был объявлен статически, и его можно посмотреть просто по названию, тут всё как везде
А теперь попробуем посмотреть содержимое динамически выделенного массива:
Здесь, так же как и везде, дебаггер отобразит лишь первый элемент (в кавычках можно увидеть содержимое до первого \0
). Однако, в отличие от, например, Keil MDK, мы можем явно указать, как именно следует воспринимать данный указатель:
Такая возможность часто бывает необходима не только для динамически выделенных массивов, но и, например, при передаче в функцию указателя на какой-либо буфер.
Также мы можем переопределить этот указатель написав, например, такой запрос:*(uint16_t*)data@8
Тогда в Watch Window будет показано отображение массива типа short
, а не uchar
ссылка на оригинал статьи https://habr.com/ru/post/713432/
Добавить комментарий