Компиляция проекта для HAL STM32F103C8T6 STM32CubeMX в среде Clion 2016.2 (cmake) и arm-none-eabi-gcc

Для сборки проекта, использующего воможности автоматической генерации кода HAL для указанного (или большинства других) микроконтроллеров следует выполнить такие шаги:

  1. Генерация проекта в STM32CubeMX
  2. Импорт проекта в Clion
  3. Разработка своего или коррекция чужого CMAKE_TOOLCHAIN_FILE для обеспечения возможностей кросс-платфрменной компиляции
  4. Настройка cmake для сборки проекта

Для любого начинающего, первое погружение в технологию всегда сложно. И я не исключение.

Когда я решил использовать микроконтроллеры семейства arm в первый раз, то поразился, насколько разительна разница между самими микроконтроллерами и стеком программных технологий над ними. Совершенство микроконтроллеров полностью перекрывается страшно питекантропскими подходами для обеспечения удобства работы с ними.

Большинство комментариев от “сообщества”, которые мне удалось собрать относились к двум одинаково тупым (с моей дилетантской точки зрения) позициям:

  1. Часть людей страшно гордится возможностью писать “на низком уровне” и с презрением отсылает всех к ассемблеру, регистрам, vim и даташитам.
  2. Вторая большая часть сообщества использует единожды зарекомендовавшие себя рецепты в виде сочетания библиотек, сред разработки (чаще всего либо ворованных, либо какой-то странный, нишевый opensource). Своё тайное знание с презрением вываливает на всех вокруг, понося все альтернативы как еретические.

И лишь небольшая часть людей относится взвешено и без фанатизма к проблеме, не переоценивает ценность всех этих “знаний” и, к сожалению, чаще всего не пишет никуда.

По-моему мнению, истина где-то там. Даташиты — это всегда прекрасно и читать их необходимо. Также здорово, когда средство разработки обеспечивает тебе самое главное: возможность быстрого и эфективного рефакторинга. Все эти блокноты с кнопками, вимы и прочие скрипты — это из 80-90 годов прошлого века. Заниматься этим может либо гений (я вполне допускаю это), либо идиот.


Всё это фигня, которая не относится к теме. Если мне будет интересно, то напишу позже свой анализ всей этой ситуации и причины появления автогенерации HAL для микроконтроллеров ST.

Cmake далеко не предел моих мечтаний. Жутко имплицитная штука. Работать с ней противно и я был вынужден делать это просто для сборки под CLion, который мне обоснованно нравится. Intellij (долгих им лета), одна из немногих российских компаний, которая за последние 15 лет вызывала у меня только гордость. Талантливые ребята, гениальные продукты.

По-моему мнению, как средство сборки, QBS от QtCreator лучше (a как среда разработки CLion совершенне, даже с несовершенным cmake). Лучше QBS ситема сборки тем, что это, по всей видимости, QBS это не набор “magic words”, а обычный JavaScript и он прозрачнее и предсказуемее, расширяемее и более отлаживаемый, чем cmake. В целом-же, вынужден констатировать, что за последние 30 лет мало что поменялось: сборка C, C++ и ASM это по-прежнему адская боль. Makefiles и прочий дремучий изврат оставляю на “профессионалов”. Им оно как-то сподручнее ковыряться в этом всём. В vim-е.

Предусловия

  1. Ставим arm-none-eabi-gcc для своей платформы
  2. Clion
  3. STM32CubeMX (нужна JRE >= 1.7)

Автогенерация кода HAL для выбранного uK

Загружаете STM32CubeMX. Запускаете. Генерируете.

На что обратить внимание НОВИЧКАМ:

  1. Сначала вы видите фильтр микроконтроллеров. Здесь следует выбрать с чем Вы будете работать.
  2. Чаще всего Вам потребуется выбрать наличие внешнего источника генерации тактовых импульсов (если на вашей плате он есть) в разделе RCС. По-умолчанию, считается, что работаете вы от калиброванного внутреннего источника.
  3. Следует обязательно включить необходимые опции в разделе SYS. А то всё соберётся, а работать не будет.
  4. Во второй вкладке возможна автоматическая настройка делителей генератора. Очень удобная штука. Не забываем, что появление внешнего генератора возможно на первой вкладке.
  5. На третьей вкладке настраиваете модули. Включаете DMA, если нужно и т.п.

Потом дуем в меню ProjectSettings... и выбираем для кого компилируем. Берите SW4STM32. По-большому счёту, почти без разницы. Всё равно всё выпилим.

Всё объяснять нет никакого смысла. CubeMX реально понятен. По-крайней мере мне так кажется.

Закончив играться, жмём ProjectGenerate Code.

Импорт проекта в Clion

Тут всё понятно. Удаляем лишние файлы. На что обратить внимание:

  1. Нам очень-очень нужен файл-скрипт для линковщика. Он лежит в корне скомпилированного проекта и называется как-то так: STM32F103C8Tx_FLASH.ld. ЕГО ОСТАВЛЯЕМ!
  2. Также оставляем все папочки Drivers, Inc, Src.

Отслальное:

“...резать к чёртовой матери не дожидаясь перетонита!” (С)

CMAKE_TOOLCHAIN_FILE

Когда создатели cmake создали и наслаждались своим творением, они думали об удобстве создания, сборки ПО на определённой платформе.

О кросс-компиляции они точно не думали. Поэтому всё, что касается кросс-компиляции было вкручено потом и на костылях. Главный такой костыль — файл, который они называют CMAKE_TOOLCHAIN_FILE c расширением .cmake, который указывается в качестве параметра, определяемого, когда cmake только стартует. Определяется в CLion он вот так:

Файл называется (в моём случае) STM32F103C8T6.cmake и представляет собой приблизительно вот это:

STM32F103C8T6.cmake

include(CMakeForceCompiler)

set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR cortex-m3)

# Find the cross compiler
find_program(ARM_CC arm-none-eabi-gcc
            ${TOOLCHAIN_DIR}/bin)
find_program(ARM_CXX arm-none-eabi-g++
            ${TOOLCHAIN_DIR}/bin)
find_program(ARM_OBJCOPY arm-none-eabi-objcopy
            ${TOOLCHAIN_DIR}/bin)
find_program(ARM_SIZE_TOOL arm-none-eabi-size
            ${TOOLCHAIN_DIR}/bin)
find_program(ARM_AS arm-none-eabi-as
            ${TOOLCHAIN_DIR}/bin)


CMAKE_FORCE_C_COMPILER(${ARM_CC} GNU)
CMAKE_FORCE_CXX_COMPILER(${ARM_CXX} GNU)

set(COMMON_FLAGS
        "-fno-common -ffunction-sections -fdata-sections")

set(CMAKE_ASM_FLAGS
        ${CMAKE_ASM_FLAGS} "-mcpu=cortex-m3 -mthumb")

if (CMAKE_SYSTEM_PROCESSOR STREQUAL cortex-m3)
    set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS}
            "-mcpu=cortex-m3 -mthumb -mthumb-interwork -msoft-float")
else ()
    message(WARNING
                    Processor not recognised in toolchain file,
                    compiler flags not configured.)
endif ()

set(LINKER_SCRIPT ${PROJECT_SOURCE_DIR}/STM32F103C8Tx_FLASH.ld)

set(CMAKE_EXE_LINKER_FLAGS "-Wl,-gc-sections -T ${LINKER_SCRIPT}")

# fix long strings (CMake appends semicolons)
string(REGEX REPLACE ";" " " CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}" CACHE STRING "")
set(BUILD_SHARED_LIBS OFF)

и позволяет собрать на текущей платформе код для другой-целевой. Короче — кросс-компиляция.

обратить внимание

  1. На имена файлов, на которые вы ссылаетесь. Внимательно!
  2. На ключи. Убедитесь, что они соответствуют вашему uK
  3. На выставленную переменную (на скриншоте TOOLCHAIN_DIR)

Теперь мы определяем файл, который будет заниматься сборкой:

CMakeLists.txt

Его листинг для моего случая представлен ниже:

project(STM23F103C8T6 C CXX ASM)
cmake_minimum_required(VERSION 3.5.0)

set(CMAKE_VERBOSE_M‌​AKEFILE ON)

add_definitions(-DSTM32F103x6)


file(GLOB_RECURSE USER_SOURCES Src/*.c)
file(GLOB_RECURSE HAL_SOURCES Drivers/STM32F1xx_HAL_Driver/Src/*.c)

add_library(CMSIS)

target_sources(CMSIS
        PUBLIC
        ${PROJECT_SOURCE_DIR}/Drivers/CMSIS/Device/ST/STM32F1xx/Source/Templates/system_stm32f1xx.c
        ${PROJECT_SOURCE_DIR}/Drivers/CMSIS/Device/ST/STM32F1xx/Source/Templates/gcc/startup_stm32f103xb.s)

include_directories(
        Drivers/CMSIS/Device/ST/STM32F1xx/Include
        Drivers/CMSIS/Include
        Drivers/STM32F1xx_HAL_Driver/Inc
        Inc)

add_executable(${PROJECT_NAME}.elf ${USER_SOURCES} ${HAL_SOURCES} ${LINKER_SCRIPT})

target_link_libraries(${PROJECT_NAME}.elf CMSIS)


set(HEX_FILE ${PROJECT_SOURCE_DIR}/build/${PROJECT_NAME}.hex)
set(BIN_FILE ${PROJECT_SOURCE_DIR}/build/${PROJECT_NAME}.bin)

add_custom_command(TARGET ${PROJECT_NAME}.elf POST_BUILD
        COMMAND ${CMAKE_OBJCOPY} -Oihex $<TARGET_FILE:${PROJECT_NAME}.elf> ${HEX_FILE}
        COMMAND ${CMAKE_OBJCOPY} -Obinary $<TARGET_FILE:${PROJECT_NAME}.elf> ${BIN_FILE}
        COMMENT Building ${HEX_FILE} \nBuilding ${BIN_FILE})

Обратить внимание

  1. add_definitions(-DSTM32F103x6) — найдите соответствующий вашему uK дефинишен в заголовочном файле Drivers/CMSIS/Device/ST/STM32F1xx/Include/stm32f1xx.h
  2. Сборка может быть осуществлена под любой интересующий профиль. От отладочного до минимального по размеру. (у меня минимальный получился 18K.18K, Карл! И при этом там только DMA, I2C и USART). Предварительный анализ показал, что в STM тоже есть чудаки-программисты. Очень ни любят условную компиляцию. Видать к vim-у приучены.
  3. В проекте есть один ассемблерный файл, определяющий поведение начальной инициализации и точку входа _start. Его компиляция и компиляция ещё одного шаблонного файла объединены в малюсенькую библиотеку CMSIS.

Вроде всё. Если Вы всё сделали внимательно, то у вас после BuildAll должен получиться “папка”, с результатами компиляции.

Прошивка, отладка и т.п. будет дальше. Дальше будут и размышления, зачем нам нужен HAL, если есть регистры, зачем нам нужен рефакторинг, когда есть мозги и прочие темы. И так больше чем планировал нынче получилось.

Опубликовано 11 августа 2016 г.

Лахтин Станислав Евгеньевич

Комментарии

Комментарий находится на премодерации и не доступен для просмотра.

Ваш комментарий