A control system framework for personal automation.
Makefiles are necessary in order to compile firmware into a .hex file that can be loaded onto the physical node’s microcontroller. Makefiles are essentially a recipe instructing the compiler how to build a .hex file from an input C++ file.
We have created a “standard” makefile that can be used to compile your Gestalt code. Because makefiles are inherently confusing, we’ll step you thru our standard makefile here.
The makefile is divided into roughly three sections. The first is where you will define a bunch of parameters that control how your code is compiled.
This is where you provide the name of your node’s main C++ file. Leave off the extension; we assume it ends in .cpp:
PROJECT = projectName
Defines the microcontroller type. This is needed by the AVR-GCC compiler in order to map register definitions correctly. A list of options is avaliable on the AVR-GCC website:
MCU = atmega328p
The clock frequency, in Hz. This is required for time-based macros like _delay_us() to accurately function:
FREQ = 18432000
The starting memory address of the compiled code. Use the above if you are compiling a standard node application:
ADDRESS = 0x0000
Or, use the below INSTEAD if you are compiling a bootloader. This is valid for the Atmega 328 and 324. If you are compiling for a microcontroller with a different sized memory (e.g. the Atmega 168), you’ll need to check the correct starting memory address for the bootloader section:
ADDRESS = 0x7000
Here we are defining a bunch of flags that alter the functionality of the code by affecting which lines are compiled:
GESTALT_DEFS = -DstandardGestalt -DnetworkedGestalt -Dgestalt328
The following flags are supported by the Gestalt firmware library:
The makefile includes all of the following options. You should comment out all except the one you want, or modify to taste:
# -> Use for a networked Gestalt node application
GESTALT_DEFS = -DstandardGestalt -DnetworkedGestalt -Dgestalt328
# -> Use below for a networked Gestalt node bootloader
GESTALT_DEFS = -DstandardGestalt -Dbootloader -DnetworkedGestalt -Dgestalt328
# -> Use below for a non-networked Gestalt node application
GESTALT_DEFS = -DstandardGestalt -Dgestalt328
# -> Use below for a non-networked Gestalt node bootloader
GESTALT_DEFS = -DstandardGestalt -Dbootloader -Dgestalt328
Lastly, we’ll tell the compiler where it can find the Gestalt firmware library (gestalt.cpp and gestalt.h). You should change this to match where you’ve installed (or symlinked) the Gestalt library.
GESTALT_DIR = users/imoyer/gsArduino
Here the makefile is just taking the options above and putting them into the format needed by the compiler and linker.
This builds up the absolute path of the Gestalt library:
GESTALT_FILE = $(GESTALT_DIR)/gestalt.cpp
Tells the linker where the code section starts:
LDSECTION = --section-start=.text=$(ADDRESS)
Builds a list of the primary source files needed to compile:
SOURCES = $(PROJECT).cpp $(GESTALT_FILE)
Collates all compiler flags:
CFLAGS = -g -Wall -Os -mmcu=$(MCU) -DF_CPU=$(FREQ) -I$(GESTALT_DIR) $(GESTALT_DEFS)
Collates all linker flags:
LDFLAGS = -Wl,$(LDSECTION)
The following line builds the project and then deletes all intermediate files. This ideally would be in the next section after all of the avr-g++ calls, but for whatever reason this causes the compilation process to stop prematurely:
all: $(PROJECT).hex clean
This is the default behavior, and can be evoked simply by running make.
>> make
Builds an object file from the source code:
$(PROJECT).o: $(SOURCES)
avr-g++ $(CFLAGS) -c -Wall $(SOURCES)
Builds an executable and linkable format (ELF) file from the object file:
$(PROJECT).elf: $(PROJECT).o
avr-g++ $(CFLAGS) $(LDFLAGS) gestalt.o -o $@ $^
Converts the ELF file into a hex file, and display resource requirements:
$(PROJECT).hex: $(PROJECT).elf
avr-objcopy -j .text -j .data -O ihex $< $@
avr-size -C --mcu=$(MCU) $(PROJECT).elf
The following additional lines in the makefile define options you can invoke from the terminal. Each is presented first as the makefile line, and then the corresponding terminal command.
Deletes all intermediate files created in the build process:
clean:
rm -rf *.o *.elf
In the terminal:
>> make clean
Deletes ALL files created in the build process. This is typically used in conjuncture with a programmer:
clean-all:
rm -rf *.o *.elf $(PROJECT).hex
In the terminal:
>> make clean-all
The following builds the code and then programs the target microcontroller using the Universal Personality Programmer. You can alternatively replace the line with the terminal command for avrdude, etc…
flash:
python UPPloader.py $(PROJECT).hex
In the terminal:
>> make flash
This will build the code, program the microcontroller, and then delete all of the built files:
load: $(PROJECT).hex flash clean
In the terminal:
>> make load
It is worth noting that typically we only use this command when flashing a Gestalt bootloader onto a fresh microcontroller. Application code can be more easily loaded onto the MCU via the virtual node bootloader functions.