Where I discuss a simplified approach to development automation using make in AVR_C.
- moved the device programming setup to env.make at the root folder
- use one Makefile at the root folder then use “include ../../Makefile” in a file named makefile in each of the examples in the examples folder
- added a
DEPTHvariable to each local makefile (the one in the examples folder)
- removed some of the targets to simplify the file
Here are detailed instructions as to how to use make, the Makefile and env.make to configure and execute your development process.
Arduino IDE Comparison
- As mentioned before, the Makefile controls the compile/link/load process for AVR C. If you execute the command make, with nothing else, it is the same as the verify command (checkmark) and make flash is the same as upload (right arrow) in the Arduino IDE.
- The Arduino IDE uses Tools->Board and Tools->Port to define the board to be used and the port on which to program the board. In AVR C, the env.make file provides the same capability.
Files used for make process
makefile in each example (local makefile)
Note the small “m” in the filename. This file is also known as the “local makefile” and consists of a two lines
DEPTH = ../../ include $(DEPTH)Makefile
The first line indicates the number of levels, this particular makefile is from the root folder. And it uses the number in the second line to find the main Makefile. This configuration enables the ability to have a single Makefile at the root folder AVR_C, simplifying make management. If you create a new folder for a new capability, you will need to add a copy of this specific file in the folder along with your main.c file.
This allows you to make a change to the Makefile and have it changed for every example. (Previously, I attempted to use a symbolic link is similar to an alias in macOS or shortcut in Windows. This worked well for MacOS and Linux, however, symbolic links are handled differently in Windows. This new approach works on all three operating systems.)
Makefile at root folder (main Makefile)
Note the capital “m” in the filename. This Makefile controls all aspects of the development process of AVR C. It does so by automating the specific commands required to:
- Compile the source files (main.c etc)
- Link the source object files with the required object files from the Library (analogWrite(), avrlib, stdio etc)
- Create an executable file in the correct format (main.hex)
- Upload the executable file to the ATmega328P board
- Perform various clean up activites which delete the immediate compiled code, make clean or delete all of the compiled Library code make LIB_clean.
- Provide additional information such as size of code, make size or a listing file, make disasm.
The Makefile uses env.make to provide the required, local details to be successful.
env.make at root folder
As I developed AVR C for multiple processors, multiple operating systems and different CPU’s, it became apparent I needed a more sophisticated system than the multiple targets approach used in the original Makefile. I switched to a specific file which wouldn’t be tracked by git, which would define all of the local requirements. Here is an annotated example block:
# Arduino UNO et al using Optiboot (standard Arduino IDE approach) MCU = atmega328p SERIAL = /dev/cu.usbmodem3101 F_CPU = 16000000UL BAUD = 250000UL SOFT_RESET = 0 LIBDIR = $(DEPTH)Library PROGRAMMER_TYPE = Arduino PROGRAMMER_ARGS = -F -V -P $(SERIAL) -b 115200
As I add processors or new boards, I adjust the parameters accordingly. When I need to make a change, I do it by switching blocks. For example, if I’m going to add a xplainedmini 328PB board, I’ll duplicate a block and make the changes to the new block. I’ll also comment out the old block. It would look like this:
# Arduino UNO et al using Optiboot (standard Arduino IDE approach) # MCU = atmega328p # processor on board, typically 168p, 328p or 328pb # SERIAL = /dev/cu.usbserial-01D5BFFC # specific serial port on local machine to board # F_CPU = 16000000UL # processor clock speed # BAUD = 9600UL # baud rate for serial communications with board # SOFT_RESET = 0 # when set to 1, allows using any push button on Port B as a reset # LIBDIR = $(DEPTH)Library # Library folder for additional functionality # PROGRAMMER_TYPE = Arduino # type of programmer, required by avrdude # PROGRAMMER_ARGS = -F -V -P $(SERIAL) -b 115200 # additional arguments required by avrdude # Microchip 328PB Xplained Mini board MCU = atmega328pb SERIAL = /dev/cu.usbmodem5102 F_CPU = 16000000UL BAUD = 9600UL SOFT_RESET = 1 LIBDIR = $(DEPTH)Library PROGRAMMER_TYPE = xplainedmini PROGRAMMER_ARGS =
Note the first line always needs to be a comment, it merely describes the block. And remember the easiest method to determining the port is to use the Arduino IDE, Tools->Port command to identify the port.
Adding a new folder or example in examples/
If you wanted to add a new example folder, you would add your main.c file as you did before. And create a new file called makefile with this two lines in it
DEPTH = ../../ include $(DEPTH)Makefile
A note on speed and size
The Makefile has two ways to compile the source code, with and without debug information. The method of doing so provides the following results when running examples/blink_avr:
// or remove the delays and determine fastest blink is 2.02MHz w/ -Og -ggdb // or remove the delays and determine fastest blink is 2.68MHz w/ -Os -g
In other words, if you are looking to pick up a little bit of speed AND your program is completely debugged do the following in the Makefile:
- Comment line 44 (the line with -Og) by placing a “#” in front of it
- Uncomment line 46 (the line with -Os) by removing the “#” in front of it.
The code size might shrink and the speed might increase, as it did for this blink_avr example.