- Регистрация
- 23 Авг 2023
- Сообщения
- 3,969
- Реакции
- 0
- Баллы
- 36
Ofline
Собрать прошивку компилятором IAR с помощью GNU Make — это не просто возможно, это стандартный подход для автоматизации сборки, например, на CI/CD серверах, где использование IDE неудобно. IAR поставляется с набором консольных утилит, которые делают этот процесс вполне прямолинейным.
Главный вопрос:
Как собрать прошивку для микроконтроллера stm32f407ve компилятором IAR из самостоятельно написанных GNU Make скриптов? То есть без использования пресловутого XML-образного .ewp файла. Как должен выглядеть Makefile для IAR и ключи компилятору и компоновщику?
Необходимость этой задачи обусловлена прежде всего потребностями пере использования конфигов для электронных плат, микроконтроллеров и процессорных ядер при создании новых похожих сборок и приблизительно одинаковым функционалом . При сборке из скриптов очень легко добавить новую сборку. Достаточно только написать конфиг и 3 строчки в отдельном Makefile и вот у вас новая специфическая сборка. Подробнее про это можно почитать в отдельном тексте .
Если коротко, то самостоятельно написанные make скрипты открывают вам двери в новые возможности разработки. Начиная с автоматического выравнивая отступов, заканчивая автоматической отправкой артефактов потребителям по электронной почте. С make скриптами вы не будете привязаны к какой-то конкретной IDE и сможете писать код в любом текстовом редакторе, который вам импонирует. В MakeFile очень просто менять компиляторы. Это, буквально, заменить одну строчку. С GCC на Clang или GHS или IAR. Сборка двумя компиляторами поможет вам найти больше ошибок в проекте. При сборке из makefile вам вообще всё равно для какой целевой платформы собирать код прошивки. Вы можете минимальными изменениями в makefile собрать прошивку и крутить её даже на x86.
Вот у меня есть работающий проект прошивки, которая мигает светодиодом для STM32 собранный компилятором GCC. Я хочу пересобрать код прошивки компилятором IAR.
Вашим основным документом для этого является IAR C/C++ Development Guide Compiling and Linking for Arm Limited’s Arm Cores. Там буквально 736 страниц. В документе расписано, что значит каждая опция компилятора IAR. Обычно в репозитории для IAR лежит проект, состоящий из файлов расширений
Исходные файлы | Пояснение |
*.icf | Настройки для компоновщика |
*.s | Исходный ассемблер код |
.c | Исходный C код |
.h | Заголовочные файлы |
К слову, ассемблер IAR отличается от ассемблера GCC. Для начала проанализируем лог сборки обыкновенной GUI-IDE. Я сгенерировал в STMCubeMX IAR проект, запустил сборку из-под IDE, дождался окончания и стал внимательно анализировать лог. И вот, что я там увидел.
Что же вызывает IAR-GUI система сборки?
Утилита | Файл на входе | Файл на выходе | Ключи |
iasmarm.exe | *.s | *.o | -s+ -M<> -w+ -r --cpu Cortex-M4 --fpu VFPv4_sp |
iccarm.exe | *.c | *.o | --no_cse --no_unroll --no_inline --no_code_motion --no_tbaa --no_clustering --no_scheduling --debug --endian=little --cpu=Cortex-M4 -e --fpu=VFPv4_sp --dlib_config -On |
ilinkarm.exe | *.o .icf | .map .out | --semihosting --entry __iar_program_start --vfe --text_out locale |
ielftool.exe | .out | .hex | --ihex --verbose |
Выглядит так, что IAR ToolChain на самом деле простой и примитивный. Состоит всего из 4х утилит. Все они после установки попадают в папку C:\Program Files (x86)\IAR Systems\Embedded Workbench 8.1\arm\bin. К слову, этот путь надо сразу прописать в переменную PATH.
Программа | Утилита |
Ассемблер | iasmarm.exe |
Компилятор | iccarm.exe |
Компоновщик | ilinkarm.exe |
Бинарный парсер (binutils) | ielftool.exe |
Схематически процесс сборки c IAR можно изобразить так
Скрипт сборки
В скрипте сборки make надо определить переменные окружения на утилиты, которые и делают всю работу по сборке программы.
Код:
# binaries
#IAR_PATH=""
$(info IAR_PATH=$(IAR_PATH))
# The IAR compiler bin path can be either defined in make command via IAR_PATH
# variable (> make IAR_PATH=xxx)
# either it can be added to the PATH environment variable.
ifdef IAR_PATH
$(info WithPath)
PREPROCESSOR_TOOL =$(IAR_PATH)/$(PREFIX)iccarm.exe
CC = $(IAR_PATH)/$(PREFIX)iccarm.exe
AS = $(IAR_PATH)/$(PREFIX)iasmarm.exe
ELF_TOOL = $(IAR_PATH)/$(PREFIX)ielftool.exe
AR = $(IAR_PATH)/$(PREFIX)iarchive.exe
LD = $(IAR_PATH)/$(PREFIX)ilinkarm.exe
else
$(info WithOutPath)
PREPROCESSOR_TOOL = $(PREFIX)iccarm.exe
CC = $(PREFIX)iccarm.exe
AS = $(PREFIX)iasmarm.exe
ELF_TOOL = $(PREFIX)ielftool.exe
AR = $(PREFIX)iarchive.exe
LD = $(PREFIX)ilinkarm.exe
endif
MAIN_TARGET_FILE=$(TARGET).out
HEX = $(ELF_TOOL) --ihex --verbose
BIN = $(ELF_TOOL) --bin --verbose
Это ключевые опции компилятора IAR
Ключ | Назначение |
-e | Активировать IARовские расширения языка С |
--cpu=Cortex-M4 | Выбор процессорного ядра |
--fpu=VFPv4_sp | Выбор FPU |
--endian=little | Выбор порядка байт |
--debug | Добавить отладочную информацию |
--no_inline | Запрет вставных функций |
в make скрипте это выглядит так
Код:
COMPILE_IAR_OPT += -DHAS_IAR
#COMPILE_IAR_OPT += -D HAS_IAR
COMPILE_IAR_OPT += -D__ICCARM__=1
#COMPILE_IAR_OPT += -D __ICCARM__
COMPILE_IAR_OPT +=--no_cse
COMPILE_IAR_OPT +=--no_unroll
COMPILE_IAR_OPT +=--no_inline
COMPILE_IAR_OPT +=--no_code_motion
COMPILE_IAR_OPT +=--no_tbaa
COMPILE_IAR_OPT +=--no_clustering
COMPILE_IAR_OPT +=--no_scheduling
COMPILE_IAR_OPT +=--debug
COMPILE_IAR_OPT +=--endian=little
COMPILE_IAR_OPT +=--cpu=Cortex-M4
COMPILE_IAR_OPT +=-e
COMPILE_IAR_OPT +=--fpu=VFPv4_sp
COMPILE_IAR_OPT +=--diag_suppress=Pe029
COMPILE_IAR_OPT +=--diag_suppress=Pe1345
COMPILE_IAR_OPT +=--diag_suppress=Pe513
COMPILE_IAR_OPT +=--diag_suppress=Pe144
COMPILE_IAR_OPT +=--diag_suppress=Pe188
ASM_FLAGS += -s+
#ASM_FLAGS += -M<>
ASM_FLAGS += -w+
ASM_FLAGS += -r
ASM_FLAGS += --cpu Cortex-M4
ASM_FLAGS += --fpu VFPv4_sp
LDFLAGS +=--semihosting
LDFLAGS +=--entry __iar_program_start
LDFLAGS +=--vfe
LDFLAGS +=--text_out locale
LDFLAGS +=--redirect _Printf=_PrintfFull
LDFLAGS +=--redirect _Scanf=_ScanfFull
LDFLAGS +=--no_out_extension
LDFLAGS +=--map $(BUILD_DIR)/$(TARGET).map
LDFLAGS += --config $(LDSCRIPT)
CFLAGS += $(COMPILE_IAR_OPT)
Основной скрипт сборки
Код:
CSTANDARD = -std=c11
mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
$(info mkfile_path:$(mkfile_path) )
#$(info MAKE:$(MAKE))
#$(info MAKEFILE_LIST:$(MAKEFILE_LIST))
MK_PATH:=$(subst /cygdrive/c/,C:/,$(MK_PATH))
$(info MK_PATH=$(MK_PATH))
BUILD_DIR=build
EXTRA_TARGETS=
INCDIR := $(subst /cygdrive/c/,C:/, $(INCDIR))
#@echo $(error INCDIR=$(INCDIR))
#$(error SOURCES_DIAG_C=$(SOURCES_DIAG_C))
#$(error SOURCES_THIRD_PARTY_C=$(SOURCES_THIRD_PARTY_C))
SOURCES_TOTAL_C += $(SOURCES_C)
SOURCES_TOTAL_C += $(SOURCES_DIAG_C)
SOURCES_TOTAL_C += $(SOURCES_CONFIGURATION_C)
SOURCES_TOTAL_C += $(SOURCES_THIRD_PARTY_C)
SOURCES_TOTAL_C := $(subst /cygdrive/c/,C:/, $(SOURCES_TOTAL_C))
#@echo $(error SOURCES_TOTAL_C=$(SOURCES_TOTAL_C))
SOURCES_ASM := $(subst /cygdrive/c/,C:/, $(SOURCES_ASM))
#@echo $(error SOURCES_ASM=$(SOURCES_ASM))
LIBS := $(subst /cygdrive/c/,C:/, $(LIBS))
LDSCRIPT := $(subst /cygdrive/c/,C:/, $(LDSCRIPT))
#@echo $(error SOURCES_ASM=$(SOURCES_ASM))
WORKSPACE_LOC := $(realpath $(WORKSPACE_LOC))
WORKSPACE_LOC := $(subst /cygdrive/c/,C:/, $(WORKSPACE_LOC))
include $(WORKSPACE_LOC)/make_scripts/toolchain.mk
# CFLAGS
#https://gcc.gnu.org/onlinedocs/gcc/ARM-Options.html
AS_DEFS =
AS_INCLUDES =
# OPT_C += -O0
include $(WORKSPACE_LOC)/make_scripts/compiler_options.mk
include $(WORKSPACE_LOC)/make_scripts/compiler_errors.mk
include $(WORKSPACE_LOC)/make_scripts/warning_options.mk
include $(WORKSPACE_LOC)/make_scripts/linker_options.mk
MCAL_OPT += $(OPT_C)
CFLAGS += $(MCAL_OPT)
ASFLAGS += $(MCU)
ASFLAGS += $(AS_DEFS)
ASFLAGS += $(AS_INCLUDES)
ASFLAGS += $(MCAL_OPT)
ASFLAGS += $(COMPILE_OPT)
ASFLAGS += -Wall
ASFLAGS +=-fdata-sections
ASFLAGS += -ffunction-sections
#@echo $(error LDSCRIPT=$(LDSCRIPT))
LIBDIR =
ARTIFACTS += $(BUILD_DIR)/$(TARGET).bin
ARTIFACTS += $(BUILD_DIR)/$(TARGET).hex
ARTIFACTS += $(BUILD_DIR)/$(MAIN_TARGET_FILE)
#@echo $(error ARTIFACTS=$(ARTIFACTS))
.PHONY: all
# default action: build all
all: $(EXTRA_TARGETS) $(ARTIFACTS)
.PHONY: generate_definitions
# build the application
# list of objects
OBJECTS = $(addprefix $(BUILD_DIR)/,$(notdir $(SOURCES_TOTAL_C:.c=.o)))
vpath %.c $(sort $(dir $(SOURCES_TOTAL_C)))
# list of ASM program objects
#@echo $(error SOURCES_ASM=$(SOURCES_ASM))
ASM_OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(SOURCES_ASM:.s=.o)))
#@echo $(error ASM_OBJECTS=$(ASM_OBJECTS))
ELF_OBJECTS += $(OBJECTS)
#@echo $(error ASM_OBJECTS=$(ASM_OBJECTS))
ELF_OBJECTS += $(ASM_OBJECTS)
#@echo $(error ELF_OBJECTS=$(ELF_OBJECTS))
ifeq ($(IAR),Y)
vpath %.s $(sort $(dir $(SOURCES_ASM)))
endif
TOTAL_FILES := $(words $(OBJECTS))
$(info TOTAL_FILES:$(TOTAL_FILES) )
#@echo $(error COMPILE_GCC_OPT=$(COMPILE_GCC_OPT))
ifeq ($(IAR),Y)
$(BUILD_DIR)/%.o: %.s Makefile | $(BUILD_DIR)
@echo Compile Asm $@
#@ $(CC) -c -MD $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@
$(AS) -c $(ASM_FLAGS) $< -o $@
endif
$(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR)
$(eval CURRENT_CNT=$(shell echo $$(($(CURRENT_CNT)+1))))
@echo Compiling $(CURRENT_CNT)/$(TOTAL_FILES) $@
#@ $(CC) -c -MD $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@
$(CC) -c $(CFLAGS) $< -o $@
$(BUILD_DIR)/%.o: %.S Makefile | $(BUILD_DIR)
$(AS) -c $(CFLAGS) $< -o $@
#@echo $(error MAIN_TARGET_FILE=$(MAIN_TARGET_FILE))
#@echo $(error LDFLAGS=$(LDFLAGS))
$(BUILD_DIR)/$(MAIN_TARGET_FILE): $(ELF_OBJECTS) Makefile $(BUILD_DIR)
@echo GenerateMainArtifact $@
$(LD) $(ELF_OBJECTS) $(LDFLAGS) -o $@
$(SZ) $@
$(BUILD_DIR)/%.hex: $(BUILD_DIR)/$(MAIN_TARGET_FILE) | $(BUILD_DIR)
@echo GenerateHex $@
$(HEX) $< $@
#@echo $(error MAIN_TARGET_FILE=$(MAIN_TARGET_FILE))
$(BUILD_DIR)/%.bin: $(BUILD_DIR)/$(MAIN_TARGET_FILE) $(BUILD_DIR)
@echo GenerateBin $@
$(BIN) $< $@
$(BUILD_DIR):
mkdir -p $@
# clean up
.PHONY: clean
clean:
-rm -fR $(BUILD_DIR)
# dependencies
-include $(wildcard $(BUILD_DIR)/*.d)
# *** EOF ***
Чтобы инициировать процесс построения прошивки надо запустить на исполнение файл build_from_make.bat
Код:
echo off
cls
call clean_temp.bat
make -i clean 2>&1 | tee clean_log.txt
make -i all | tee build_log.txt
Тут скрипт файл clean_temp.bat просто делает удаление временных файлов
Код:
@echo off
del /S *.o
del /S *.obj
del /S *.d
del /S *.map
del /S *.hex
del /S *.elf
del /S *.lst
del /S *.bin
del /S *.su
del /S *.pp
del /S *.bak
Сравнение GCC и IAR
Между компиляторами GCC и IAR есть серия существенных отличий.
Параметр | GCC | IAR |
Файл на выходе | .elf | .out |
Компилятор (CC ) | gcc | iccarm.exe |
Ассемблер (AS) | gcc -x assembler-with-cpp | iasmarm.exe |
Бинарный парсер (CP) | objcopy | ielftool.exe |
Архиватор (AR ) | ar | iarchive.exe |
Компоновщик (LD ) | gcc | ilinkarm.exe |
Скрипт компоновщика | .ld | .icf |
Отладка прошивки
Загружать и отлаживать программу можно при помощи Segger Ozone. Выбираем микроконтролер STM32F407VET6, интерфейс JTAG, скорость 4MHz, загружаем *.out файл и можно пошагово отлаживаться.
Как видите, прошивку, которую я собрал из Make скриптов можно прекраснейшим образом пошагово отлаживать в отладчике Ozone.
Итоги
Удалось собрать прошивку для STM32 при помощи компилятора IAR и системы сборки GNU Make. Это открывает дорогу для иcпользования мощных средств заложенных в компилятор IAR (например автоматическая проверка MISRA). Плюс позволяет легко и веерно мигрировать существующий функционал на другие платы и микроконтроллеры. Теперь вы можете забыть про *.ewp файл. Он вам больше не нужен. Всё, что вам надо это .c .h .mk .icf и .s файлы.
Сборка проекта двумя-тремя компиляторами (GCC+ IAR + MinGW) - это хорошая практика при разработке ответственных систем. Если один компилятор не обнаружил ни одной ошибки, то второй компилятор может найти какую-нибудь серьезную ошибку в программе.
Ссылки
Название | URL |
How to set up IAR to use GNU make (makefile)? | |
Почему Сборка с Помощью GUI-IDE — это Тупиковый Путь | |
Эффективное использование GNU Make | |
Основы по GNU Make | |
Статический Анализ С-кода | |
Почему важно собирать код из скриптов | |
IAR Eclipse Setup Guide Part 3 — Makefile Project | |
Дымовая Завеса в Eclipse IDE | |
EWARM_DevelopmentGuide.ENU.pdf | |
Сборка firmware для CC2652 из Makefile | |
Техникум: Автоматическое Aрхивирование Aртефактов | |
Интеграция утилиты Artistic Style в скрипт сборки прошивки | |
Интеграция clang-format в Процесс Сборки | |
Progress Bar для Сборки Программы | |
Настройка ToolChain(а) для Win10+GCC+С+Makefile+ARM Cortex-Mx+GDB | |
Интеграция Стилистического Анализа в общий Make Скрипт Сборки Проекта | |
Обновление Прошивки из Make Скрипта | |
IAR Embedded Workbench & Makefiles |
Вопросы
--Зачем в make скриптах нужно ключевое слово VPATH? VPATH позволяет держать объектные файлы отдельно от исходников.
--Как отлаживать прошивку, если она заклинивает при старте и нет возможности воспользоваться пошаговым отладчиком? Использовать GPIO toggle и осциллограф.