пятница, 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\*)


среда, 7 августа 2013 г.

Настройка среды сборки для контроллеров ARM (AT91SAM7Sxxx и STM32F3xx)

1. Конфигурация системы
Развёртывание и конфигурирование среды сборки производилось в операционной системе Windows 7 x86-64. Использовались демонстрационная плата AT91SAM7S-EK с JTAG-отладчиком J-Link-ARM, шедшим с ней в комплекте, и плата STM32373C-EVAL.
2. Переключение Windows в тестовый режим
Ранее на этом же компьютере был установлен драйвер ввода-вывода dlportio, что потребовало переключения Windows в тестовый режим, в котором отсутствует проверка цифровой подписи драйверов. Переключение между режимами описано в этой статье, там же приведена и ссылка на утилиту, с помощью которой производится переключение.
3. Компилятор gcc-arm-none-eabi
На сайте кросскомпилятора GCC можно скачать требуемую версию GCC-ARM, в данный момент используется версия GCC ARM Embedded 4.7-2013-q1-update. Архив нужно распаковать в выбранный каталог, в переменную окружения Path операционной системы путь к каталогу disk:\path_to_directory\gcc-arm-none-eabi-4_7-2013q1-20130313-win32\bin добавлять нет необходимости, он явно задан в Makefile проекта, который описывается в следующей заметке.
4. Библиотека периферии для контроллеров AT91SAM7Sxx демонстрационной платы AT91SAM7S-EK
Для доступа к регистрам контроллеров по их псевдонимам, а не по адресам, требуется скачать библиотеки периферии. На сайте Atmel найти их можно по ключевым словам 'demoboard-name Software Package for IAR 5.2, Keil and GNU'. Кроме того, архив содержит некоторые утилиты и драйверы, которые могут быть полезны в разработке (TWI, LCD, Ethernet и другие).
5. Библиотека периферии для контроллеров STM32F3XX
Архив с библиотеками периферии. В архиве находятся следующие каталоги:
Libraries/CMSIS (Cortex Microcontroller Software Interface Standard -- стандартные определения для контроллеров на ядре ARM Cortex); Libraries/STM32F37x_I2C_CPAL_Driver (исходные коды и заголовочные файлы библиотеки шины I2C); Libraries/STM32F37x_StdPeriph_Driver (исходные коды и заголовочные файлы библиотеки работы с периферией контроллера).
Project/STM32F37x_StdPeriph_Examples (примеры использования библиотеки CMSIS); Project/STM32F37x_StdPeriph_Templates (шаблоны проектов для различных средств разработки).
Utilities/STM32_EVAL/Common (шрифты для ЖКИ-дисплея отладочной платы STM32373C-EVAL и функции вывода); Utilities/STM32_EVAL/STM32373C_EVAL (базовые исходные коды и заголовочные файлы для периферии, размещённой на отладочной плате).
6. Отладчик OpenOCD
Для программирования контроллера платы AT91SAM7S-EK использовался USB-JTAG адаптер J-Link-ARM, плата STM32373C-EVAL может программироваться как через JTAG, так и посредством размещённого на ней же USB-адаптера ST-LINK V2. Для программирования обеих плат использовалась программа OpenOCD.
7. Установка драйверов libUsb для адаптеров JLink и ST-LINK V2 с помощью утилиты zadig
После подключения к компьютеру адаптеров они не распознаются системой автоматически. Для их корректной работы с OpenOCD нужно скачать утилиту zadig, с помощью которой производится установка драйверов USB для адаптеров. После её запуска в выпадающем списке будут показаны USB-устройства, для которых не установлены драйверы. В списке драйверов (Target Driver) следует выбрать драйвер libusb-win32 (v1.2.6.0), и нажать кнопку Install Driver.

На этом развёртывание среды сборки можно считать завершённым.