Настройка VSCode для программирования stm32 в Linux и не только в Linux

Собственно идея написать эту статью как памятку себе любимому, ну может ещё кому пригодится пришла в голову год назад, после того как убил немало времени на это нехитрое занятие. Недавно оказалось, что проблема актуальна по сей день. Почему-то ни один из найденных вариантов сам по себе не помогает и данная статься является результатом обработки всей найденной информации. При решении вопроса, больше всего бесило — возьмите мой проект и будет вам счастье, а проекта там уже и нет… Такой подход я плохо переношу, поэтому и сам делать так не буду.

Всё ниже описанное является следствием моего личного опыта, и ни на какую истинность не претендует. Все советы рассчитаны не людей только решившихся на переход с AVR на STM32

Вопросы типа почему Linux, VSCode и прочее, думаю, освещения не требуют. Считаю, что все заинтересованные в вопросе, на эти мелочи давно нашли СВОЙ ответ. Однако отмечу, в Винде всё это тоже работает, проверено, и проекты спокойно переживают миграцию между машинами.

Пожалуй начнём!

Этап установки VSCode опущу, этого добра настролько навалом, что даже через чур. Скажу только, что минимально нужно поставить модули C/C++ от Microsoft (считаю, что плагин от крупного автора имеет больше шансов на долгую жизнь), Cortex-Debug от marus25 (альтернатив пока нет) и Makefile Tools от Microsoft (анализирует Makefile и сам настраивает IntelliSense, давно ждал такую штуку, было хоть сам пиши).

Самый простой способ получить заготовку проекта — собрать его в CubeMX. Процесс интуитивно понятный, сотни раз описанный в сети, поэтому отвлекаться на него не буду. Отмечу пару важных моментов.

Нужно не забыть в настройках порта разрешить отладочную шину

image-loader.svg

Очень песпонтовая ошибка. По умолчанию все выводы переводятся на вход и после первой прошивки у Вас отваливается программатор. Так как у всех начинающих программатор — китайский минимальный клон, то никакого сброса для STM32 там нет и что дальше делать не всем понятно.

Решение довольно простое — нужно исправить досадную ошибку и запустить процесс программирования или стирания удерживая кнопку сброса. Когда программа будет выполнять повторы подключения, отпустить сброс. Получиться может не с первого раза, но обязательно получится. Ещё на днях подсказали способ — переключить джамперы загрузки на положение отличное от Flash, что бы не дать запуститься нашей косячной программе и переписать камень из такого положения (сам не пробовал).

Как и у меня в своё время, у большинства начинающих в распоряжении так называемая Синяя Пилюля, поэтому давайте включим выход к которому подключен светодиод (PC13).

image-loader.svg

Так как светодиод через резистор подключен к питанию, то вывод настроим в режим Open-Drain, хотя от Push-Pull хуже не будет.

Настройку тактировки мне приводить лень, пхать сюда огромную бессмысленную картинку не виду смысла, а от уменьшеной смысла ещё меньше. К тому же CubeMX предлагает сам настроить все коэффициенты, да и для ручного режима всё более чем интуитивно понятно.

Поэтому завершаем работу с CubeMX задав имя проекта и обязательно переключив *Toolchain/IDE* на *Makefile*

image-loader.svg

После генерации проекта, в целевом каталоге получаем вот такой набор файлов.

image-loader.svg

Всё бы хорошо, но для отладки нам необходим SVD-файл, в нём информация для отладчика, необходимая для человеческого отображения регистров периферии, ядра и т.п.

Где взять этот файл? С одной стороны всё довольно быстро ищется, но не всегда это будут свежие версии. Лучше всего взять с сайта ST. Идём на st.com, дальше Products Microcontrollers & Microprocessors и ищем там свой проц. В нашем случае STM32 32-bit Arm Cortex MCUsSTM32 Mainstream MCUsSTM32F1 SeriesSTM32F103

image-loader.svg

Тут можно найти всю возможную документацию по процессору, но сейчас нас интересует вкладка CAD Resources. На ней находим HW Model, CAD Libraries & SVDSystem View Description. Скачиваем найденый архив. Для ленивых ссылка на страницу. В архиве найдёте несколько svd-файлов. Нас сейчас интересует — STM32F103.svd. Не долго думая кидаем его в папку с проектом.

Пришло время запустить VSCode!!! Лично я предпочитаю в нужном каталоге дать команду code ., а там каждому своё… Программа спросит, доверяете ли вы авторам этого каталога, придётся сказать, что доверяете. Makefile Tool проанализирует Makefile, о чём выдаст много текста в панели, и настроит IntelliSense. Ещё не так давно приходилось его настраивать вручную, не сложно, но не интересно.

Не забываем сохранить Рабочую Область!!!

Теперь немного дополняем Makefile — добавляем ещё одну цель prog

prog: $(BUILD_DIR)/$(TARGET).elf
    openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg -c "program build/$(TARGET).elf verify exit reset"

Небольшое пояснение. Скрипты interface/stlink-v2.cfg и target/stm32f1x.cfg позволяют openocd узнать через какой адаптер и с кем он должен работать. Сами скрипты распологаются в каталоге scripts с установленным openocd (для Винды) или в каталоге /usr/share/openocd в Linux. Приведённый пример работает для китайского клона ST-Link v2 и Синей Пилюли. Если у Вас другой программатор или камень, то необходимые файлы найдёте в тех же каталогах.

Собственно зачем нужна эта байда? Иногда нужно записать программу в процессор не запуская отладку — просто записать и посмотреть, что произойдёт. Вот за это и отвечает -c «program build/$(TARGET).elf verify exit reset

Следующим этапом я настраиваю git, но это по вкусу. Ну как настраиваю, создаю файл *.gitignore* ну и инициализацию репозиторий. Пример .gitignore

    DSP/
    Templates/
    Examples/
    NN/
    /build/
    *.log
    *.d
    .mxproject
    *.ioc

по списку поясню только каталог build — в него производиться сборка проекта, поэтому что бы не отвлекаться на него и случайно не нагадить в коммит его и игнорим. Логи любит создвать Makefile Tools, они мне тоже ни к чему.

Если очень чешутся руки, то на данном этапе уже можно в терминале VSCode дать команду `make prog`, соберётся Ваш пустой проект и запишется в процессор. Процес сборки будет отобразаться здесь же в терминале, а об успешной записи Вам сообщит openocd примерно вот так

...
Info : auto-selecting first available session transport "hla_swd". To override use 'transport select '.
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
Info : clock speed 1000 kHz
Info : STLINK V2J37S7 (API v2) VID:PID 0483:3748
Info : Target voltage: 3.169781
Info : stm32f1x.cpu: hardware has 6 breakpoints, 4 watchpoints
Info : starting gdb server for stm32f1x.cpu on 3333
Info : Listening on port 3333 for gdb connections
target halted due to debug-request, current mode: Thread 
xPSR: 0x01000000 pc: 0x08000c74 msp: 0x20005000
** Programming Started **
Info : device id = 0x20036410
Info : flash size = 64kbytes
** Programming Finished **
** Verify Started **
** Verified OK **
** Resetting Target **
shutdown command invoked

Желающие почесали руки, продолжаем. В каталоге .vscode проекта нужно создать файл tasks.json примерно такого содержания

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Build",
            "type": "shell",
            "group": "build",
            "command": "make",
            "problemMatcher": []
        },
        {
            "label": "Clean",
            "type": "shell",
            "group": "build",
            "command": "make clean",
            "problemMatcher": []
        },
        {
            "label": "Write firmware",
            "type": "shell",
            "command": "make prog",
            "problemMatcher": []
        }
    ]
}

Собственно здесь объявляются три задачи: сборка проекта, очистка рабочего каталога и прошивка контроллера. Можно конечно и здесь расписать все команды с параметрами, раньше так и делал, но потом стало лень дублировать команды, следить что бы они были одинаковыми в Makefile и тут… Ну в общем остановился на таком варианте. Работает же…

Теперь создаём launch.json c вот таким содержимым

{
	"version": "0.2.0",
	"configurations": [
		{
			"name": "openocd",
			"type": "cortex-debug",
			"request": "launch",
			"cwd": "${workspaceRoot}",
			"servertype": "openocd",
			"executable": "./build/Habr.elf",
			"svdFile": "STM32F103.svd",
			"configFiles": [
				"interface/stlink-v2.cfg",
				"target/stm32f1x.cfg"
			],
			"preLaunchTask": "Build"
		}
	]
}

Страшная штука. Собственно «name» может иметь любое значение, оно влияет только на отображение. Поле «executable» должно иметь значение файла в который собирается ваша программа, с указанием пути от каталога проекта. У Вас оно своё, поэтому вместо Habr должно быть то, чему у вас равно TARGET = в Makefile. В «svdFile» прописываем svd файл нашего процессора. Если вы его положили не в корень проекта, то нужно указать путь от каталога проекта. В «configFiles» указываем те самые скрипты, которые мы добавляли в Makefile для прошивки контроллера. И последний момент «preLaunchTask»: «Build» — запуск задачи сборки программы из tasks.json, что бы было чего прошивать и отлаживать.

А теперь момент без которого всё это добро не работает — необходимо сообщить программе, где лежат бинарники openocd и gdb, причём не пути к каталогам с ними, а именно сами программы. Сделать это нужно в глобальном файле settings.json, пока так стабильно работает. Так как сам этот файл слегка закопан, к тому же, в Linux и Windows находится в разных местах, то я для себя нашёл простой способ его открыть. Идём ФайлНастройкиПараметры, откроется вкладка с настройками. Далее Текстовый редакторШрифт и ищем надпись Изменить в settings.json. В открывшийся файл нужно добавить следующие строчки

"cortex-debug.armToolchainPath": "usr/bin",
"cortex-debug.openocdPath": "/usr/bin/openocd",
"cortex-debug.gdbPath": "/usr/bin/gdb-multiarch",

«cortex-debug.armToolchainPath» — просто путь к каталогу в котором ваш *arm-none-eabi-gcc*, вот тут просто каталог

«cortex-debug.openocdPath» — полный путь к бинарнику openocd, для винды будет заканчиваться на .exe

«cortex-debug.gdbPath» — полный путь к бинарнику gdb котрым Вы будете пользоваться

Ну и финишная прямая.

В файле *main.c* чуть-чуть меняем функцию *main ()* на вот такое

int main(void)
{
  uint32_t tempTick;
 
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();

  __ASM("NOP");
  while (1)
  {
    tempTick = HAL_GetTick();
    while (HAL_GetTick() - tempTick < 500);
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, 1);
    tempTick = HAL_GetTick();
    while (HAL_GetTick() - tempTick < 500);
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, 0);
  }
}

Честно говоря страшнее кода придумать с ходу не смог. Хочу просто показать, что ЭТО ВСЁ может жить.

Теперь на __ASM («NOP»); ставим точку останова, переходим «Запуск и Отладка» и запускаем всё это добро, нажав на зелёный треугольничек.

image-loader.svg

В Терминале побежали надписи процесса компиляции и через пару секунд всё остановиться на вот такой картинке

image-loader.svg

**ПОЗДРАВЛЯЮ, ВЫ В ОТЛАДКЕ!!!**

Можете просто нажать F5 или значёк проигрывания и наслаждаться мигающим светодиодом!

На этом у меня всё! Можно было бы ещё рассказать про настройку IntelliSense, но во-первых такого добра и так навалом, а во-вторых проблема уже частично решается плагином Makefile Tools, хоть пока и неидеально, но для начала хватает.

© Habrahabr.ru