diff --git a/Arduino.mk b/Arduino.mk index d245c36..a238fe6 100644 --- a/Arduino.mk +++ b/Arduino.mk @@ -261,7 +261,9 @@ else endif # include Common.mk now we know where it is -include $(ARDMK_DIR)/Common.mk +ifndef COMMON_INCLUDED + include $(ARDMK_DIR)/Common.mk +endif # show_config_variable macro is available now. So let's print config details for ARDMK_DIR ifndef ARDMK_DIR_MSG @@ -317,18 +319,19 @@ else ifeq ($(ARCHITECTURE),avr) ARDUINO_ARCH_FLAG = -DARDUINO_ARCH_AVR else - ifeq ($(ARCHITECTURE),sam) - ARDUINO_ARCH_FLAG = -DARDUINO_ARCH_SAM - else - ARDUINO_ARCH_FLAG = -DARDUINO_ARCH_$(shell echo $(ARCHITECTURE) | tr '[:lower:]' '[:upper:]') - endif + ARDUINO_ARCH_FLAG = -DARDUINO_ARCH_$(shell echo $(ARCHITECTURE) | tr '[:lower:]' '[:upper:]') endif endif ######################################################################## # 1.5.x vendor - defaults to arduino ifndef ARDMK_VENDOR - ARDMK_VENDOR = arduino + ARCH_LINUX := $(shell grep "Arch Linux" /etc/os-release 2>/dev/null) + ifdef ARCH_LINUX + ARDMK_VENDOR = archlinux-arduino + else + ARDMK_VENDOR = arduino + endif $(call show_config_variable,ARDMK_VENDOR,[DEFAULT]) else $(call show_config_variable,ARDMK_VENDOR,[USER]) @@ -454,7 +457,14 @@ ifndef AVR_TOOLS_DIR AVR_TOOLS_DIR = $(SYSTEMPATH_AVR_TOOLS_DIR) $(call show_config_variable,AVR_TOOLS_DIR,[AUTODETECTED],(found in $$PATH)) else - echo $(error No AVR tools directory found) + # One last attempt using avr-gcc in case using arm + SYSTEMPATH_AVR_TOOLS_DIR := $(call dir_if_exists,$(abspath $(dir $(shell which $(avr-gcc)))/..)) + ifdef SYSTEMPATH_AVR_TOOLS_DIR + AVR_TOOLS_DIR = $(SYSTEMPATH_AVR_TOOLS_DIR) + $(call show_config_variable,AVR_TOOLS_DIR,[AUTODETECTED],(found in $$PATH)) + else + echo $(error No AVR tools directory found) + endif endif # SYSTEMPATH_AVR_TOOLS_DIR endif # BUNDLED_AVR_TOOLS_DIR @@ -644,6 +654,9 @@ ifeq ($(strip $(NO_CORE)),) USB_PID := $(call PARSE_BOARD,$(BOARD_TAG),menu.(chip|cpu).$(BOARD_SUB).build.pid) endif endif + + # add caterina flag to ARD_RESET_OPTS + ARD_RESET_OPTS += --caterina endif # normal programming info @@ -745,34 +758,21 @@ endif # Reset ifndef RESET_CMD - ARD_RESET_ARDUINO := $(shell which ard-reset-arduino 2> /dev/null) - ifndef ARD_RESET_ARDUINO - # same level as *.mk in bin directory when checked out from git - # or in $PATH when packaged - ARD_RESET_ARDUINO = $(ARDMK_DIR)/bin/ard-reset-arduino - endif - ifneq ($(CATERINA),) - ifneq (,$(findstring CYGWIN,$(shell uname -s))) - # confirm user is using default cygwin unix Python (which uses ttySx) and not Windows Python (which uses COMx) - ifeq ($(shell which python),/usr/bin/python) - RESET_CMD = $(ARD_RESET_ARDUINO) --caterina $(ARD_RESET_OPTS) $(DEVICE_PATH) - else - RESET_CMD = $(ARD_RESET_ARDUINO) --caterina $(ARD_RESET_OPTS) $(call get_monitor_port) - endif - else - RESET_CMD = $(ARD_RESET_ARDUINO) --caterina $(ARD_RESET_OPTS) $(call get_monitor_port) - endif + ARD_RESET_ARDUINO := $(shell which ard-reset-arduino 2> /dev/null) + ifndef ARD_RESET_ARDUINO + # same level as *.mk in bin directory when checked out from git + # or in $PATH when packaged + ARD_RESET_ARDUINO = $(ARDMK_DIR)/bin/ard-reset-arduino + endif + ifneq (,$(findstring CYGWIN,$(shell uname -s))) + # confirm user is using default cygwin unix Python (which uses ttySx) and not Windows Python (which uses COMx) + ifeq ($(shell which python),/usr/bin/python) + RESET_CMD = $(ARD_RESET_ARDUINO) $(ARD_RESET_OPTS) $(DEVICE_PATH) + else + RESET_CMD = $(ARD_RESET_ARDUINO) $(ARD_RESET_OPTS) $(call get_monitor_port) + endif else - ifneq (,$(findstring CYGWIN,$(shell uname -s))) - # confirm user is using default cygwin unix Python (which uses ttySx) and not Windows Python (which uses COMx) - ifeq ($(shell which python),/usr/bin/python) - RESET_CMD = $(ARD_RESET_ARDUINO) $(ARD_RESET_OPTS) $(DEVICE_PATH) - else - RESET_CMD = $(ARD_RESET_ARDUINO) $(ARD_RESET_OPTS) $(call get_monitor_port) - endif - else - RESET_CMD = $(ARD_RESET_ARDUINO) $(ARD_RESET_OPTS) $(call get_monitor_port) - endif + RESET_CMD = $(ARD_RESET_ARDUINO) $(ARD_RESET_OPTS) $(call get_monitor_port) endif endif @@ -815,7 +815,7 @@ ifeq ($(strip $(CHK_SOURCES)),) $(call show_config_info,No .pde or .ino files found. If you are compiling .c or .cpp files then you need to explicitly include Arduino header files) else #TODO: Support more than one file. https://github.com/sudar/Arduino-Makefile/issues/49 - $(error Need exactly one .pde or .ino file. This makefile doesn't support multiple .ino/.pde files yet) + $(error Need exactly one .pde or .ino file. This makefile doesn\'t support multiple .ino/.pde files yet) endif endif @@ -830,13 +830,26 @@ ifeq ($(strip $(NO_CORE)),) CORE_CPP_SRCS = $(wildcard $(ARDUINO_CORE_PATH)/*.cpp) CORE_AS_SRCS = $(wildcard $(ARDUINO_CORE_PATH)/*.S) + # USB Core if samd or sam + ifeq ($(findstring sam, $(strip $(ARCHITECTURE))), sam) + CORE_C_SRCS += $(wildcard $(ARDUINO_CORE_PATH)/USB/*.c) + CORE_CPP_SRCS += $(wildcard $(ARDUINO_CORE_PATH)/USB/*.cpp) + endif + ifneq ($(strip $(NO_CORE_MAIN_CPP)),) CORE_CPP_SRCS := $(filter-out %main.cpp, $(CORE_CPP_SRCS)) $(call show_config_info,NO_CORE_MAIN_CPP set so core library will not include main.cpp,[MANUAL]) endif + # Put alt core variant file for M0 devices in OTHER_OJBS + ifdef ALT_CORE_CPP_SRCS + ALT_CORE_OBJ_FILES = $(ALT_CORE_C_SRCS:.c=.c.o) $(ALT_CORE_CPP_SRCS:.cpp=.cpp.o) $(ALT_CORE_AS_SRCS:.S=.S.o) + OTHER_OBJS := $(patsubst $(ALTERNATE_CORE_PATH)/variants/$(VARIANT)/%, \ + $(OBJDIR)/core/%,$(ALT_CORE_OBJ_FILES)) + endif + CORE_OBJ_FILES = $(CORE_C_SRCS:.c=.c.o) $(CORE_CPP_SRCS:.cpp=.cpp.o) $(CORE_AS_SRCS:.S=.S.o) - CORE_OBJS = $(patsubst $(ARDUINO_CORE_PATH)/%, \ + CORE_OBJS += $(patsubst $(ARDUINO_CORE_PATH)/%, \ $(OBJDIR)/core/%,$(CORE_OBJ_FILES)) endif else @@ -908,6 +921,7 @@ endif TARGET_HEX = $(OBJDIR)/$(TARGET).hex TARGET_ELF = $(OBJDIR)/$(TARGET).elf TARGET_EEP = $(OBJDIR)/$(TARGET).eep +TARGET_BIN = $(OBJDIR)/$(TARGET).bin CORE_LIB = $(OBJDIR)/libcore.a # Names of executables - chipKIT needs to override all to set paths to PIC32 @@ -1023,6 +1037,7 @@ endif # SoftwareSerial requires -Os (some delays are tuned for this optimization level) %SoftwareSerial.cpp.o : OPTIMIZATION_FLAGS = -Os +%Uart.cpp.o : OPTIMIZATION_FLAGS = -Os ifndef MCU_FLAG_NAME MCU_FLAG_NAME = mmcu @@ -1100,7 +1115,7 @@ ifeq ($(shell expr $(CC_VERNUM) '>' 490), 1) endif LDFLAGS += -$(MCU_FLAG_NAME)=$(MCU) -Wl,--gc-sections -O$(OPTIMIZATION_LEVEL) ifeq ($(shell expr $(CC_VERNUM) '>' 490), 1) - LDFLAGS += -flto -fuse-linker-plugin + LDFLAGS += -flto -fuse-linker-plugin endif SIZEFLAGS ?= --mcu=$(MCU) -C @@ -1308,7 +1323,24 @@ $(OBJDIR)/core/%.S.o: $(ARDUINO_CORE_PATH)/%.S $(COMMON_DEPS) | $(OBJDIR) @$(MKDIR) $(dir $@) $(CC) -MMD -c $(CPPFLAGS) $(ASFLAGS) $< -o $@ +# alt core files +$(OBJDIR)/core/%.c.o: $(ALTERNATE_CORE_PATH)/variants/$(VARIANT)/%.c $(COMMON_DEPS) | $(OBJDIR) + @$(MKDIR) $(dir $@) + $(CC) -MMD -c $(CPPFLAGS) $(CFLAGS) $< -o $@ + +$(OBJDIR)/core/%.cpp.o: $(ALTERNATE_CORE_PATH)/variants/$(VARIANT)/%.cpp $(COMMON_DEPS) | $(OBJDIR) + @$(MKDIR) $(dir $@) + $(CXX) -MMD -c $(CPPFLAGS) $(CXXFLAGS) $< -o $@ + +$(OBJDIR)/core/%.S.o: $(ALTERNATE_CORE_PATH)/variants/$(VARIANT)/%.S $(COMMON_DEPS) | $(OBJDIR) + @$(MKDIR) $(dir $@) + $(CC) -MMD -c $(CPPFLAGS) $(ASFLAGS) $< -o $@ + # various object conversions +$(OBJDIR)/%.bin: $(OBJDIR)/%.elf $(COMMON_DEPS) + @$(MKDIR) $(dir $@) + -$(OBJCOPY) -O binary $< $@ + $(OBJDIR)/%.hex: $(OBJDIR)/%.elf $(COMMON_DEPS) @$(MKDIR) $(dir $@) $(OBJCOPY) -O ihex -R .eeprom $< $@ @@ -1448,12 +1480,21 @@ endif # so we do not set it by default. AVRDUDE_ISP_OPTS = -c $(ISP_PROG) -b $(AVRDUDE_ISP_BAUDRATE) -ifndef $(ISP_PORT) +ifndef ISP_PORT ifneq ($(strip $(ISP_PROG)),$(filter $(ISP_PROG), atmelice_isp usbasp usbtiny gpio linuxgpio avrispmkii dragon_isp dragon_dw)) - AVRDUDE_ISP_OPTS += -P $(call get_isp_port) + # switch for sam devices as bootloader will be on usb serial if using stk500_v2 + ifeq ($(findstring sam, $(strip $(ARCHITECTURE))), sam) + AVRDUDE_ISP_OPTS += -P $(call get_monitor_port) + else + AVRDUDE_ISP_OPTS += -P $(call get_isp_port) + endif endif else - AVRDUDE_ISP_OPTS += -P $(call get_isp_port) + ifeq ($(CURRENT_OS), WINDOWS) + AVRDUDE_ISP_OPT += -P ISP_PORT + else + AVRDUDE_ISP_OPTS += -P $(call get_isp_port) + endif endif ifndef ISP_EEPROM @@ -1471,7 +1512,7 @@ endif ######################################################################## # Explicit targets start here -all: $(TARGET_EEP) $(TARGET_HEX) +all: $(TARGET_EEP) $(TARGET_BIN) $(TARGET_HEX) # Rule to create $(OBJDIR) automatically. All rules with recipes that # create a file within it, but do not already depend on a file within it @@ -1485,8 +1526,15 @@ $(OBJDIR): pre-build pre-build: $(call runscript_if_exists,$(PRE_BUILD_HOOK)) +# copied from arduino with start-group, end-group $(TARGET_ELF): $(LOCAL_OBJS) $(CORE_LIB) $(OTHER_OBJS) +# sam devices need start and end group +ifeq ($(findstring sam, $(strip $(ARCHITECTURE))), sam) + $(CC) $(LINKER_SCRIPTS) -Wl,-Map=$(OBJDIR)/$(TARGET).map -o $@ $(LOCAL_OBJS) $(OTHER_OBJS) $(OTHER_LIBS) $(LDFLAGS) $(CORE_LIB) -Wl,--end-group +# otherwise traditional +else $(CC) $(LDFLAGS) -o $@ $(LOCAL_OBJS) $(CORE_LIB) $(OTHER_OBJS) $(OTHER_LIBS) -lc -lm $(LINKER_SCRIPTS) +endif $(CORE_LIB): $(CORE_OBJS) $(LIB_OBJS) $(PLATFORM_LIB_OBJS) $(USER_LIB_OBJS) $(AR) rcs $@ $(CORE_OBJS) $(LIB_OBJS) $(PLATFORM_LIB_OBJS) $(USER_LIB_OBJS) @@ -1494,21 +1542,47 @@ $(CORE_LIB): $(CORE_OBJS) $(LIB_OBJS) $(PLATFORM_LIB_OBJS) $(USER_LIB_OBJS) error_on_caterina: $(ERROR_ON_CATERINA) - # Use submake so we can guarantee the reset happens # before the upload, even with make -j upload: $(TARGET_HEX) verify_size +ifeq ($(findstring sam, $(strip $(ARCHITECTURE))), sam) +# do reset toggle at 1200 BAUD to enter bootloader if using avrdude or bossa +ifeq ($(strip $(UPLOAD_TOOL)), avrdude) + $(MAKE) reset +else ifeq ($(findstring bossac, $(strip $(UPLOAD_TOOL))), bossac) + $(MAKE) reset +endif + $(MAKE) do_sam_upload +else $(MAKE) reset $(MAKE) do_upload +endif raw_upload: $(TARGET_HEX) verify_size +ifeq ($(findstring sam, $(strip $(ARCHITECTURE))), sam) + $(MAKE) do_sam_upload +else $(MAKE) error_on_caterina $(MAKE) do_upload +endif do_upload: $(AVRDUDE) $(AVRDUDE_COM_OPTS) $(AVRDUDE_ARD_OPTS) \ $(AVRDUDE_UPLOAD_HEX) +do_sam_upload: $(TARGET_BIN) verify_size +ifeq ($(findstring openocd, $(strip $(UPLOAD_TOOL))), openocd) + $(OPENOCD) $(OPENOCD_OPTS) -c "telnet_port disabled; program {{$(TARGET_BIN)}} verify reset $(BOOTLOADER_SIZE); shutdown" +else ifeq ($(findstring bossac, $(strip $(UPLOAD_TOOL))), bossac) + $(BOSSA) $(BOSSA_OPTS) $(TARGET_BIN) +else ifeq ($(findstring gdb, $(strip $(UPLOAD_TOOL))), gdb) + $(GDB) $(GDB_UPLOAD_OPTS) +else ifeq ($(strip $(UPLOAD_TOOL)), avrdude) + $(MAKE) ispload +else + @$(ECHO) "$(BOOTLOADER_UPLOAD_TOOL) not currently supported!\n\n" +endif + do_eeprom: $(TARGET_EEP) $(TARGET_HEX) $(AVRDUDE) $(AVRDUDE_COM_OPTS) $(AVRDUDE_ARD_OPTS) \ $(AVRDUDE_UPLOAD_EEP) @@ -1541,14 +1615,22 @@ ispload: $(TARGET_EEP) $(TARGET_HEX) verify_size $(AVRDUDE_ISPLOAD_OPTS) burn_bootloader: -ifneq ($(strip $(AVRDUDE_ISP_FUSES_PRE)),) - $(AVRDUDE) $(AVRDUDE_COM_OPTS) $(AVRDUDE_ISP_OPTS) -e $(AVRDUDE_ISP_FUSES_PRE) -endif -ifneq ($(strip $(AVRDUDE_ISP_BURN_BOOTLOADER)),) - $(AVRDUDE) $(AVRDUDE_COM_OPTS) $(AVRDUDE_ISP_OPTS) $(AVRDUDE_ISP_BURN_BOOTLOADER) -endif -ifneq ($(strip $(AVRDUDE_ISP_FUSES_POST)),) - $(AVRDUDE) $(AVRDUDE_COM_OPTS) $(AVRDUDE_ISP_OPTS) $(AVRDUDE_ISP_FUSES_POST) +ifeq ($(findstring sam, $(strip $(ARCHITECTURE))), sam) + ifeq ($(strip $(BOOTLOADER_UPLOAD_TOOL)), openocd) + $(OPENOCD) $(OPENOCD_OPTS) -c "telnet_port disabled; init; halt; $(BOOTLOADER_UNPROTECT); program {{$(BOOTLOADER_PARENT)/$(BOOTLOADER_FILE)}} verify reset; shutdown" + else + @$(ECHO) "$(BOOTLOADER_UPLOAD_TOOL) not currently supported!\n\n" + endif +else + ifneq ($(strip $(AVRDUDE_ISP_FUSES_PRE)),) + $(AVRDUDE) $(AVRDUDE_COM_OPTS) $(AVRDUDE_ISP_OPTS) -e $(AVRDUDE_ISP_FUSES_PRE) + endif + ifneq ($(strip $(AVRDUDE_ISP_BURN_BOOTLOADER)),) + $(AVRDUDE) $(AVRDUDE_COM_OPTS) $(AVRDUDE_ISP_OPTS) $(AVRDUDE_ISP_BURN_BOOTLOADER) + endif + ifneq ($(strip $(AVRDUDE_ISP_FUSES_POST)),) + $(AVRDUDE) $(AVRDUDE_COM_OPTS) $(AVRDUDE_ISP_OPTS) $(AVRDUDE_ISP_FUSES_POST) + endif endif set_fuses: @@ -1586,6 +1668,12 @@ else $(MONITOR_CMD) $(call get_monitor_port) $(MONITOR_BAUDRATE) endif +debug_init: + $(OPENOCD) + +debug: + $(GDB) $(GDB_OPTS) + disasm: $(OBJDIR)/$(TARGET).lss @$(ECHO) "The compiled ELF file has been disassembled to $(OBJDIR)/$(TARGET).lss\n\n" @@ -1605,7 +1693,6 @@ generate_assembly: $(OBJDIR)/$(TARGET).s generated_assembly: generate_assembly @$(ECHO) "\"generated_assembly\" target is deprecated. Use \"generate_assembly\" target instead\n\n" -.PHONY: tags tags: ifneq ($(words $(wildcard $(TAGS_FILE))), 0) rm -f $(TAGS_FILE) @@ -1640,6 +1727,8 @@ help: make show_boards - list all the boards defined in boards.txt\n\ make show_submenu - list all board submenus defined in boards.txt\n\ make monitor - connect to the Arduino's serial port\n\ + make debug_init - start openocd gdb server\n\ + make debug - connect to gdb target and begin debugging\n\ make size - show the size of the compiled output (relative to\n\ resources, if you have a patched avr-size).\n\ make verify_size - verify that the size of the final file is less than\n\ @@ -1661,7 +1750,7 @@ help: .PHONY: all upload raw_upload raw_eeprom error_on_caterina reset reset_stty ispload \ clean depends size show_boards monitor disasm symbol_sizes generated_assembly \ - generate_assembly verify_size burn_bootloader help pre-build + generate_assembly verify_size burn_bootloader help pre-build tags debug debug_init # added - in the beginning, so that we don't get an error if the file is not present -include $(DEPS) diff --git a/Common.mk b/Common.mk index a8bd46a..5f30fba 100644 --- a/Common.mk +++ b/Common.mk @@ -1,3 +1,4 @@ +COMMON_INCLUDED = TRUE # Useful functions # Returns the first argument (typically a directory), if the file or directory # named by concatenating the first and optionally second argument @@ -26,8 +27,11 @@ show_config_variable = $(call show_config_info,$(1) = $($(1)) $(3),$(2)) # Just a nice simple visual separator show_separator = $(call arduino_output,-------------------------) +# Master Arduino Makefile include (after user Makefile) +ardmk_include = $(shell basename $(word 2,$(MAKEFILE_LIST))) + $(call show_separator) -$(call arduino_output,Arduino.mk Configuration:) +$(call arduino_output,$(call ardmk_include) Configuration:) ######################################################################## # diff --git a/HISTORY.md b/HISTORY.md index e18a065..434ed96 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -19,6 +19,7 @@ I tried to give credit whenever possible. If I have missed anyone, kindly add it - New: Add template Makefile and project boilerplate initialise script, `ardmk-init`. (https://github.com/tuna-f1sh) - New: Support atmelice_isp JTAG tool as ISP programmer. (https://github.com/tuna-f1sh) - New: Compatibility with deprecated pgmspace.h API can now be disabled since it sometimes causes bogus compiler warnings (issue #546) +- New: Support Arduino ARM-based (SAM/SAMD) devices. (https://github.com/tuna-f1sh) ### 1.6.0 (2017-07-11) - Fix: Allowed for SparkFun's weird usb pid/vid submenu shenanigans (issue #499). (https://github.com/sej7278) diff --git a/README.md b/README.md index 953d067..f3b5e20 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ This is a very simple Makefile which knows how to build Arduino sketches. It def - Very robust - Highly customizable - Supports all official AVR-based Arduino boards +- Supports official ARM-based Arduino boards using Atmel SAM chip family + (Cortex M0) and includes on-device debugging targets. - Supports chipKIT - Supports Teensy 3.x (via Teensyduino) - Works on all three major OS (Mac, Linux, Windows) @@ -313,6 +315,72 @@ See examples/BlinkOpenCM for example usage. For large Robotis projects, [libmaple](https://github.com/Rhoban/Maple) may be more appropriate, as the OpenCM IDE uses a very old compiler release. +## Arduino ARM Boards + +For Arduino boards using ARM architechure, specifically the Atmel SAM series +(Arduino M0 [Pro], Zero, MKR1000, Feather M0, etc.), first +install the board support package from the IDE or other distribution channels. + +Define`ARDUINO_PACKAGE_DIR` as the root path containing the ARM support +package (the manufacturer folder) and the `BOARD_TAG` (see `make show_boards` +for help) within your project Makefile. Include 'Sam.mk' rather than + 'Arduino.mk' at the end of your file - see examples/ZeroBlink and + examples/MZeroBlink for example usage. + +**Note**: The Arduino IDE does not install board support packages to +the base Arduino installation directory (the directory that will work with AVR +Makefiles). They are generally installed to a '.arduino15/packages' folder in +the users home directory. This is the reason for the new `ARDUINO_PACKAGE_DIR` +define. On Windows, the package directory is often in the user home directory +so advice is to create a symblic link to avoid slash/space in path problems. +You can also manually install support packages in your Sketchbook 'hardware' +folder, then define ARDUINO_PACKAGE_DIR as this path. + +If using a SAM board from a manufacturer other than Arduino, one must still +install the Arduino board support as above (unless using externally defined +toolchain) and then define the location of the manufacturer board support core +using the ALTERNATIVE_CORE_PATH define. For example: `ALTERNATE_CORE_PATH = +$(ARDUINO_SKETCHBOOK)/hardware/sparkfun/samd` + +The programing method will auto-detect based on the `BOARD_TAG` settings read +from boards.txt: + +Programming using OpenOCD CMSIS-DAP with the Programming/debug USB is +currently supported (the same method used by the IDE), including burning +bootloaders. External CMSIS tools such as Atmel Ice will also work with this +method. Black Magic Probe (BMP) support is also included using GDB for both +uploading and debugging. + +Native USB programing using Bossa (Zero, MKR1000, Feather style bootloaders) +and avrdude (M0 bootloaders) is supported. The bootloaders on these devices +requires a double press of the reset button or open/closing the serial port at +1200 BAUD. The automatic entry of the bootloader is attempted using +`ard-reset-arduino` when using the general `make upload` target by polling +attached devices until the bootloader port re-attaches (same method as the +IDE). On Windows, the USB enumerates as differnt COM ports for the CDC Serial +and bootloader and these must be defined. On encountering problems, one can +manually enter the bootloader then upload using the `make raw_upload` target. +Note that the `make reset` target will enter the bootloader on these devices; +there is no way to reset over USB. + +If using system installed tools, be aware that `openocd` and `bossa` were +orginally forked for Arduino support and system distributions may not be up +to date with merged changes. `bossa` must be version 1.7->. `openocd` should +work but there may be problems at run time +[ref](https://github.com/pda/arduino-zero-without-ide). Ideally, use the +support packaged version or compile and install the Arduino fork. + +With the ARM chipset and using a CMSIS-DAP tool, on-device debugging is made available: + +* `debug_init` and `debug` targets for on-device debugging using GDB. To use + this, one must start the GDB server with `make debug_init &`, followed by + connecting to the target with `make debug`. If using a Black Magic Probe, + one can just use `make debug`. At the moment, a system wide `arm-none-eabi-gdb` must be + installed as the one supplied with the Arduino toolchain + does not appear to work. +* Example usage: https://asciinema.org/a/Jarz7Pr3gD6mqaZvCACQBzqix +* See the examples/MZeroBlink Makefile for a commented example. + ## Versioning The current version of the makefile is `1.6.0`. You can find the full history in the [HISTORY.md](HISTORY.md) file @@ -332,9 +400,8 @@ Also checkout the [contribution guide](CONTRIBUTING.md) for more details. If you are looking for ideas to work on, then check out the following TODO items or the [issue tracker](https://github.com/sudar/Arduino-Makefile/issues/). -## Limitations / Know Issues / TODO's +## Limitations / Known Issues / TODO's -- Doesn't support SAM boards yet. - Since it doesn't do any pre processing like Arduino IDE, you have to declare all methods before you use them ([issue #59](https://github.com/sudar/Arduino-Makefile/issues/59)) - More than one .ino or .pde file is not supported yet ([issue #49](https://github.com/sudar/Arduino-Makefile/issues/49)) - When you compile for the first time, it builds all libs inside Arduino directory even if it is not needed. But while linking only the relevant files are linked. ([issue #29](https://github.com/sudar/Arduino-Makefile/issues/29)). Even Arduino IDE does the same thing though. diff --git a/Sam.mk b/Sam.mk new file mode 100644 index 0000000..8b93ee4 --- /dev/null +++ b/Sam.mk @@ -0,0 +1,481 @@ +######################################################################## +# +# Support for Arduino Atmel SAM boards (sam and samd) +# +# You must install a SAM board hardware support package (such as Arduino Zero) +# to use this, then define ARDUINO_PACKAGE_DIR as the path to the root +# directory containing the support package. +# +# 2018 John Whittington @j_whittington +# +######################################################################## + +arduino_output = +# When output is not suppressed and we're in the top-level makefile, +# running for the first time (i.e., not after a restart after +# regenerating the dependency file), then output the configuration. +ifndef ARDUINO_QUIET + ifeq ($(MAKE_RESTARTS),) + ifeq ($(MAKELEVEL),0) + arduino_output = $(info $(1)) + endif + endif +endif + +ifndef ARDMK_DIR + ARDMK_DIR := $(realpath $(dir $(realpath $(lastword $(MAKEFILE_LIST))))) +endif + +# include Common.mk now we know where it is +ifndef COMMON_INCLUDED + include $(ARDMK_DIR)/Common.mk +endif + +ifndef ARDUINO_PACKAGE_DIR + # attempt to find based on Linux, macOS and Windows default + ARDUINO_PACKAGE_DIR := $(firstword \ + $(call dir_if_exists,$(HOME)/.arduino15/packages) \ + $(call dir_if_exists,$(ARDUINO_DIR)/packages) \ + $(call dir_if_exists,$(HOME)/Library/Arduino15/packages) \ + $(call dir_if_exists,$(USERPROFILE)/AppData/Local/Arduino15/packages) ) + $(call show_config_variable,ARDUINO_PACKAGE_DIR,[AUTODETECTED],(from DEFAULT)) +else + $(call show_config_variable,ARDUINO_PACKAGE_DIR,[USER]) +endif + +ifndef ARDMK_VENDOR + ARDMK_VENDOR := arduino +endif + +ifndef ARCHITECTURE + ARCHITECTURE := samd +endif + +ifndef CORE_VER + CORE_VER := $(wildcard $(ARDUINO_PACKAGE_DIR)/$(ARDMK_VENDOR)/hardware/$(ARCHITECTURE)/1.*) + ifdef CORE_VER + CORE_VER := $(shell basename $(CORE_VER)) + $(call show_config_variable,CORE_VER,[AUTODETECTED],(from ARDUINO_PACKAGE_DIR)) + endif +else + $(call show_config_variable,CORE_VER,[USER]) +endif + +ifndef CMSIS_VER + CMSIS_VER := $(shell basename $(wildcard $(ARDUINO_PACKAGE_DIR)/$(ARDMK_VENDOR)/tools/CMSIS/4.*)) + $(call show_config_variable,CMSIS_VER,[AUTODETECTED],(from ARDUINO_PACKAGE_DIR)) +else + $(call show_config_variable,CMSIS_VER,[USER]) +endif + +ifndef CMSIS_ATMEL_VER + CMSIS_ATMEL_VER := $(shell basename $(wildcard $(ARDUINO_PACKAGE_DIR)/$(ARDMK_VENDOR)/tools/CMSIS-Atmel/1.*)) + $(call show_config_variable,CMSIS_ATMEL_VER,[AUTODETECTED],(from ARDUINO_PACKAGE_DIR)) +else + $(call show_config_variable,CMSIS_ATMEL_VER,[USER]) +endif + +ifndef CMSIS_DIR + CMSIS_DIR := $(ARDUINO_PACKAGE_DIR)/$(ARDMK_VENDOR)/tools/CMSIS/$(CMSIS_VER)/CMSIS + $(call show_config_variable,CMSIS_DIR,[AUTODETECTED],(from ARDUINO_PACKAGE_DIR)) +else + $(call show_config_variable,CMSIS_DIR,[USER]) +endif + +ifndef CMSIS_ATMEL_DIR + CMSIS_ATMEL_DIR := $(ARDUINO_PACKAGE_DIR)/$(ARDMK_VENDOR)/tools/CMSIS-Atmel/$(CMSIS_ATMEL_VER)/CMSIS + $(call show_config_variable,CMSIS_ATMEL_DIR,[AUTODETECTED],(from ARDUINO_PACKAGE_DIR)) +else + $(call show_config_variable,CMSIS_ATMEL_DIR,[USER]) +endif + +# Arduino Settings (will get shown in Arduino.mk as computed) +ifndef ALTERNATE_CORE_PATH + ifdef CORE_VER + ALTERNATE_CORE_PATH = $(ARDUINO_PACKAGE_DIR)/$(ARDMK_VENDOR)/hardware/$(ARCHITECTURE)/$(CORE_VER) + else + ALTERNATE_CORE_PATH = $(ARDUINO_PACKAGE_DIR)/$(ARDMK_VENDOR)/hardware/$(ARCHITECTURE) + endif +endif +ifndef ARDUINO_CORE_PATH + ARDUINO_CORE_PATH = $(ALTERNATE_CORE_PATH)/cores/arduino +endif +ifndef BOARD_TXT + BOARDS_TXT = $(ALTERNATE_CORE_PATH)/boards.txt +endif + +# Check boards file exists before continuing as parsing non-existant file can create problems +ifneq ($(findstring boards.txt, $(wildcard $(ALTERNATE_CORE_PATH)/*.txt)), boards.txt) + echo $(error $(CORE_VER) Cannot find boards file $(BOARDS_TXT). Check ARDUINO_PACKAGE_DIR path: $(ARDUINO_PACKAGE_DIR) and board support installed) +endif + +# add CMSIS includes +CPPFLAGS += -I$(CMSIS_DIR)/Include/ +CPPFLAGS += -I$(CMSIS_ATMEL_DIR)/Device/ATMEL +# path for Cortex library +LIB_PATH = $(CMSIS_DIR)/Lib/GCC +BOOTLOADER_PARENT = $(ALTERNATE_CORE_PATH)/bootloaders + +# Utility from ard-mk to parse boards.txt for flags +ifndef PARSE_BOARD + PARSE_BOARD = $(shell grep -Ev '^\#' $(BOARDS_TXT) | grep -E '^[ \t]*$(1).$(2)=' | cut -d = -f 2 | cut -d : -f 2) +endif + +ifndef VARIANT + VARIANT := $(call PARSE_BOARD,$(BOARD_TAG),menu.(chip|cpu).$(BOARD_SUB).build.variant) + ifndef VARIANT + VARIANT := $(call PARSE_BOARD,$(BOARD_TAG),build.variant) + endif +endif + +# grab any sources in the variant core path (variant.cpp defines pin/port mapping on SAM devices) +ALT_CORE_C_SRCS := $(wildcard $(ALTERNATE_CORE_PATH)/variants/$(VARIANT)/*.c) +ALT_CORE_CPP_SRCS := $(wildcard $(ALTERNATE_CORE_PATH)/variants/$(VARIANT)/*.cpp) +ALT_CORE_S_SRCS := $(wildcard $(ALTERNATE_CORE_PATH)/variants/$(VARIANT)/*.S) + +# Use arm-toolchain from Arduino install if exists and user has not defined global version +ifndef ARM_TOOLS_DIR + ARM_TOOLS_DIR = $(call dir_if_exists,$(wildcard $(ARDUINO_PACKAGE_DIR)/$(ARDMK_VENDOR)/tools/arm-none-eabi-gcc/*)) + $(call show_config_variable,ARM_TOOLS_DIR,[COMPUTED],(from ARDUINO_PACKAGE_DIR)) +else + $(call show_config_variable,ARM_TOOLS_DIR,[USER]) +endif + +# define plaform lib dir from Arduino ARM support +ifndef ARDUINO_PLATFORM_LIB_PATH + ARDUINO_PLATFORM_LIB_PATH := $(ALTERNATE_CORE_PATH)/libraries + $(call show_config_variable,ARDUINO_PLATFORM_LIB_PATH,[COMPUTED],(from ARDUINO_PACKAGE_DIR)) +endif + +######################################################################## +# command names + +ifndef CC_NAME + CC_NAME := $(call PARSE_BOARD,$(BOARD_TAG),build.command.gcc) + ifndef CC_NAME + CC_NAME := arm-none-eabi-gcc + else + $(call show_config_variable,CC_NAME,[COMPUTED]) + endif +endif + +ifndef CXX_NAME + CXX_NAME := $(call PARSE_BOARD,$(BOARD_TAG),build.command.g++) + ifndef CXX_NAME + CXX_NAME := arm-none-eabi-g++ + else + $(call show_config_variable,CXX_NAME,[COMPUTED]) + endif +endif + +ifndef AS_NAME + AS_NAME := $(call PARSE_BOARD,$(BOARD_TAG),build.command.as) + ifndef AS_NAME + AS_NAME := arm-none-eabi-gcc-as + else + $(call show_config_variable,AS_NAME,[COMPUTED]) + endif +endif + +ifndef OBJCOPY_NAME + OBJCOPY_NAME := $(call PARSE_BOARD,$(BOARD_TAG),build.command.objcopy) + ifndef OBJCOPY_NAME + OBJCOPY_NAME := arm-none-eabi-objcopy + else + $(call show_config_variable,OBJCOPY_NAME,[COMPUTED]) + endif +endif + +ifndef OBJDUMP_NAME + OBJDUMP_NAME := $(call PARSE_BOARD,$(BOARD_TAG),build.command.objdump) + ifndef OBJDUMP_NAME + OBJDUMP_NAME := arm-none-eabi-objdump + else + $(call show_config_variable,OBJDUMP_NAME,[COMPUTED]) + endif +endif + +ifndef AR_NAME + AR_NAME := $(call PARSE_BOARD,$(BOARD_TAG),build.command.ar) + ifndef AR_NAME + AR_NAME := arm-none-eabi-ar + else + $(call show_config_variable,AR_NAME,[COMPUTED]) + endif +endif + +ifndef SIZE_NAME + SIZE_NAME := $(call PARSE_BOARD,$(BOARD_TAG),build.command.size) + ifndef SIZE_NAME + SIZE_NAME := arm-none-eabi-size + else + $(call show_config_variable,SIZE_NAME,[COMPUTED]) + endif +endif + +ifndef NM_NAME + NM_NAME := $(call PARSE_BOARD,$(BOARD_TAG),build.command.nm) + ifndef NM_NAME + NM_NAME := arm-none-eabi-gcc-nm + else + $(call show_config_variable,NM_NAME,[COMPUTED]) + endif +endif + +ifndef GDB_NAME + GDB_NAME := $(call PARSE_BOARD,$(BOARD_TAG),build.command.gdb) + ifndef GDB_NAME + GDB_NAME := arm-none-eabi-gdb + else + $(call show_config_variable,GDB_NAME,[COMPUTED]) + endif +endif + +ifndef UPLOAD_TOOL + UPLOAD_TOOL := $(call PARSE_BOARD,$(BOARD_TAG),upload.tool) + ifndef UPLOAD_TOOL + UPLOAD_TOOL := openocd + else + $(call show_config_variable,UPLOAD_TOOL,[COMPUTED]) + endif +endif + +ifndef BOOTLOADER_UPLOAD_TOOL + BOOTLOADER_UPLOAD_TOOL := $(call PARSE_BOARD,$(BOARD_TAG),bootloader.tool) + ifndef BOOTLOADER_UPLOAD_TOOL + BOOTLOADER_UPLOAD_TOOL := openocd + else + $(call show_config_variable,BOOTLOADER_UPLOAD_TOOL,[COMPUTED]) + endif +endif + +# processor stuff +ifndef MCU + MCU := $(call PARSE_BOARD,$(BOARD_TAG),build.mcu) +endif + +ifndef MCU_FLAG_NAME + MCU_FLAG_NAME=mcpu +endif + +# native port emulates an AVR chip to use AVRDUDE +ifndef AVRDUDE_MCU + AVRDUDE_MCU := $(call PARSE_BOARD,$(BOARD_TAG),build.emu.mcu) +endif + +# GDP settings +ifndef GDB_PORT + # default to localhost default OpenOCD port + GDB_PORT = localhost:3333 +endif + +ifndef GDB_OPTS + # if using BMP do a scan and attach + ifeq ($(findstring /dev/tty, $(strip $(GDB_PORT))), /dev/tty) + GDB_OPTS = -ex "target extended-remote $(GDB_PORT)" -ex "monitor swdp_scan" -ex "attach 1" -ex "load" -d $(OBJDIR) $(TARGET_ELF) + else + GDB_OPTS = -ex "target extended-remote $(GDB_PORT)" -ex "load" -d $(OBJDIR) $(TARGET_ELF) + endif +endif + +ifndef GDB_UPLOAD_OPTS + GDB_UPLOAD_OPTS = $(GDB_OPTS) -ex "set confirm off" -ex "set target-async off" -ex "set remotetimeout 30" -ex "detach" -ex "kill" -ex "quit" +endif + +######################################################################## +# OpenOCD for SAM devices + +ifndef OPENOCD + BUNDLED_OPENOCD_DIR := $(call dir_if_exists,$(ARDUINO_PACKAGE_DIR)/$(ARDMK_VENDOR)/tools/openocd) + # Try Arduino support package first + ifdef BUNDLED_OPENOCD_DIR + OPENOCD_VER := $(shell basename $(wildcard $(BUNDLED_OPENOCD_DIR)/*)) + OPENOCD = $(BUNDLED_OPENOCD_DIR)/$(OPENOCD_VER)/bin/openocd -s $(BUNDLED_OPENOCD_DIR)/$(OPENOCD_VER)/share/openocd/scripts/ + $(call show_config_variable,OPENOCD,[AUTODETECTED],(from ARDUINO_PACKAGE_DIR)) + else + # Otherwise look on user path + OPENOCD := $(shell which openocd 2>/dev/null) + ifdef OPENOCD + $(call show_config_variable,OPENOCD,[AUTODETECTED],(found in $$PATH)) + endif + endif +else + $(call show_config_variable,OPENOCD,[USER]) +endif + +ifndef OPENOCD_OPTS + OPENOCD_OPTS += -d2 -f $(ALTERNATE_CORE_PATH)/variants/$(VARIANT)/$(OPENOCD_SCRIPT) +endif + +######################################################################## +# Bossa for SAM devices + +ifndef BOSSA + BUNDLED_BOSSA_DIR := $(call dir_if_exists,$(ARDUINO_PACKAGE_DIR)/$(ARDMK_VENDOR)/tools/bossac) + # Try Arduino support package first + ifdef BUNDLED_BOSSA_DIR + BOSSA_VER := $(shell basename $(wildcard $(BUNDLED_BOSSA_DIR)/*)) + BOSSA = $(BUNDLED_BOSSA_DIR)/$(BOSSA_VER)/bossac + $(call show_config_variable,BOSSA,[AUTODETECTED],(from ARDUINO_PACKAGE_DIR)) + else + # Otherwise look on user path + BOSSA := $(shell which bossac 2>/dev/null) + ifdef BOSSA + $(call show_config_variable,BOSSA,[AUTODETECTED],(found in $$PATH)) + endif + endif +else + $(call show_config_variable,BOSSA,[USER]) +endif + +ifndef BOSSA_OPTS + BOSSA_OPTS += -d --info --erase --write --verify --reset +endif + +get_bootloader = $(shell $(RESET_CMD) | tail -1) + +# if not bootloader port defined (ISP_PORT), automatically grab first port after reset +# if not on windows +ifndef ISP_PORT + ifeq ($(CURRENT_OS), WINDOWS) + BOSSA_OPTS += --port=$(COM_STYLE_MONITOR_PORT) + else + BOSSA_OPTS += --port=$(call get_monitor_port) + endif +else + BOSSA_OPTS += --port=$(ISP_PORT) +endif + +######################################################################## +# EXECUTABLES +# Define them here to use ARM_TOOLS_PATH and allow auto finding of AVR_TOOLS_PATH +OVERRIDE_EXECUTABLES = 1 + +ARM_TOOLS_PATH := $(ARM_TOOLS_DIR)/bin +CC = $(ARM_TOOLS_PATH)/$(CC_NAME) +CXX = $(ARM_TOOLS_PATH)/$(CXX_NAME) +AS = $(ARM_TOOLS_PATH)/$(AS_NAME) +OBJCOPY = $(ARM_TOOLS_PATH)/$(OBJCOPY_NAME) +OBJDUMP = $(ARM_TOOLS_PATH)/$(OBJDUMP_NAME) +AR = $(ARM_TOOLS_PATH)/$(AR_NAME) +SIZE = $(ARM_TOOLS_PATH)/$(SIZE_NAME) +NM = $(ARM_TOOLS_PATH)/$(NM_NAME) +#GDB = $(ARM_TOOLS_PATH)/$(GDB_NAME) +# Use system gdb for now as Arduino supplied has lib error? +GDB = $(GDB_NAME) + +######################################################################## +# FLAGS + +ifndef USB_TYPE + USB_TYPE = USBCON +endif + +ifndef USB_PRODUCT + USB_PRODUCT := $(call PARSE_BOARD,$(BOARD_TAG),build.usb_product) + ifdef USB_PRODUCT + $(call show_config_variable,USB_PRODUCT,[COMPUTED]) + endif +endif + +ifndef USB_MANUFACTURER + USB_MANUFACTURER := $(call PARSE_BOARD,$(BOARD_TAG),build.usb_manufacturer) + ifndef USB_MANUFACTURER + USB_MANUFACTURER = "Unknown" + else + $(call show_config_variable,USB_MANUFACTURER,[COMPUTED]) + endif +endif + +ifndef USB_VID + USB_VID := $(call PARSE_BOARD,$(BOARD_TAG),build.vid) + ifdef USB_VID + $(call show_config_variable,USB_VID,[COMPUTED]) + endif +endif + +ifndef USB_PID + USB_PID := $(call PARSE_BOARD,$(BOARD_TAG),build.pid) + ifdef USB_PID + $(call show_config_variable,USB_PID,[COMPUTED]) + endif +endif + +# Bootloader settings +ifndef BOOTLOADER_SIZE + BOOTLOADER_SIZE := $(call PARSE_BOARD,$(BOARD_TAG),bootloader.size) + ifndef BOOTLOADER_SIZE + BOOTLOADER_SIZE := 0x2000 + else + $(call show_config_variable,BOOTLOADER_SIZE,[COMPUTED]) + endif +endif + +ifndef BOOTLOADER_UNPROTECT + BOOTLOADER_UNPROTECT := $(call PARSE_BOARD,$(BOARD_TAG),bootloader.cmd_unprotect) + ifndef BOOTLOADER_UNPROTECT + BOOTLOADER_UNPROTECT := at91samd bootloader 0 + else + $(call show_config_variable,BOOTLOADER_UNPROTECT,[COMPUTED]) + endif +endif + +ifndef BOOTLOADER_PROTECT + BOOTLOADER_PROTECT := $(call PARSE_BOARD,$(BOARD_TAG),bootloader.cmd_protect) + ifndef BOOTLOADER_PROTECT + BOOTLOADER_PROTECT := at91samd bootloader 16384 + else + $(call show_config_variable,BOOTLOADER_PROTECT,[COMPUTED]) + endif +endif + +ifndef BOOTLOADER_PROTECT_VERIFY + BOOTLOADER_PROTECT_VERIFY := $(call PARSE_BOARD,$(BOARD_TAG),bootloader.cmd_protect_verify) + ifndef BOOTLOADER_PROTECT_VERIFY + BOOTLOADER_PROTECT_VERIFY := at91samd bootloader + else + $(call show_config_variable,BOOTLOADER_PROTECT_VERIFY,[COMPUTED]) + endif +endif + +# C99 with GNU extensions required for C sources using old compiler +CC_VERNUM = $(shell $(CC) -dumpversion | sed 's/\.//g') +ifneq ($(shell expr $(CC_VERNUM) '>' 490), 1) + CFLAGS_STD = -std=gnu99 +endif + +CPPFLAGS += -DMD -D$(USB_TYPE) '-DUSB_PRODUCT=$(USB_PRODUCT)' '-DUSB_MANUFACTURER=$(USB_MANUFACTURER)' + +# Get extra define flags from boards.txt +EXFLAGS := $(shell echo $(call PARSE_BOARD,$(BOARD_TAG),build.extra_flags) | grep -oE '(-D)\w+') + +# Strip only defines from extra flags as boards file appends user {build.usb} +CPPFLAGS += $(EXFLAGS) +CPPFLAGS += -DUSB_VID=$(USB_VID) +CPPFLAGS += -DUSB_PID=$(USB_PID) +# Cortex compiler flags +CPPFLAGS += -mthumb -nostdlib --param max-inline-insns-single=500 -fno-exceptions -Wl,-Map=$(OBJDIR)/$(TARGET).map +CXXFLAGS += -fno-rtti -fno-threadsafe-statics -std=gnu++11 + +AMCU := $(call PARSE_BOARD,$(BOARD_TAG),build.mcu) +BOARD_LINKER_SCRIPT := $(call PARSE_BOARD,$(BOARD_TAG),build.ldscript) +OPENOCD_SCRIPT := $(call PARSE_BOARD,$(BOARD_TAG),build.openocdscript) +# TODO Hard defines Cortex M0 math lib - should be dynamic +LDFLAGS += --specs=nano.specs --specs=nosys.specs -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--start-group -L$(LIB_PATH) -larm_cortexM0l_math -lm +LINKER_SCRIPTS := -T$(ALTERNATE_CORE_PATH)/variants/$(VARIANT)/$(BOARD_LINKER_SCRIPT) +OTHER_LIBS := $(call PARSE_BOARD,$(BOARD_TAG),build.flags.libs) + +# OpenOCD reset command only for now +ifeq ($(strip $(UPLOAD_TOOL)), openocd) + RESET_CMD = $(OPENOCD) $(OPENOCD_OPTS) -c "telnet_port disabled; init; targets; reset run; shutdown" +else + # Set zero flag for ard-reset for 1200 baud boot to bootloader + ARD_RESET_OPTS += --zero +endif + +######################################################################## +# automatially include Arduino.mk for the user + +$(call show_separator) +$(call arduino_output,Arduino.mk Configuration:) +include $(ARDMK_DIR)/Arduino.mk diff --git a/Teensy.mk b/Teensy.mk index 8bd822b..3d0114c 100644 --- a/Teensy.mk +++ b/Teensy.mk @@ -146,7 +146,7 @@ endif # processor stuff ifndef MCU - MCU := $(call PARSE_TEENSY,$(BOARD_TAG),build.cpu) + MCU := $(call PARSE_TEENSY,$(BOARD_TAG),build.mcu) endif ifndef MCU_FLAG_NAME diff --git a/arduino-mk-vars.md b/arduino-mk-vars.md index d19d3d6..e3b6f07 100644 --- a/arduino-mk-vars.md +++ b/arduino-mk-vars.md @@ -11,6 +11,7 @@ The following are the different variables that can be overwritten in the user ma * [Avrdude setting variables](#avrdude-setting-variables) * [Bootloader variables](#bootloader-variables) * [ChipKIT variables](#chipkit-variables) +* [ARM variables](#arm-variables) * [Ctags variables](#ctags-variables) ## Global variables @@ -73,6 +74,29 @@ AVR_TOOLS_DIR = /usr/share/arduino/hardware/tools/avr ---- +### ARM_TOOLS_DIR + +**Description:** + +Directory where the arm toolchain is installed. `arm-none-eabi-*` should be +within a /bin subdirectory. + +Can usually be detected from `$ARDUINO_PACKAGE_DIR` /tools subdirectory when ARM +device support is installed. + +**Example:** + +```Makefile +ARM_TOOLS_DIR = /usr +# or +ARM_TOOLS_DIR = +/usr/share/arduino/hardware/tools/arm-none-eabi-gcc/VERSION +``` + +**Requirement:** *Optional* + +---- + ### RESET_CMD **Description:** @@ -114,6 +138,27 @@ ARDUINO_DIR = /Applications/Arduino.app/Contents/Java ---- +### ARDUINO_PACKAGE_DIR + +**Description:** + +Directory where the Arduino package support files are stored. Can auto-detect based on default OS IDE locations. + +**Example:** + +```Makefile +# Linux +ARDUINO_PACKAGE_DIR = $(HOME)/.arduino15/packages +# Mac OS X +ARDUINO_PACKAGE_DIR = $(HOME)/Library/Arduino15/packages +# Windows +ARDUINO_PACKAGE_DIR = $(USERPROFILE)/AppData/Local/Arduino15/packages +``` + +**Requirement:** *Optional* + +---- + ### ARDUINO_PLATFORM_LIB_PATH **Description:** @@ -155,12 +200,13 @@ ARDUINO_VERSION = 105 Architecture for Arduino 1.5+ -Defaults to unset for 1.0 or `avr` for 1.5+ +Defaults to unset for 1.0 or `avr` for 1.5+. This value is not literally the chip architecture but will often be +the chip series within a vendor's 'hardware' folder. For example, will default to `samd` if using Sam.mk. **Example:** ```Makefile -ARCHITECTURE = sam +ARCHITECTURE = arm ``` **Requirement:** *Optional* @@ -171,9 +217,9 @@ ARCHITECTURE = sam **Description:** -Board vendor/maintainer. +Board vendor/maintainer/series. -Defaults to `arduino` +Defaults to `arduino`. **Example:** @@ -658,7 +704,8 @@ ISP_PROG = stk500v1 **Description:** -Device path to ArduinoISP. Not needed for hardware ISP's. +Device path to ArduinoISP. Not needed for hardware ISP's. Also used to define +bootloader port on SAMD devices. **Example:** @@ -871,6 +918,18 @@ NM_NAME = pic32-nm ---- +### GDB_NAME + +**Description:** + +GDB utility. + +Defaults to `arm-none-eabi-gdb` + +**Requirement:** *Optional* + +---- + ### OPTIMIZATION_LEVEL **Description:** @@ -1044,7 +1103,7 @@ ASFLAGS += -my-as-only-flag **Description:** -Flags passed to the C pre-processor (for C, C++ and assembly source flies). Add +Flags passed to the C pre-processor (for C, C++ and assembly source files). Add more flags to this variable using `+=`. Defaults to all flags required for a typical build. @@ -1229,6 +1288,54 @@ ALTERNATE_CORE_PATH = $(HOME)/sketchbook/hardware/arduino-tiny/cores/tiny ---- +### CORE_VER + +**Description:** + +Alternate core release version. The Arduino board support packages are within +a sub-directory indicated by this define. + +Defaults to package current release. + +**Example:** + +```Makefile +CORE_VER = 1.6.17 +``` + +**Requirement:** *Optional* + +---- + +### CMSIS_DIR + +**Description:** + +Path to ARM CMSIS. Normally installed as part of ARM board support. + +Defaults to `ARDUINO_PACKAGE_DIR/tools/CMSIS/4.5.0/CMSIS` + +**Example:** + +```Makefile +CMSIS_DIR = /usr/share/CMSIS +``` + +**Requirement:** *Optional* + +---- + +### CMSIS_ATMEL_DIR + +**Description:** + +Path to CMSIS-Atmel directory. Installed with ARM support package. + +Defaults to `ARDUINO_PACKAGE_DIR/tools/CMSIS-Atmel/1.1.0/CMSIS` + +**Requirement:** *Optional* +---- + ### BOARDS_TXT **Description:** @@ -1385,6 +1492,67 @@ Would result in an absolute path to the bootloader hex file of `$(HOME)/sketchbo ---- +### BOOTLOADER_SIZE + +**Description:** + +Size of bootloader on ARM devices, ensures correct start address when flashing +application area. Normally parsed from boards.txt + +Defaults to `0x2000` + +**Requirement:** *Optional* + +---- + +### BOOTLOADER_UNPROTECT + +**Description:** + +Bootloader unprotect sequence for upload tool. Normally parsed from boards.txt + +Defaults to `at91samd bootloader 0` + +**Requirement:** *Optional* + +---- + +### BOOTLOADER_PROTECT + +**Description:** + +Bootloader protect sequence for upload tool. Normally parsed from boards.txt + +Defaults to `at91samd bootloader 16384` + +**Requirement:** *Optional* + +---- + +### BOOTLOADER_PROTECT_VERIFY + +**Description:** + +Bootloader protect and verify sequence for upload tool. Normally parsed from boards.txt + +Defaults to `at91samd bootloader` + +**Requirement:** *Optional* + +---- + +### BOOTLOADER_UPLOAD_TOOL + +**Description:** + +Bootloader upload binary to use. Normally parsed from boards.txt. + +Defaults to `openocd` + +**Requirement:** *Optional* + +---- + ## ChipKIT variables ### MPIDE_DIR @@ -1403,6 +1571,163 @@ MPIDE_DIR = $(HOME)/mpide **Requirement:** *Optional* +---- + +### MPIDE_PREFERENCES_PATH + +**Description:** + +Path to chipKIT `preferences.txt` file. + +Usually can be auto-detected as `AUTO_MPIDE_PREFERENCES_PATH` from the defaults `$(HOME)/.mpide/preferences.txt` (Linux) or `$(HOME)/Library/Mpide/preferences.txt` (OSX) + +**Example:** + +```Makefile +MPIDE_PREFERENCES_PATH = $(HOME)/chipkit/preferences.txt +``` + +**Requirement:** *Optional* + +---- + +## ARM variables + +### UPLOAD_TOOL + +**Description:** + +Tool to upload binary to device. Normally parsed from boards.txt. + +Defaults to `openocd` + +**Example:** + +```Makefile +UPLOAD_TOOL = gdb +``` + +**Requirement:** *Optional* + +---- + +### DEBUG + +**Description:** + +Define to set `DEBUG_FLAGS` and allow stepping of code using GDB. + +Defaults to undefined. + +**Example:** + +```Makefile +DEBUG = 1 +``` + +**Requirement:** *Optional* + +---- + +### GDB_PORT + +**Description:** + +Server port to use for GDB debugging or upload. Default assumes server running +on localhost but can re-define to use Black Magic Probe serial port. + +Defaults to `localhost:3333` + +**Example:** + +```Makefile +GDB_PORT = /dev/ttyACM0 +``` + +**Requirement:** *Optional* + +---- + +### GDB_OPTS + +**Description:** + +Optional arguments to parse to GDB command. + +Defaults to `-ex "target extended-remote $(GDB_PORT)" -ex "monitor swdp_scan" -ex "attach 1" -ex "load" -d $(OBJDIR) $(TARGET_ELF)` + +**Requirement:** *Optional* + +---- + +### GDB_UPLOAD_OPTS + +**Description:** + +Optional arguments to parse to GDB command when uploading binary only. + +Defaults to `GDB_UPLOAD_OPTS = $(GDB_OPTS) -ex "set confirm off" -ex "set target-async off" -ex "set remotetimeout 30" -ex "detach" -ex "kill" -ex "quit"` + +**Requirement:** *Optional* + +---- + +### BOSSA + +**Description:** + +Path to bossac binary. + +Can usually be detected from `$ARDUINO_PACKAGE_DIR` /tools subdirectory when ARM +device support is installed. + +**Requirement:** *Optional* + +---- + +### BOSSA_OPTS + +**Description:** + +Flags to pass to bossac command. + +Defaults to `-d --info --erase --write --verify --reset` + +**Requirement:** *Optional* + +---- + +### OPENOCD + +**Description:** + +Path to openocd binary. + +Can usually be detected from `$ARDUINO_PACKAGE_DIR` /tools subdirectory when ARM +device support is installed. + +**Requirement:** *Optional* + +---- + +### OPENOCD_OPTS + +**Description:** + +Flags to pass to openocd command. If using openocd from non-Arduino +distributions, one should define this with the path to the Arduino openocd script. + +Defaults to `-d2` + +Example: + +```Makefile +OPENOCD_OPTS = $(ARDUINO_PACKAGE_DIR)/$(ARDMK_VENDOR)/tools/openocd/0.9.0-arduino6-static/share/openocd/scripts/ -f $(ARDUINO_PACKAGE_DIR)/$(ARDMK_VENDOR)/hardware/samd/1.6.17/variants/$(VARIANT)/$(OPENOCD_SCRIPT) +``` + +**Requirement:** *Optional* + + ---- ## Ctags variables @@ -1453,21 +1778,3 @@ CTAGS_CMD = /usr/local/bin/ ``` **Requirement:** *Optional* - ----- - -### MPIDE_PREFERENCES_PATH - -**Description:** - -Path to chipKIT `preferences.txt` file. - -Usually can be auto-detected as `AUTO_MPIDE_PREFERENCES_PATH` from the defaults `$(HOME)/.mpide/preferences.txt` (Linux) or `$(HOME)/Library/Mpide/preferences.txt` (OSX) - -**Example:** - -```Makefile -MPIDE_PREFERENCES_PATH = $(HOME)/chipkit/preferences.txt -``` - -**Requirement:** *Optional* diff --git a/bin/ard-reset-arduino b/bin/ard-reset-arduino index 1f2c7e9..d6f974f 100755 --- a/bin/ard-reset-arduino +++ b/bin/ard-reset-arduino @@ -2,6 +2,7 @@ from __future__ import print_function import serial +import serial.tools.list_ports import os.path import argparse from time import sleep @@ -13,13 +14,100 @@ except: pyserial_version = 2 # less than 2.3 parser = argparse.ArgumentParser(description='Reset an Arduino') +parser.add_argument('--zero', action='store_true', help='Reset Arduino Zero or similar Native USB to enter bootloader') parser.add_argument('--caterina', action='store_true', help='Reset a Leonardo, Micro, Robot or LilyPadUSB.') parser.add_argument('--verbose', action='store_true', help="Watch what's going on on STDERR.") parser.add_argument('--period', default=0.1, help='Specify the DTR pulse width in seconds.') parser.add_argument('port', nargs=1, help='Serial device e.g. /dev/ttyACM0') args = parser.parse_args() -if args.caterina: + +def list_ports(output=False): + """ Lists serial ports attached + + :returns + A list of paths to serial ports on system + """ + ports = serial.tools.list_ports.comports() + connected = [port[0] for port in ports] + if output: + print(connected) + + return connected + + +def new_port(old, new): + """ Checks if a new port has attached + + Args: + old: previous list of ports to check + new: current list of ports to check + Returns: + index of port in 'new' if new port found, otherwise -1 + """ + new_port = -1 + + for port in new: + if port not in old: + new_port = new.index(port) + break + + return new_port + + +if args.zero: + # number of trys to attempt + zero_attempts = 20 # ~2 seconds + initial_ports = list_ports(args.verbose) + + if args.verbose: + print('Attempting to enter bootloader using 1200 bps open/close on port %s' % args.port[0]) + + ser = serial.Serial(args.port[0], 57600) + ser.close() + + if pyserial_version < 3: + ser.setBaudrate(1200) + else: + ser.baudrate = 1200 + + # do the open/close at 1200 BAUD + ser.open() + ser.close() + + if args.verbose: + print('Done. Waiting for bootloader port to attach...') + + # get new list of ports + reset_ports = list_ports(args.verbose) + + # wait for new port or port to return + port_index = new_port(initial_ports, reset_ports) + + # keep checking until new port appears or timeout + while port_index < 0: + # count down attempts and leave if expired + zero_attempts -= 1 + if zero_attempts < 0: + break + sleep(0.1) + # get list of ports after bootloader toggle performed + reset_ports = list_ports(args.verbose) + # if a port drops, set initial ports to reset ports so that + # next attached device will be new port + if (len(reset_ports) < len(initial_ports)): + initial_ports = reset_ports + # check if a new port has attached and return the index if it has + port_index = new_port(initial_ports, reset_ports) + # return the new port if detected, otherwise return passed port + if port_index is -1: + bootloader_port = args.port[0] + else: + bootloader_port = reset_ports[port_index] + + # print so that `tail -1` can be piped for bootloader port + print(bootloader_port) +elif args.caterina: if args.verbose: print('Forcing reset using 1200bps open/close on port %s' % args.port[0]) ser = serial.Serial(args.port[0], 57600) ser.close() diff --git a/examples/MZeroBlink/MZeroBlink.ino b/examples/MZeroBlink/MZeroBlink.ino new file mode 100644 index 0000000..f9a59a9 --- /dev/null +++ b/examples/MZeroBlink/MZeroBlink.ino @@ -0,0 +1,19 @@ +/* + Blink + Turns on an LED on for one second, then off for one second, repeatedly. + + This example code is in the public domain. + */ + +void setup() { + // initialize the digital pin as an output. + // Pin 13 has an LED connected on most Arduino boards: + pinMode(13, OUTPUT); +} + +void loop() { + digitalWrite(13, HIGH); // set the LED on + delay(1000); // wait for a second + digitalWrite(13, LOW); // set the LED off + delay(1000); // wait for a second +} diff --git a/examples/MZeroBlink/Makefile b/examples/MZeroBlink/Makefile new file mode 100644 index 0000000..29cb90b --- /dev/null +++ b/examples/MZeroBlink/Makefile @@ -0,0 +1,24 @@ +# Arduino M0 Pro Programming Port +BOARD_TAG = mzero_pro_bl_dbg + +# Define debug if you want to use gdb +#DEBUG = 1 + +# Define port if using Black Magic Probe rather than default localhost:3333 +#GDB_PORT = /dev/ttyACM0 + +# Define ARM toolchain dir if not using Arduino supplied +#ARM_TOOLS_DIR = /usr + +# Define AVR toolchain dir if not using Arduino supplied and using native port +#AVR_TOOLS_DIR = /usr + +# Define Arduino support package installation path where SAM device support has been installed +# Linux +# ARDUINO_PACKAGE_DIR := $(HOME)/.arduino15/packages +# macOS +# ARDUINO_PACKAGE_DIR := $(HOME)/Library/Arduino15/packages +# Windows +# ARDUINO_PACKAGE_DIR := "C:/Users/$(USER)/AppData/Local/Arduino15/packages" + +include ../../Sam.mk diff --git a/examples/ZeroBlink/Makefile b/examples/ZeroBlink/Makefile new file mode 100644 index 0000000..60c8435 --- /dev/null +++ b/examples/ZeroBlink/Makefile @@ -0,0 +1,30 @@ +# Arduino Zero Native Port (should work with Feather, MKR1000 etc.) +# BOOTLOADER: The bootloader on these devices loaded when reset is pressed twice +# or the port is opened/closed at 1200 BAUD. If there is no program on the device, +# you may have to manually enter bootloader by toggling reset twice. +# see http://www.avdweb.nl/arduino/samd21/virus.html +BOARD_TAG = arduino_zero_native + +# Define alternative core path if using another board supplier +#ALTERNATE_CORE_PATH = $(HOME)/Arduino/hardware/sparkfun/samd + +# Define monitor port and isp port (bootloader port). +# Will automatically detect if Linux/macOS but MUST be defined on Windows +#MONITOR_PORT = com40 # CDC serial +#ISP_PORT = com39 # bootloader + +# Define ARM toolchain dir if not using Arduino supplied +#ARM_TOOLS_DIR = /usr + +# Define AVR toolchain dir if not using Arduino supplied and using native port +#AVR_TOOLS_DIR = /usr + +# Define Arduino support package installation path where SAM device support has been installed +# Linux +#ARDUINO_PACKAGE_DIR := $(HOME)/.arduino15/packages +# macOS +#ARDUINO_PACKAGE_DIR := $(HOME)/Library/Arduino15/packages +# Windows +#ARDUINO_PACKAGE_DIR := "C:/Users/$(USER)/AppData/Local/Arduino15/packages" + +include ../../Sam.mk diff --git a/examples/ZeroBlink/ZeroBlink.ino b/examples/ZeroBlink/ZeroBlink.ino new file mode 100644 index 0000000..f9a59a9 --- /dev/null +++ b/examples/ZeroBlink/ZeroBlink.ino @@ -0,0 +1,19 @@ +/* + Blink + Turns on an LED on for one second, then off for one second, repeatedly. + + This example code is in the public domain. + */ + +void setup() { + // initialize the digital pin as an output. + // Pin 13 has an LED connected on most Arduino boards: + pinMode(13, OUTPUT); +} + +void loop() { + digitalWrite(13, HIGH); // set the LED on + delay(1000); // wait for a second + digitalWrite(13, LOW); // set the LED off + delay(1000); // wait for a second +} diff --git a/tests/script/runtests.sh b/tests/script/runtests.sh index 7792186..648a0cf 100755 --- a/tests/script/runtests.sh +++ b/tests/script/runtests.sh @@ -7,7 +7,7 @@ failures=() # These examples cannot be tested easily at the moment as they require # alternate cores. The MakefileExample doesn't actually contain any source code # to compile. -NON_TESTABLE_EXAMPLES=(ATtinyBlink MakefileExample TinySoftWareSerial BlinkOpenCM BlinkTeensy BlinkNetworkRPi BlinkInAVRC) +NON_TESTABLE_EXAMPLES=(ATtinyBlink MakefileExample TinySoftWareSerial BlinkOpenCM BlinkTeensy BlinkNetworkRPi BlinkInAVRC MZeroBlink ZeroBlink) for dir in $TESTS_DIR/*/ do