Skip to content

Commit 80b8167

Browse files
authored
Merge pull request #543 from tuna-f1sh/sam
Arduino Atmel SAM family Support (ARM architecture) Thanks @tuna-f1sh !
2 parents 8480373 + f804866 commit 80b8167

File tree

13 files changed

+1201
-77
lines changed

13 files changed

+1201
-77
lines changed

Arduino.mk

Lines changed: 136 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,9 @@ else
261261
endif
262262

263263
# include Common.mk now we know where it is
264-
include $(ARDMK_DIR)/Common.mk
264+
ifndef COMMON_INCLUDED
265+
include $(ARDMK_DIR)/Common.mk
266+
endif
265267

266268
# show_config_variable macro is available now. So let's print config details for ARDMK_DIR
267269
ifndef ARDMK_DIR_MSG
@@ -317,11 +319,7 @@ else
317319
ifeq ($(ARCHITECTURE),avr)
318320
ARDUINO_ARCH_FLAG = -DARDUINO_ARCH_AVR
319321
else
320-
ifeq ($(ARCHITECTURE),sam)
321-
ARDUINO_ARCH_FLAG = -DARDUINO_ARCH_SAM
322-
else
323-
ARDUINO_ARCH_FLAG = -DARDUINO_ARCH_$(shell echo $(ARCHITECTURE) | tr '[:lower:]' '[:upper:]')
324-
endif
322+
ARDUINO_ARCH_FLAG = -DARDUINO_ARCH_$(shell echo $(ARCHITECTURE) | tr '[:lower:]' '[:upper:]')
325323
endif
326324
endif
327325

@@ -454,7 +452,14 @@ ifndef AVR_TOOLS_DIR
454452
AVR_TOOLS_DIR = $(SYSTEMPATH_AVR_TOOLS_DIR)
455453
$(call show_config_variable,AVR_TOOLS_DIR,[AUTODETECTED],(found in $$PATH))
456454
else
457-
echo $(error No AVR tools directory found)
455+
# One last attempt using avr-gcc in case using arm
456+
SYSTEMPATH_AVR_TOOLS_DIR := $(call dir_if_exists,$(abspath $(dir $(shell which $(avr-gcc)))/..))
457+
ifdef SYSTEMPATH_AVR_TOOLS_DIR
458+
AVR_TOOLS_DIR = $(SYSTEMPATH_AVR_TOOLS_DIR)
459+
$(call show_config_variable,AVR_TOOLS_DIR,[AUTODETECTED],(found in $$PATH))
460+
else
461+
echo $(error No AVR tools directory found)
462+
endif
458463
endif # SYSTEMPATH_AVR_TOOLS_DIR
459464

460465
endif # BUNDLED_AVR_TOOLS_DIR
@@ -644,6 +649,9 @@ ifeq ($(strip $(NO_CORE)),)
644649
USB_PID := $(call PARSE_BOARD,$(BOARD_TAG),menu.(chip|cpu).$(BOARD_SUB).build.pid)
645650
endif
646651
endif
652+
653+
# add caterina flag to ARD_RESET_OPTS
654+
ARD_RESET_OPTS += --caterina
647655
endif
648656

649657
# normal programming info
@@ -745,34 +753,21 @@ endif
745753
# Reset
746754

747755
ifndef RESET_CMD
748-
ARD_RESET_ARDUINO := $(shell which ard-reset-arduino 2> /dev/null)
749-
ifndef ARD_RESET_ARDUINO
750-
# same level as *.mk in bin directory when checked out from git
751-
# or in $PATH when packaged
752-
ARD_RESET_ARDUINO = $(ARDMK_DIR)/bin/ard-reset-arduino
753-
endif
754-
ifneq ($(CATERINA),)
755-
ifneq (,$(findstring CYGWIN,$(shell uname -s)))
756-
# confirm user is using default cygwin unix Python (which uses ttySx) and not Windows Python (which uses COMx)
757-
ifeq ($(shell which python),/usr/bin/python)
758-
RESET_CMD = $(ARD_RESET_ARDUINO) --caterina $(ARD_RESET_OPTS) $(DEVICE_PATH)
759-
else
760-
RESET_CMD = $(ARD_RESET_ARDUINO) --caterina $(ARD_RESET_OPTS) $(call get_monitor_port)
761-
endif
762-
else
763-
RESET_CMD = $(ARD_RESET_ARDUINO) --caterina $(ARD_RESET_OPTS) $(call get_monitor_port)
764-
endif
756+
ARD_RESET_ARDUINO := $(shell which ard-reset-arduino 2> /dev/null)
757+
ifndef ARD_RESET_ARDUINO
758+
# same level as *.mk in bin directory when checked out from git
759+
# or in $PATH when packaged
760+
ARD_RESET_ARDUINO = $(ARDMK_DIR)/bin/ard-reset-arduino
761+
endif
762+
ifneq (,$(findstring CYGWIN,$(shell uname -s)))
763+
# confirm user is using default cygwin unix Python (which uses ttySx) and not Windows Python (which uses COMx)
764+
ifeq ($(shell which python),/usr/bin/python)
765+
RESET_CMD = $(ARD_RESET_ARDUINO) $(ARD_RESET_OPTS) $(DEVICE_PATH)
766+
else
767+
RESET_CMD = $(ARD_RESET_ARDUINO) $(ARD_RESET_OPTS) $(call get_monitor_port)
768+
endif
765769
else
766-
ifneq (,$(findstring CYGWIN,$(shell uname -s)))
767-
# confirm user is using default cygwin unix Python (which uses ttySx) and not Windows Python (which uses COMx)
768-
ifeq ($(shell which python),/usr/bin/python)
769-
RESET_CMD = $(ARD_RESET_ARDUINO) $(ARD_RESET_OPTS) $(DEVICE_PATH)
770-
else
771-
RESET_CMD = $(ARD_RESET_ARDUINO) $(ARD_RESET_OPTS) $(call get_monitor_port)
772-
endif
773-
else
774-
RESET_CMD = $(ARD_RESET_ARDUINO) $(ARD_RESET_OPTS) $(call get_monitor_port)
775-
endif
770+
RESET_CMD = $(ARD_RESET_ARDUINO) $(ARD_RESET_OPTS) $(call get_monitor_port)
776771
endif
777772
endif
778773

@@ -815,7 +810,7 @@ ifeq ($(strip $(CHK_SOURCES)),)
815810
$(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)
816811
else
817812
#TODO: Support more than one file. https://github.com/sudar/Arduino-Makefile/issues/49
818-
$(error Need exactly one .pde or .ino file. This makefile doesn't support multiple .ino/.pde files yet)
813+
$(error Need exactly one .pde or .ino file. This makefile doesn\'t support multiple .ino/.pde files yet)
819814
endif
820815
endif
821816

@@ -830,13 +825,26 @@ ifeq ($(strip $(NO_CORE)),)
830825
CORE_CPP_SRCS = $(wildcard $(ARDUINO_CORE_PATH)/*.cpp)
831826
CORE_AS_SRCS = $(wildcard $(ARDUINO_CORE_PATH)/*.S)
832827

828+
# USB Core if samd or sam
829+
ifeq ($(findstring sam, $(strip $(ARCHITECTURE))), sam)
830+
CORE_C_SRCS += $(wildcard $(ARDUINO_CORE_PATH)/USB/*.c)
831+
CORE_CPP_SRCS += $(wildcard $(ARDUINO_CORE_PATH)/USB/*.cpp)
832+
endif
833+
833834
ifneq ($(strip $(NO_CORE_MAIN_CPP)),)
834835
CORE_CPP_SRCS := $(filter-out %main.cpp, $(CORE_CPP_SRCS))
835836
$(call show_config_info,NO_CORE_MAIN_CPP set so core library will not include main.cpp,[MANUAL])
836837
endif
837838

839+
# Put alt core variant file for M0 devices in OTHER_OJBS
840+
ifdef ALT_CORE_CPP_SRCS
841+
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)
842+
OTHER_OBJS := $(patsubst $(ALTERNATE_CORE_PATH)/variants/$(VARIANT)/%, \
843+
$(OBJDIR)/core/%,$(ALT_CORE_OBJ_FILES))
844+
endif
845+
838846
CORE_OBJ_FILES = $(CORE_C_SRCS:.c=.c.o) $(CORE_CPP_SRCS:.cpp=.cpp.o) $(CORE_AS_SRCS:.S=.S.o)
839-
CORE_OBJS = $(patsubst $(ARDUINO_CORE_PATH)/%, \
847+
CORE_OBJS += $(patsubst $(ARDUINO_CORE_PATH)/%, \
840848
$(OBJDIR)/core/%,$(CORE_OBJ_FILES))
841849
endif
842850
else
@@ -908,6 +916,7 @@ endif
908916
TARGET_HEX = $(OBJDIR)/$(TARGET).hex
909917
TARGET_ELF = $(OBJDIR)/$(TARGET).elf
910918
TARGET_EEP = $(OBJDIR)/$(TARGET).eep
919+
TARGET_BIN = $(OBJDIR)/$(TARGET).bin
911920
CORE_LIB = $(OBJDIR)/libcore.a
912921

913922
# Names of executables - chipKIT needs to override all to set paths to PIC32
@@ -1023,6 +1032,7 @@ endif
10231032

10241033
# SoftwareSerial requires -Os (some delays are tuned for this optimization level)
10251034
%SoftwareSerial.cpp.o : OPTIMIZATION_FLAGS = -Os
1035+
%Uart.cpp.o : OPTIMIZATION_FLAGS = -Os
10261036

10271037
ifndef MCU_FLAG_NAME
10281038
MCU_FLAG_NAME = mmcu
@@ -1094,7 +1104,7 @@ ifeq ($(shell expr $(CC_VERNUM) '>' 490), 1)
10941104
endif
10951105
LDFLAGS += -$(MCU_FLAG_NAME)=$(MCU) -Wl,--gc-sections -O$(OPTIMIZATION_LEVEL)
10961106
ifeq ($(shell expr $(CC_VERNUM) '>' 490), 1)
1097-
LDFLAGS += -flto -fuse-linker-plugin
1107+
LDFLAGS += -flto -fuse-linker-plugin
10981108
endif
10991109
SIZEFLAGS ?= --mcu=$(MCU) -C
11001110

@@ -1302,7 +1312,24 @@ $(OBJDIR)/core/%.S.o: $(ARDUINO_CORE_PATH)/%.S $(COMMON_DEPS) | $(OBJDIR)
13021312
@$(MKDIR) $(dir $@)
13031313
$(CC) -MMD -c $(CPPFLAGS) $(ASFLAGS) $< -o $@
13041314

1315+
# alt core files
1316+
$(OBJDIR)/core/%.c.o: $(ALTERNATE_CORE_PATH)/variants/$(VARIANT)/%.c $(COMMON_DEPS) | $(OBJDIR)
1317+
@$(MKDIR) $(dir $@)
1318+
$(CC) -MMD -c $(CPPFLAGS) $(CFLAGS) $< -o $@
1319+
1320+
$(OBJDIR)/core/%.cpp.o: $(ALTERNATE_CORE_PATH)/variants/$(VARIANT)/%.cpp $(COMMON_DEPS) | $(OBJDIR)
1321+
@$(MKDIR) $(dir $@)
1322+
$(CXX) -MMD -c $(CPPFLAGS) $(CXXFLAGS) $< -o $@
1323+
1324+
$(OBJDIR)/core/%.S.o: $(ALTERNATE_CORE_PATH)/variants/$(VARIANT)/%.S $(COMMON_DEPS) | $(OBJDIR)
1325+
@$(MKDIR) $(dir $@)
1326+
$(CC) -MMD -c $(CPPFLAGS) $(ASFLAGS) $< -o $@
1327+
13051328
# various object conversions
1329+
$(OBJDIR)/%.bin: $(OBJDIR)/%.elf $(COMMON_DEPS)
1330+
@$(MKDIR) $(dir $@)
1331+
-$(OBJCOPY) -O binary $< $@
1332+
13061333
$(OBJDIR)/%.hex: $(OBJDIR)/%.elf $(COMMON_DEPS)
13071334
@$(MKDIR) $(dir $@)
13081335
$(OBJCOPY) -O ihex -R .eeprom $< $@
@@ -1442,12 +1469,21 @@ endif
14421469
# so we do not set it by default.
14431470
AVRDUDE_ISP_OPTS = -c $(ISP_PROG) -b $(AVRDUDE_ISP_BAUDRATE)
14441471

1445-
ifndef $(ISP_PORT)
1472+
ifndef ISP_PORT
14461473
ifneq ($(strip $(ISP_PROG)),$(filter $(ISP_PROG), atmelice_isp usbasp usbtiny gpio linuxgpio avrispmkii dragon_isp dragon_dw))
1447-
AVRDUDE_ISP_OPTS += -P $(call get_isp_port)
1474+
# switch for sam devices as bootloader will be on usb serial if using stk500_v2
1475+
ifeq ($(findstring sam, $(strip $(ARCHITECTURE))), sam)
1476+
AVRDUDE_ISP_OPTS += -P $(call get_monitor_port)
1477+
else
1478+
AVRDUDE_ISP_OPTS += -P $(call get_isp_port)
1479+
endif
14481480
endif
14491481
else
1450-
AVRDUDE_ISP_OPTS += -P $(call get_isp_port)
1482+
ifeq ($(CURRENT_OS), WINDOWS)
1483+
AVRDUDE_ISP_OPT += -P ISP_PORT
1484+
else
1485+
AVRDUDE_ISP_OPTS += -P $(call get_isp_port)
1486+
endif
14511487
endif
14521488

14531489
ifndef ISP_EEPROM
@@ -1465,7 +1501,7 @@ endif
14651501
########################################################################
14661502
# Explicit targets start here
14671503

1468-
all: $(TARGET_EEP) $(TARGET_HEX)
1504+
all: $(TARGET_EEP) $(TARGET_BIN) $(TARGET_HEX)
14691505

14701506
# Rule to create $(OBJDIR) automatically. All rules with recipes that
14711507
# create a file within it, but do not already depend on a file within it
@@ -1479,30 +1515,63 @@ $(OBJDIR): pre-build
14791515
pre-build:
14801516
$(call runscript_if_exists,$(PRE_BUILD_HOOK))
14811517

1518+
# copied from arduino with start-group, end-group
14821519
$(TARGET_ELF): $(LOCAL_OBJS) $(CORE_LIB) $(OTHER_OBJS)
1520+
# sam devices need start and end group
1521+
ifeq ($(findstring sam, $(strip $(ARCHITECTURE))), sam)
1522+
$(CC) $(LINKER_SCRIPTS) -Wl,-Map=$(OBJDIR)/$(TARGET).map -o $@ $(LOCAL_OBJS) $(OTHER_OBJS) $(OTHER_LIBS) $(LDFLAGS) $(CORE_LIB) -Wl,--end-group
1523+
# otherwise traditional
1524+
else
14831525
$(CC) $(LDFLAGS) -o $@ $(LOCAL_OBJS) $(CORE_LIB) $(OTHER_OBJS) $(OTHER_LIBS) -lc -lm $(LINKER_SCRIPTS)
1526+
endif
14841527

14851528
$(CORE_LIB): $(CORE_OBJS) $(LIB_OBJS) $(PLATFORM_LIB_OBJS) $(USER_LIB_OBJS)
14861529
$(AR) rcs $@ $(CORE_OBJS) $(LIB_OBJS) $(PLATFORM_LIB_OBJS) $(USER_LIB_OBJS)
14871530

14881531
error_on_caterina:
14891532
$(ERROR_ON_CATERINA)
14901533

1491-
14921534
# Use submake so we can guarantee the reset happens
14931535
# before the upload, even with make -j
14941536
upload: $(TARGET_HEX) verify_size
1537+
ifeq ($(findstring sam, $(strip $(ARCHITECTURE))), sam)
1538+
# do reset toggle at 1200 BAUD to enter bootloader if using avrdude or bossa
1539+
ifeq ($(strip $(UPLOAD_TOOL)), avrdude)
1540+
$(MAKE) reset
1541+
else ifeq ($(findstring bossac, $(strip $(UPLOAD_TOOL))), bossac)
1542+
$(MAKE) reset
1543+
endif
1544+
$(MAKE) do_sam_upload
1545+
else
14951546
$(MAKE) reset
14961547
$(MAKE) do_upload
1548+
endif
14971549

14981550
raw_upload: $(TARGET_HEX) verify_size
1551+
ifeq ($(findstring sam, $(strip $(ARCHITECTURE))), sam)
1552+
$(MAKE) do_sam_upload
1553+
else
14991554
$(MAKE) error_on_caterina
15001555
$(MAKE) do_upload
1556+
endif
15011557

15021558
do_upload:
15031559
$(AVRDUDE) $(AVRDUDE_COM_OPTS) $(AVRDUDE_ARD_OPTS) \
15041560
$(AVRDUDE_UPLOAD_HEX)
15051561

1562+
do_sam_upload: $(TARGET_BIN) verify_size
1563+
ifeq ($(findstring openocd, $(strip $(UPLOAD_TOOL))), openocd)
1564+
$(OPENOCD) $(OPENOCD_OPTS) -c "telnet_port disabled; program {{$(TARGET_BIN)}} verify reset $(BOOTLOADER_SIZE); shutdown"
1565+
else ifeq ($(findstring bossac, $(strip $(UPLOAD_TOOL))), bossac)
1566+
$(BOSSA) $(BOSSA_OPTS) $(TARGET_BIN)
1567+
else ifeq ($(findstring gdb, $(strip $(UPLOAD_TOOL))), gdb)
1568+
$(GDB) $(GDB_UPLOAD_OPTS)
1569+
else ifeq ($(strip $(UPLOAD_TOOL)), avrdude)
1570+
$(MAKE) ispload
1571+
else
1572+
@$(ECHO) "$(BOOTLOADER_UPLOAD_TOOL) not currently supported!\n\n"
1573+
endif
1574+
15061575
do_eeprom: $(TARGET_EEP) $(TARGET_HEX)
15071576
$(AVRDUDE) $(AVRDUDE_COM_OPTS) $(AVRDUDE_ARD_OPTS) \
15081577
$(AVRDUDE_UPLOAD_EEP)
@@ -1535,14 +1604,22 @@ ispload: $(TARGET_EEP) $(TARGET_HEX) verify_size
15351604
$(AVRDUDE_ISPLOAD_OPTS)
15361605

15371606
burn_bootloader:
1538-
ifneq ($(strip $(AVRDUDE_ISP_FUSES_PRE)),)
1539-
$(AVRDUDE) $(AVRDUDE_COM_OPTS) $(AVRDUDE_ISP_OPTS) -e $(AVRDUDE_ISP_FUSES_PRE)
1540-
endif
1541-
ifneq ($(strip $(AVRDUDE_ISP_BURN_BOOTLOADER)),)
1542-
$(AVRDUDE) $(AVRDUDE_COM_OPTS) $(AVRDUDE_ISP_OPTS) $(AVRDUDE_ISP_BURN_BOOTLOADER)
1543-
endif
1544-
ifneq ($(strip $(AVRDUDE_ISP_FUSES_POST)),)
1545-
$(AVRDUDE) $(AVRDUDE_COM_OPTS) $(AVRDUDE_ISP_OPTS) $(AVRDUDE_ISP_FUSES_POST)
1607+
ifeq ($(findstring sam, $(strip $(ARCHITECTURE))), sam)
1608+
ifeq ($(strip $(BOOTLOADER_UPLOAD_TOOL)), openocd)
1609+
$(OPENOCD) $(OPENOCD_OPTS) -c "telnet_port disabled; init; halt; $(BOOTLOADER_UNPROTECT); program {{$(BOOTLOADER_PARENT)/$(BOOTLOADER_FILE)}} verify reset; shutdown"
1610+
else
1611+
@$(ECHO) "$(BOOTLOADER_UPLOAD_TOOL) not currently supported!\n\n"
1612+
endif
1613+
else
1614+
ifneq ($(strip $(AVRDUDE_ISP_FUSES_PRE)),)
1615+
$(AVRDUDE) $(AVRDUDE_COM_OPTS) $(AVRDUDE_ISP_OPTS) -e $(AVRDUDE_ISP_FUSES_PRE)
1616+
endif
1617+
ifneq ($(strip $(AVRDUDE_ISP_BURN_BOOTLOADER)),)
1618+
$(AVRDUDE) $(AVRDUDE_COM_OPTS) $(AVRDUDE_ISP_OPTS) $(AVRDUDE_ISP_BURN_BOOTLOADER)
1619+
endif
1620+
ifneq ($(strip $(AVRDUDE_ISP_FUSES_POST)),)
1621+
$(AVRDUDE) $(AVRDUDE_COM_OPTS) $(AVRDUDE_ISP_OPTS) $(AVRDUDE_ISP_FUSES_POST)
1622+
endif
15461623
endif
15471624

15481625
set_fuses:
@@ -1580,6 +1657,12 @@ else
15801657
$(MONITOR_CMD) $(call get_monitor_port) $(MONITOR_BAUDRATE)
15811658
endif
15821659

1660+
debug_init:
1661+
$(OPENOCD)
1662+
1663+
debug:
1664+
$(GDB) $(GDB_OPTS)
1665+
15831666
disasm: $(OBJDIR)/$(TARGET).lss
15841667
@$(ECHO) "The compiled ELF file has been disassembled to $(OBJDIR)/$(TARGET).lss\n\n"
15851668

@@ -1599,7 +1682,6 @@ generate_assembly: $(OBJDIR)/$(TARGET).s
15991682
generated_assembly: generate_assembly
16001683
@$(ECHO) "\"generated_assembly\" target is deprecated. Use \"generate_assembly\" target instead\n\n"
16011684

1602-
.PHONY: tags
16031685
tags:
16041686
ifneq ($(words $(wildcard $(TAGS_FILE))), 0)
16051687
rm -f $(TAGS_FILE)
@@ -1634,6 +1716,8 @@ help:
16341716
make show_boards - list all the boards defined in boards.txt\n\
16351717
make show_submenu - list all board submenus defined in boards.txt\n\
16361718
make monitor - connect to the Arduino's serial port\n\
1719+
make debug_init - start openocd gdb server\n\
1720+
make debug - connect to gdb target and begin debugging\n\
16371721
make size - show the size of the compiled output (relative to\n\
16381722
resources, if you have a patched avr-size).\n\
16391723
make verify_size - verify that the size of the final file is less than\n\
@@ -1655,7 +1739,7 @@ help:
16551739

16561740
.PHONY: all upload raw_upload raw_eeprom error_on_caterina reset reset_stty ispload \
16571741
clean depends size show_boards monitor disasm symbol_sizes generated_assembly \
1658-
generate_assembly verify_size burn_bootloader help pre-build
1742+
generate_assembly verify_size burn_bootloader help pre-build tags debug debug_init
16591743

16601744
# added - in the beginning, so that we don't get an error if the file is not present
16611745
-include $(DEPS)

Common.mk

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
COMMON_INCLUDED = TRUE
12
# Useful functions
23
# Returns the first argument (typically a directory), if the file or directory
34
# named by concatenating the first and optionally second argument
@@ -26,8 +27,11 @@ show_config_variable = $(call show_config_info,$(1) = $($(1)) $(3),$(2))
2627
# Just a nice simple visual separator
2728
show_separator = $(call arduino_output,-------------------------)
2829

30+
# Master Arduino Makefile include (after user Makefile)
31+
ardmk_include = $(shell basename $(word 2,$(MAKEFILE_LIST)))
32+
2933
$(call show_separator)
30-
$(call arduino_output,Arduino.mk Configuration:)
34+
$(call arduino_output,$(call ardmk_include) Configuration:)
3135

3236
########################################################################
3337
#

HISTORY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ I tried to give credit whenever possible. If I have missed anyone, kindly add it
1818
- New: Add generation of tags file using ctags, which automatically includes project libs and Arduino core. (https://github.com/tuna-f1sh)
1919
- New: Add template Makefile and project boilerplate initialise script, `ardmk-init`. (https://github.com/tuna-f1sh)
2020
- New: Support atmelice_isp JTAG tool as ISP programmer. (https://github.com/tuna-f1sh)
21+
- New: Support Arduino ARM-based (SAM/SAMD) devices. (https://github.com/tuna-f1sh)
2122

2223
### 1.6.0 (2017-07-11)
2324
- Fix: Allowed for SparkFun's weird usb pid/vid submenu shenanigans (issue #499). (https://github.com/sej7278)

0 commit comments

Comments
 (0)