summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ports/samd/Makefile100
-rw-r--r--ports/samd/README.md7
-rw-r--r--ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.mk4
-rw-r--r--ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/link.ld17
-rw-r--r--ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.h7
-rw-r--r--ports/samd/boards/ADAFRUIT_TRINKET_M0/board.mk4
-rw-r--r--ports/samd/boards/ADAFRUIT_TRINKET_M0/link.ld17
-rw-r--r--ports/samd/boards/ADAFRUIT_TRINKET_M0/mpconfigboard.h2
-rw-r--r--ports/samd/main.c98
-rw-r--r--ports/samd/makefile12
-rw-r--r--ports/samd/modmachine.c72
-rw-r--r--ports/samd/modutime.c47
-rw-r--r--ports/samd/mpconfigport.h109
-rw-r--r--ports/samd/mphalport.c112
-rw-r--r--ports/samd/mphalport.h39
-rw-r--r--ports/samd/qstrdefsport.h1
-rw-r--r--ports/samd/samd_isr.c252
-rw-r--r--ports/samd/samd_soc.c152
-rw-r--r--ports/samd/samd_soc.h53
-rw-r--r--ports/samd/sections.ld37
-rw-r--r--ports/samd/tusb_config.h47
-rw-r--r--ports/samd/tusb_port.c146
22 files changed, 1335 insertions, 0 deletions
diff --git a/ports/samd/Makefile b/ports/samd/Makefile
new file mode 100644
index 000000000..f4a09ad7c
--- /dev/null
+++ b/ports/samd/Makefile
@@ -0,0 +1,100 @@
+BOARD ?= ADAFRUIT_ITSYBITSY_M4_EXPRESS
+BOARD_DIR ?= boards/$(BOARD)
+BUILD ?= build-$(BOARD)
+
+CROSS_COMPILE ?= arm-none-eabi-
+UF2CONV ?= $(TOP)/tools/uf2conv.py
+
+ifeq ($(wildcard $(BOARD_DIR)/.),)
+$(error Invalid BOARD specified: $(BOARD_DIR))
+endif
+
+include ../../py/mkenv.mk
+include $(BOARD_DIR)/board.mk
+
+# Qstr definitions (must come before including py.mk)
+QSTR_DEFS = qstrdefsport.h
+QSTR_GLOBAL_DEPENDENCIES = $(BOARD_DIR)/mpconfigboard.h
+
+# Include py core make definitions
+include $(TOP)/py/py.mk
+
+INC += -I.
+INC += -I$(TOP)
+INC += -I$(BUILD)
+INC += -I$(BOARD_DIR)
+INC += -I$(TOP)/lib/cmsis/inc
+INC += -I$(TOP)/lib/asf4/$(shell echo $(MCU_SERIES) | tr '[:upper:]' '[:lower:]')/include
+INC += -I$(TOP)/lib/tinyusb/src
+
+CFLAGS_MCU_SAMD21 = -mtune=cortex-m0plus -mcpu=cortex-m0plus -msoft-float
+CFLAGS_MCU_SAMD51 = -mtune=cortex-m4 -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard
+CFLAGS = $(INC) -Wall -Werror -std=c99 -nostdlib -mthumb $(CFLAGS_MCU_$(MCU_SERIES)) -fsingle-precision-constant -Wdouble-promotion
+CFLAGS += -DMCU_$(MCU_SERIES) -D__$(CMSIS_MCU)__
+LDFLAGS = -nostdlib $(addprefix -T,$(LD_FILES)) -Map=$@.map --cref
+LIBS = $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
+
+# Tune for Debugging or Optimization
+ifeq ($(DEBUG),1)
+CFLAGS += -O0 -ggdb
+else
+CFLAGS += -Os -DNDEBUG
+LDFLAGS += --gc-sections
+CFLAGS += -fdata-sections -ffunction-sections
+endif
+
+SRC_C = \
+ main.c \
+ modutime.c \
+ modmachine.c \
+ mphalport.c \
+ samd_isr.c \
+ samd_soc.c \
+ tusb_port.c \
+ lib/libc/string0.c \
+ lib/libm/ef_sqrt.c \
+ lib/libm/fmodf.c \
+ lib/libm/math.c \
+ lib/libm/nearbyintf.c \
+ lib/mp-readline/readline.c \
+ lib/tinyusb/src/class/cdc/cdc_device.c \
+ lib/tinyusb/src/common/tusb_fifo.c \
+ lib/tinyusb/src/device/usbd.c \
+ lib/tinyusb/src/device/usbd_control.c \
+ lib/tinyusb/src/tusb.c \
+ lib/utils/printf.c \
+ lib/utils/pyexec.c \
+ lib/utils/stdout_helpers.c \
+
+ifeq ($(MCU_SERIES),SAMD21)
+SRC_C += lib/tinyusb/src/portable/microchip/samd21/dcd_samd21.c
+SRC_S = lib/utils/gchelper_m0.s
+else
+SRC_C += lib/tinyusb/src/portable/microchip/samd51/dcd_samd51.c
+SRC_S = lib/utils/gchelper_m3.s
+endif
+
+# List of sources for qstr extraction
+SRC_QSTR += modutime.c modmachine.c
+
+OBJ += $(PY_O)
+OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
+OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o))
+
+# Workaround for bug in older gcc, warning on "static usbd_device_t _usbd_dev = { 0 };"
+$(BUILD)/lib/tinyusb/src/device/usbd.o: CFLAGS += -Wno-missing-braces
+
+all: $(BUILD)/firmware.uf2
+
+$(BUILD)/firmware.elf: $(OBJ)
+ $(ECHO) "LINK $@"
+ $(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
+ $(Q)$(SIZE) $@
+
+$(BUILD)/firmware.bin: $(BUILD)/firmware.elf
+ $(Q)$(OBJCOPY) -O binary -j .isr_vector -j .text -j .data $^ $(BUILD)/firmware.bin
+
+$(BUILD)/firmware.uf2: $(BUILD)/firmware.bin
+ $(Q)$(PYTHON) $(UF2CONV) -b $(TEXT0) -c -o $@ $<
+
+include $(TOP)/py/mkrules.mk
diff --git a/ports/samd/README.md b/ports/samd/README.md
new file mode 100644
index 000000000..b2ff4023e
--- /dev/null
+++ b/ports/samd/README.md
@@ -0,0 +1,7 @@
+Port of MicroPython to Microchip SAMD MCUs
+==========================================
+
+Supports SAMD21 and SAMD51.
+
+Features:
+- REPL over USB VCP
diff --git a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.mk b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.mk
new file mode 100644
index 000000000..8cbd1885e
--- /dev/null
+++ b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/board.mk
@@ -0,0 +1,4 @@
+MCU_SERIES = SAMD51
+CMSIS_MCU = SAMD51G19A
+LD_FILES = $(BOARD_DIR)/link.ld sections.ld
+TEXT0 = 0x4000
diff --git a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/link.ld b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/link.ld
new file mode 100644
index 000000000..e0baa9bba
--- /dev/null
+++ b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/link.ld
@@ -0,0 +1,17 @@
+/*
+ GNU linker script for SAMD51
+*/
+
+/* Specify the memory areas */
+MEMORY
+{
+ FLASH (rx) : ORIGIN = 0x00004000, LENGTH = 512K - 16K
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 192K
+}
+
+/* Top end of the stack, with room for double-tap variable */
+_estack = ORIGIN(RAM) + LENGTH(RAM) - 8;
+_sstack = _estack - 16K;
+
+_sheap = _ebss;
+_eheap = _sstack;
diff --git a/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.h b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.h
new file mode 100644
index 000000000..490704ead
--- /dev/null
+++ b/ports/samd/boards/ADAFRUIT_ITSYBITSY_M4_EXPRESS/mpconfigboard.h
@@ -0,0 +1,7 @@
+#define MICROPY_HW_BOARD_NAME "ItsyBitsy M4 Express"
+#define MICROPY_HW_MCU_NAME "SAMD51G19A"
+
+#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT)
+#define MICROPY_PY_BUILTINS_COMPLEX (0)
+#define MICROPY_PY_MATH (0)
+#define MICROPY_PY_CMATH (0)
diff --git a/ports/samd/boards/ADAFRUIT_TRINKET_M0/board.mk b/ports/samd/boards/ADAFRUIT_TRINKET_M0/board.mk
new file mode 100644
index 000000000..3955a4f71
--- /dev/null
+++ b/ports/samd/boards/ADAFRUIT_TRINKET_M0/board.mk
@@ -0,0 +1,4 @@
+MCU_SERIES = SAMD21
+CMSIS_MCU = SAMD21E18A
+LD_FILES = $(BOARD_DIR)/link.ld sections.ld
+TEXT0 = 0x2000
diff --git a/ports/samd/boards/ADAFRUIT_TRINKET_M0/link.ld b/ports/samd/boards/ADAFRUIT_TRINKET_M0/link.ld
new file mode 100644
index 000000000..b7d59c315
--- /dev/null
+++ b/ports/samd/boards/ADAFRUIT_TRINKET_M0/link.ld
@@ -0,0 +1,17 @@
+/*
+ GNU linker script for SAMD21
+*/
+
+/* Specify the memory areas */
+MEMORY
+{
+ FLASH (rx) : ORIGIN = 0x00002000, LENGTH = 256K - 8K
+ RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 32K
+}
+
+/* Top end of the stack, with room for double-tap variable */
+_estack = ORIGIN(RAM) + LENGTH(RAM) - 8;
+_sstack = _estack - 8K;
+
+_sheap = _ebss;
+_eheap = _sstack;
diff --git a/ports/samd/boards/ADAFRUIT_TRINKET_M0/mpconfigboard.h b/ports/samd/boards/ADAFRUIT_TRINKET_M0/mpconfigboard.h
new file mode 100644
index 000000000..d3a6ba2d8
--- /dev/null
+++ b/ports/samd/boards/ADAFRUIT_TRINKET_M0/mpconfigboard.h
@@ -0,0 +1,2 @@
+#define MICROPY_HW_BOARD_NAME "Trinket M0"
+#define MICROPY_HW_MCU_NAME "SAMD21E18A"
diff --git a/ports/samd/main.c b/ports/samd/main.c
new file mode 100644
index 000000000..a66bdfbeb
--- /dev/null
+++ b/ports/samd/main.c
@@ -0,0 +1,98 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/compile.h"
+#include "py/runtime.h"
+#include "py/gc.h"
+#include "py/mperrno.h"
+#include "py/stackctrl.h"
+#include "lib/utils/gchelper.h"
+#include "lib/utils/pyexec.h"
+
+extern uint8_t _sstack, _estack, _sheap, _eheap;
+
+void samd_main(void) {
+ mp_stack_set_top(&_estack);
+ mp_stack_set_limit(&_estack - &_sstack - 1024);
+
+ for (;;) {
+ gc_init(&_sheap, &_eheap);
+ mp_init();
+ mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_path), 0);
+ mp_obj_list_append(mp_sys_path, MP_OBJ_NEW_QSTR(MP_QSTR_));
+ mp_obj_list_init(MP_OBJ_TO_PTR(mp_sys_argv), 0);
+
+ for (;;) {
+ if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) {
+ if (pyexec_raw_repl() != 0) {
+ break;
+ }
+ } else {
+ if (pyexec_friendly_repl() != 0) {
+ break;
+ }
+ }
+ }
+
+ mp_printf(MP_PYTHON_PRINTER, "MPY: soft reboot\n");
+ gc_sweep_all();
+ mp_deinit();
+ }
+}
+
+void gc_collect(void) {
+ gc_collect_start();
+ uintptr_t regs[10];
+ uintptr_t sp = gc_helper_get_regs_and_sp(regs);
+ gc_collect_root((void**)sp, ((uintptr_t)MP_STATE_THREAD(stack_top) - sp) / sizeof(uint32_t));
+ gc_collect_end();
+}
+
+mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
+ mp_raise_OSError(MP_ENOENT);
+}
+
+mp_import_stat_t mp_import_stat(const char *path) {
+ return MP_IMPORT_STAT_NO_EXIST;
+}
+
+mp_obj_t mp_builtin_open(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_open_obj, 1, mp_builtin_open);
+
+void nlr_jump_fail(void *val) {
+ for (;;) {
+ }
+}
+
+#ifndef NDEBUG
+void MP_WEAK __assert_func(const char *file, int line, const char *func, const char *expr) {
+ mp_printf(MP_PYTHON_PRINTER, "Assertion '%s' failed, at file %s:%d\n", expr, file, line);
+ for(;;) {
+ }
+}
+#endif
diff --git a/ports/samd/makefile b/ports/samd/makefile
new file mode 100644
index 000000000..336d6f280
--- /dev/null
+++ b/ports/samd/makefile
@@ -0,0 +1,12 @@
+#BOARD = TRINKET
+UF2DEV = /dev/sdb
+#UF2CONV = /home/damien/others/uf2/utils/uf2conv.py
+
+include Makefile
+
+deploy: $(BUILD)/firmware.uf2
+ $(ECHO) "Copying $< to the board"
+ mount $(UF2DEV)
+ cat /mnt/INFO_UF2.TXT > /dev/null
+ cp $< /mnt
+ umount /mnt
diff --git a/ports/samd/modmachine.c b/ports/samd/modmachine.c
new file mode 100644
index 000000000..5362ef172
--- /dev/null
+++ b/ports/samd/modmachine.c
@@ -0,0 +1,72 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/runtime.h"
+#include "extmod/machine_mem.h"
+#include "samd_soc.h"
+
+#if defined(MCU_SAMD21)
+#define DBL_TAP_ADDR ((volatile uint32_t *)(0x20000000 + 32 * 1024 - 4))
+#elif defined(MCU_SAMD51)
+#define DBL_TAP_ADDR ((volatile uint32_t *)(0x20000000 + 192 * 1024 - 4))
+#endif
+#define DBL_TAP_MAGIC_LOADER 0xf01669ef
+#define DBL_TAP_MAGIC_RESET 0xf02669ef
+
+STATIC mp_obj_t machine_reset(void) {
+ *DBL_TAP_ADDR = DBL_TAP_MAGIC_RESET;
+ NVIC_SystemReset();
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_0(machine_reset_obj, machine_reset);
+
+STATIC mp_obj_t machine_bootloader(void) {
+ *DBL_TAP_ADDR = DBL_TAP_MAGIC_LOADER;
+ NVIC_SystemReset();
+ return mp_const_none;
+}
+MP_DEFINE_CONST_FUN_OBJ_0(machine_bootloader_obj, machine_bootloader);
+
+STATIC mp_obj_t machine_freq(void) {
+ return MP_OBJ_NEW_SMALL_INT(CPU_FREQ);
+}
+MP_DEFINE_CONST_FUN_OBJ_0(machine_freq_obj, machine_freq);
+
+STATIC const mp_rom_map_elem_t machine_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_umachine) },
+ { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&machine_reset_obj) },
+ { MP_ROM_QSTR(MP_QSTR_bootloader), MP_ROM_PTR(&machine_bootloader_obj) },
+ { MP_ROM_QSTR(MP_QSTR_freq), MP_ROM_PTR(&machine_freq_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mem8), MP_ROM_PTR(&machine_mem8_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mem16), MP_ROM_PTR(&machine_mem16_obj) },
+ { MP_ROM_QSTR(MP_QSTR_mem32), MP_ROM_PTR(&machine_mem32_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(machine_module_globals, machine_module_globals_table);
+
+const mp_obj_module_t mp_module_machine = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&machine_module_globals,
+};
diff --git a/ports/samd/modutime.c b/ports/samd/modutime.c
new file mode 100644
index 000000000..c3c152bb7
--- /dev/null
+++ b/ports/samd/modutime.c
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "extmod/utime_mphal.h"
+
+STATIC const mp_rom_map_elem_t time_module_globals_table[] = {
+ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utime) },
+
+ { MP_ROM_QSTR(MP_QSTR_sleep), MP_ROM_PTR(&mp_utime_sleep_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sleep_ms), MP_ROM_PTR(&mp_utime_sleep_ms_obj) },
+ { MP_ROM_QSTR(MP_QSTR_sleep_us), MP_ROM_PTR(&mp_utime_sleep_us_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&mp_utime_ticks_ms_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ticks_us), MP_ROM_PTR(&mp_utime_ticks_us_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ticks_cpu), MP_ROM_PTR(&mp_utime_ticks_cpu_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ticks_add), MP_ROM_PTR(&mp_utime_ticks_add_obj) },
+ { MP_ROM_QSTR(MP_QSTR_ticks_diff), MP_ROM_PTR(&mp_utime_ticks_diff_obj) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(time_module_globals, time_module_globals_table);
+
+const mp_obj_module_t mp_module_utime = {
+ .base = { &mp_type_module },
+ .globals = (mp_obj_dict_t*)&time_module_globals,
+};
diff --git a/ports/samd/mpconfigport.h b/ports/samd/mpconfigport.h
new file mode 100644
index 000000000..5b81d96b3
--- /dev/null
+++ b/ports/samd/mpconfigport.h
@@ -0,0 +1,109 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+// Options controlling how MicroPython is built, overriding defaults in py/mpconfig.h
+
+// Board specific definitions
+#include "mpconfigboard.h"
+
+// Memory allocation policies
+#define MICROPY_GC_STACK_ENTRY_TYPE uint16_t
+#define MICROPY_GC_ALLOC_THRESHOLD (0)
+#define MICROPY_ALLOC_PARSE_CHUNK_INIT (32)
+#define MICROPY_ALLOC_PATH_MAX (256)
+#define MICROPY_QSTR_BYTES_IN_HASH (1)
+
+// Compiler configuration
+#define MICROPY_COMP_CONST (0)
+
+// Python internal features
+#define MICROPY_ENABLE_GC (1)
+#define MICROPY_KBD_EXCEPTION (1)
+#define MICROPY_HELPER_REPL (1)
+#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ)
+#define MICROPY_ENABLE_SOURCE_LINE (1)
+#define MICROPY_ERROR_REPORTING (MICROPY_ERROR_REPORTING_TERSE)
+#define MICROPY_CPYTHON_COMPAT (0)
+#define MICROPY_CAN_OVERRIDE_BUILTINS (1)
+
+// Control over Python builtins
+#define MICROPY_PY_ASYNC_AWAIT (0)
+#define MICROPY_PY_BUILTINS_STR_COUNT (0)
+#define MICROPY_PY_BUILTINS_MEMORYVIEW (1)
+#define MICROPY_PY_BUILTINS_SET (0)
+#define MICROPY_PY_BUILTINS_FROZENSET (0)
+#define MICROPY_PY_BUILTINS_PROPERTY (0)
+#define MICROPY_PY_BUILTINS_ENUMERATE (0)
+#define MICROPY_PY_BUILTINS_FILTER (0)
+#define MICROPY_PY_BUILTINS_REVERSED (0)
+#define MICROPY_PY_BUILTINS_MIN_MAX (0)
+#define MICROPY_PY___FILE__ (0)
+#define MICROPY_PY_MICROPYTHON_MEM_INFO (1)
+#define MICROPY_PY_ARRAY_SLICE_ASSIGN (1)
+#define MICROPY_PY_ATTRTUPLE (0)
+#define MICROPY_PY_COLLECTIONS (0)
+#define MICROPY_PY_SYS_MAXSIZE (1)
+
+// Extended modules
+#define MICROPY_PY_UTIME_MP_HAL (1)
+#define MICROPY_PY_MACHINE (1)
+
+// Hooks to add builtins
+
+#define MICROPY_PORT_BUILTINS \
+ { MP_ROM_QSTR(MP_QSTR_open), MP_ROM_PTR(&mp_builtin_open_obj) },
+
+extern const struct _mp_obj_module_t mp_module_machine;
+extern const struct _mp_obj_module_t mp_module_utime;
+
+#define MICROPY_PORT_BUILTIN_MODULES \
+ { MP_ROM_QSTR(MP_QSTR_machine), MP_ROM_PTR(&mp_module_machine) }, \
+ { MP_ROM_QSTR(MP_QSTR_utime), MP_ROM_PTR(&mp_module_utime) }, \
+
+#define MICROPY_PORT_ROOT_POINTERS \
+ const char *readline_hist[8];
+
+#define MP_STATE_PORT MP_STATE_VM
+
+// Miscellaneous settings
+
+#define MICROPY_EVENT_POLL_HOOK \
+ do { \
+ extern void mp_handle_pending(void); \
+ mp_handle_pending(); \
+ __WFI(); \
+ } while (0);
+
+#define MICROPY_MAKE_POINTER_CALLABLE(p) ((void*)((mp_uint_t)(p) | 1))
+#define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len)
+
+#define MP_SSIZE_MAX (0x7fffffff)
+typedef int mp_int_t; // must be pointer size
+typedef unsigned mp_uint_t; // must be pointer size
+typedef long mp_off_t;
+
+// Need to provide a declaration/definition of alloca()
+#include <alloca.h>
diff --git a/ports/samd/mphalport.c b/ports/samd/mphalport.c
new file mode 100644
index 000000000..9f3105c69
--- /dev/null
+++ b/ports/samd/mphalport.c
@@ -0,0 +1,112 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "py/mpstate.h"
+#include "py/mphal.h"
+#include "lib/utils/interrupt_char.h"
+#include "samd_soc.h"
+#include "tusb.h"
+
+#if MICROPY_KBD_EXCEPTION
+
+void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) {
+ (void)itf;
+ (void)wanted_char;
+ tud_cdc_read_char(); // discard interrupt char
+ mp_keyboard_interrupt();
+}
+
+void mp_hal_set_interrupt_char(int c) {
+ if (c != -1) {
+ mp_obj_exception_clear_traceback(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)));
+ }
+ tud_cdc_set_wanted_char(c);
+}
+
+void mp_keyboard_interrupt(void) {
+ MP_STATE_VM(mp_pending_exception) = MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception));
+ #if MICROPY_ENABLE_SCHEDULER
+ if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) {
+ MP_STATE_VM(sched_state) = MP_SCHED_PENDING;
+ }
+ #endif
+}
+
+#endif
+
+void mp_hal_delay_ms(mp_uint_t ms) {
+ ms += 1;
+ uint32_t t0 = systick_ms;
+ while (systick_ms - t0 < ms) {
+ MICROPY_EVENT_POLL_HOOK
+ }
+}
+
+void mp_hal_delay_us(mp_uint_t us) {
+ uint32_t ms = us / 1000 + 1;
+ uint32_t t0 = systick_ms;
+ while (systick_ms - t0 < ms) {
+ __WFI();
+ }
+}
+
+int mp_hal_stdin_rx_chr(void) {
+ for (;;) {
+ if (USARTx->USART.INTFLAG.bit.RXC) {
+ return USARTx->USART.DATA.bit.DATA;
+ }
+ if (tud_cdc_connected() && tud_cdc_available()) {
+ uint8_t buf[1];
+ uint32_t count = tud_cdc_read(buf, sizeof(buf));
+ if (count) {
+ return buf[0];
+ }
+ }
+ __WFI();
+ }
+}
+
+void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) {
+ if (tud_cdc_connected()) {
+ for (size_t i = 0; i < len;) {
+ uint32_t n = len - i;
+ uint32_t n2 = tud_cdc_write(str + i, n);
+ if (n2 < n) {
+ while (!tud_cdc_write_flush()) {
+ __WFI();
+ }
+ }
+ i += n2;
+ }
+ while (!tud_cdc_write_flush()) {
+ __WFI();
+ }
+ }
+ while (len--) {
+ while (!(USARTx->USART.INTFLAG.bit.DRE)) { }
+ USARTx->USART.DATA.bit.DATA = *str++;
+ }
+}
diff --git a/ports/samd/mphalport.h b/ports/samd/mphalport.h
new file mode 100644
index 000000000..52562652e
--- /dev/null
+++ b/ports/samd/mphalport.h
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_SAMD_MPHALPORT_H
+#define MICROPY_INCLUDED_SAMD_MPHALPORT_H
+
+#include <stdint.h>
+
+extern volatile uint32_t systick_ms;
+
+void mp_hal_set_interrupt_char(int c);
+
+static inline mp_uint_t mp_hal_ticks_ms(void) { return systick_ms; }
+static inline mp_uint_t mp_hal_ticks_us(void) { return systick_ms * 1000; }
+static inline mp_uint_t mp_hal_ticks_cpu(void) { return 0; }
+
+#endif // MICROPY_INCLUDED_SAMD_MPHALPORT_H
diff --git a/ports/samd/qstrdefsport.h b/ports/samd/qstrdefsport.h
new file mode 100644
index 000000000..3ba897069
--- /dev/null
+++ b/ports/samd/qstrdefsport.h
@@ -0,0 +1 @@
+// qstrs specific to this port
diff --git a/ports/samd/samd_isr.c b/ports/samd/samd_isr.c
new file mode 100644
index 000000000..8341df8c6
--- /dev/null
+++ b/ports/samd/samd_isr.c
@@ -0,0 +1,252 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "samd_soc.h"
+
+typedef void (*ISR)(void);
+
+extern uint32_t _estack, _sidata, _sdata, _edata, _sbss, _ebss;
+
+const ISR isr_vector[];
+uint32_t systick_ms;
+
+void Reset_Handler(void) __attribute__((naked));
+void Reset_Handler(void) {
+ // Set stack pointer
+ #if __CORTEX_M >= 0x03
+ __asm volatile ("ldr sp, =_estack");
+ #else
+ __asm volatile ("ldr r0, =_estack");
+ __asm volatile ("mov sp, r0");
+ #endif
+ // Copy .data section from flash to RAM
+ for (uint32_t *src = &_sidata, *dest = &_sdata; dest < &_edata;) {
+ *dest++ = *src++;
+ }
+ // Zero out .bss section
+ for (uint32_t *dest = &_sbss; dest < &_ebss;) {
+ *dest++ = 0;
+ }
+
+ // When we get here: stack is initialised, bss is clear, data is copied
+
+ #if __FPU_PRESENT == 1 && __FPU_USED == 1
+ // Set CP10 and CP11 Full Access
+ SCB->CPACR |= (3UL << 10 * 2) | (3UL << 11 * 2);
+ #endif
+
+ // SCB->VTOR
+ *((volatile uint32_t*)0xe000ed08) = (uint32_t)&isr_vector;
+
+ // SCB->CCR: enable 8-byte stack alignment for IRQ handlers, in accord with EABI
+ *((volatile uint32_t*)0xe000ed14) |= 1 << 9;
+
+ // Initialise the cpu and peripherals
+ samd_init();
+
+ // Now that we have a basic system up and running we can call main
+ samd_main();
+
+ // we must not return
+ for (;;) {
+ }
+}
+
+void Default_Handler(void) {
+ for (;;) {
+ }
+}
+
+void SysTick_Handler(void) {
+ systick_ms += 1;
+}
+
+const ISR isr_vector[] __attribute__((section(".isr_vector"))) = {
+ (ISR)&_estack,
+ &Reset_Handler,
+ &Default_Handler, // NMI_Handler
+ &Default_Handler, // HardFault_Handler
+ &Default_Handler, // MemManage_Handler
+ &Default_Handler, // BusFault_Handler
+ &Default_Handler, // UsageFault_Handler
+ 0,
+ 0,
+ 0,
+ 0,
+ &Default_Handler, // SVC_Handler
+ &Default_Handler, // DebugMon_Handler
+ 0,
+ &Default_Handler, // PendSV_Handler
+ &SysTick_Handler, // SysTick_Handler
+ 0, // line 0
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ #if defined(MCU_SAMD21)
+ USB_Handler_wrapper, // line 7
+ #else
+ 0,
+ #endif
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ #if defined(MCU_SAMD51)
+ &USB_0_Handler_wrapper, // line 80
+ &USB_1_Handler_wrapper,
+ &USB_2_Handler_wrapper,
+ &USB_3_Handler_wrapper,
+ #else
+ 0,
+ 0,
+ 0,
+ 0,
+ #endif
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+};
diff --git a/ports/samd/samd_soc.c b/ports/samd/samd_soc.c
new file mode 100644
index 000000000..569cd3802
--- /dev/null
+++ b/ports/samd/samd_soc.c
@@ -0,0 +1,152 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "samd_soc.h"
+#include "tusb.h"
+
+static void uart0_init(void) {
+ #if defined(MCU_SAMD21)
+
+ // SERCOM0, TX=PA06=PAD2, RX=PA07=PAD3, ALT-D
+ PORT->Group[0].PMUX[3].reg = 0x33;
+ PORT->Group[0].PINCFG[6].reg = 1;
+ PORT->Group[0].PINCFG[7].reg = 1;
+
+ PM->APBCMASK.bit.SERCOM0_ = 1;
+ GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID_SERCOM0_CORE;
+ while (GCLK->STATUS.bit.SYNCBUSY) { }
+
+ uint32_t rxpo = 3;
+ uint32_t txpo = 1;
+
+ #elif defined(MCU_SAMD51)
+
+ // SERCOM3, TX=PA17=PAD0, RX=PA16=PAD1, ALT-D
+ PORT->Group[0].PMUX[8].reg = 0x33;
+ PORT->Group[0].PINCFG[16].reg = 1;
+ PORT->Group[0].PINCFG[17].reg = 1;
+
+ // Use Generator 0 which is already enabled and switched to DFLL @ 48MHz
+ GCLK->PCHCTRL[SERCOM3_GCLK_ID_CORE].reg = GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN_GCLK0;
+ MCLK->APBBMASK.bit.SERCOM3_ = 1;
+
+ uint32_t rxpo = 1;
+ uint32_t txpo = 2;
+
+ #endif
+
+ while (USARTx->USART.SYNCBUSY.bit.SWRST) { }
+ USARTx->USART.CTRLA.bit.SWRST = 1;
+ while (USARTx->USART.SYNCBUSY.bit.SWRST) { }
+
+ USARTx->USART.CTRLA.reg =
+ SERCOM_USART_CTRLA_DORD
+ | SERCOM_USART_CTRLA_RXPO(rxpo)
+ | SERCOM_USART_CTRLA_TXPO(txpo)
+ | SERCOM_USART_CTRLA_MODE(1)
+ ;
+ USARTx->USART.CTRLB.reg = SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN;
+ while (USARTx->USART.SYNCBUSY.bit.CTRLB) { }
+ #if CPU_FREQ == 8000000
+ uint32_t baud = 50437; // 115200 baud; 65536*(1 - 16 * 115200/8e6)
+ #elif CPU_FREQ == 48000000
+ uint32_t baud = 63019; // 115200 baud; 65536*(1 - 16 * 115200/48e6)
+ #elif CPU_FREQ == 120000000
+ uint32_t baud = 64529; // 115200 baud; 65536*(1 - 16 * 115200/120e6)
+ #endif
+ USARTx->USART.BAUD.bit.BAUD = baud;
+ USARTx->USART.CTRLA.bit.ENABLE = 1;
+ while (USARTx->USART.SYNCBUSY.bit.ENABLE) { }
+}
+
+static void usb_init(void) {
+ // Init USB clock
+ #if defined(MCU_SAMD21)
+ GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID_USB;
+ PM->AHBMASK.bit.USB_ = 1;
+ PM->APBBMASK.bit.USB_ = 1;
+ uint8_t alt = 6; // alt G, USB
+ #elif defined(MCU_SAMD51)
+ GCLK->PCHCTRL[USB_GCLK_ID].reg = GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN_GCLK1;
+ while (GCLK->PCHCTRL[USB_GCLK_ID].bit.CHEN == 0) { }
+ MCLK->AHBMASK.bit.USB_ = 1;
+ MCLK->APBBMASK.bit.USB_ = 1;
+ uint8_t alt = 7; // alt H, USB
+ #endif
+
+ // Init USB pins
+ PORT->Group[0].DIRSET.reg = 1 << 25 | 1 << 24;
+ PORT->Group[0].OUTCLR.reg = 1 << 25 | 1 << 24;
+ PORT->Group[0].PMUX[12].reg = alt << 4 | alt;
+ PORT->Group[0].PINCFG[24].reg = PORT_PINCFG_PMUXEN;
+ PORT->Group[0].PINCFG[25].reg = PORT_PINCFG_PMUXEN;
+
+ tusb_init();
+}
+
+void samd_init(void) {
+ #if defined(MCU_SAMD21)
+
+ NVMCTRL->CTRLB.bit.MANW = 1; // errata "Spurious Writes"
+ NVMCTRL->CTRLB.bit.RWS = 1; // 1 read wait state for 48MHz
+
+ // Enable DFLL48M
+ SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE;
+ while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {}
+ SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP(1) | SYSCTRL_DFLLMUL_FSTEP(1)
+ | SYSCTRL_DFLLMUL_MUL(48000);
+ uint32_t coarse = (*((uint32_t*)FUSES_DFLL48M_COARSE_CAL_ADDR) & FUSES_DFLL48M_COARSE_CAL_Msk)
+ >> FUSES_DFLL48M_COARSE_CAL_Pos;
+ if (coarse == 0x3f) {
+ coarse = 0x1f;
+ }
+ uint32_t fine = 512;
+ SYSCTRL->DFLLVAL.reg = SYSCTRL_DFLLVAL_COARSE(coarse) | SYSCTRL_DFLLVAL_FINE(fine);
+ SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_CCDIS | SYSCTRL_DFLLCTRL_USBCRM
+ | SYSCTRL_DFLLCTRL_MODE | SYSCTRL_DFLLCTRL_ENABLE;
+ while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {}
+
+ GCLK->GENDIV.reg = GCLK_GENDIV_ID(0) | GCLK_GENDIV_DIV(1);
+ GCLK->GENCTRL.reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DFLL48M | GCLK_GENCTRL_ID(0);
+ while (GCLK->STATUS.bit.SYNCBUSY) { }
+
+ // Configure PA10 as output for LED
+ PORT->Group[0].DIRSET.reg = 1 << 10;
+
+ #elif defined(MCU_SAMD51)
+
+ GCLK->GENCTRL[1].reg = 1 << GCLK_GENCTRL_DIV_Pos | GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DFLL;
+ while (GCLK->SYNCBUSY.bit.GENCTRL1) { }
+
+ // Configure PA22 as output for LED
+ PORT->Group[0].DIRSET.reg = 1 << 22;
+
+ #endif
+
+ SysTick_Config(CPU_FREQ / 1000);
+ uart0_init();
+ usb_init();
+}
diff --git a/ports/samd/samd_soc.h b/ports/samd/samd_soc.h
new file mode 100644
index 000000000..5f68610e4
--- /dev/null
+++ b/ports/samd/samd_soc.h
@@ -0,0 +1,53 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_SAMD_SAMD_SOC_H
+#define MICROPY_INCLUDED_SAMD_SAMD_SOC_H
+
+#include <stdint.h>
+#include "sam.h"
+
+#if defined(MCU_SAMD21)
+
+#define CPU_FREQ (48000000)
+#define USARTx SERCOM0
+
+#elif defined(MCU_SAMD51)
+
+#define CPU_FREQ (48000000)
+#define USARTx SERCOM3
+
+#endif
+
+void samd_init(void);
+void samd_main(void);
+
+void USB_Handler_wrapper(void);
+void USB_0_Handler_wrapper(void);
+void USB_1_Handler_wrapper(void);
+void USB_2_Handler_wrapper(void);
+void USB_3_Handler_wrapper(void);
+
+#endif // MICROPY_INCLUDED_SAMD_SAMD_SOC_H
diff --git a/ports/samd/sections.ld b/ports/samd/sections.ld
new file mode 100644
index 000000000..cbcad463d
--- /dev/null
+++ b/ports/samd/sections.ld
@@ -0,0 +1,37 @@
+/* Define output sections */
+SECTIONS
+{
+ .text :
+ {
+ . = ALIGN(4);
+ KEEP(*(.isr_vector))
+ *(.text)
+ *(.text*)
+ *(.rodata)
+ *(.rodata*)
+ . = ALIGN(4);
+ _etext = .;
+ _sidata = _etext;
+ } >FLASH
+
+ .data : AT ( _sidata )
+ {
+ . = ALIGN(4);
+ _sdata = .;
+ *(.data)
+ *(.data*)
+ . = ALIGN(4);
+ _edata = .;
+ } >RAM
+
+ .bss :
+ {
+ . = ALIGN(4);
+ _sbss = .;
+ *(.bss)
+ *(.bss*)
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } >RAM
+}
diff --git a/ports/samd/tusb_config.h b/ports/samd/tusb_config.h
new file mode 100644
index 000000000..07fa680cb
--- /dev/null
+++ b/ports/samd/tusb_config.h
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef MICROPY_INCLUDED_SAMD_TUSB_CONFIG_H
+#define MICROPY_INCLUDED_SAMD_TUSB_CONFIG_H
+
+// Common configuration
+
+#if defined(MCU_SAMD21)
+#define CFG_TUSB_MCU OPT_MCU_SAMD21
+#elif defined(MCU_SAMD51)
+#define CFG_TUSB_MCU OPT_MCU_SAMD51
+#endif
+#define CFG_TUSB_RHPORT0_MODE OPT_MODE_DEVICE
+#define CFG_TUSB_MEM_SECTION
+#define CFG_TUSB_MEM_ALIGN TU_ATTR_ALIGNED(4)
+
+// Device configuration
+
+#define CFG_TUD_ENDOINT0_SIZE (64)
+#define CFG_TUD_CDC (1)
+#define CFG_TUD_CDC_RX_BUFSIZE (64)
+#define CFG_TUD_CDC_TX_BUFSIZE (64)
+
+#endif // MICROPY_INCLUDED_SAMD_TUSB_CONFIG_H
diff --git a/ports/samd/tusb_port.c b/ports/samd/tusb_port.c
new file mode 100644
index 000000000..23c242b40
--- /dev/null
+++ b/ports/samd/tusb_port.c
@@ -0,0 +1,146 @@
+/*
+ * This file is part of the MicroPython project, http://micropython.org/
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Damien P. George
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "samd_soc.h"
+#include "tusb.h"
+
+#define USBD_VID (0xf055)
+#define USBD_PID (0x9802)
+
+#define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN)
+#define USBD_MAX_POWER_MA (250)
+
+#define USBD_ITF_CDC (0) // needs 2 interfaces
+#define USBD_ITF_MAX (2)
+
+#define USBD_CDC_EP_CMD (0x81)
+#define USBD_CDC_EP_OUT (0x02)
+#define USBD_CDC_EP_IN (0x82)
+#define USBD_CDC_CMD_MAX_SIZE (8)
+
+#define USBD_STR_0 (0x00)
+#define USBD_STR_MANUF (0x01)
+#define USBD_STR_PRODUCT (0x02)
+#define USBD_STR_SERIAL (0x03)
+#define USBD_STR_CDC (0x04)
+
+// Note: descriptors returned from callbacks must exist long enough for transfer to complete
+
+static const tusb_desc_device_t usbd_desc_device = {
+ .bLength = sizeof(tusb_desc_device_t),
+ .bDescriptorType = TUSB_DESC_DEVICE,
+ .bcdUSB = 0x0200,
+ .bDeviceClass = TUSB_CLASS_MISC,
+ .bDeviceSubClass = MISC_SUBCLASS_COMMON,
+ .bDeviceProtocol = MISC_PROTOCOL_IAD,
+ .bMaxPacketSize0 = CFG_TUD_ENDOINT0_SIZE,
+ .idVendor = USBD_VID,
+ .idProduct = USBD_PID,
+ .bcdDevice = 0x0100,
+ .iManufacturer = USBD_STR_MANUF,
+ .iProduct = USBD_STR_PRODUCT,
+ .iSerialNumber = USBD_STR_SERIAL,
+ .bNumConfigurations = 1,
+};
+
+static const uint8_t usbd_desc_cfg[USBD_DESC_LEN] = {
+ TUD_CONFIG_DESCRIPTOR(USBD_ITF_MAX, USBD_STR_0, USBD_DESC_LEN,
+ TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, USBD_MAX_POWER_MA),
+
+ TUD_CDC_DESCRIPTOR(USBD_ITF_CDC, USBD_STR_CDC, USBD_CDC_EP_CMD,
+ USBD_CDC_CMD_MAX_SIZE, USBD_CDC_EP_OUT, USBD_CDC_EP_IN, CFG_TUD_CDC_RX_BUFSIZE),
+};
+
+static const char *const usbd_desc_str[] = {
+ [USBD_STR_MANUF] = "MicroPython",
+ [USBD_STR_PRODUCT] = "Board in FS mode",
+ [USBD_STR_SERIAL] = "000000000000", // TODO
+ [USBD_STR_CDC] = "Board CDC",
+};
+
+const uint8_t *tud_descriptor_device_cb(void) {
+ return (const uint8_t*)&usbd_desc_device;
+}
+
+const uint8_t *tud_descriptor_configuration_cb(uint8_t index) {
+ (void)index;
+ return usbd_desc_cfg;
+}
+
+const uint16_t *tud_descriptor_string_cb(uint8_t index) {
+ #define DESC_STR_MAX (20)
+ static uint16_t desc_str[DESC_STR_MAX];
+
+ uint8_t len;
+ if (index == 0) {
+ desc_str[1] = 0x0409; // supported language is English
+ len = 1;
+ } else {
+ if (index >= sizeof(usbd_desc_str) / sizeof(usbd_desc_str[0])) {
+ return NULL;
+ }
+ const char* str = usbd_desc_str[index];
+ for (len = 0; len < DESC_STR_MAX - 1 && str[len]; ++len) {
+ desc_str[1 + len] = str[len];
+ }
+ }
+
+ // first byte is len, second byte is string type
+ desc_str[0] = TUD_DESC_STR_HEADER(len);
+
+ return desc_str;
+}
+
+#if defined(MCU_SAMD21)
+
+void USB_Handler_wrapper(void) {
+ USB_Handler();
+ tud_task();
+}
+
+#elif defined(MCU_SAMD51)
+
+void USB_0_Handler_wrapper(void) {
+ USB_0_Handler();
+ tud_task();
+}
+
+void USB_1_Handler_wrapper(void) {
+ USB_1_Handler();
+ tud_task();
+}
+
+void USB_2_Handler_wrapper(void) {
+ USB_2_Handler();
+ tud_task();
+}
+
+void USB_3_Handler_wrapper(void) {
+ USB_3_Handler();
+ tud_task();
+}
+
+#endif