6. Build system & version control setup
Since we're getting closer to the point of 'platform independent' code, I thought it's time to setup a git repository for the car dashboard project before it gets out of hand. This required rewriting the Makefile and restructuring directories to accommodate BL2 and a simple operating system. BL2 will be the bootloader that is responsible for loading the OS. In a more productive setup, I would not be writing Makefiles by hand, and will probably use Autotools with nested Makefiles for recursive building, but I promised in the introductory post of this series that I will only use make for building the whole project, besides, I believe knowing your way around Makefiles is an essential skill that would come in handy when your make based build system starts acting up.
The directories are intuitively named, but you have to understand that the central piece of the software stack is BL1, the following command shows the directories structure:
korena@korena-solid:~/Development/Projects/Embedded/tiny210$ ls -R .: asm bl2 host_bin host_scripts host_tools include linker.lds Makefile src target_bin ./asm: startup.s ./bl2: asm BL2_linker.lds ./bl2/asm: bl2_asm.s ./host_bin: ./host_scripts: fuseBin.sh ./host_tools: imageMaker.c readFileBytes.c ./include: S5PV210.inc ./src: ./target_bin:
The top level source directories belong to BL1, because it is the primary focus here. A sub directory was created for BL2, and another will be created for the operating system when we come to the OS part of the project, the reason why we treat BL2 and the OS as sub parts of the project is because we plan to use u-boot as bootloader, which will replace BL2, and Linux as a substitute for the simple OS we'll build, the only part that will be kept from this project setup is BL1.
Finally, a Git repository was created for version control, you can clone the project from my public github account.
Only a single top level Makefile is used here, which is not what you'd want to use in a similar real life project, because of the fact that this project encompasses three separate modules, and it would be wiser to have a Makefile for each sub module (BL1, BL2 and OS), preferably using an auto build system. The reason I went with a single Makefile is the fact that maintaining Makefiles manually is something I dread.
# for home #CROSS_COMPILE= /home/korena/Development/Compilers/gcc-arm-none-eabi-4_7-2013q1/bin/arm-none-eabi- # for work CROSS_COMPILE =arm-none-eabi- AS = $(CROSS_COMPILE)as LD = $(CROSS_COMPILE)ld CC = $(CROSS_COMPILE)gcc AR = $(CROSS_COMPILE)ar NM = $(CROSS_COMPILE)nm STRIP = $(CROSS_COMPILE)strip OBJCOPY = $(CROSS_COMPILE)objcopy OBJDUMP = $(CROSS_COMPILE)objdump HEX = $(OBJCOPY) -O ihex BIN = $(OBJCOPY) -O binary -S PRJ_ROOT_DIR := $(shell pwd) PROJECT_HOME := $(shell pwd) ASM_SRC_DIR = $(PROJECT_HOME)/asm SRC_DIR = $(PROJECT_HOME)/src HOST_TOOLS_DIR= $(PROJECT_HOME)/host_tools HOST_SCRIPTS_DIR=$(PROJECT_HOME)/host_scripts # add include directories here ... INCLUDES_DIR = $(PROJECT_HOME)/include ##### bootloader related (second stage) ##### BL2_ROOT_DIR = $(PROJECT_HOME)/bl2 BL2_ASM_DIR = $(BL2_ROOT_DIR)/asm BL2_INC_DIR = $(BL2_ROOT_DIR)/include BL2_C_SRC_DIR = $(BL2_ROOT_DIR)/src TARGET_BIN_DIR = $(PROJECT_HOME)/target_bin HOST_BIN_DIR = $(PROJECT_HOME)/host_bin # Target Name TARGET_NAME := Tiny210_SDK PROJECT_TYPE := embedded_app # Version Number MAJOR := 1 MINOR := 00 IMGMAKE =$(HOST_BIN_DIR)/imageMaker BL1_BIN = $(TARGET_BIN_DIR)/BL1.bin BL1_ELF = $(TARGET_BIN_DIR)/BL1.elf BL1_LDS = linker.lds BL2_BIN = $(TARGET_BIN_DIR)/BL2.bin BL2_ELF = $(TARGET_BIN_DIR)/BL2.elf BL2_LDS = $(BL2_ROOT_DIR)/BL2_linker.lds #BL1 source files expressions ... BL1_SRCs_ASM += $(wildcard $(ASM_SRC_DIR)/*.s) BL1_SRCs_C += $(wildcard $(SRC_DIR)/*.c) OBJS_BL1 = $(BL1_SRCs_ASM:.s=.o) $(BL1_SRCs_C:.c=.o) # BL1 include files expression ... ASM_INCLUDES += $(wildcard $(INCLUDES_DIR)/*.inc) C_INCLUDES += $(wildcard $(INCLUDES_DIR)/*.h) #BL2 source files expressions ... BL2_SRCs_ASM += $(wildcard $(BL2_ASM_DIR)/*.s) BL2_SRCs_C += $(wildcard $(BL2_C_SRC_DIR)/*.c) OBJS_BL2 = $(BL2_SRCs_ASM:.s=.o) $(BL2_SRCs_C:.c=.o) CFLAGS = -Os -nostdlib CFLAGS_HOST = -Os -Wall all: $(IMGMAKE) $(BL1_BIN).boot $(BL1_BIN) $(BL2_BIN) $(BL1_BIN): $(OBJS_BL1) $(LD) -T $(BL1_LDS) -o $(BL1_ELF) -Map BL1.map $(OBJS_BL1) $(OBJCOPY) -O binary $(BL1_ELF) $(BL1_BIN) $(BL1_BIN).boot: $(BL1_BIN) $(IMGMAKE) $(IMGMAKE) ./$(BL1_BIN) ./$(BL1_BIN).boot $(BL2_BIN): $(OBJS_BL2) $(LD) -T $(BL2_LDS) -o $(BL2_ELF) -Map $(BL2_ROOT_DIR)/BL2.map $(OBJS_BL2) $(OBJCOPY) -O binary $(BL2_ELF) $(BL2_BIN) $(IMGMAKE): gcc $(CFLAGS_HOST) -o $(IMGMAKE) $(HOST_TOOLS_DIR)/imageMaker.c fuse: $(BL1_BIN).boot $(BL2_BIN) . $(HOST_SCRIPTS_DIR)/fuseBin.sh %.o: %.c $(CC) -c $(CFLAGS) -I . $(INCLUDES_DIR) $< -o $@ %.o: %.s $(AS) -c $(AFLAGS) -I $(ASM_INCLUDES) $< -o $@ %elf: $(OBJS_BL1) $(CC) $(OBJS_BL1) $(LDFLAGS) $(LIBS) -o $@ %hex: %elf $(HEX) $< $@ %bin: %elf $(BIN) $< $@ readFileBytes: gcc $(CFLAGS_HOST) -o $(HOST_BIN_DIR)/readBytes $(HOST_TOOLS_DIR)/readFileBytes.c clean: rm -rf $(OBJS) $(HOST_BIN_DIR)/* $(TARGET_BIN_DIR)/*.bin $(TARGET_BIN_DIR)/*.elf $(TARGET_BIN_DIR)/*.boot $(TARGET_BIN_DIR)/*.o *.map *.o $(ASM_SRC_DIR)/*.o SRC_DIR/*.o $(BL2_ASM_DIR)/*.o $(BL2_ROOT_DIR)/*.map
There are a few things to note about this makefile, it maintains host tools that are compiled to run on the host machine, in addition to the compilation of binaries to run on the target. It also runs a script that is used to fuse binaries into the MMC card.
All intermediate objects that are produced through the compilation process reside in the same directory as their sources, but the final result of target binaries are produced in the target_bin directory for target binaries, and host_bin for host tools. Some Makefile targets are for testing purposes, and are not used in the build process.
Operating system build rules are missing, and will be completed when we need them, some BL2 rules are also missing, and will be completed as we progress through the next couple of posts.
Last but not least, a great deal of attention should be paid to the $(HOST_BIN_DIR)/* bit under clean: target, if you misspell the variable name, or provide a variable name that holds no value, then the simple command make clean will recursively and forcefully remove your root directory and its contents, this is basically death.
Finally, some files related to BL2 are added for testing purposes, they will be modified soon, we are now focusing on building BL1.
Next, we'll go back to programming. We'll initialize the UART subsystem to assist us in finishing the low level initialization of the system.