– Или скрещиваем Льва с Пингвином
Статья описывает установку IDE CLion на Linux и Windows, настройку её для работы с STM32, запуск отладки, используя нативные инструменты.

Вступление
Обновление основного рабочего инструмента — большая перемена в жизни. Для меня это была покупка нового ноутбука.
Чтобы рабочий процесс был наиболее эффективен, захотелось пересесть на Linux.

Первое знакомство с STM32 случилось в начале 2020 года. Как и многие, разработку я вёл в бесплатном инструменте STM32CubeIDE. На самом деле это Eclipse, окружённый плагинами.
После установки на Linux сначала меня встретил пустой Target selector.

Как оказалось, этот баг встречался ещё с 2019 года, на май 2022 его уже починили.
Всё дело в графическом сервере. По умолчанию Fedora использует Wayland, который, в отличие от Xorg (X11), самостоятельно не отрисовывает интерфейсы, а кладёт эту задачу на приложение. Если оно этого не предусматривает, то пустота и будет.
Хоть основная беда и исправлена, остальные остались. Связаны они с масштабированием дисплея.
Для моих 4К на 14 дюймов надо включать масштаб 200%.
Проблемы в данном случае такие: текст местами размыт, значки сломались, подсказки к методам убегают, а то и вовсе намертво вешают IDE.

Отсюда ясно, что пользоваться этим совсем неприятно. А ещё риск потерять несохранённый код из-за очередного бага.
Избавляемся от CubeIDE
Среда CubeIDE нравилась мне как готовый “комбайн” для производства прошивок. Полный цикл: от настройки МК, до полноценной, глубокой отладки.
Но до сих пор я не решался уходить с неё. В других средах меня пугало огромное количество всяких конфигов, настраиваемых, в основном, вручную.
Какие есть альтернативы?
Во-первых, существуют профильные решения: Keil, IAR, MikroC, и так далее… Какие-то не понравились мне функционалом или интерфейсом. У некоторых закрытая ценовая политика. Какие-то вовсе нативно не поддерживаются на линуксе.
Во-вторых, существует масса плагинов для отладки ARM в других IDE. Первое, что приходит на ум — Visual GDB для Visual Studio. [Видео-инструкция]
Так как на Linux доступен только VSCode, можно прикрутить вот такой плагин, или другой плагин. [Инструкция]
На самом деле, я бы так и использовал этот вариант, если бы случайно не наткнулся на эту статью.
Ещё со школы я был знаком с CLion, но удивился тому, что только сейчас узнал об этом функционале.
Уже через несколько минут получил студенческую лицензию, подтвердив через доменную почту ВУЗа.

[UPD 05.2022]
JB приостановили продажи в РФ, можно попробовать оплатить с иностранной карты.
Будем ждать, что всё наладится 🤞
Установка CLion
Загрузить IDE удобнее всего через Toolbox. Он лишает нас всей возни с распаковкой и генерацией ярлычков. Ставим, логинимся, загружаем среду.


Установка CubeMX
Сам по себе CLion не способен генерировать HAL-овский код. Для этого нужен CubeMX.
При попытке установки может возникнуть такая проблема:

Возможно, накосячили с поставляемым в комплекте с установщиком JRE. Возможно, дело в версии JDK системы (на Fedora 36 его обновили с 11 до 17).
В любом случае, это всё решаемо. Для начала надо установить пакет JDK из репозиториев:
sudo dnf install java-11-openjdk
Далее перейти в директорию установки: usr/lib/jvm/java-11-openjdk-xxx/
И подменить папку с JRE установщика на свою (не забудьте переименовать):

Далее запускаем установщик:
# chmod u+x SetupSTM32CubeMX-6.5.0 # - если установщик не запускается
./SetupSTM32CubeMX-6.5.0
После установки надо прописать ярлычок в системное меню:
cd /usr/share/applications
sudo nano st-cubemx.desktop
Пропишем такие строки:
[Desktop Entry]
Name=CubeMX
Comment=CubeMX
GenericName=CubeMX
Exec=/home/enik/STM32CubeMX/STM32CubeMX %F
Icon=/home/enik/STM32CubeMX/help/STM32CubeMX.ico
Path=/home/enik/STM32CubeMX/
Terminal=false
StartupNotify=true
Type=Application
Categories=Development
Ctrl+X – выход с сохранением.
Настройка CLion
Установка пакетов
Для начала надо установить все компиляторы и пакеты GNU-Toolchain. Выполним команду:
sudo dnf install make gcc g++ arm-none-eabi-*
Звёздочка указывает, что установятся все пакеты, содержащие arm-none-eabi
Проверим, что всё установилось и работает корректно:

Инструментарий для Windows
Для винды всё менее тривиально. Для сборки десктопных приложений там используется MinGW.
Установим и его тоже, выберем такие пакеты:

GNU Toolchain нужно скачать и установить с сайта. Обратите внимание, нужен именно arm-none-eabi.
Настройка тулчейна
При первом запуске CLion конфигурируются рабочие инструменты. Будет подобное окошко, которое потом можно найти в настройках. Здесь мы можем убедиться, что весь инструментарий корректно увиделся.

Для Windows есть ремарка:
В отличие от UNIX-систем, нужно выбрать ARM-овский дебаггер, иначе отладка не заведётся.

Подключение доп. инструмента
Для embedded-разработки CLion предполагает наличие двух инструментов: CubeMX и отладчик OpenOCD.
Их нужно подключить самостоятельно в настройках, в специальной вкладке.
В Linux устанавливается одной командой:


Для винды есть установщик. Загружаем, ставим, подключаем.

Создание проекта
Создание с нуля
В меню создания проекта выберем CubeMX. Среда создаст директорию с готовым .ioc-файликом под процессор F0 и предложит его отредактировать.


Важный нюанс: при смене процессора в кубе всегда создаётся новый файл. Старый нужно удалить, а одноимённый новый записать в ту же директорию.


После конфигурации сохраняемся и генерируем код. Обязательно под CubeIDE и в корне (root) директории.

Перенос существующего проекта из CubeIDE
Перенести старый проект довольно просто. В меню открытия проекта нужно открыть директорию или .ioc-файл.


Настройка OpenOCD
При первом запуске проекта предложат выбрать конфиг для OpenOCD.

Позже его можно выбрать в конфигурации отладки.

Теперь можно загружать прошивку и производить отладку.
Настройки CMake
CMake — это инструмент автоматизации сборки. Его задача — подготовить файлы проекта, задать настройки, передать всё это компилятору.
Для конфигурации процесса используется CMakeLists.txt.
В embedded проектах он формируется из .ioc файла по шаблону: CMakeLists_template.txt.
При каждом изменении .ioc-файла, все правки затираются. Поэтому туда стоит вносить только временные, а потом переносить в шаблон.
В целом, эта конфигурация делает то же, что и настройки проекта в CubeIDE. Вот только здесь их проще редактировать.
Например, FPU. Если в МК есть этот блок (Cortex-M4 и выше), то можно включить аппаратную поддержку чисел с плавающей запятой. За это отвечают следующих 3 строчки:
#Uncomment for hardware floating point
add_compile_definitions(ARM_MATH_CM4;ARM_MATH_MATRIX_CHECK;ARM_MATH_ROUNDING)
add_compile_options(-mfloat-abi=hard -mfpu=fpv4-sp-d16)
add_link_options(-mfloat-abi=hard -mfpu=fpv4-sp-d16)
Пользовательские директории вносятся в include.
Я обычно добавляю руками и все остальные директории. Так проще контролировать.
Надо не забыть прописать и директории, где лежат source-файлы (.c/.cpp/…).

Не забудьте перенести изменения в Template, иначе при новой генерации проекта в кубе все изменения слетят.
Нативный отладчик
Дело в том, что мне совсем не нравится OpenOCD.
Нужно иметь конфигурации под каждый МК. Под G4, например, я так сразу и не нашёл.
Точки останова иногда не ставятся, локальные переменные иногда не отображаются.
Может быть, дело в кривых конфигах или руках, но в любом случае, это совсем не дело. CLI убогий. Ну кто красит сообщения в цвет ошибки?
В общем, пользоваться таким инструментом я не хочу.


Самый лёгкий способ отказаться от OpenOCD — перейти на родной, проприетарный ST-шный GDB-отладчик. За более, чем 1.5 года с ним не было никаких проблем. Получить дебаггер и загрузчик можно в составе CubeIDE.
Для начала узнаем путь к утилите сервера:
Linux:
/opt/st/stm32cubeide_xxx/plugins/com.st.stm32cube.ide.mcu.externaltools.stlink-gdb-server.linux64_xxx/tools/bin/ST-LINK_gdbserver
Windows:
C:\ST\STM32CubeIDE_xxx\STM32CubeIDE\plugins\com.st.stm32cube.ide.mcu.externaltools.stlink-gdb-server.win32_xxx\tools\bin\ST-LINK_gdbserver.exe
Ещё нужно узнать путь к загрузчику CubeProgrammer.
Linux:
/opt/st/stm32cubeide_xxx/plugins/com.st.stm32cube.ide.mcu.externaltools.cubeprogrammer.linux64_xxx/tools
Windows:
C:\ST\STM32CubeIDE_xxx\STM32CubeIDE\plugins\com.st.stm32cube.ide.mcu.externaltools.cubeprogrammer.win32_xxx\tools\bin\
Внесём эти директории в глобальные системные переменные. Откроем файл инициализации переменных:
cd ~
nano .bashrc
В конец впишем:
export PATH=$PATH:/opt/st/stm32cubeide_xxx/plugins/com.st.stm32cube.ide.mcu.externaltools.stlink-gdb-server.linux64_xxx/tools/bin
export CUBE_DL="/opt/st/stm32cubeide_xxx/plugins/com.st.stm32cube.ide.mcu.externaltools.cubeprogrammer.linux64_xxx/tools/bin"
Ctrl+X — выход.
Что мы сделали? Добавили сервер в PATH и создали переменную для загрузчика: CUBE_DL.

* PATH – Системная переменная, в которой хранятся каталоги исполняемых файлов.
При вызове исполняемого файла из любой директории, он будет найден в PATH и запущен.
Чтобы всё обновилось, достаточно сделать Log Out – Log In. Или обновить среду bash одной из команд:
source ~/.bashrc # вариант 1
. ~/.bashrc # вариант 2
После обновления сразу можно попробовать открыть терминал и прописать:
ST-LINK_gdbserver -cp $CUBE_DL
Должно выдать что-то вроде:

Если ругается на отсутствие библиотеки:
ST-LINK_gdbserver: error while loading shared libraries: libSTLinkUSBDriver.so: cannot open shared object file: No such file or directory
Зайдём в директорию с библиотекой …/{ST gdb_server}/tools/bin/native/linux_x64/, скопируем оттуда .so-файлик:
sudo cp libSTLinkUSBDriver.so /usr/lib
sudo cp libSTLinkUSBDriver.so /usr/lib64
Сервер настраивается через аргументы [Оригинальный мануал]:
• -h / --help – Вызов справки
• --halt – Останавливать все ядра во время reset
• -c <config file> / --config-file <config file> – Вызов аргументов из файла конфигурации (Appendix B in 2576)
• -f <log file> / --log-file <log file> – Запись логов. Стандартный файл - debug_log.txt.
• -l <log level> / --log-level <log level> – Уровень логирования - число [0, 31]. Стандартное значение: 31
– = 0: Выключить логирование.
– ≥ 1: Логирование ошибок.
– ≥ 2: Логирование warning-ов.
– ≥ 4: Логирование команд протокола.
– ≥ 8: Логирование всех информационных сообщений.
– ≥ 16: Логирование всех аппаратных команд.
Если параметры для -f и для -l не обозначены, будут применены стандартные.
• -p <port number> / --port-number <port number> – Установка TCP-порта сервера. Стандартный - 61234.
• -v / --verbose – Подробный режим (вывод debug логов)
• -r <refresh delay> / --refresh-delay <refresh delay> – Интервал опроса hardware status в файл логов. [c]. Стандартный интервал - 5 секунд.
• -s / --verify – Верификация после загрузки.
• -e / --persistant – Запуск сервера в persistent (постоянном) режиме. По умолчанию выключен.
• -d / --swd – Включение SWD-режима, вместо JTAG.
Актуально только для SWO (SWV):
• -z <port number> / --swo-port <port number> – Выбор порта для опроса SWO.
• -a <cpu clock> / --cpu-clock <cpu clock> – Частота МК в Гц.
• -b <SWO CLOCKDIV> / --swo-clock-div <SWO CLOCKDIV> – Установка делителя для SWO.
Пример настройки SWO (fCPU = 72МГц, fSWO = 125КГц): -z 61235 –a 72000000 –b 576.
• -k / --initialize-reset – Инициализация во время reset.
• -q / --debuggers – Вывести список подключенных ST-Link.
• -i <ST-LINK S/N> / --serial-number <ST-LINK S/N> – Подключение к конкретному ST-Link по серийному номеру.
• --frequency <max freq kHz> – Максимальная частота коммуникации [КГц]: {5, 25, 100, 240, 950, 1800, 4000, 8000, 24000}.
• -m <apID> / --apid <apID> – Выбор appID для отладки. [Для многоядерных систем]
• -g / --attach – Подключиться к запущенному МК (без загрузки кода и reset).
• -t / --shared – Позволяет нескольким отладчикам присоединиться к одному серверу. [Для сервера]
• --erase-all – Очистка всей памяти.
• --memory-map <device id> – Вывод memory map по идентификатору устройства, например 0x410.
Работа с внешней памятью:
• --ext-memory-loaders – Вывод доступных загрузчиков внешней памяти.
• -el <file_path> / --extload <file_path> – Выбор загрузчика внешней памяти.
• --external-init – Инициализация внешней памяти после reset.
• -cp <path> / --stm32cubeprogrammer-path <path> – Директория установки STM32CubeProgrammer (STM32CubeProg).
• --pend-halt-timeout <Pending halt timeout> – Таймаут остановки ядра. Стандартное время - 2 секунды.
• --temp-path <path> – Обозначить к папке для создания временных файлов.
• --preserve-temps – Не удалять временные файлы.
• --licenses – Вывод списка используемых инструментов и лицензий.
• -- / --ignore-rest – Игнорировать все аргументы после этого флага.
• --version – Вывод версии и выход из утилиты.
Типичные достаточные флаги запуска:
-p 61234 -l 1 -d -s -cp $CUBE_DL -m 0 -k
- Порт: 61234
- Уровень логгирования: только ошибки
- Отладка по SWD
- Проверка после загрузки
- Путь к загрузчику
- Отладка 0-го ядра (потока)
- Инициализация во время reset
А теперь лайфхак, который сразу должен прийти на ум более-менее опытному линуксоиду.
Вместо того, что бы вспоминать и прописывать каждый раз флаги запуска, пропишем скрипт.
В блокноте создадим файл ST_GDB.sh, сохраним куда-нибудь в home. Содержание:
#!/bin/sh
ST-LINK_gdbserver -p 61234 -l 1 -d -s -cp $CUBE_DL -m 0 -k
Запустить его не получится, потому что скрипту надо задать права на запуск.
chmod u+x ST_GDB.sh
Попробуем:

Для Windows операции примерно те же, только используем .bat-скрипт, в нём можно обойтись ярлычками.

Теперь нужно создать конфигурацию отладки “Embedded GDB Server”.
В ней указываем адрес сервера: localhost:61234, т.е. с указанным в параметрах портом.
А также указываем скрипт на запуск. Всё!


Запуск отладки
После настройки всего и вся, обязательно ставим первый breakpoint и запускаем отладку.

В окошке “Debugger” видны локальные переменные:

Для HEX-отображения переменных, нужно включить эту опцию.
Глобальные переменные добавляются через watch или evaluate:

Так же, как и в CubeIDE, можно посмотреть аппаратные регистры микроконтроллера. Для этого надо загрузить .svd файл — XML-таблицу этих регистров. Удобно то, что можно выбрать только отдельные регистры для наблюдения.


Если иногда возникают проблемы с точками останова, достаточно воспользоваться GDB-командами в терминале.

Serial порт
Я не приверженец SWO, во всех своих проектах обычно использую старый-добрый UART.
Скорее из тех соображений, что для него не нужно специальное ПО, а чтение шины может быть независимым и выполняться на другой машине. Отдельный мостик не нужен, всё есть в ST-Link v.2.1 как VCP.
В CLion для чтения COM-порта можно использовать встроенное окошко терминала. На винде я этим не пользовался, поэтому инструмент подсказать не смогу, а на линуксе я предпочитаю minicom.
Именно так получается иметь процесс отладки внутри единого окна, а не городить массу остальных.

Перспективы
Что хочется увидеть в будущем? Пожалуй, основные багфиксы и улучшения уже внесли, но есть парочка:
- Фундаментальная вещь — дизассемблирование кода, как в профильных IDE. Тикет висит почти 10 лет.
- Более гибкая конфигурация embedded GDB сервера, это нужно для других отладчиков. Тикет
Выводы
Неважно, какой инструмент используется в программировании. Ключевая цель — удобство разработчика.
Что касается ценовой политики — цена очень демократичная. За первый год 90 долларов — порядка 500 руб в месяц. Дорого это или нет, решать каждому.
Безусловно, не все готовы тратить свои личные средства на эту IDE.
Во-первых, бесплатная лицензия доступна не только для студентов, но и для open-source проектов.
Во-вторых, многие компании готовы покупать софт своим сотрудникам.
В-третьих, если инструмент приносит доход, то инвестировать его часть в собственный комфорт — отличная практика.
Я уже полностью пересел на CLion, с ним работать стало гораздо приятнее. Однажды попробовав, уже не захотелось возвращаться на Eclipse, даже на домашнем ПК с Windows.
Комментарии открыты для дискуссий, дополнений, возражений.
Лёгкого кодинга и удачи в мире Embedded!
Ссылки
https://www.jetbrains.com/help/clion/clion-quick-start-guide.html
https://stm32club.ru/environment/setup-clion-for-stm32.html
https://habr.com/ru/post/345670/ — Разработчик плагина
https://habr.com/ru/post/572044/ — Гайд без CubeMX
Добрый день! Настроил CLion в Windows по статье. Подскажите пожалуйста, как добавить файлы в проект (хидеры и сёрсы). Добавляю файлы в соответствующие директории (даже создаю новые из CLion) – проект собирается, но ругается на отсутствие этих файлов.
AR19DD~1.EXE: error: Core/Src/bme280.c: No such file or directory
mingw32-make[2]: *** [CMakeFiles\Main_MCU.elf.dir\build.make:527: Main_MCU.elf] Error 1
mingw32-make[1]: *** [CMakeFiles\Makefile2:82: CMakeFiles/Main_MCU.elf.dir/all] Error 2
mingw32-make: *** [Makefile:90: all] Error 2
В CMakeLists.txt дописываю:
перезагружаю проект – те же ошибки. Спасибо!
Если оно в Inc/Src валяется, то дополнительно прописывать ничего не нужно.
Выше ведь прописано:
Вот он из этих папок всё и подхватывает сам