Создание проекта в STM32CubeIDE
В STM32CubeIDE 2.2.0 откройте File → STM32 Project Create/Import → Create New STM32 Project → STM32 CMake Project. В мастере выберите микроконтроллер STM32F401RETx и тип проекта Executable. Назовите проект FirstProject. Укажите родительский каталог для проектов: IDE создаст внутри него папку с именем проекта.
STM32F401RETx обозначает семейство и корпус микроконтроллера, установленного на NUCLEO-F401RE. На этом шаге мы выбираем чип, для которого компилятор и компоновщик подготовят прошивку. Сам проект пока ничего не делает с выводами платы.
Файлы, созданные мастером
| Файл | Назначение |
|---|---|
CMakeLists.txt |
Перечисляет исходники, заголовочные пути, определения и параметры сборки. |
CMakePresets.json |
Хранит настройки сборок Debug и Release. |
cubeide-gcc.cmake |
Выбирает компиляторы arm-none-eabi-gcc и arm-none-eabi-g++. |
Startup/startup_stm32f401retx.s |
Содержит таблицу векторов и код, запускаемый после сброса. |
STM32F401RETX_FLASH.ld |
Размещает код и данные во Flash и RAM микроконтроллера. |
Sources/main.c |
Исходная точка прикладной программы; позже переименуем файл в main.cpp. |
Startup-файл и скрипт компоновщика остаются частью проекта при переходе на C++. Компилятор собирает исходники в объектные файлы, а компоновщик по правилам .ld создаёт прошивку в формате ELF. Вкладка CMake управляет составом этой прошивки.
Подключение CMSIS
Для обращения к регистрам по именам нужны две части CMSIS. CMSIS Core описывает ядро Cortex-M4, а CMSIS Device содержит определения для STM32F401, включая RCC и GPIOA. Добавим нужные файлы в сам проект FirstProject.
- Мы используем STM32CubeIDE 2.2.0. В этой версии IDE нет встроенного средства для загрузки пакетов STM32Cube, поэтому скачайте архив STM32CubeF4 с сайта ST (кнопка Get latest) и распакуйте его. В распакованном пакете найдите папку
STM32Cube_FW_F4_V…/Drivers/CMSIS. - В Project Explorer щёлкните правой кнопкой по
FirstProjectи выберите New → Folder: создайте папкуDrivers. Так же создайте внутри неё папкуCMSIS. - В STM32CubeIDE выберите File → Import… → General → File System. В поле исходного каталога укажите папку
Drivers/CMSISвнутри распакованного пакетаSTM32Cube_FW_F4_V…, а в качестве назначения —FirstProject/Drivers/CMSIS. - В дереве импорта отметьте
Core/Include,Device/ST/STM32F4xx/Includeи файлDevice/ST/STM32F4xx/Source/Templates/system_stm32f4xx.c. Нажмите Finish. Сохраните вложенные каталоги: они нужны для путей вCMakeLists.txt.
Правки в CMakeLists.txt
Мастер уже заполнил списки PROJECT_SOURCES, PROJECT_DEFINES и PROJECT_INCLUDES в CMakeLists.txt. Сохраните их содержимое и добавьте в эти списки файлы CMSIS из папки проекта.
В существующий set(PROJECT_SOURCES ...) перед закрывающей скобкой добавьте строку:
Drivers/CMSIS/Device/ST/STM32F4xx/Source/Templates/system_stm32f4xx.c
В существующий set(PROJECT_INCLUDES ...) перед закрывающей скобкой добавьте две строки:
Drivers/CMSIS/Core/Include
Drivers/CMSIS/Device/ST/STM32F4xx/Include
Если system_stm32f4xx.c или указанные каталоги CMSIS уже есть в списках мастера, не добавляйте их повторно. Проверьте также, что в существующем PROJECT_DEFINES есть STM32F401xE; добавьте его только при отсутствии. Пути Drivers/CMSIS/... отсчитываются от каталога FirstProject, где находится CMakeLists.txt. Определение STM32F401xE выбирает в заголовках описание нужного микроконтроллера. Файл system_stm32f4xx.c предоставляет SystemInit(), который вызывает startup-файл.
В этом же шаблоне проверьте согласованность параметров ядра и FPU: для STM32F401 используется Cortex-M4, -mfpu=fpv4-sp-d16 и -mfloat-abi=hard. Одинаковые настройки должны применяться ко всем C и C++ исходникам проекта.
Переход на C++20
Переименуйте Sources/main.c в Sources/main.cpp. В PROJECT_SOURCES замените строку Sources/main.c на Sources/main.cpp. Файлы syscalls.c, sysmem.c и system_stm32f4xx.c остаются исходниками C.
При переименовании удалите из сгенерированного файла блок с предупреждением FPU is not initialized. Startup-файл вызывает SystemInit() из system_stm32f4xx.c до main(); этот код включает FPU. Оставшееся предупреждение при -Werror остановит сборку.
В верхнем блоке настроек CMakeLists.txt задайте стандарт C++20, а рядом с существующим CMAKE_C_FLAGS укажите флаги для C++:
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_FLAGS
"${MCPU} ${MFPU} ${MFLOAT_ABI} ${RUNTIME_LIBRARY} -mthumb -Wall -Werror")
Первый блок требует именно C++20. Вторая настройка передаёт C++ компилятору параметры ядра, FPU и ABI, уже используемые для C. При сборке main.cpp компилирует arm-none-eabi-g++. Если редактор CubeIDE по-прежнему воспринимает проект только как C, добавьте внутри <natures> файла .project строку <nature>org.eclipse.cdt.core.ccnature</nature>.
Итоговый CMakeLists.txt
После подключения CMSIS и перехода на C++20 файл FirstProject/CMakeLists.txt должен выглядеть так. В нём сохранены параметры и исходники, созданные мастером:
#############################################################################################################################
# file: CMakeLists.txt
# brief: Template "CMakeLists.txt" for building of executables and static libraries.
#
# usage: Edit "VARIABLES"-section to suit project requirements.
# For debug build:
# cmake -DCMAKE_TOOLCHAIN_FILE=cubeide-gcc.cmake -S ./ -B Debug -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug
# make -C Debug VERBOSE=1 -j
# For release build:
# cmake -DCMAKE_TOOLCHAIN_FILE=cubeide-gcc.cmake -S ./ -B Release -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Release
# make -C Release VERBOSE=1 -j
#############################################################################################################################
cmake_minimum_required(VERSION 3.20)
###################### CONSTANTS ######################################
set (PROJECT_TYPE_EXECUTABLE "exe")
set (PROJECT_TYPE_STATIC_LIBRARY "static-lib")
set (MCPU_CORTEX_M0 "-mcpu=cortex-m0")
set (MCPU_CORTEX_M0PLUS "-mcpu=cortex-m0plus")
set (MCPU_CORTEX_M3 "-mcpu=cortex-m3")
set (MCPU_CORTEX_M4 "-mcpu=cortex-m4")
set (MCPU_CORTEX_M7 "-mcpu=cortex-m7")
set (MCPU_CORTEX_M33 "-mcpu=cortex-m33")
set (MCPU_CORTEX_M55 "-mcpu=cortex-m55")
set (MCPU_CORTEX_M85 "-mcpu=cortex-m85")
set (MFPU_FPV4_SP_D16 "-mfpu=fpv4-sp-d16")
set (MFPU_FPV4 "-mfpu=vfpv4")
set (MFPU_FPV5_D16 "-mfpu=fpv5-d16")
set (RUNTIME_LIBRARY_REDUCED_C "--specs=nano.specs")
set (RUNTIME_LIBRARY_STD_C "")
set (RUNTIME_LIBRARY_SYSCALLS_MINIMAL "--specs=nosys.specs")
set (RUNTIME_LIBRARY_SYSCALLS_NONE "")
set (MFLOAT_ABI_SOFTWARE "-mfloat-abi=soft")
set (MFLOAT_ABI_HARDWARE "-mfloat-abi=hard")
set (MFLOAT_ABI_MIX "-mfloat-abi=softfp")
#######################################################################
###################### VARIABLES ######################################
set (PROJECT_NAME "FirstProject")
set (PROJECT_TYPE "exe")
set (LINKER_SCRIPT "../STM32F401RETX_FLASH.ld")
set (MCPU "-mcpu=Cortex-M4")
set (MFPU "-mfpu=fpv4-sp-d16")
set (MFLOAT_ABI "-mfloat-abi=hard")
set (RUNTIME_LIBRARY "--specs=nano.specs")
set (RUNTIME_LIBRARY_SYSCALLS "--specs=nosys.specs")
set (CMAKE_CXX_STANDARD 20)
set (CMAKE_CXX_STANDARD_REQUIRED ON)
set (CMAKE_CXX_EXTENSIONS OFF)
set (PROJECT_SOURCES
Startup/startup_stm32f401retx.s
Sources/main.cpp
Sources/syscalls.c
Sources/sysmem.c
Drivers/CMSIS/Device/ST/STM32F4xx/Source/Templates/system_stm32f4xx.c
)
set (PROJECT_DEFINES
STM32F401xE
)
set (PROJECT_INCLUDES
Drivers/CMSIS/Core/Include
Drivers/CMSIS/Device/ST/STM32F4xx/Include
)
#######################################################################
################## PROJECT SETUP ######################################
project(${PROJECT_NAME})
enable_language(ASM)
if (${PROJECT_TYPE} MATCHES ${PROJECT_TYPE_EXECUTABLE})
add_executable(${PROJECT_NAME} ${PROJECT_SOURCES})
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_SIZE} $<TARGET_FILE:${CMAKE_PROJECT_NAME}>)
elseif (${PROJECT_TYPE} MATCHES ${PROJECT_TYPE_STATIC_LIBRARY})
add_library(${PROJECT_NAME} ${PROJECT_SOURCES})
endif()
add_compile_definitions (${PROJECT_DEFINES})
include_directories (${PROJECT_INCLUDES})
set (CMAKE_EXECUTABLE_SUFFIX ".elf")
set (CMAKE_STATIC_LIBRARY_SUFFIX ".a")
set (CMAKE_C_FLAGS "${MCPU} -std=gnu11 ${MFPU} ${MFLOAT_ABI} ${RUNTIME_LIBRARY} -mthumb -Wall -Werror")
set (CMAKE_CXX_FLAGS "${MCPU} ${MFPU} ${MFLOAT_ABI} ${RUNTIME_LIBRARY} -mthumb -Wall -Werror")
set (CMAKE_EXE_LINKER_FLAGS "-T${LINKER_SCRIPT} ${RUNTIME_LIBRARY_SYSCALLS} -Wl,-Map=test.map -Wl,--gc-sections -static -Wl,--start-group -lc -lm -Wl,--end-group")
set (CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS} -x assembler-with-cpp")
Сборка Debug
Выберите конфигурацию Debug и запустите в STM32CubeIDE Build Project. В результате должен появиться Debug/FirstProject.elf. Это исполняемый файл для микроконтроллера вместе с информацией, по которой отладчик связывает машинные инструкции с исходным кодом.
Здесь main() пока содержит только бесконечный цикл. Сборка подтверждает, что исходники и CMSIS связаны правильно, но сама по себе не записывает программу на плату.
Подключение платы
Подключите NUCLEO-F401RE к компьютеру через разъём встроенного ST-LINK. Отдельный программатор и провода к выводам микроконтроллера для этой платы не требуются: ST-LINK уже соединён с целевым STM32 по интерфейсу SWD. STM32CubeIDE использует это соединение для записи прошивки и отладки.
Конфигурация отладки Debug
В Project Explorer щёлкните правой кнопкой мыши по проекту и выберите Debug As → Debug Configurations.... В левой части окна выберите STM32 C/C++ Application и создайте новую конфигурацию кнопкой с изображением чистого листа. Назовите её, например, FirstProject Debug.
- На вкладке Main выберите проект
FirstProjectи приложениеDebug/FirstProject.elf. Проверьте, что указан ELF текущей сборки Debug. - На вкладке Debugger выберите встроенный ST-LINK и режим SWD.
- На вкладке Startup в таблице Load Image and Symbols найдите строку с нужным ELF. В её столбцах Download и Load symbols должны стоять отметки. Включите Set breakpoint at: main.
- На вкладке Common выберите сохранение конфигурации как Shared file в каталоге проекта, чтобы файл
.launchможно было хранить вместе с исходниками. Нажмите Apply, затем Debug.
CubeIDE запишет ELF во Flash и подключит отладчик. Если выполнение остановилось в main, исходный файл и текущая строка будут видны в редакторе. Нажмите Resume или F8, чтобы программа продолжила работу. В пустом проекте после этого не будет видимого эффекта на плате: бесконечный цикл пока ничего не делает.
Запуск без отладки (Run)
Для записи прошивки и запуска без пошаговой отладки откройте у проекта Run As → Run Configurations.... В разделе STM32 C/C++ Application выберите уже созданную конфигурацию FirstProject Debug. Убедитесь, что на вкладке Main указан Debug/FirstProject.elf, затем нажмите Run. Отдельную конфигурацию для Run создавать не обязательно: одну конфигурацию можно запускать и кнопкой Debug, и кнопкой Run.
Debug открывает сеанс отладки: можно останавливать программу, смотреть регистры и выполнять код по шагам. Run записывает прошивку и запускает её без остановки в main и пошаговой отладки. Слово Debug в пути к ELF обозначает конфигурацию сборки, а не режим запуска. Отдельная конфигурация запуска понадобится, только если вы захотите использовать другой ELF или другие параметры. При изменении исходников сначала пересоберите Debug, чтобы в обоих случаях использовался новый ELF.