[Из песочницы] STM32 + CMSIS + STM32CubeIDE
Здесь я расскажу как создать минимальный проект на CMSIS с использованием «родной» IDE для микроконтроллеров STM — STM32CubeIDE.
Возможно STM32CubeIDE и обладает рядом недостатков, но у нее, на мой взгляд, есть несколько преимуществ — таких как проприетарность и бесплатность, ради которых, как минимум, стоит обратить внимание на эту среду разработки, если вы не сделали этого раньше.

Объектом прошивки выбран не очень распространенный микроконтроллер STM32F072 с ядром ARM Cortex-M0, для более привычных STM32F103 на ARM Cortex-M3, с поправкой на ядро, процесс идентичен.
Все необходимые ресурсы можно скачать с сайта st.com, и вот что понадобится:
- Сама IDE, я использую Windows версию, но также доступны версии под Mac и Linux
- Библиотека CMSIS для ARM Cortex-M0, она находится в архиве STM32CubeFx, разбитом по версиям ядра. Сам архив, помимо CMSIS, содержит великое множество других ресурсов начиная от примеров работы с периферией до драйверов USB, собственно, именно этот архив используется, если создавать проект с помощью STM32Cube
- Не помешает Datasheet и Reference Manual
После установки, запуска и выбора папки Workspace можно начать создание проекта. На текущий момент STM32CubeIDE версии 1.1.0, так что по расположению различных настроек следует исходить из этого.
Создание нового проекта — File/New/STM32Project. После некоторого раздумия появляется окно выбора микроконтроллера, в моем случае это STM32F072RB в корпусе LQFP64, выбираю нужную строку, жму далее. Далее предлагается выбрать имя проекта, расположение, язык программирования C/C++, исполняемый файл/статическая библиотека и будет-ли проект сгенерирован с помощью CubeMX или сами с усами. Генерация кубом, в данном случае не нужна, поэтому тип проекта Empty — финиш.



Слева, в окне Project Explorer, появилось дерево проекта, правда он не совсем Empty, как заказывали. Впринципе, если устраивает сгенерированная структура папок, можно добавить туда файлы из библиотеки CMSIS и работать дальше, но здесь я покажу как можно привести структуру проекта в гармонию со своим чувством прекрасного, поэтому удаляется всё, кроме скрипта линкера т.е. файла c расширением .ld — он еще пригодится.


Все манипуляции с папками и файлами можно проводить как в проводнике так и внутри IDE, нажав правой кнопкой на название проекта, к примеру: правая кнопка –> new –> Folder. Если структура проекта изменялась вне IDE, то нужно просто обновить проект: правая кнопка –> Refresh.
Мой вариант структуры проекта выглядит так:
- Startup — здесь будет храниться скрипт линкера, тот самый, оставшийся от сгенерированного проекта, а также startup файл взятый из CMSIS
- CMSIS\src и CMSIS\inc — здесь будут лежать исходники, файлы с расширением .c в папке scr и заголовочные файлы с расширением .h в папке inc соответственно, относящиеся к библиотеке CMSIS
- Core\src и Core\inc — здесь будет расположен собственно сам проект, для начала стоит положить туда main.c и main.h

Теперь нужно перенести файлы библиотеки CMSIS в проект. Библиотека состоит из файлов ядра и файлов периферии. Файлы ядра начинаются с core_ или cmsis_ они общие для всех микроконтроллеров, использующих данное ядро. Файлы периферии содержат в названии наименование микроконтроллера stm32 и специфичны для конкретного производителя, в данном случае, компании STM.
В распакованном виде архив содержит папку STM32Cube_FW_F0_V1.11.0, все пути указаны относительно этой папки. Итого, нужно скопировать:
В CMSIS\inc:
- Drivers\CMSIS\Include\cmsis_compiler.h
- Drivers\CMSIS\Include\cmsis_gcc.h
- Drivers\CMSIS\Include\cmsis_version.h
- Drivers\CMSIS\Include\core_cm0.h
- Drivers\CMSIS\Device\ST\STM32F0xx\Include\stmf0xx.h
- Drivers\CMSIS\Device\ST\STM32F0xx\Include\stm32f072xb.h
- Drivers\CMSIS\Device\ST\STM32F0xx\Include\system_stm32f0xx.h
В CMSIS\src:
- Drivers\CMSIS\Device\ST\STM32F0xx\Source\Templates\system_stm32f0xx.c
В Startup:
- Drivers\CMSIS\Device\ST\STM32F0xx\Source\Templates\gcc\startup_stm32f072xb.s
Так выглядит проект в заполненном виде.

Так как были проведены некоторые манипуляции с папками проекта, нужно отобразить это в настройках.
Правая кнопка по названию проекта → Properties → C/C++ Build → Settings → Tool Settings → MCU GCC Linker → General — здесь нужно указать новое расположение скрипта линкера с помощью кнопки Browse…

Также нужно указать пути к файлам проекта
Properties → C/C++ General → Includes
Properties → C/C++General → Source Location
В Includes пути к папкам inc, а в Source Location логично было-бы к папкам src, но если так сделать, то в дереве проекта будут отдельно добавлены эти папки. Чтобы не загромождать визуально дерево, в Source Location можно указать корневые папки Core, CMSIS и Startup.


Для того чтобы проект скомпилировался нужно раскомментировать в файле stm32f0xx.h строку с названием микроконтроллера ну и конечно же в main.c добавить функцию main.


Собственно всё. Безошибочная компиляция и сразу же куда-то подевалось целых полтора килобайта памяти ОЗУ она же RAM, и сразу же вспоминается стек и куча, в процессе создания проекта они нигде не упоминались. Величина стека и кучи указана в файле скрипта линкера, тот что с расширением .ld, их можно и нужно изменять в соответствии с требованиями проекта. Эти значения находятся в начале файла в виде меток _Min_Heap_Size/_Min_Stack_Size с указанием размера в шестнадцатеричном виде.

В качестве примера, приведу небольшой проект традиционного мигания светодиодом.
Светодиод будет мигать на отладочной плате STM32F072B-DISCO, тактирование осуществляться от внутреннего генератора HSI48 частотой 48 МГц, а в качестве источника задержки использоваться таймер SysTick, генерирующий прерывания с периодом в 1 мс, при помощи которых отсчитывается точное время задержки. Светодиод подключен к выводу 6 порта С, настроенного на выход push-pull.
Надеюсь, данная информация кому-то пригодится, т.к. в свое время, несмотря на обилие материалов по программированию STM32, мне пришлось перелопатить достаточно много мануалов, чтобы осознать вещи, кажущиеся сейчас очевидными.