вторник, 25 октября 2016 г.

Makefile для сборки проектов на STM32, v2

В процессе использования Makefile, описанного в данной заметке, стали видны некоторые неудобства в его использовании. А именно: вынесение некоторых переменных в отдельные файлы создаёт проблемы при переносе и клонировании проекта, необходимость явного указания как файлов исходного кода, так и получаемых из них объектных файлов создаёт обширное поле для ошибок, также явное задание правил компиляции каждого файла добавляет неразберихи и, опять же, возможности для ошибок, в проект.
Хотелось, чтобы после задания произвольного количества файлов исходного кода их компиляция в объектные файлы происходила без явного создания правил для каждого из них. Также желательно не использовать сторонние средства (внешние скриптовые языки, Perl, Python и проч.), а ограничиться возможностями языка Makefile.
В результате получился следующий файл:

# Выбор типа ядра контроллера
MCU = cortex-m4
# Адрес начала внутренней FLASH-памяти контроллера
LOADADDRESS = 0x08000000
# Использовать драйверы периферийных устройств, предоставленные ST.
# Компиляция для контроллеров серии STM32F373x
DEFINES = -DUSE_STDPERIPH_DRIVER -DSTM32F373xC

# Путь к каталогу драйверов периферии контроллера и вспомогательных библиотек
BASEDIRNAME = /c/STM32Cube/Repository/STM32Cube_FW_L1_V1.6.0/
# Скрипт линковщика, специфичный для контроллера
# Возможно, придётся забрать его в каталог проекта,
# и внести изменения (размер стека, объём внутренней
# FLASH- и RAM-памяти)
LDSCRIPT = $(BASEDIRNAME)Drivers/CMSIS/Device/ST/STM32F3xx/Source/Templates/gcc/linker/STM32F373XC_FLASH.ld
# Путь к каталогу кросскомпилятора
GCCDIRNAME = /c/gcc-arm-none-eabi-5_3-2016q1-20160330-win32/bin/
# Префикс кросскомпилятора
PREFIX = arm-none-eabi-

# Файл конфигурации OpenOCD для программирования заданного контроллера
OPENOCDBOARD = stm32f3discovery.cfg
# Путь к каталогу OpenOCD
PROGRAMMERDIR = /c/openocd-0.9.0/
# Путь к исполняемому файлу OpenOCD, для разных платформ у него разные имена
PROGRAMMERBIN = $(PROGRAMMERDIR)bin-x64/openocd.exe
# Если программируем самодельную плату, то используется один файл конфигурации
# Для демонстрационной платы -- другой
ifdef OPENOCDINTERFACE
 OPENOCDCONFIG = -f $(PROGRAMMERDIR)scripts/interface/$(OPENOCDINTERFACE)
else ifdef OPENOCDBOARD
 OPENOCDCONFIG = -f $(PROGRAMMERDIR)scripts/board/$(OPENOCDBOARD)
else
 $(error "Not defined OPENOCDINTERFACE or OPENOCDBOARD")
endif
# Команды OpenOCD для загрузки файла в контроллер
OPENOCDLOAD = "program result.bin $(LOADADDRESS) verify"
OPENOCDPROGRAM =\
$(OPENOCDCONFIG)\
-c "init"\
-c "halt"\
-c $(OPENOCDLOAD)\
-c "reset run"\
-c "shutdown"
## To unlock chip use next commands after "halt":
# -c "flash protect 0 0 last off"\
# -c "shutdown"

# Для компиляции всех типов файлов и линковки используем gcc.exe
# Он сам разберётся, что вызывать для переданного файла
AS = $(GCCDIRNAME)$(PREFIX)gcc
CC = $(GCCDIRNAME)$(PREFIX)gcc
CXX = $(GCCDIRNAME)$(PREFIX)gcc
LD = $(GCCDIRNAME)$(PREFIX)gcc
# Получение листинга из объектного файла
OBJDUMP = $(GCCDIRNAME)$(PREFIX)objdump
# Преобразование между форматами бинарных файлов
OBJCOPY = $(GCCDIRNAME)$(PREFIX)objcopy

OFLAGS = -Os
CXXSTANDARD = -std=c++11
CSTANDARD = -std=c11

# Каталоги, в которых будут искаться заголовочные файлы
INCLUDES = $(shell pwd)/
INCLUDES += $(BASEDIRNAME)Drivers/CMSIS/Include/
INCLUDES += $(BASEDIRNAME)Drivers/CMSIS/Device/ST/STM32F3xx/Include/
INCLUDES += $(BASEDIRNAME)Drivers/STM32F3xx_HAL_Driver/Inc/

# Флаги, общие для почти всех команд сборки проекта
COMMONFLAGS = -mcpu=$(MCU) -mthumb -MD $(INCLUDES:%=-I%) -c

# Флаги, специфичные для компиляции ассемблерных файлов
ASFLAGS += $(COMMONFLAGS)
# Любые файлы, переданные в переменную ASFILES, трактовать, как ассемблерные
ASFLAGS += -x assembler-with-cpp

# Флаги, специфичные для компиляции файлов C
CFLAGS += $(COMMONFLAGS)
CFLAGS += $(CSTANDARD)
CFLAGS += $(OFLAGS)
CFLAGS += $(DEFINES)
CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
CFLAGS += -Wall
CFLAGS += -fno-exceptions -ffunction-sections -fdata-sections -Wextra -Winline -Wpointer-arith -Wredundant-decls -Wshadow -Wcast-qual -Wcast-align -pedantic
CFLAGS += -ggdb3
# Любые файлы, переданные в переменную CFILES, трактовать как файлы C
CFLAGS += -x c

# Флаги, специфичные для файлов C++
CXXFLAGS += $(COMMONFLAGS)
CXXFLAGS += $(CXXSTANDARD)
CXXFLAGS += $(OFLAGS)
CXXFLAGS += $(DEFINES)
CXXFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
CXXFLAGS += -Wall
CXXFLAGS += -fno-exceptions -fno-rtti -ffunction-sections -fdata-sections -Wextra -Winline -Wpointer-arith -Wredundant-decls -Wshadow -Wcast-qual -Wcast-align -pedantic
CXXFLAGS += -ggdb3
# Любые файлы, переданные в переменную CXXFILES, трактовать как файлы C++
CXXFLAGS += -x c++

# Флаги, специфичные для линкера
LDFLAGS += -Wl,-Map=$(TARGET).map -Wl,--cref
LDFLAGS += -Wl,--start-group -lc_nano -lrdimon_nano -lm -Wl,--end-group
LDFLAGS += -Wl,--gc-sections
# Из переменной COMMONFLAGS забираем элементы с первого по второй
LDFLAGS += $(wordlist 1, 2, $(COMMONFLAGS))

OBJCOPYFLAGS = -O binary
OBJDUMPFLAGS += -x -S

# Объектные и промежуточные файлы сохраняются в этом каталоге, чтобы не засорять проект
OBJDIR = ./obj/
-include $(shell mkdir $(OBJDIR) 2> /dev/null) $(wildcard $(OBJDIR)\*)

# Из каталога с данным Makefile разбираем ассемблерные файлы,
# файлы C и C++ по соответствующим переменным
ASFILES = $(wildcard *.s *.S *.asm)
CFILES = $(wildcard *.c)
CXXFILES = $(wildcard *.cpp)
# Добавляем файлы в проект
ASFILES += $(BASEDIRNAME)Drivers/CMSIS/Device/ST/STM32F3xx/Source/Templates/gcc/startup_stm32f373xc.s
CFILES += $(BASEDIRNAME)Drivers/CMSIS/Device/ST/STM32F3xx/Source/Templates/system_stm32f3xx.c
CXXFILES +=
# Объектные файлы будут с именем соответствующих файлов исходников,
# с добавлением расширения .o
# Таким образом, на сей момент недопустимо наличие в проекте
# файлов с одинаковыми именами для каждого из типов (asm, C, C++).
# В дальнейшем надеюсь это поправить
ASOBJFILES = $(patsubst %,$(OBJDIR)%,$(notdir $(ASFILES:%=%.o)))
COBJFILES = $(patsubst %,$(OBJDIR)%,$(notdir $(CFILES:%=%.o)))
CXXOBJFILES = $(patsubst %,$(OBJDIR)%,$(notdir $(CXXFILES:%=%.o)))

.PHONY : clean all program

# Из элементов переменной *FILES для компиляции выбирается файл,
# имя и расширение которого совпадают с одним из элементов
# переменной *OBJFILES с отброшенным расширением .o
# Если в переменной *FILES окажутся файлы с одинаковыми именами
# и расширениями, то компиляция пройдёт некорректно.
$(ASOBJFILES) : $(ASFILES)
 @echo "-> compiling $@ as ASM-file"
 $(AS) $(ASFLAGS) $(filter %$(notdir $(@:%.o=%)),$^) -o $@

$(COBJFILES) : $(CFILES)
 @echo "-> compiling $@ as C-file"
 $(CC) $(CFLAGS) $(filter %$(notdir $(@:%.o=%)),$^) -o $@
 $(OBJDUMP) $(OBJDUMPFLAGS) $@ > $(@:%.o=%.lst)

$(CXXOBJFILES) : $(CXXFILES)
 @echo "-> compiling $@ as C++-file"
 $(CXX) $(CXXFLAGS) $(filter %$(notdir $(@:%.o=%)),$^) -o $@
 $(OBJDUMP) $(OBJDUMPFLAGS) $@ > $(@:%.o=%.lst)

# Сборка axf-файла из полученных объектных файлов
result.axf : $(ASOBJFILES) $(COBJFILES) $(CXXOBJFILES)
 @echo "-> linking"
 $(LD) -T$(LDSCRIPT) $^ $(LDFLAGS) -o $@

# Преобразование axf-файла в бинарный, и получение ассемблерного листинга
all : result.axf
 @echo "-> copying"
 $(OBJCOPY) $(OBJCOPYFLAGS) $^ result.bin
 $(OBJDUMP) $(OBJDUMPFLAGS) $^ > result.lst

# Заливка бинарного файла в контроллер
program :
 @echo "-> load firmware to controller"
 $(PROGRAMMERBIN) $(OPENOCDPROGRAM)

# Очистка проекта
clean :
 $(RM) -f *.axf *.map *.lst $(OBJDIR)*.d *.bin $(OBJDIR)*.o $(OBJDIR)*.lst


В дальнейшем планирую избавиться от требования уникальности имён файлов, и добавить возможность переопределения флагов компиляции для каждого файла.

четверг, 14 августа 2014 г.

Две идеи рядом:
1. Сделать мышь для компьютера на акселерометре. В простейшем варианте будут проблемы с движением по негоризонтальным поверхностям, но, возможно, не сильно хитрой математикой + статистикой удастся обеспечить распознавание угла наклона;
2. Опять таки мышь, но в виде приложения для смартфона. Bluetooth там есть, камера с достаточным разрешением тоже, процессор, графический ускоритель -- фотографируй, рассчитывай, куда двинули корпус, отдавай в компьютер по Bluetooth-у. Нажатие кнопок, прокрутка -- сенсорный экран. Можно на него ещё и функцию трекбола навесить, чтобы корпус смарта не тягать, а по экрану пальцами, пальцами. А ещё в смартфонах бывает акселерометр (см. идею 1).

Заняться на досуге, что ли?

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

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

четверг, 29 ноября 2012 г.

Boost Spirit::Qi, разбор выражений с числом элементов, большим десяти

При попытке разобрать парсером Spirit::Qi выражение, в котором более десяти элементов, компилятор сообщает об ошибках вида error: '_10' is not a member of 'qi'. Продолжительные и нерегулярные :-) раскопки исходников Qi, а так же связанных с ним Phoenix-а и fusion-а, в конце концов привели к следующим определениям, которые нужно изменить в нужную для себя сторону:
#define PHOENIX_LIMIT                   20 /* Или сколько там надо их парсить... */
#define FUSION_MAX_VECTOR_SIZE          PHOENIX_LIMIT
#define BOOST_RESULT_OF_NUM_ARGS        PHOENIX_LIMIT

После их явного задания требуемые данные успешно распарсились в вектор кортежей:
namespace ph = boost::phoenix;
namespace qi = boost::spirit::qi;
using boost::spirit::ascii::space_type;
//--------------------------------------------------------------------------
typedef double ValueType;
typedef ValueType First;        static const size_t FirstIndex = 0;
typedef ValueType Second;       static const size_t SecondIndex = FirstIndex + 1;
typedef ValueType Third;        static const size_t ThirdIndex = SecondIndex + 1;
typedef ValueType Fourth;       static const size_t FourthIndex = ThirdIndex + 1;
typedef ValueType Fifth;        static const size_t FifthIndex = FourthIndex + 1;
typedef ValueType Sixth;        static const size_t SixthIndex = FifthIndex + 1;
typedef ValueType Seventh;      static const size_t SeventhIndex = SixthIndex + 1;
typedef ValueType Eight;        static const size_t EightIndex = SeventhIndex + 1;
typedef ValueType Ninth;        static const size_t NinthIndex = EightIndex + 1;
typedef ValueType Tenth;        static const size_t TenthIndex = NinthIndex + 1;
typedef ValueType Eleventh;     static const size_t EleventhIndex = TenthIndex + 1;
typedef ValueType Twelfth;      static const size_t TwelfthIndex = EleventhIndex + 1;
typedef bool Locked;            static const size_t LockedIndex = TwelfthIndex + 1;
//--------------------------------------------------------------------------
typedef std::tuple<First,Second,Third,Fourth,Fifth,Sixth,       \
                   Seventh,Eight,Ninth,Tenth,Eleventh,Twelfth,  \
                   Locked> Data;
typedef std::vector<Data> DataContainer;
//--------------------------------------------------------------------------
struct phoenix_make_tuple_impl
{ /* Tuple create adapter  */
  template <typename... Args>
  struct result
  {
    typedef std::tuple<Args...> type;
  };
  template <typename... Args>
  typename result<Args...>::type operator () (Args... args) const
  {
    return std::make_tuple(args...);
  }
};
ph::function<phoenix_make_tuple_impl> const phoenix_make_tuple = phoenix_make_tuple_impl();
//--------------------------------------------------------------------------
template <typename Iterator,typename Container> \
struct ParserGrammar : qi::grammar              \
<Iterator,Container(),qi::blank_type>           \
{
  typedef typename Container::value_type Value;
  ParserGrammar(Container& container) :         \
    ParserGrammar::base_type(start)
  {
    start = qi::lit("Data") >> qi::lit("=") >>     \
      containerData                                \
      [ph::push_back(ph::ref(container),qi::_1)] % \
      qi::eol;
    containerData =                                     \
      (first >> second >> third >> fourth >>            \
       fifth >> sixth >> seventh >> eight >>            \
       ninth >> tenth >> eleventh >> twelfth >>         \
       locked)                                          \
      [qi::_val = phoenix_make_tuple                    \
       (qi::_1,qi::_2,qi::_3,qi::_4,qi::_5,qi::_6,      \
        qi::_7,qi::_8,qi::_9,qi::_10,qi::_11,qi::_12,   \
        qi::_13)];
    first = second = third = fourth = fifth =         \
      sixth = seventh = eight = ninth = tenth =       \
      eleventh = twelfth = qi::double_;
    locked = qi::bool_;
    return;
  }
  qi::rule<Iterator,Container(), qi::blank_type> start;
  qi::rule<Iterator,Value(), qi::blank_type> containerData;
  qi::rule<Iterator,double()>                   \
    first,second,third,fourth,fifth,sixth,      \
    seventh,eight,ninth,tenth,eleventh,twelfth;
  qi::rule<Iterator, bool()> locked;
};
//--------------------------------------------------------------------------
const std::string dataString = "Data = 1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 9.9 10.10 11.11 12.12\n\
10.10 20.20 30.30 40.40 50.50 60.60 70.70 80.80 90.90 100.100 110.110 120.120\n";


вторник, 24 июля 2012 г.

Компиляция проектов Qt версии ниже 4.8.1 с использованием MinGW GCC 4.7.0

При компиляции проектов Qt версии ниже 4.8.1 компилятором MinGW GCC 4.7.0 с использованием флага -std=c++11 некоторые макросы распознаются как пользовательские литералы, что приводит к ошибкам компиляции. Для версии Qt 4.8.1 выпущен патч, а для предыдущих версий предлагается следующий заголовочный файл, корректно (с точки зрения C++11) определяющий нужные макросы:
#ifndef CXX0XCOMPATIBILITY_HPP__20120723__1427
#define CXX0XCOMPATIBILITY_HPP__20120723__1427

/*
 * For compatibility with C++-0x mode in GCC 4.7.x
 */
//-------------------------------------------------------------------------
# ifndef QT_NO_DEBUG
#  ifdef QLOCATION
#  undef QLOCATION
#  define QLOCATION "\0" __FILE__ ":" QTOSTRING(__LINE__)
#   ifndef QT_NO_KEYWORDS
#    ifdef METHOD
#    undef METHOD
#    define METHOD(a)   qFlagLocation("0" #a QLOCATION)
#    endif
#   endif
#  endif
#  ifdef SLOT
#  undef SLOT
#  define SLOT(a)     qFlagLocation("1" #a QLOCATION)
#  endif
#  ifdef SIGNAL
#  undef SIGNAL
#  define SIGNAL(a)   qFlagLocation("2" #a QLOCATION)
#  endif
# else
#  ifndef QT_NO_KEYWORDS
#   ifdef METHOD
#   undef METHOD
#   define METHOD(a)   "0" #a
#   endif
#  endif
#  ifdef SLOT
#  undef SLOT
#  define SLOT(a)     "1" #a
#  endif
#  ifdef SIGNAL
#  undef SIGNAL
#  define SIGNAL(a)   "2" #a
#  endif
# endif

#endif//

Включение этого файла после подключенных заголовочных файлов Qt позволяет "малой кровью", без пересборки самой библиотеки Qt, решить проблему этой ошибки.

воскресенье, 26 февраля 2012 г.

Прочистка форсунок стеклоомывателя

При езде в сырую погоду часто случается досадная неприятность: грязью из-под колёс забиваются форсунки стеклоомывателя. После чего на очистку лобового (а у кого и заднего) стекла приходится тратить гораздо больше времени. Разумеется, это очень снижает безопасность вождения. При попытке прочистить каналы форсунок простой проволокой, зачастую, грязь только проталкивается дальше, к трубке подачи жидкости. В худшем случае проволока может обломиться внутри форсунки, и тогда её остаётся только заменить на новую. А до автомагазина ещё надо доехать... Решение по прочистке было найдено неожиданно, и оказалось очень эффективным. Прочищать надо такой специальной стоматологической штуковиной, под названием эндодонтический файл. Можно выпросить его (с подходящим диаметром) в стоматологическом кабинете, а можно купить в магазине, торгующем медтехникой. Цена их крайне мала -- от 10 рублей за штуку, делаются они из прочной, гибкой стали, так что сломать его внутри форсунки почти невозможно. Так же он имеет конусообразную форму, и резьбу, что позволяет вкрутить его в скопление грязи/ржавчины/чем-там-ещё-может-забиться-форсунка, и вытащить всё это богатство наружу. В общем -- рекомендую. Очень полезная штука.