пятница, 30 августа 2013 г.

Makefile для проектов на контроллерах STM32

Проекты, если иное не указано явно, состоят из четырёх пользовательских файлов: main.cpp, main.hpp, interrupts.cpp и interrupts.hpp. Предполагается, что среда сборки настроена в соответствии с рекомендациями, приведёнными в предыдущей заметке.
Для обеспечения быстрой смены компилятора (при выходе новой версии) и/или программатора пути к их каталогам и некоторые команды вынесены в отдельные файлы, подключаемые в проект. Путь к компилятору находится в файле GccDir.mk, путь к программатору и его команды -- в Programmator.mk. Оба этих файла находятся в директории на уровень выше (../), что обеспечивает возможность централизованного перехода на новые версии компилятора/программатора для всех проектов сразу.

Makefile с путями к компилятору
# GccDir.mk
GCCDIRNAME = /d/bin/gcc-arm-none-eabi-4_8-2014q1-20140314-win32
#GCCDIRNAME = /d/bin/gcc-arm-none-eabi-4_8-2013q4-20131204-win32
#GCCDIRNAME = /d/bin/gcc-arm-none-eabi-4_7-2013q3-20130916-win32
#GCCDIRNAME = /d/bin/gcc-arm-none-eabi-4_7-2013q2-20130614-win32
#GCCDIRNAME = /d/bin/gcc-arm-none-eabi-4_7-2013q1-20130313-win32
# Вот сколько версий вышло с момента публикации

Makefile с путями и командами программаторов OpenOCD и ST-Link. OpenOCD успел обновиться до версии 0.8.0.
# Programmator.mk
# **********************************************************************************************
#                            FLASH PROGRAMMING
#
# Alternate make target for flash programming only
#
# OpenOCD is run in "batch" mode with a special configuration file and a script file containing
# the flash commands. When flash programming completes, OpenOCD terminates.
#
# Note that the script file of flash commands (script.ocd) is part of the project
#
# Programmers: Martin Thomas, Joseph M Dupre, James P Lynch
# **********************************************************************************************


# OpenOCD directory
OPENOCDDIR = $(GCCDIRNAME)/downloads/openocd-0.8.0
# OpenOCD binary
OPENOCD = $(OPENOCDDIR)/bin-x64/openocd-x64-0.8.0.exe
# OpenOCD config
OPENOCDCONFIG =\
-f $(OPENOCDDIR)/scripts/interface/stlink-v2.cfg\
-f $(OPENOCDDIR)/scripts/board/stm32f3discovery.cfg

ifeq ($(STARTFROMRAM), true)
LOADCOMMAND = "load_image $(TARGET)-$(MCU)-$(BINFILESUFFIX).bin $(STARTADDRESS) bin"
else
LOADCOMMAND = "program $(TARGET)-$(MCU)-$(BINFILESUFFIX).bin $(STARTADDRESS) verify"
endif

# OpenOCD command
OPENOCDCOMMAND =\
-c "init"\
-c "halt"\
-c $(LOADCOMMAND)\
-c "reset run"\
-c "shutdown"
## To unlock chip use next commands after "halt":
# -c "flash protect 0 0 last off"\
# -c "shutdown"

# **********************************************************************************************
#                                 ST-Link programmator
# **********************************************************************************************
STLINKDIR = "/c/Program Files (x86)/STMicroelectronics/STM32 ST-LINK Utility/ST-LINK Utility"
STLINK = $(STLINKDIR)/ST-LINK_CLI.exe
STLINKCOMMAND = -c SWD UR -Halt -P "$(TARGET)-$(MCU)-$(BINFILESUFFIX).bin" $(STARTADDRESS) -Rst -V

program:
 @echo "STARTADDRESS = $(STARTADDRESS)"
 # $(STLINK) $(STLINKCOMMAND)
 $(OPENOCD) $(OPENOCDCONFIG) $(OPENOCDCOMMAND)

Makefile проекта.
TARGET = main
# Использовать драйверы периферийных устройств, предоставленные ST
DEFS = -DUSE_STDPERIPH_DRIVER

# Адрес начала внутренней FLASH-памяти контроллера
STARTADDRESS = 0x08000000
BINFILESUFFIX = flash

# Выбор типа контроллера и названия демонстрационной платы
MCU = cortex-m4
CHIP = STM32F37x
BOARD = STM32373C-EVAL
# Подключаем файлы с путями и командами компилятора и программатора
include ../GccDir.mk
include ../Programmator.mk

# Путь к каталогу стандартный драйверов периферии, и вспомогательных библиотек
STM32BASE = $(GCCDIRNAME)/downloads/$(CHIP)_DSP_StdPeriph_Lib_V1.0.0/Libraries
# Путь к каталогу специфичных для демонстрационной платы определений и функций
STM32373CBASE = $(STM32BASE)/../Utilities/STM32_EVAL
# Пути поиска заголовочных файлов, и файлов исходных кодов
INCLUDES =\
-I.\
-I'$(STM32BASE)/$(CHIP)_StdPeriph_Driver/inc'\
-I'$(STM32BASE)/$(CHIP)_StdPeriph_Driver/src'\
-I'$(STM32BASE)/CMSIS/Device/ST/$(CHIP)/Include'\
-I'$(STM32BASE)/CMSIS/Device/ST/$(CHIP)/Source/Templates'\
-I'$(STM32BASE)/CMSIS/Include'\
-I'$(STM32BASE)/../Project/$(CHIP)_StdPeriph_Templates'\
-I'$(STM32373CBASE)/Common'\
-I'$(STM32373CBASE)/$(subst -,_,$(BOARD))'

# Программы, используемые при сборке проекта
PREFIX = arm-none-eabi-
AR = $(GCCDIRNAME)/bin/$(PREFIX)ar
CC = $(GCCDIRNAME)/bin/$(PREFIX)gcc
CXX = $(GCCDIRNAME)/bin/$(PREFIX)g++
AS = $(CC)
LD = $(CC)
OBJCOPY = $(GCCDIRNAME)/bin/$(PREFIX)objcopy
OBJDUMP = $(GCCDIRNAME)/bin/$(PREFIX)objdump

# Уровень оптимизации
OPTIMIZE = -Os

# Общие влаги компиляции
FLAGS = -mcpu=$(MCU) -mthumb
FLAGS += -MD
FLAGS += $(INCLUDES)
FLAGS += $(DEFS)

# Скрипт линковщика, специфичный для контроллера
# Возможно, придётся забрать его в каталог проекта,
# и внести изменения (размер стека, объём внутренней
# FLASH- и RAM-памяти)
LD_SCRIPT = $(STM32BASE)/../Project/$(CHIP)_StdPeriph_Templates/TrueSTUDIO/$(BOARD)/STM32_FLASH.ld

# Флаги, специфичные для компиляции ассемблерных файлов
AFLAGS = $(FLAGS)
AFLAGS  += -x assembler-with-cpp -c

# Флаги, специфичные для компиляции файлов C++
CXXFLAGS = $(FLAGS)
CXXFLAGS += $(OPTIMIZE)
CXXFLAGS += -g
CXXFLAGS += -fno-exceptions -fno-rtti
CXXFLAGS += -ffunction-sections -fdata-sections
CXXFLAGS += -fno-threadsafe-statics
CXXFLAGS += -funsigned-bitfields -fshort-enums
CXXFLAGS += -Wall -Wextra
CXXFLAGS += -Winline
CXXFLAGS += -Wpointer-arith -Wredundant-decls
CXXFLAGS += -Wshadow -Wcast-qual -Wcast-align -pedantic
CXXFLAGS        += -c -std=c++11

# Использовать библиотеку C-runtime,
# оптимизированную для применения в микроконтроллерах
USE_NANO = --specs=nano.specs
# Использовать "заглушки" для некоторых
# функций C-runtime, неиспользуемых в микроконтроллерах
USE_SEMIHOST = --specs=rdimon.specs

# Флаги линкера
LD_FLAGS = -mcpu=$(MCU)
LD_FLAGS += -mthumb
LD_FLAGS += -Wl,-Map="$(MAP)",--cref
LD_FLAGS += -Wl,--gc-sections
LD_FLAGS += -T$(LD_SCRIPT)
LD_FLAGS        += $(USE_NANO)
LD_FLAGS        += $(USE_SEMIHOST)
# Для использования в проекте функций, обращающихся к C- C++-runtime
# после -lrdimon добавить -lc и/или -lstdc++
LD_FLAGS        += -Wl,$(LINKPATH),--start-group -lrdimon -Wl,--end-group

# Флаги для objcopy, создание бинарного файла прошивки
CPFLAGS = --output-target=binary
# Флаги для objdump, создание листинга программы (ассемблерный код).
ODFLAGS = -h -S

# Чтобы не разводить свалку объектных файлов в корневом каталоге проекта, будем складывать их в отдельный каталог
OBJDIR = ./obj

# Начальная инициализация микроконтроллера
STM32STARTUPFILENAME = startup_$(CHIP)
STM32SYSTEMFILENAME = system_$(CHIP)
# Запуск микроконтроллера
STM32STARTUP = $(STM32BASE)/CMSIS/Device/ST/$(CHIP)/Source/Templates/gcc_ride7/$(STM32STARTUPFILENAME).s
STM32SYSTEM  = $(STM32BASE)/CMSIS/Device/ST/$(CHIP)/Source/Templates/$(STM32SYSTEMFILENAME).c

# Библиотека ввода-вывода (GPIO)
GPIOSTDFILENAME = $(CHIP)_gpio
GPIOSTD = $(STM32BASE)/$(CHIP)_StdPeriph_Driver/src/$(GPIOSTDFILENAME).c

# Библиотека управления тактированием микроконтроллера (RCC)
RCCSTDFILENAME = $(CHIP)_rcc
# RCC stdlib code
RCCSTD = $(STM32BASE)/$(CHIP)_StdPeriph_Driver/src/$(RCCSTDFILENAME).c

# Определения и функции, специфичные для демонстрационной платы
EVBOARDHARDWFILENAME = $(subst -,_,$(BOARD))
EVBOARDHARDW = $(STM32373CBASE)/$(subst -,_,$(BOARD))/$(EVBOARDHARDWFILENAME).c

# Обработчики прерываний
INTWORKFILENAME = interrupts
INTWORK = ./$(INTWORKFILENAME).cpp

# Создание map-файла
MAP = $(TARGET).map

# Пути к объектным файлам из корневого каталога проекта
STM32STARTUPOBJ = $(OBJDIR)/$(STM32STARTUPFILENAME).o
STM32SYSTEMOBJ = $(OBJDIR)/$(STM32SYSTEMFILENAME).o
GPIOSTDOBJ = $(OBJDIR)/$(GPIOSTDFILENAME).o
RCCSTDOBJ = $(OBJDIR)/$(RCCSTDFILENAME).o
EVBOARDHARDWOBJ = $(OBJDIR)/$(EVBOARDHARDWFILENAME).o
INTWORKOBJ = $(OBJDIR)/$(INTWORKFILENAME).o
TARGETOBJ = $(OBJDIR)/$(TARGET).o

# Объектные файлы, из которых будет собираться финальный образ
OBJECTS =\
$(STM32STARTUPOBJ) $(STM32SYSTEMOBJ) $(GPIOSTDOBJ)\
$(RCCSTDOBJ) $(EVBOARDHARDWOBJ) $(INTWORKOBJ)\
$(TARGETOBJ)

# Сборка финального образа программы, и её листинга
all: $(TARGET)-$(MCU).axf
 @echo "....copying"
 $(OBJCOPY) $(CPFLAGS) $^ $(TARGET)-$(MCU)-$(BINFILESUFFIX).bin
 $(OBJDUMP) $(ODFLAGS) $^ > $(TARGET)-$(MCU).lst

# Линковка промежуточного образа программы
$(TARGET)-$(MCU).axf: $(OBJECTS) $(LDSCRIPT)
 @echo "...linking"
 $(LD) $^ $(LD_FLAGS) -o $@

$(STM32STARTUPOBJ): $(STM32STARTUP)
 @echo "..assembling of $^"
 $(AS) $(AFLAGS) $< -o $@

$(STM32SYSTEMOBJ): $(STM32SYSTEM)
 @echo ".compiling of $^"
 $(CXX) $(CXXFLAGS) $< -o $@

$(GPIOSTDOBJ): $(GPIOSTD)
 @echo ".compiling of $^"
 $(CXX) $(CXXFLAGS) $< -o $@

$(RCCSTDOBJ): $(RCCSTD)
 @echo ".compiling of $^"
 $(CXX) $(CXXFLAGS) $< -o $@

$(EVBOARDHARDWOBJ): $(EVBOARDHARDW)
 @echo ".compiling of $^"
 $(CXX) $(CXXFLAGS) $< -o $@

$(INTWORKOBJ): $(INTWORK)
 @echo ".compiling of $^"
 $(CXX) $(CXXFLAGS) $< -o $@

$(TARGETOBJ): $(TARGET).cpp
 @echo ".compiling of $^"
 $(CXX) $(CXXFLAGS) $< -o $@

clean:
 rm -f $(OBJECTS) $(TARGET)*.axf *.map *.lst $(OBJDIR)/*.d *.bin *.o

# Создаём каталог для объектных файлов, если уже создан -- ошибки не будет
-include $(shell mkdir obj 2> /dev/null) $(wildcard obj\*)


2 комментария:

  1. Пробую научиться по вашим урокам. Стараюсь делать всё поэтапно, как у вас написано.
    При запуске файла выдаётся ошибка:

    make: *** Нет правила для сборки цели `Libraries/CMSIS/Device/ST/STM32F0xx/Source/Templates/gcc_ride7/startup_STM32F0xx.s', требуемой для `startup_STM32F0xx.o'. Останов.

    ОтветитьУдалить
  2. У меня библиотеки сложены в каталог Downloads, который лежит в корневом каталоге кросскомпилятора. У вас библиотеки могут располагаться по другому пути, и Make не находит требуемых файлов. Проверьте, что переменная STM32BASE указывает в нужный каталог.

    ОтветитьУдалить