Проект и общая библиотека

В первом уроке мы настроили сборку CMake и подключение CMSIS. Для мигания светодиодом используем отдельный проект f401_led_blink из репозитория курса. Повторять работу мастера создания проекта не потребуется.

Папка Libraries находится на одном уровне с папками проектов. Внутри неё лежит одна копия STM32CubeF4, к которой обращаются оба проекта и смогут обращаться следующие. CMSIS не нужно копировать в каждый новый проект.

Stm32Course2026/
├── Libraries/
│   └── STM32CubeF4/
│       └── Drivers/
│           └── CMSIS/
│               ├── Core/Include/
│               └── Device/ST/STM32F4xx/
├── f401_swd_debug/
└── f401_led_blink/
    ├── CMakeLists.txt
    ├── CMakePresets.json
    ├── Startup/startup_stm32f401retx.s
    └── Sources/main.cpp

STM32CubeF4 записан в репозитории курса как подмодуль Git. Каталог CMSIS Device внутри него тоже является подмодулем. Если репозиторий ещё не получен, откройте PowerShell в выбранном родительском каталоге и выполните:

git clone https://github.com/Annihilatorrr/Stm32Course2026.git
cd .\Stm32Course2026
git submodule update --init Libraries/STM32CubeF4
git -C Libraries/STM32CubeF4 submodule update --init Drivers/CMSIS/Device/ST/STM32F4xx

Если репозиторий уже клонирован, выполните две последние команды из его корня. Они загружают только нужные для этого урока подмодули. Проверьте, что файлы CMSIS появились:

Test-Path .\Libraries\STM32CubeF4\Drivers\CMSIS\Core\Include
Test-Path .\Libraries\STM32CubeF4\Drivers\CMSIS\Device\ST\STM32F4xx\Include
Test-Path .\Libraries\STM32CubeF4\Drivers\CMSIS\Device\ST\STM32F4xx\Source\Templates\system_stm32f4xx.c

Каждая проверка должна вывести True. Если одна из них вывела False, вернитесь к командам инициализации подмодулей и убедитесь, что выполняете их из каталога Stm32Course2026.

Импорт проекта в STM32CubeIDE 2.2.0

Откройте File → STM32 Project Create/Import → Import STM32 Project → STM32 CMake Project. На странице Project with existing CMake sources введите в поле Project name имя f401_led_blink. Оставьте включёнными Use default location и Use default build directory: остальные пути мастер заполнит автоматически. Нажмите Next. На странице Configure default tool-chain settings for the project оставьте Toolchain: MCU ARM GCC, нажмите Select... рядом с полем MCU и выберите STM32F401RETx. Завершите импорт. Проект f401_led_blink появится в Project Explorer.

Проект уже содержит исходники, CMake-пресеты Debug и Release, startup-файл и скрипт компоновщика. Файлы CMSIS остаются в общей папке Libraries, поэтому для успешной сборки важна показанная выше структура каталогов.

Как CMake находит CMSIS

В f401_led_blink/CMakeLists.txt корень библиотеки вычисляется относительно самого CMake-файла:

get_filename_component(STM32CUBEF4_ROOT
    "${CMAKE_CURRENT_LIST_DIR}/../Libraries/STM32CubeF4" ABSOLUTE)

CMAKE_CURRENT_LIST_DIR указывает на f401_led_blink, а .. возвращает нас в корень репозитория. Оттуда CMake переходит в общую папку Libraries/STM32CubeF4. В проекте используются два каталога заголовков и один исходник CMSIS Device:

${STM32CUBEF4_ROOT}/Drivers/CMSIS/Core/Include
${STM32CUBEF4_ROOT}/Drivers/CMSIS/Device/ST/STM32F4xx/Include
${STM32CUBEF4_ROOT}/Drivers/CMSIS/Device/ST/STM32F4xx/Source/Templates/system_stm32f4xx.c

В PROJECT_DEFINES задано STM32F401xE, чтобы заголовки CMSIS выбрали определения нужного микроконтроллера. Все эти пути уже есть в проекте: править CMake перед сборкой не требуется.

Светодиод LD2 и вывод PA5

На NUCLEO-F401RE пользовательский светодиод LD2 связан с выводом PA5. Высокий уровень на выводе включает светодиод, низкий выключает.

Тактирование — это подача регулярных импульсов, по которым работает блок микроконтроллера. После сброса тактирование порта GPIOA отключено: прежде чем настраивать PA5, программа включает его битом GPIOAEN в RCC->AHB1ENR, а затем выбирает режим выхода в GPIOA->MODER.

Сама система после сброса использует внутренний генератор HSI с номинальной частотой 16 МГц. В этом проекте источник и делители системной частоты не меняем; их настройку разберём позже. Включение тактирования GPIOA лишь разрешает работу порта, не повышая частоту процессора.

Регистр GPIOA->BSRR позволяет установить или сбросить уровень вывода записью: GPIO_BSRR_BS5 включает LD2, GPIO_BSRR_BR5 выключает его. Перед переключением PA5 в режим выхода программа записывает низкий уровень, чтобы светодиод не включился в момент настройки.

Мигание в основном цикле

В f401_led_blink/Sources/main.cpp после подключения заголовка CMSIS задана короткая пауза, а в main() последовательно настраивается GPIOA и повторяется включение и выключение LD2:

#include <cstdint>

#include "stm32f4xx.h"

namespace {

constexpr std::uint32_t kDelayIterations = 2'000'000U;

void delay()
{
    for (std::uint32_t i = 0; i < kDelayIterations; ++i) {
        __NOP();
    }
}

}  // namespace

int main()
{
    RCC->AHB1ENR = RCC->AHB1ENR | RCC_AHB1ENR_GPIOAEN;
    (void)RCC->AHB1ENR;

    GPIOA->BSRR = GPIO_BSRR_BR5;
    GPIOA->MODER = (GPIOA->MODER & ~GPIO_MODER_MODER5) | GPIO_MODER_MODER5_0;

    for (;;) {
        GPIOA->BSRR = GPIO_BSRR_BS5;
        delay();
        GPIOA->BSRR = GPIO_BSRR_BR5;
        delay();
    }
}

Чтение RCC->AHB1ENR после включения тактирования отделяет эту запись от первого обращения к GPIOA. Выражение с GPIO_MODER_MODER5 очищает оба бита режима PA5, а GPIO_MODER_MODER5_0 выбирает обычный цифровой выход. Бесконечный цикл включает светодиод, ждёт, выключает его и снова ждёт.

Сборка в STM32CubeIDE

В Project Explorer выберите f401_led_blink и конфигурацию сборки Debug. Затем запустите Project → Build Project. После сборки должен появиться файл f401_led_blink/Debug/f401_led_blink.elf. Это прошивка с отладочной информацией; одна сборка ещё не записывает её во Flash платы.

Если CMake сообщает, что не найдены заголовки или system_stm32f4xx.c, проверьте результаты Test-Path и расположение папки Libraries. Если CubeIDE не находит компилятор, проверьте настройку MCU Toolchain импортированного проекта.

Запуск и проверка на плате

Подключите NUCLEO-F401RE через USB-разъём встроенного ST-LINK. В Project Explorer откройте для проекта Debug As → Debug Configurations..., выберите STM32 C/C++ Application и создайте конфигурацию f401_led_blink Debug.

  1. На вкладке Main выберите проект f401_led_blink и приложение Debug/f401_led_blink.elf.
  2. На вкладке Debugger выберите встроенный ST-LINK и интерфейс SWD.
  3. На вкладке Startup проверьте, что для нужного ELF включены Download и Load symbols. Для пошаговой проверки включите Set breakpoint at: main.
  4. Нажмите Apply, затем Debug. Если выполнение остановилось на main(), нажмите Resume или F8.

LD2 должен попеременно загораться и гаснуть. Чтобы в дальнейшем записывать прошивку и запускать её без остановки в main(), откройте Run As → Run Configurations... и запустите ту же конфигурацию через Run. Перед новым запуском после правок в main.cpp снова выполните Build Project.

Исходный код

GitHub: Stm32Course2026. Проект этого урока — f401_led_blink, путь: Stm32Course2026/f401_led_blink.