Введение
Привет всем.
На данный момент я активно осваиваю разработку ПО для STM32 и хотел бы поделиться моим опытом.
Как известно, для STM32 имеется много сред для разработки, однако часть из них, несмотря на удобность, имеют ограничения по использованию в случае пробной версии. Так, для IAR размер прошивки ограничивается 32 кБ, что весьма немного.
В данной публикации будет рассмотрен способ настройки окружения для полноценной разработки и отладки ПО для микроконтроллеров STM32 в среде QtCreator.
Прежде всего, определимся, что нам понадобится для проведения экспериментов.
Железо
В качестве примера я использую плату bluepill на базе STM32F103C8T6. В моем случае openocd жаловался на некорректный номер STM32. Решается 2 способами: или подменой номера в конфиге openocd или заменой МК на оригинальный. Я выбрал 2 вариант. Для загрузки и отладки программ в МК будем использовать интерфейс ST-Link.
Софт
Сами эксперименты проводились на виртуальной машине ОС Windows 10 в Virtual Box.
Для настройки окружения понадобится следующее ПО:
QtCreator. Можно скачать онлайн-установщик с сайта Qt. Но в нем при установке требуется регистрация и, кроме того, нам нужен только сам QtCreator. Поэтому я обычно его скачиваю непосредственно с GitHub. https://github.com/qt-creator/qt-creator/tags.
gcc-arm-none-eabi. https://developer.arm.com/downloads/-/gnu-rm.
Git. https://git-scm.com/downloads.
openocd. https://github.com/openocd-org/openocd/tags. Это программа для загрузки прошивки и отладки микроконтроллера STM.
ST-LINK Utility. Программа для прошивки STM32 + драйвер для самого ST-Link. https://www.st.com/en/development-tools/stsw-link004.html
Python2.7. https://www.python.org/downloads/release/python-2718/
Прежде всего, скачиваем и распаковываем QtCreator. Затем гит, компилятор, openocd, python, make и st-link.
QtCreator и openocd распаковал в C:\Tools. Все программы, кроме QtCreator, должны быть добавлены в Path.
Проверяем, что компилятор и openocd подтянулись в path вызовом из командной строки.
Далее перейдем к настройке QtCreator.
Настройка QtCreator
Запускаем QtCreator. Для работы нужно установить плагины BareMetal и GenericProjectManager. Для этого идем в Help->About Plugins. После настройки перезапускаем QtCreator.
Переходим в Edit->Preferences. Выбираем Kits слева. Тут видим наш комплект для сборки ARM, который подтянулся из Path. Идем в раздел Devices на вкладку Bare Metal и добавляем OpenOCD server. Выбираем название, в моем случае OpenOCD-STM32F103.
В поле Executable file пишем путь к нашему openocd (по-идее, можно взять из path).
В поле Root scripts directory указываем на директорию со скриптами в openocd.
В поле Additional arguments указываем аргументы для прошивки MK. В нашем случае конфиг для STLink и target. Применяем.
Переходим на вкладку Devices. Нажимаем Add->Bare Metal Device и Start Wizard. В появившемся окне выбираем Debug server provider ранее созданный OpenOCD-STM32F103. Далее Finish.
Возвращаемся в Kits и донастраиваем наш комплект. Выбираем Device type и Device – Bar Metal Device. Применяем.
На этом QtCreator пока откладываем и переходим к настройке самого проекта.
Настройка проекта
Теперь можно приступить непосредственно к созданию и настройке репозитория. Создадим простейший проект на CMSIS, который будет моргать светодиодами.
Прежде всего, нужно подтянуть необходимые библиотеки в виде submodules из официальных репозиториев ARM и ST. Открываем bash-терминал, который устанавливается с git. Создадим папку led_blink_cmsis и перейдем в нее.
mkdir led_blink_cmsis && cd led_blink_cmsis
Внутри создадим папки build, lib и src.
mkdir build && mkdir src && mkdir lib
В папке build будут артефакты сборки, в src – наши исходники, а в lib – сторонние библиотеки.
Инициализируем git.
git init
Далее добавим сторонние библиотеки cmsis для билда с использованием git submodules. Первая библиотека – форк от ARM, вторая содержит настройки и определения для STM32 семейства F1.
git submodule add https://github.com/STMicroelectronics/cmsis_core lib/cmsis_core && cd lib/cmsis_core
git checkout v5.6.0 && cd ../..
git submodule add https://github.com/STMicroelectronics/cmsis_device_f1 lib/cmsis_device_f1 && cd lib/cmsis_device_f1
git checkout v4.3.3 && cd ../..
Git checkout здесь необходим, чтобы использовать релизные версии библиотек, в данном случае 5.6.0 и 4.3.3 для cmsis_core и cmsis_device соответственно.
Далее создадим файлы main.c, init.h и init.c в папке src, в которых будем писать исходный код.
touch src/main.c src/init.h src/init.c
Наполним файлы кодом. В файле main.c находится код, которые включает и выключает светодиод, а также вызывает функции clock_init и port_init. Эти функции настраивает тактовую частоту МК и тактирование от кварца, а также работу порта C на выход в режиме пуш-пулл. Кроме того, init.c содержит реализацию функции delay_ms.
main.c
#include "init.h"
int main(void)
{
clock_init(); //Clock initialisation
port_init(); //Port initialisation
while(1)
{
GPIOC->BSRR = GPIO_BSRR_BR13; //Pin 13 of PORT C on
delay_ms(100);
GPIOC->BSRR = GPIO_BSRR_BS13; //Pin 13 of PORT C off
delay_ms(100);
}
return 0;
}
init.h
#ifndef STM32F103xB
#define STM32F103xB
#endif
#include "stm32f1xx.h"
int clock_init();
void port_init();
void delay_ms(uint16_t);
init.c
#include "init.h"
volatile uint32_t SysTickDelayMsec = 0;
void SysTick_Handler(void)
{
--SysTickDelayMsec;
}
/*
OSC - 8 MHz
PLLSRC - 8 MHz
SYSCLK - 16 MHz
PLL - 2
AHB - 1/16
*/
int clock_init()
{
RCC->CR |= RCC_CR_HSEON; //Start HSE generator
for(volatile int StartUpCounter = 0; ; ++StartUpCounter) //Wait for successfull start or timeout
{
if(RCC->CR & RCC_CR_HSERDY) //If started successfully, break the cycle
{
break;
}
if(StartUpCounter > 4096) //If not started - turn off and return an error
{
RCC->CR &= ~RCC_CR_HSEON; //Stop HSE
return 1;
}
}
RCC->CFGR = 0; //PLL mult is equal 2
RCC->CFGR |= RCC_CFGR_PLLSRC; //Clock PLL from HSE
RCC->CR |= RCC_CR_PLLON; //Start PLL
for(volatile int StartUpCounter = 0; ; ++StartUpCounter) //Wait for successfull start or timeout
{
if(RCC->CR & RCC_CR_PLLRDY) //If started successfully, break the cycle
{
break;
}
if(StartUpCounter > 4096) //If PLL didn't start , turn off everything and return an error
{
RCC->CR &= ~RCC_CR_HSEON; //Stop HSE
RCC->CR &= ~RCC_CR_PLLON; //Stop PLL
return 2;
}
}
FLASH->ACR |= FLASH_ACR_LATENCY; //0 cycles for flash, core clock 16 MHz
RCC->CFGR |= RCC_CFGR_PPRE2; //APB2 turned off (0 by default)
RCC->CFGR |= RCC_CFGR_HPRE_3 |
RCC_CFGR_HPRE_1 |
RCC_CFGR_HPRE_0; //AHB prescaler 16
RCC->CFGR |= RCC_CFGR_SW_1; //Switch to PLL
while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); //Wait for switch to PLL
RCC->CR &= ~RCC_CR_HSION; //Turn off the internal clock for energy save
SystemCoreClockUpdate(); //Apply alterations to generator
SysTick_Config(SystemCoreClock/1000); //Initialisation of interrupt (1 ms)
return 0; //Return 0 if success
}
void port_init()
{
RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; //Turn on clock for GPIOC
GPIOC->CRH = 0;
GPIOC->CRH |= GPIO_CRH_MODE13; //Pin 13 of PORT C in Push-Pull mode
GPIOC->BSRR |= GPIO_BSRR_BR13; //Pin 13 of PORT C reset
}
void delay_ms(uint16_t msec) //Delay function
{
SysTickDelayMsec = msec;
while (SysTickDelayMsec);
}
И, наконец, добавим в проект Makefile, в соответствии с которыми будут собираться наша прошивка. Шаблон этого файла взят из генератора кода mxcube и адаптирован под текущий проект. Файл имеет следующее содержание.
Makefile
######################################
# target
######################################
TARGET = mppt_firmware
######################################
# building variables
######################################
DEBUG = 1
OPT = -O0
#######################################
# paths
#######################################
BUILD_DIR = build
######################################
# source
######################################
C_SOURCES = \
src/main.c \
src/init.c \
lib/cmsis_device_f1/Source/Templates/system_stm32f1xx.c
ASM_SOURCES = \
lib/cmsis_device_f1/Source/Templates/gcc/startup_stm32f103xb.s
#######################################
# binaries
#######################################
PREFIX = arm-none-eabi-
ifdef GCC_PATH
CC = $(GCC_PATH)/$(PREFIX)gcc
AS = $(GCC_PATH)/$(PREFIX)gcc -x assembler-with-cpp
CP = $(GCC_PATH)/$(PREFIX)objcopy
SZ = $(GCC_PATH)/$(PREFIX)size
else
CC = $(PREFIX)gcc
AS = $(PREFIX)gcc -x assembler-with-cpp
CP = $(PREFIX)objcopy
SZ = $(PREFIX)size
endif
HEX = $(CP) -O ihex
BIN = $(CP) -O binary -S
#######################################
# CFLAGS
#######################################
CPU = -mcpu=cortex-m3
MCU = $(CPU) -mthumb $(FPU) $(FLOAT-ABI)
AS_DEFS =
C_DEFS = \
-DSTM32F103xB
AS_INCLUDES =
C_INCLUDES = \
-Isrc \
-Ilib/cmsis_core/Include \
-Ilib/cmsis_device_f1/Include
ASFLAGS = $(MCU) $(AS_DEFS) $(AS_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections
CFLAGS = $(MCU) $(C_DEFS) $(C_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections
ifeq ($(DEBUG), 1)
CFLAGS += -g -gdwarf-2
endif
CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)"
#######################################
# LDFLAGS
#######################################
LDSCRIPT = lib/cmsis_device_f1/Source/Templates/gcc/linker/STM32F103XB_FLASH.ld
LIBS = -lc -lm -lnosys
LIBDIR =
LDFLAGS = $(MCU) -specs=nano.specs -T$(LDSCRIPT) $(LIBDIR) $(LIBS) -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref -Wl,--gc-sections
#######################################
# build the application
#######################################
all: $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin
OBJECTS = $(addprefix $(BUILD_DIR)/,$(notdir $(C_SOURCES:.c=.o)))
vpath %.c $(sort $(dir $(C_SOURCES)))
OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(ASM_SOURCES:.s=.o)))
vpath %.s $(sort $(dir $(ASM_SOURCES)))
$(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR)
$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@
$(BUILD_DIR)/%.o: %.s Makefile | $(BUILD_DIR)
$(AS) -c $(CFLAGS) $< -o $@
$(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) Makefile
$(CC) $(OBJECTS) $(LDFLAGS) -o $@
$(SZ) $@
$(BUILD_DIR)/%.hex: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
$(BIN) $< $@
$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
$(BIN) $< $@
$(BUILD_DIR):
mkdir $@
clean_build: $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).bin
find $(BUILD_DIR) ! -name '$(TARGET).bin' -type f -exec rm -f {} +
#######################################
# clean up
#######################################
clean:
rm -fR $(BUILD_DIR)/*
В C_INCLUDES указываем пути к нашим .h файлам.
В C_SOURCES указываем пути к нашим .c/.cpp файлам.
DEBUG указывает на добавление дебаг-символов в прошивку. Для релиза выставляем в 0.
OPT указывает на оптимизацию. Для релиза включаем оптимизацию, например, Os.
Конечно, в качестве билд-системы можно использовать любую другую, например, CMake с тулчейном для STM32.
Добавим папку build в .gitignore, чтобы гит ее не отслеживал.
echo build/* > .gitignore
На этом настройка проекта завершена и его можно импортировать в QtCreator.
Импорт и настройка проекта в QtCreator
QtCreator не очень дружит с Makefiles. Если попытаться использовать Autotools плагин, то у меня добавлялись только .c и .cpp файлы. Поэтому импортируем проект через специальный интерфейс QtCreator. Для этого понадобится плагин GenericProjectManager.
Переходим в File->New Project. Слева в Import Existing Project.
Далее указываем название проекта led_blink_cmsis и путь C:\led_blink_cmsis. Next.
Выбираем какие директории и файлы импортировать. Выбираем пока только нашу папку src. Next.
Затем add to version control – none и нажимаем Finish. Файлы теперь импортированы.
Далее очень важная деталь – надо добавить в led_blink_cmsis.config определение нашего контроллера, #define STM32F103xB. Без этого дефайна ничего не будет работать, т.к. в библиотеке cmsis требуется указать тип контроллера для включения кода для работы с ним.
На данном этапе ide не распознает зависимости. Настроим это.
Добавим наши .c файлы в led_blink_cmsis.files
src/init.c
src/main.c
А в led_blink_cmsis.inludes пути к заголовочным файлам.
src/
lib/cmsis_core/Include
lib/cmsis_device_f1/Include
Теперь все должно отображаться корректно.
Попробуем собрать проект, нажав кнопку build. Проект должен собраться, а в конце будет таблица с размером нашей прошивки.
Теперь добавим автозагрузку нашей прошивки на МК по нажатию на кнопку Run. Переходим в Projects слева, выбираем наш комплект arm-baremetal-generic-elf-32bit, затем снизу Run. Справа, где deployment, Add Deploy Step->Make. Затем повторяем, выбрав Custom Process Step и добавляем туда команду для прошивки через ST_link CLI.
C:\Program Files (x86)\STMicroelectronics\STM32 ST-LINK Utility\ST-LINK Utility\ST-LINK_CLI.exe
-P ".\build\led_blink_cmsis.bin" 0x08000000 –Rst
Перед прошивкой подключаем наш ST-Link c МК. Мы прошиваем МК, начиная с адреса 0x08000000, и перезагружаем МК после прошивки.
Таким образом, подключив МК через ST-Link и нажав кнопку Run, все должно скомпилиться, загрузиться, а светодиод начать моргать. Это можно видеть по показаниям осциллографа, который подключен к PC13.
Таким образом, мы рассмотрели как настроить проект для STM32, его скомпилировать и загрузить в МК. Дальше настроим отладчик для комфортной отладки STM32.
Настройка отладки
Ранее мы уже настроили удаленный отладчик через openocd, и он должен работать
Однако было весьма здорово иметь возможность видеть состояние регистров МК. Добавим такую возможность. Для этого нам понадобится .svd файл для нашего МК, т.е. STM32F103. Скачать его можно, например, из этого репозитория:
Далее перейдем в QtCreator Edit->Preferences->Devices, на вкладку Bar Metal и выберем OpenOCD. Указываем в Peripherial description file наш путь .svd файлу.
Теперь в режиме отладки перейдем в View->Views->Peripheral
Registers, чтобы отобразить состояние конфигурационных регистров. Запустив
окно отладки и, кликнув правой клавишей мыши на окне Peripheral registers,
можно выбрать группу регистров для отображения, в нашем примере View Groups->GPIOC.
В итоге мы имеем все удобства для отладки устройств на STM32 в IDE QtCreator.
Заключение
Таким образом, в рамках данной статьи рассмотрена настройка QtCreator в связке с GNU компиляторами для полноценной разработки ПО для МК STM32. Надеюсь, что статья была полезна.
Спасибо за внимание!
Комментарии (19)
juramehanik
13.12.2022 15:44Спасибо за статью, но
Возвращаемся в Kits и донастраиваем наш комплект. Выбираем Device type и Device – Bar Metal Device. Применяем.
QtCreator не очень дружит с Makefiles.
Ушел много лет назад от креатора на vscode так как очень неудобно реализован процесс переносимости. В vscode достаточно плагинов cortex-debug и settings-sync для полноценной работы с cmake makefile проектами STM32 на другой машине. Все настройки для отладки и прошивки как есть хранятся в директории проекта.
В креаторе же надо было ручками заводить таргеты или копировать файлы из системной директории, я так понял в этом плане не поменялось ничего?
Ну хоть поддержка svd появилась, это хорошо!Наверное для тех кто и так кодит декстоп проекты в креаторе это имеет смысл, ну и у кого не очень новый пк, ибо vscode иногда очень аппетитный к ресурсам.
NR_electronics
13.12.2022 20:56+1Может быть Вы еще запилите подобный мануал для подключения Qt DesignStudio к STM32 ?
mctMaks
14.12.2022 15:44А зачем, если есть официальное решение от qt? https://www.qt.io/product/develop-software-microcontrollers-mcu
на youtube можно даже найти ролики, где показывают производительность системы.
те же st предлагают touch gfx, который и дизайнер, и код на с++, и заточек по stm32 более чем. и зачем тогда дизайнер?
MW_dem1305
13.12.2022 20:56-1Скачай IAR for ARM с торрента и прекрати ненужные извращения. Удивительно стремление людей усложнять себе жизнь.Твой метод-для изощрённых извращенцев.
ZhksB Автор
13.12.2022 20:57+1Я скептически отношусь к программам с торрентов. Сомневаюсь, что их там выкладывают по доброте душевной, пропатчив только лицензионную часть...
ZhksB Автор
13.12.2022 20:59И цель данной статьи была именно в настройке QtCreator - IDE, к которой привык и постоянно пользуюсь.
kuzulis
13.12.2022 22:26Все бы вроде хорошо, но использование мейкфайлов это конечно, дичь.
Для программирования МК хорошо подходит сборочная система Qbs. Хотя, на крайний случай, можно извратиться и с CMake.
Еще в QtC есть поддержка кейловского отладчика, т.е можно использовать KEIL и для сборки и для отладки в самом QtC.
Я хотел в QtC добавить и поддержку отладчика CSpy из IAREW, но это желание как то пропало после их реакции на известные события.
Кроме того, GDB отладка в QtC, требует наличия питона v2.x, а также условия чтобы сам GDB, был собран с поддержкой питона, что не во всех ARM тулчейнах сделано. Это минус у QtC, я считаю, что нельзя без питона.
Там был еще казус, в том, что они хотели дропнуть питон 2x и заменить на 3x. Я им говорил, что тогда половина bare-metal тулчейнов сразу отвалится. Те не поверили, дропнули, но у них провалился их плагин McuSupport и они откатили взад это как было. Смех и грех в общем.
А сейчас тоже, вот, присматриаюсь к VSCode, т.к. там завезли плагин отладки для IAR, для отладчика CSpy. Т.е. можно взять любимую систему сборки Qbs, или CMake и все делать из VSCode.
GDB, плагин для VSCode, был уже сто лет как. Возможно для полного комплекта подумаю, а не добавить ли туда плагин и для отладки KEIL овским отладчиком. ))
В общем, для меня VSCode, выглядит более заманчиво.
OldFashionedEngineer
15.12.2022 11:42Интересно, чем автора не устраивает CubeIDE? Среда построена на эклипс, тот же GCC в основе. Бесплатно качаешь и используешь, ни каких лицензионных ограничений. И в добавок ко всему CubeIDE поддерживается производителем МК. Я могу понять желание работать с периферией на CMSIS, но это тоже можно в кубе делать.
Ладно бы для Arduino такое сделать, там реально среда неудобная в работе.
mctMaks
15.12.2022 15:20личные предпочтения могут быть. на мой вкус, в кубике полезно две вещи: наглядное распределение пинов с возможностью выбора альтернативы и дерево тактирования. Плюс-Минус полезен расчетчик потребления (получится такие же цифры как в нем весьма не просто бывает иногда). Как редактор кода и среда отладки - не удобная, медленная.
OldFashionedEngineer
15.12.2022 15:29В каком плане "медленная"? Он вроде уже в нескольких потоках компилирует.
Графическая настройка тактирования и прочие фичи - это функции CubeMX. Его не обязательно использовать совместно с IDE. Можно отдельно скачать и использовать для генерации проектов под другие IDE. Ну, и по сути, CubeMX в CubeIDE встроен как плагин. Он даже обновляется отдельно. (Капитан очевидность в деле...)
mctMaks
15.12.2022 18:26В каком плане "медленная"?
запуск самой среды, переключение между отладка/написание кода (забыл как в экплисе это называется), по сравнению с Segger Embedded Studio тормозит.
Он вроде уже в нескольких потоках компилирует.
Сам этап компиляции может и быстро происходит, не сравнивал настолько детально.
Графическая настройка тактирования и прочие фичи - это функции CubeMX
Это нравится. Cube IDE нет.
Опять же повторюсь, на мой вкус этот фломастер не вкусный). Я не говорю что оно плохое, я говорю что оно не всем нравится. Поэтому я смотрю на альтернативы Cube IDE, тем более что она только под ST, что не есть удобно при работе с другими МК.
OldFashionedEngineer
15.12.2022 20:40Так можно щаморочиться, и заставить cubeide шить другие контроллеры)))
Я раньше на работе вынужден был использовать кейл. После этого куб как манна небесная!
GeorgeIV
mbed - не имеет ограничений и бесплатна.
mctMaks
для тех же STM и "кубик" то бесплатен со средой.
хотя в целом, что такого дает Qt, без чего трудно будет в микроконтроллере? Code Lite тоже open source, тоже можно подцепить внешний компилятор. Только более легкая по сравнению с тем Qt, особенно если последний используется только как редактор кода.
aax
Mbed это онлайн IDE, с бекэндом на не подконтрольном Вам сервере, что по определению накладывает понятные и существенные ограничения при использовании Mbed в разработках.
buldo
Вы не правы. Уже очень давно есть mbed cli. Год назад уже тосно была mbed ide на основе электрона. Плюс можно использовать все библиотеки через PlatformIO. ЕМНИП, кажется начали деприкейтить Web ide