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_DIR
is stores the particular micro-controller’s memory map header file and relevant declarations in the header file.
UTIL_DIR
contains the header file and source files for the different peripherals such as the LCD display, Motor driver etc.
DEVICE_LIB
andUTIL_LIB
both are made to specify the header file locations for tje compiler.
- User defined libraries and functions can be present in the
lib
folder. This can also be changed by changing theUTIL_DIR
variable.
- The programmer by default is set
arduino
using 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_C
variable value.
- The processor clock frequency is specified with the flag
F_CPU
. This was first not present, but as thedelay
function 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
make
as 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.c
file undersrc
directory is where the user would write the main function code.
make all
would generate the hex file for flashing. It contains the build, link and object copy stages.
CC_FLAGS
--mmcu
flag is used to tell the compiler which is the target micro-controller.
-std
is used to specify the C standard.
-c
is the flag used to indicate the source C file
-L
is the flag used to indicate the user defined library file location
-Wall
ensures 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
inc
directory.
- All the object files for
inc
directory are stored in theobj
directory under thebuild
directory.
- 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_build
would generate themain.o
object 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
inc
director, and link then to create a final object file namedmain.o
in the build directory.
- This would first generate all the required object files from the
make elf_build
also works similar. It generates the elf file from the object file generated for the target MCU.
make hex_build
generates 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
-j
flags 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 ihex
is used to specify that we require the output in hex file format.
make flash_mcu
uses theavrdude
to flash the micro-controller.avrdude -v -p $(MCU) -c $(PROGRAMMER) -P $(PORT_NO) -U flash:w:./build/main.hex:i
-p
is used to specify the part (or micro-controller target).
-c
is used to specify the programmer (arduino
here as it comes with a bootloader).
-P
is used to specify the USB port that the arduino board is connected to. Usually its/dev/ttyACM0
.
-U
is used to specify the hex file for flashing.