Understanding the Makefile
The Makefile for this project is given below.
# Compiler
CC:=avr-gcc
# Source files
SRC_DIR := ./src/
# Microcontroller
MCU := atmega328p
# Clock frequency (16MHz clock chosen)
## To give user input F_CPU, write 'make hex_build "F_CPU=12E6"' for 12MHz clock
F_CPU = 16E6
# Library and other source files
## Directory
DEVICE_DIR := ./inc/$(MCU)/
UTIL_DIR := ./inc/lib/
## Library files location
DEVICE_LIB := $(shell find $(DEVICE_DIR) -name '*.h')
UTIL_LIB := $(shell find $(UTIL_DIR) -name '*.h')
## C files location
DEVICE_C := $(shell find $(DEVICE_DIR) -name '*.c')
UTIL_C := $(shell find $(UTIL_DIR) -name '*.c')
## Collecting all C files and O file names
DEPEN_C := $(DEVICE_C) $(UTIL_C)
DEPEN_O := $(patsubst %.c,%.o,$(DEPEN_C))
# Build and object directory
BUILD_DIR := ./build/
OBJ_DIR := $(BUILD_DIR)obj/
# C standard
STD_C := gnu99
# AVRDUDE Programmer
PROGRAMMER := arduino # Try with avrftdi to avoid using arduino bootloader
# USB Port Number
PORT_NO := /dev/ttyACM0 # works for arduino programmers
#PORT_NO ?= $(shell bash -c 'read -p "USB Port number: " port_no; echo $$port_no')
#Flags
CCFLAGS:= -std=$(STD_C)
CCFLAGS+= -Wall -mmcu=$(MCU) -F_CPU=$(F_CPU)
# Build All files
all: obj_build elf_build hex_build
# Build all dependency source files to object files
$(DEPEN_O): $(DEPEN_C)
$(CC) $(CCFLAGS) -c -o $(OBJ_DIR)$(notdir $@) $(patsubst %.o,%.c,$@)
# Build main object file and dependency object files
obj_build: $(SRC_DIR)main.c $(DEPEN_O)
$(CC) $(CCFLAGS) $(SRC_DIR)main.c -c $(shell find $(OBJ_DIR) -name '*.o') -o $(BUILD_DIR)main.o
echo "\nDone Object file creation"
# Build ELF file
elf_build: $(BUILD_DIR)main.o obj_build
$(CC) $(CCFLAGS) $(BUILD_DIR)main.o $(shell find $(OBJ_DIR) -name '*.o') -o $(BUILD_DIR)main.elf
# Build Intel Hex file format for avrdude flashing
hex_build: obj_build elf_build $(BUILD_DIR)main.elf
avr-objcopy -j .text -j .data -O ihex $(BUILD_DIR)main.elf $(BUILD_DIR)main.hex
# lsusb -t -v
# Used for Flashing Microcontroller!
flash_mcu: hex_build
avrdude -v -p $(MCU) -c $(PROGRAMMER) -P $(PORT_NO) -U flash:w:./build/main.hex:i
# find the programmers using avrdude -c randomdata
clean:
rm ./build/main.*- The Makefile is made generic as possible. Listed below as the generalisations:
- Target micro-controller can be changed just by changing the variable name
MCU.
DEVICE_DIRis stores the particular micro-controller’s memory map header file and relevant declarations in the header file.
UTIL_DIRcontains the header file and source files for the different peripherals such as the LCD display, Motor driver etc.
DEVICE_LIBandUTIL_LIBboth are made to specify the header file locations for tje compiler.
- User defined libraries and functions can be present in the
libfolder. This can also be changed by changing theUTIL_DIRvariable.
- The programmer by default is set
arduinousing the variablePROGRAMMER.
- The USB port is also assigned using the variable
PORT_NO.
- The project by default uses C99 standard which is can be changed by changing the
STD_Cvariable value.
- The processor clock frequency is specified with the flag
F_CPU. This was first not present, but as thedelayfunction was used at multiple places, it was cumbersome to define it in each file, hence it was made as a flag that can be accepted from the user.- To give a different clock frequency, the user can run
makeas followsmake hex_build "F_CPU=12E6"
- To give a different clock frequency, the user can run
- Target micro-controller can be changed just by changing the variable name
- By default the project assumes the
main.cfile undersrcdirectory is where the user would write the main function code.
make allwould generate the hex file for flashing. It contains the build, link and object copy stages.
CC_FLAGS--mmcuflag is used to tell the compiler which is the target micro-controller.
-stdis used to specify the C standard.
-cis the flag used to indicate the source C file
-Lis the flag used to indicate the user defined library file location
-Wallensures that all warnings from the Compiler are printed out (for easy debugging).
$(DEPEN_O): $(DEPEN_C)- This is used to create the object files of the library source files that are present under the
incdirectory.
- All the object files for
incdirectory are stored in theobjdirectory under thebuilddirectory.
- This would then be linked if required in the next step.
- This is used to create the object files of the library source files that are present under the
make obj_buildwould generate themain.oobject file in theBUILD_DIR.$(CC) $(CCFLAGS) $(SRC_DIR)main.c -c $(shell find $(OBJ_DIR) -name '*.o') -o $(BUILD_DIR)main.o- This would first generate all the required object files from the
incdirector, and link then to create a final object file namedmain.oin the build directory.
- This would first generate all the required object files from the
make elf_buildalso works similar. It generates the elf file from the object file generated for the target MCU.
make hex_buildgenerates the Intel compatible hex file format which can be used to flash the micro-controller.avr-objcopy -j .text -j .data -O ihex $(BUILD_DIR)main.elf $(BUILD_DIR)main.hex-jflags are used to mention which segments of the elf file we wish to join (Needs to be verified!) ⇒ here we join the text and data segment.
-o ihexis used to specify that we require the output in hex file format.
make flash_mcuuses theavrdudeto flash the micro-controller.avrdude -v -p $(MCU) -c $(PROGRAMMER) -P $(PORT_NO) -U flash:w:./build/main.hex:i-pis used to specify the part (or micro-controller target).
-cis used to specify the programmer (arduinohere as it comes with a bootloader).
-Pis used to specify the USB port that the arduino board is connected to. Usually its/dev/ttyACM0.
-Uis used to specify the hex file for flashing.