Visual Studio 2017 + STM32CubeMX

После написания статьи о применении Visual Studio 2017 и WiFi SoC захотелось проверить, насколько сложно или просто будет откомпилировать и отлаживать проект для более рядовых микроконтроллеров, таких как STM32. Исходный проект будет сгенерирован в STM32CubeMX и с минимальными дополнениями будет открыт в Visual Studio, более того, проект также можно будет обновлять из STM32CubeMX, как для других IDE.

B63-0

Все наглядно, по шагам под катом. :)

Проект для примера

Итак. Будем высокотехнологичную создавать мигалку светодиодом! Не просто так в main цикле, а с таймером — архисложный вариант проекта. Я взял первую попавшуюся под руку плату на STM32F042F6P6 в TSSOP-20 корпусе, выбор МК абсолютно не важен для примера. Создаём проект и включаем SWD, вывод для светодиода на выход и таймер:

B63-1

Тактирование будем брать со встроенного генератора 48 МГц (для USB, фишка этой серии), везде тактируем все от этой частоты:

B63-2

Не забываем настроить таймер для прерывания раз в 500 мс:

B63-3

И, собственно, создать обработчик прерывания:

B63-4

Вот и всё. Генерируем проект. Здесь только одну вещь поменял — тип проекта должен быть Makefile:

B63-5

Примечание: при открытии проекта STM32CubeMX и перегенерации его у вас, скорее всего, в конце появится сообщение об ошибке: 

B63-6

Это проблема STM32CubeMX — он не может обновить сам файл Makefile, и необходимо перед генерацией его удалить, но будьте осторожны, если вносили изменения в Makefile — не забывайте делать бекап. ;)

Подготовка проекта

Подготовка в целом аналогична описанию из первой статьи — скопировать или создать файлы CppProperties.json, .vs\Launch.vs.json, .vs\Tasks.vs.json и скрипты для J-Link (в случае использования другого отладчика — эту часть изменяете под себя).

По порядку, первый файл CppProperties.json — описание проекта и общие настройки:

{
 "configurations": [
 {
 "inheritEnvironments": [ "linux-gcc-arm" ],
 "name": "firmware",
 "includePath": [
 // Типы данных
 "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Enterprise\\Linux\\gcc_arm\\arm-none-eabi\\include",
 "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Enterprise\\Linux\\gcc_arm\\arm-none-eabi\\include\\sys",
 // Файлы проекта
 "${workspaceRoot}\\Drivers\\**",
 "${workspaceRoot}\\Middlewares\\**",
 "${workspaceRoot}\\Inc\\**",
 "${workspaceRoot}\\Src\\**"
 ],
 "defines": [
 // Скопировано из Makefile
 "USE_HAL_DRIVER",
 "STM32F042x6",
 "M0",
 "GCC_ARMCM0"
 ],
 "intelliSenseMode": "linux-gcc-arm",
 "browse": {
 "path": [
 "${workspaceRoot}"
 ],
 "limitSymbolsToIncludedHeaders": false,
 "databaseFilename": ""
 }
 }
 ],
 "environments": [
 {
 // Для сборки в Windows
 "BUILDTOOLS": "\"C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Enterprise\\Linux\\GNU MCU Eclipse\\Build Tools\\2.9-20170629-1013\"",
 // GCC_PATH нужен для компиляции в Windows, для компиляции в WSL путь прописывается в Makefile
 "GCC_PATH": "\"C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Enterprise\\Linux\\gcc_arm\\bin\"",
 // Для прошивки и отладки
 "JLINKPATH": "C:\\Data\\JLink_V632a",
 // Для компиляции в WSL
 "BASHPATH": "C:\\Windows\\sysnative",
 // Добавляем всё в PATH
 "PATH": "${env.BUILDTOOLS};${env.BUILDTOOLS}\\bin;${env.JLINKPATH};${env.BASHPATH};${env.PATH}"
 }
 ]
}

Минимальные задачи для работы задаются в файле .vs\Tasks.vs.json :

{
 "version": "0.2.1",
 "tasks": [
 {
 "taskName": "Build",
 "appliesTo": "Makefile",
 "contextType": "build",
 "type": "default",
 "command": "${env.COMSPEC}",
 "args": [
 //"make -s -j 5 all"
 "bash -l -c 'make -s -j 5 all'"
 ]
 },
 {
 "taskName": "Clean",
 "appliesTo": "Makefile",
 "contextType": "clean",
 "type": "default",
 "command": "${env.COMSPEC}",
 "args": [
 //"make -s clean"
 "bash -l -c 'make -s clean'"
 ]
 },
 // Команды для J-Link
 {
 "taskName": "Write to Flash MCU",
 "appliesTo": "Makefile",
 "type": "default",
 "command": "${env.COMSPEC}",
 "args": [
 "JLink.exe -Device STM32F042F6 -If SWD -Speed 1000 JLink\\FlashMCU.jlink"
 ]
 },
 {
 "taskName": "Read Flash from MCU",
 "appliesTo": "Makefile",
 "type": "default",
 "command": "${env.COMSPEC}",
 "args": [
 "JLink.exe -Device STM32F042F6 -If SWD -Speed 1000 JLink\\ReadMCU.jlink"
 ]
 },
 {
 "taskName": "Erase Flash MCU",
 "appliesTo": "Makefile",
 "type": "default",
 "command": "${env.COMSPEC}",
 "args": [
 "JLink.exe -Device STM32F042F6 -If SWD -Speed 1000 JLink\\EraseMCU.jlink"
 ]
 },
 {
 "taskName": "Reset MCU",
 "appliesTo": "Makefile",
 "type": "default",
 "command": "${env.COMSPEC}",
 "args": [
 "JLink.exe -Device STM32F042F6 -If SWD -Speed 1000 JLink\\ResetMCU.jlink"
 ]
 }
 ]
}

Здесь я привёл два варианта сборки: в Windows (закомментирован) и в WSL (по умолчанию) — выберете нужный вам, работают оба на одной и той же машине (проверено).

Также, как можно видеть, команды чтения, записи и очистки флешки МК, а также его принудительный сброс сделаны на основе J-Link скриптов. Скрипты расположены в папке JLink. Сделаны на основе официальной документации UM08001 — J-Link/J-Trace User Guide от Segger. В качестве примера скрипт-файл JLink\FlashMCU.jlink — для записи и верификации прошивки:

erase
loadbin build\FirmwareF042.bin, 0x00
verifybin build\FirmwareF042.bin, 0x00
r
g
q

Если нужна отладка, то прописываем в файле .vs\Launch.vs.json настройки или генерируем их… в главе про прошивку будет описано как:

{
 "version": "0.2.1",
 "defaults": {},
 "configurations": [
 {
 "type": "cppdbg",
 "name": "FirmwareF042.bin",
 "project": "build\\FirmwareF042.bin",
 "cwd": "${workspaceRoot}",
 "program": "${workspaceRoot}\\build\\FirmwareF042.elf",
 "MIMode": "gdb",
 "externalConsole": true,
 "inheritEnvironments": [
 "linux-gcc-arm"
 ],
 "miDebuggerPath": "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Enterprise\\Linux\\gcc_arm\\bin\\arm-none-eabi-gdb.exe",
 "setupCommands": [
 {
 "text": "-environment-cd ${workspaceRoot}\\build"
 },
 {
 "text": "-file-exec-and-symbols FirmwareF042.elf",
 "description": "load file",
 "ignoreFailures": false
 },
 {
 "text": "monitor reset halt",
 "ignoreFailures": true
 },
 {
 "text": "monitor reset init",
 "ignoreFailures": true
 },
 {
 "text": "-enable-pretty-printing",
 "ignoreFailures": true
 }
 ],
  "miDebuggerServerAddress": "localhost:2331",
  "visualizerFile": "${debugInfo.linuxNatvisPath}",
  "showDisplayString": true,
  "launchCompleteCommand": "None",
  // Нестабильно работает, VS не подключается к запущенному экземпляру
  // Поэтому, в случае чего, просто комментируем следующие 2 строки
  // и запускаем GDB сервер вручную - JLink-GDBServerM0.bat
  "debugServerPath": "C:\\Data\\JLink_V632a\\JLinkGDBServer.exe",
  "debugServerArgs": "-select USB -device Cortex-M0 -if SWD -speed 1000 -ir",
  //"serverStarted": "GDB\\ server\\ started",
  "filterStderr": true,
  "filterStdout": true
 }
 ]
}

И последнее, что необходимо сделать, если будете компилировать в WSL, — добавить строку в сгенерированный Makefile:

...
# ASM sources
ASM_SOURCES = \
startup_stm32f042x6.s

GCC_PATH ?= ~/gcc-arm-none-eabi-7-2017-q4-major/bin
#######################################
# binaries
#######################################
PREFIX = arm-none-eabi-
...

Таким образом мы прописываем путь к тулчейну в WSL.

Также советую добавить следующие строки, хоть это и не обязательно, но так будет отображаться текущий компилируемый файл и наглядно будет виден процесс сборки:

...
$(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR)
@echo $<
$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@
$(BUILD_DIR)/%.o: %.s Makefile | $(BUILD_DIR)
@echo $<
$(AS) -c $(CFLAGS) $< -o $@
$(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) Makefile
$(CC) $(OBJECTS) $(LDFLAGS) -o $@
$(SZ) $@
$(BUILD_DIR)/%.hex: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
$(HEX) $< $@
$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
$(BIN) $< $@
$(BUILD_DIR):
mkdir $@
...

Теперь чуть добавим кода в проект, чтобы светодиодом можно было высокотехнологично помигать.

В main.c добавим строки запуска таймера и разрешения прерывания:

 /* USER CODE BEGIN 2 */
 HAL_TIM_Base_Start(&htim1);
 HAL_TIM_Base_Start_IT(&htim1);
 /* USER CODE END 2 */

А в файле stm32f0xx_it.c добавим небольшую обработку прерывания:

/* USER CODE BEGIN 0 */
volatile uint8_t ledState = 0;
/* USER CODE END 0 */

void TIM1_BRK_UP_TRG_COM_IRQHandler(void)
{
/* USER CODE BEGIN TIM1_BRK_UP_TRG_COM_IRQn 0 */
if (__HAL_TIM_GET_FLAG(&htim1, TIM_FLAG_UPDATE) != RESET)
{
if (ledState)
{
HAL_GPIO_WritePin(USER_LED_GPIO_Port, USER_LED_Pin, GPIO_PIN_RESET);
ledState = 0;
}
else
{
HAL_GPIO_WritePin(USER_LED_GPIO_Port, USER_LED_Pin, GPIO_PIN_SET);
ledState = 0xFF;
}
}
/* USER CODE END TIM1_BRK_UP_TRG_COM_IRQn 0 */
HAL_TIM_IRQHandler(&htim1);
/* USER CODE BEGIN TIM1_BRK_UP_TRG_COM_IRQn 1 */
/* USER CODE END TIM1_BRK_UP_TRG_COM_IRQn 1 */
}

Компиляция

Собираем проект командой:

B63-7

Процесс сборки:

B63-8

Вот и всё… толком и описывать нечего. :)

Прошивка, отладка

Прошиваем МК командой:

B63-9

Появится окно J-Link с прогрессом прошивки на буквально пару секунд:

B63-10

Лог прошивки:

B63-11

И долгожданный момент:

B63-12

Вери-сириоз проджект! По такому делу я даже впервые гифку сделал. :D

Теперь отладка, тут всё так же просто — выбираем файл прошивки и назначаем его как Startup Item:

B63-13

Далее, если вы ранее вручную не внесли настройки в .vs\Launch.vs.json, жмём Debug and Launch Settings — это создаст заготовку .vs\Launch.vs.json,  внимание, если вы уже создали файл, то эта команда перезапишет его! Из правок здесь по факту только запуск GDB сервера, так что для новичка это будет отличное решение, т. к. исключит ошибки в именах и путях.

Всё, теперь можно стартовать отладку (F5):

B63-15

Мгновенно запускается GDB сервер, подключится к МК и МК будет находится в Halt состоянии:

B63-16

Примечание: возможна ситуация, что сервер запускается, подключается к МК, а к серверу Visual Studio не подключается, как решение — просто комментируем строки запуска GDB сервера, и перед отладкой вручную запускаем его с помощью бат-файла — JLink-GDBServerM0.bat (включен в пример). 

Жмякаем на кнопку сброса на плате, стартует прошивка и вуаля, срабатывает первая установленная бряка:

B63-17

B63-18

Вывод

Всё проще некуда. :) Зачем нужны всякие ардуины и т. п., если есть такие мощные средства для разработки прошивок и отладки, мне непонятно, но большинство почему-то выбирает именно худший вариант…

Не уподобляйтесь большинству, изучайте все доступные варианты, и надеюсь, эта статья сподвигнет хотя бы кого-то на использование Visual Studio 2017 в качестве IDE для микроконтроллеров.

Ссылки

 

Реклама

Добавить комментарий

Please log in using one of these methods to post your comment:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход /  Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход /  Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход /  Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход /  Изменить )

w

Connecting to %s