Как-то раз я начал работать с одним большим проектом для микроконтроллера. Как многие legacy-проекты в embedded, он привязан к старой версии IDE. В моем случае это оказался IAR 7. Эта среда обладает хорошими отладочными средствами, но работать с кодом в ней не очень комфортно: отсутствует много привычных комбинаций клавиш (Ctrl + точка, например), нет темной темы, скромная подсветка синтаксиса.
VS Code с расширениями смотрит на проект из IAR
Со временем я стал все больше пользоваться VS Code для работы с кодом, а для проверки работоспособности переключался в IAR. Тогда я задумался, можно ли перенести основную работу над проектом в VS Code? Достоинств у редактора много: приятный настраиваемый интерфейс, интегрированный Git, расширения на любой вкус и задачу. Главный нюанс состоял в том, что проект должен собираться компилятором IAR, ибо написан он был строго под него.
Коротко о проекте: он огромен, стар (самое раннее упоминание — 2007 год), в нем много всего привязано к компилятору. Проект написан для серии приборов с небольшим количеством модификаций. Программатор J-Link, микроконтроллеры ARM Cortex-M0 и M4.
План
Какие возможности я хотел получить от новой среды разработки? Для начала:
-
сборка прошивки в VS Code;
-
работа с программатором — очистка чипа, запись готового .hex;
-
отображение ошибок компиляции в проекте.
К чему я стремился из плюсов среды:
-
удобство работы с кодом (подсветка синтаксиса, форматирование);
-
автоматизация рутинных задач через tasks;
-
работа с Git;
-
проверка кода анализатором.
Задачи в VS Code
Небольшой ликбез. Задачи в VS Code — это механизм, который позволяет запускать внешние скрипты и программы прямо из редактора. С их помощью можно автоматизировать некоторые действия, например прошивку микроконтроллера, удаление/создание папок и т. п.
Описываются задачи в файле .VS Code/tasks.json и выглядят примерно так:
{ "label": "Flash: Erase chip", "type": "shell", "command": "JFlash.exe", "args": [ "-openprj${workspaceFolder}\_scripts\J-flash.jflash", "-erasechip", "-exit" ], "group": "build", "presentation": { "reveal": "always", }}
Эта задача запускает SEGGER J-Flash, в нем открывает проект J-flash, стирает чип и закрывает программу. Подробнее про задачи можно почитать в блоге VS Code.
Сборка проекта
Для начала рассмотрим сборку через расширения для VS Code. IAR Build и IAR Debug позволяют перенести работу с прошивкой в VS Code (сборку и отладку), но увы, минимальная поддерживаемая версия IAR — восьмая, так что это не мой вариант.
Чуть более интересный способ — это сборка через IarBuild.exe, поставляемого вместе с IAR. Эта утилита позволяет скомпилировать проект без графической IDE и работает довольно просто. Ее необходимо вызвать, передав ей одну из команд:
-
-makeпересобирает, что изменилось; -
-build— уже полная пересборка проекта; -
-cleanудаляет промежуточные и выходные файлы.
Чтобы запустить сборку проекта, из bat-скрипта вызываем:
"%IAR_DIR%commonbinIarBuild.exe" "%REPO_DIR%name.ewp" -build %CONFIG% -log all
Здесь:
-
IAR_DIR— адрес папки IAR, -
REPO_DIR— папка с проектом, -
name.ewp— файл проекта, -
CONFIG— конфигурация прибора по умолчанию (Release или Debug), а в моем случае еще и конфигурации под каждый вид прибора, -
log all— вывод сообщений сборки.
Далее в скрипте можно добавить действия с готовой прошивкой — например, прописать заводские настройки или объединить файл с bootloader.
Но вернемся к VS Code. Для компиляции прошивки надо запустить bat-файл, указав необходимую модификацию. Каждой модификации прибора соответствует отдельная конфигурация сборки в IAR. Я создал одноименный список приборов в tasks.json:
"inputs": [{ "id": "device", "type": "pickString", "description": "Выберите прибор для сборки", "options": [ "Device1", "Device2", "Device3" ]}]
Вот задача, которая в начале дает выбор модификации, а затем запускает сборку необходимой конфигурации:
{ "label": "IAR: Build Device", "type": "shell", "command": "${workspaceFolder}\build_device.bat", "args": [ "${input:device}" ], "options": { "cwd": "${workspaceFolder}", "shell": { "executable": "cmd.exe", "args": ["/d", "/c"] } }, "group": "build", "problemMatcher": { "owner": "IAR-build", "fileLocation": "absolute", "source": "IAR", "pattern": { "regexp": "^(.+)\((\d+)\)\s*:\s*(Warning|Error)\[[^\]]+\]:\s*(.*)$", "file": 1, "line": 2, "severity": 3, "message": 4 } }}
Тут интересен момент с problemMatcher: при компиляции все ошибки передаются в VS Code и будут отображаться в окне problems. Очень удобно. В панели Problems сразу появилась сотня предупреждений. Добавляются предупреждения и ошибки сборки с указанием места, так что можно все найти и поправить.
![]()
Раз уж зашла речь об ошибках, то поговорим и про IntelliSense. По умолчанию VS Code использует IntelliSense из расширения C/C++ для анализа кода, и он поначалу выдавал огромное количество ошибок, так как не мог найти те или иные элементы. Так как меня интересуют только ошибки из IAR, я отключил отображение ошибок от IntelliSense, создав файл settings.json с таким содержанием:
{ "C_Cpp.errorSquiggles": "disabled", "C_Cpp.intelliSenseEngine": "default"}
При этом сам IntelliSense я оставил включенным, поскольку он обеспечивает автодополнение и навигацию по коду. Для корректной работы этих функций необходимо настроить пути к заголовочным файлам. Чтобы не писать их вручную, попросил нейросеть сгенерировать скрипт на Python, который бы создавал файл c_cpp_properties.json со списком путей, импортированных из проекта IAR:
import jsonimport sysimport xml.etree.ElementTree as ETfrom pathlib import PathIAR_DIR = r"F:progIARarm"project = Path(sys.argv[1]).resolve()config_name = sys.argv[2]# Открываем проект и ищем конфигурациюroot = ET.parse(project).getroot()config = next( (c for c in root.findall(".//configuration") if c.findtext("name") == config_name), None)if config is None: sys.exit(f"Configuration not found: {config_name}")# Извлекаем пути заголовочных файловincludes = []for option in config.findall(".//option"): if option.findtext("name") == "CCIncludePath2": for state in option.findall("state"): if state.text: path = state.text.strip() path = path.replace("$PROJ_DIR$", str(project.parent)) path = path.replace("$TOOLKIT_DIR$", IAR_DIR) includes.append(Path(path).resolve().as_posix())# Формируем настройки VS Codedata = { "configurations": [{ "name": config_name, "includePath": list(dict.fromkeys(includes)), "intelliSenseMode": "gcc-arm", "compilerPath": "", "cStandard": "c99", "cppStandard": "c++98" }], "version": 4}# Сохраняем файлoutput = Path(__file__).resolve().parent.parent / ".vscode" / "c_cpp_properties.json"output.parent.mkdir(exist_ok=True)output.write_text(json.dumps(data, indent=4), encoding="utf-8")print(f"Created: {output}")print(f"Include paths: {len(includes)}")
Кнопку сбора прошивки и отображение ошибок разобрали, идем дальше.
Прошивка контроллера
Следующий пункт автоматизации — работа с программатором J-Link через задачи. Для J-Flash я создал проект с моим контроллером, всеми выставленными настройками и написал необходимые мне задачи: одна для прошивки, вторая для стирания чипа.
{ // прошивка "label": "Flash: artifacts", "type": "shell", "command": "JFlash.exe", "args": [ "-openprj${workspaceFolder}\_scripts\J-flash.jflash", "-open${workspaceFolder}\programm.hex", "-auto", "-exit" ], "group": "build", "problemMatcher": []},{ // стирание "label": "Flash: Erase chip", "type": "shell", "command": "JFlash.exe", "args": [ "-openprj${workspaceFolder}\_scripts\J-flash.jflash", "-erasechip", "-exit" ], "group": "build", "presentation": { "reveal": "always", }}
Все задачи пишут результат своего выполнения в терминал. Можно отдельно прописать, что если задача выполнена успешно, то терминал автоматически закрывается, но мне это показалось неудобным. Отвлечешься и неясно, а запускал ли ты задачу вообще.
Отладка
Внимательный читатель наверняка уже сидит с вопросом: а как же отладка проекта? Ведь написание и сборка проекта — это далеко не всё, проект надо еще и дебажить! Тут, увы, результатами похвастаться не получится: последний камень преткновения перенести не удалось. Расширение для отладки не подошло из-за разницы в версиях IAR. Единственное, чем я пользуюсь, это отладка через UART, а вот за полноценной отладкой приходится идти обратно в IAR.
Полезные расширения
План «минимум» закрыл, собрать прошивку и перепрошить контроллер могу, не выходя из VS Code. Теперь рассмотрим расширения, которые мне помогают в работе:
Code Spell Checker — проверяет правильность написания слов. Бывало, что после запушенного на сервер изменения вы находили опечатку в своем комментарии? С этим расширением таких ситуаций больше не будет. Одна беда: постоянно ругается на опечатки, которые внесли другие программисты в проект.
Подсвечивает место ошибки, по нажатию «Ctrl + .» показывает варианты замены, по повторному нажатию исправляет на первое значение.

Также есть отдельное окошко, в котором показаны все ошибки в проверенных файлах. Имеется вариант приложения для русского языка.
Trailing Spaces — показывает лишние пробелы, например, в конце строки. Пишем чище.

VS Code-icons — меняет иконки папок и файлов в Explorer, становится визуально проще ориентироваться в проекте.
Serial monitor — позволяет работать с COM-портом в отдельном окошке, я использую его для отладки по UART.

Doxygen Documentation Generator — расширение для генерации шаблона описания функции. Создает ту самую шапку:
/******************************************************************************** * @brief тестирует исправность АЦП * * @param num_channel - номер канала * @return uint16_t значение на канале ********************************************************************************/uint16_t ADC_test (uint8_t num_channel){
Преимущества использования VS Code
Теперь рассмотрю коротко, что я получил, начав работать с кодом в VS Code:
-
Настраиваемую подсветку синтаксиса и темную тему. Честно говоря, даже одного этого было бы достаточно для того, чтобы начать в этом разбираться.
-
Форматирование кода.
-
Удобный поиск по всему проекту.
-
Структура проекта соответствует структуре папок. В IAR расположение файлов в дереве проекта может не иметь ничего общего с реальным расположением.
-
Удобно открывать среду: зашел в папку проекта, нажал правой кнопкой мыши — «открыть с помощью code» — и всё, проект открыт.
-
Можно посмотреть почти любой файл в IDE, разве что с офисными документами не работает.
-
В любом участке проекта я вижу, кто именно и как давно написал тот или иной код. Особенно полезно в работе с командой.
-
Подключил анализатор кода — cppcheck. После анализа он выдал тысячу предупреждений. Конечно, это не все места с ошибками, но рассмотреть стоит. Полезно для поиска потенциальных ошибок.
Выводы
Стал ли я все время работать в VS Code, забыв, как выглядит ярлык IAR? Увы, нет. Бо́льшая часть отладки проекта все так же происходит в IAR. Но вся работа по написанию кода и работа с Git теперь перенесена в приятную среду. Сейчас я не перепроверяю орфографию комментариев, стало заметно легче ориентироваться в коде, а часть задач решается через отладку по UART прямо в VS Code. Считаю, что по большей части моя изначальная задача выполнена.
Далее я попытаюсь прикрутить к проекту хоть какое-нибудь автоматическое тестирование, чтобы меньше работать 😂
Ссылки
-
Задачи в VS Code
-
VS Code как IDE для embedded-разработки — про полноценную работу с МК в VS Code. Подглядел для себя парочку полезных расширений там.
-
Настройка VS Code
Источник: habr.com