From 30680c6eb396a2bb06928afd69edae9908ac84fb Mon Sep 17 00:00:00 2001
From: patrickmt <40182064+patrickmt@users.noreply.github.com>
Date: Wed, 29 Aug 2018 15:07:52 -0400
Subject: Massdrop keyboard support (#3780)
* Massdrop SAMD51
Massdrop SAMD51 keyboards initial project upload
* Removing relocated files
Removing files that were relocated and not deleted from previous location
* LED queue fix and cleaning
Cleaned some white space or comments.
Fix for LED I2C command queue.
Cleaned up interrupts.
Added debug function for printing numbers to scope through m15 line.
* Factory programmed serial usage
Ability to use factory programmed serial in hub and keyboard usb descriptors
* USB serial number and bugfix
Added support for factory programmed serial and usage.
Incorporated bootloader's conditional compiling to align project closer.
Fixed issue when USB device attempted to send before enabled.
General white space and comment cleanup.
* Project cleanup
Cleaned up project in terms of white space, commented code, and unecessary files.
NKRO keyboard is now using correct setreport although KBD was fine to use.
Fixed broken linkage to __xprintf for serial debug statements.
* Fix for extra keys
Fixed possible USB hang on extra keys report set missing
* I2C cleanup
I2C cleanup and file renames necessary for master branch merge
* Boot tracing and clocks cleanup
Added optional boot debug trace mode through debug LED codes.
General clock code cleanup.
* Relocate ARM/Atmel headers
Moved ARM/Atmel header folder from drivers to lib and made necessary makefile changes.
* Pull request changes
Pull request changes
* Keymap and compile flag fix
Keymap fix for momentary layer.
Potential compile flag fix for Travis CI failure.
* va_list include fix
Fix for va_list compile failure
* Include file case fixes
Fixes for include files with incorrect case
* ctrl and alt67 keyboard readme
Added ctrl and alt67 keyboard readme files
---
tmk_core/arm_atsam.mk | 56 +
tmk_core/common.mk | 6 +
tmk_core/common/arm_atsam/bootloader.c | 19 +
tmk_core/common/arm_atsam/eeprom.c | 98 ++
tmk_core/common/arm_atsam/printf.h | 8 +
tmk_core/common/arm_atsam/suspend.c | 17 +
tmk_core/common/arm_atsam/timer.c | 59 +
tmk_core/common/print.h | 30 +-
tmk_core/common/report.h | 5 +
tmk_core/protocol/arm_atsam.mk | 26 +
tmk_core/protocol/arm_atsam/adc.c | 99 ++
tmk_core/protocol/arm_atsam/adc.h | 37 +
tmk_core/protocol/arm_atsam/arm_atsam_protocol.h | 45 +
tmk_core/protocol/arm_atsam/clks.c | 439 +++++++
tmk_core/protocol/arm_atsam/clks.h | 90 ++
tmk_core/protocol/arm_atsam/d51_util.c | 165 +++
tmk_core/protocol/arm_atsam/d51_util.h | 185 +++
tmk_core/protocol/arm_atsam/i2c_master.c | 585 +++++++++
tmk_core/protocol/arm_atsam/i2c_master.h | 108 ++
tmk_core/protocol/arm_atsam/issi3733_driver.h | 201 +++
tmk_core/protocol/arm_atsam/led_matrix.c | 509 +++++++
tmk_core/protocol/arm_atsam/led_matrix.h | 142 ++
tmk_core/protocol/arm_atsam/main_arm_atsam.c | 279 ++++
tmk_core/protocol/arm_atsam/main_arm_atsam.h | 23 +
tmk_core/protocol/arm_atsam/md_bootloader.h | 18 +
tmk_core/protocol/arm_atsam/spi.c | 90 ++
tmk_core/protocol/arm_atsam/spi.h | 63 +
tmk_core/protocol/arm_atsam/startup.c | 548 ++++++++
tmk_core/protocol/arm_atsam/usb/compiler.h | 1177 +++++++++++++++++
tmk_core/protocol/arm_atsam/usb/conf_usb.h | 163 +++
tmk_core/protocol/arm_atsam/usb/main_usb.c | 118 ++
tmk_core/protocol/arm_atsam/usb/spfssf.c | 268 ++++
tmk_core/protocol/arm_atsam/usb/spfssf.h | 57 +
tmk_core/protocol/arm_atsam/usb/status_codes.h | 158 +++
tmk_core/protocol/arm_atsam/usb/udc.c | 1164 ++++++++++++++++
tmk_core/protocol/arm_atsam/usb/udc.h | 260 ++++
tmk_core/protocol/arm_atsam/usb/udc_desc.h | 135 ++
tmk_core/protocol/arm_atsam/usb/udd.h | 396 ++++++
tmk_core/protocol/arm_atsam/usb/udi.h | 133 ++
tmk_core/protocol/arm_atsam/usb/udi_cdc.c | 1384 ++++++++++++++++++++
tmk_core/protocol/arm_atsam/usb/udi_cdc.h | 381 ++++++
tmk_core/protocol/arm_atsam/usb/udi_cdc_conf.h | 72 +
tmk_core/protocol/arm_atsam/usb/udi_device_conf.h | 715 ++++++++++
.../protocol/arm_atsam/usb/udi_device_epsize.h | 32 +
tmk_core/protocol/arm_atsam/usb/udi_hid.c | 162 +++
tmk_core/protocol/arm_atsam/usb/udi_hid.h | 85 ++
tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.c | 845 ++++++++++++
tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.h | 109 ++
tmk_core/protocol/arm_atsam/usb/udi_hid_kbd_conf.h | 60 +
tmk_core/protocol/arm_atsam/usb/udi_hid_kbd_desc.c | 179 +++
tmk_core/protocol/arm_atsam/usb/ui.c | 106 ++
tmk_core/protocol/arm_atsam/usb/ui.h | 82 ++
tmk_core/protocol/arm_atsam/usb/usb.c | 1144 ++++++++++++++++
tmk_core/protocol/arm_atsam/usb/usb.h | 492 +++++++
tmk_core/protocol/arm_atsam/usb/usb2422.c | 412 ++++++
tmk_core/protocol/arm_atsam/usb/usb2422.h | 405 ++++++
tmk_core/protocol/arm_atsam/usb/usb_atmel.h | 190 +++
tmk_core/protocol/arm_atsam/usb/usb_device_udd.c | 1097 ++++++++++++++++
tmk_core/protocol/arm_atsam/usb/usb_main.h | 97 ++
tmk_core/protocol/arm_atsam/usb/usb_protocol.h | 498 +++++++
tmk_core/protocol/arm_atsam/usb/usb_protocol_cdc.h | 193 +++
tmk_core/protocol/arm_atsam/usb/usb_protocol_hid.h | 319 +++++
tmk_core/protocol/arm_atsam/usb/usb_util.c | 59 +
tmk_core/protocol/arm_atsam/usb/usb_util.h | 10 +
tmk_core/protocol/arm_atsam/wait_api.h | 8 +
65 files changed, 17114 insertions(+), 1 deletion(-)
create mode 100644 tmk_core/arm_atsam.mk
create mode 100644 tmk_core/common/arm_atsam/bootloader.c
create mode 100644 tmk_core/common/arm_atsam/eeprom.c
create mode 100644 tmk_core/common/arm_atsam/printf.h
create mode 100644 tmk_core/common/arm_atsam/suspend.c
create mode 100644 tmk_core/common/arm_atsam/timer.c
create mode 100644 tmk_core/protocol/arm_atsam.mk
create mode 100644 tmk_core/protocol/arm_atsam/adc.c
create mode 100644 tmk_core/protocol/arm_atsam/adc.h
create mode 100644 tmk_core/protocol/arm_atsam/arm_atsam_protocol.h
create mode 100644 tmk_core/protocol/arm_atsam/clks.c
create mode 100644 tmk_core/protocol/arm_atsam/clks.h
create mode 100644 tmk_core/protocol/arm_atsam/d51_util.c
create mode 100644 tmk_core/protocol/arm_atsam/d51_util.h
create mode 100644 tmk_core/protocol/arm_atsam/i2c_master.c
create mode 100644 tmk_core/protocol/arm_atsam/i2c_master.h
create mode 100644 tmk_core/protocol/arm_atsam/issi3733_driver.h
create mode 100644 tmk_core/protocol/arm_atsam/led_matrix.c
create mode 100644 tmk_core/protocol/arm_atsam/led_matrix.h
create mode 100644 tmk_core/protocol/arm_atsam/main_arm_atsam.c
create mode 100644 tmk_core/protocol/arm_atsam/main_arm_atsam.h
create mode 100644 tmk_core/protocol/arm_atsam/md_bootloader.h
create mode 100644 tmk_core/protocol/arm_atsam/spi.c
create mode 100644 tmk_core/protocol/arm_atsam/spi.h
create mode 100644 tmk_core/protocol/arm_atsam/startup.c
create mode 100644 tmk_core/protocol/arm_atsam/usb/compiler.h
create mode 100644 tmk_core/protocol/arm_atsam/usb/conf_usb.h
create mode 100644 tmk_core/protocol/arm_atsam/usb/main_usb.c
create mode 100644 tmk_core/protocol/arm_atsam/usb/spfssf.c
create mode 100644 tmk_core/protocol/arm_atsam/usb/spfssf.h
create mode 100644 tmk_core/protocol/arm_atsam/usb/status_codes.h
create mode 100644 tmk_core/protocol/arm_atsam/usb/udc.c
create mode 100644 tmk_core/protocol/arm_atsam/usb/udc.h
create mode 100644 tmk_core/protocol/arm_atsam/usb/udc_desc.h
create mode 100644 tmk_core/protocol/arm_atsam/usb/udd.h
create mode 100644 tmk_core/protocol/arm_atsam/usb/udi.h
create mode 100644 tmk_core/protocol/arm_atsam/usb/udi_cdc.c
create mode 100644 tmk_core/protocol/arm_atsam/usb/udi_cdc.h
create mode 100644 tmk_core/protocol/arm_atsam/usb/udi_cdc_conf.h
create mode 100644 tmk_core/protocol/arm_atsam/usb/udi_device_conf.h
create mode 100644 tmk_core/protocol/arm_atsam/usb/udi_device_epsize.h
create mode 100644 tmk_core/protocol/arm_atsam/usb/udi_hid.c
create mode 100644 tmk_core/protocol/arm_atsam/usb/udi_hid.h
create mode 100644 tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.c
create mode 100644 tmk_core/protocol/arm_atsam/usb/udi_hid_kbd.h
create mode 100644 tmk_core/protocol/arm_atsam/usb/udi_hid_kbd_conf.h
create mode 100644 tmk_core/protocol/arm_atsam/usb/udi_hid_kbd_desc.c
create mode 100644 tmk_core/protocol/arm_atsam/usb/ui.c
create mode 100644 tmk_core/protocol/arm_atsam/usb/ui.h
create mode 100644 tmk_core/protocol/arm_atsam/usb/usb.c
create mode 100644 tmk_core/protocol/arm_atsam/usb/usb.h
create mode 100644 tmk_core/protocol/arm_atsam/usb/usb2422.c
create mode 100644 tmk_core/protocol/arm_atsam/usb/usb2422.h
create mode 100644 tmk_core/protocol/arm_atsam/usb/usb_atmel.h
create mode 100644 tmk_core/protocol/arm_atsam/usb/usb_device_udd.c
create mode 100644 tmk_core/protocol/arm_atsam/usb/usb_main.h
create mode 100644 tmk_core/protocol/arm_atsam/usb/usb_protocol.h
create mode 100644 tmk_core/protocol/arm_atsam/usb/usb_protocol_cdc.h
create mode 100644 tmk_core/protocol/arm_atsam/usb/usb_protocol_hid.h
create mode 100644 tmk_core/protocol/arm_atsam/usb/usb_util.c
create mode 100644 tmk_core/protocol/arm_atsam/usb/usb_util.h
create mode 100644 tmk_core/protocol/arm_atsam/wait_api.h
(limited to 'tmk_core')
diff --git a/tmk_core/arm_atsam.mk b/tmk_core/arm_atsam.mk
new file mode 100644
index 0000000000..ef412d59d6
--- /dev/null
+++ b/tmk_core/arm_atsam.mk
@@ -0,0 +1,56 @@
+# Hey Emacs, this is a -*- makefile -*-
+##############################################################################
+# Compiler settings
+#
+CC = arm-none-eabi-gcc
+OBJCOPY = arm-none-eabi-objcopy
+OBJDUMP = arm-none-eabi-objdump
+SIZE = arm-none-eabi-size
+AR = arm-none-eabi-ar rcs
+NM = arm-none-eabi-nm
+HEX = $(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock -R .signature
+EEP = $(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT)
+BIN =
+
+COMMON_VPATH += $(LIB_PATH)/arm_atsam/packs/atmel/SAMD51_DFP/1.0.70/include
+COMMON_VPATH += $(LIB_PATH)/arm_atsam/packs/arm/cmsis/5.0.1/CMSIS/Include
+
+COMPILEFLAGS += -funsigned-char
+COMPILEFLAGS += -funsigned-bitfields
+COMPILEFLAGS += -ffunction-sections
+COMPILEFLAGS += -fshort-enums
+COMPILEFLAGS += -fno-inline-small-functions
+COMPILEFLAGS += -fno-strict-aliasing
+COMPILEFLAGS += -mfloat-abi=hard
+COMPILEFLAGS += -mfpu=fpv4-sp-d16
+COMPILEFLAGS += -mthumb
+
+#ALLOW_WARNINGS = yes
+
+CFLAGS += $(COMPILEFLAGS)
+
+CPPFLAGS += $(COMPILEFLAGS)
+CPPFLAGS += -fno-exceptions -std=c++11
+
+LDFLAGS +=-Wl,--gc-sections
+LDFLAGS += -Wl,-Map="%OUT%%PROJ_NAME%.map"
+LDFLAGS += -Wl,--start-group
+LDFLAGS += -Wl,--end-group
+LDFLAGS += -Wl,--gc-sections
+LDFLAGS += -T$(LIB_PATH)/arm_atsam/packs/atmel/SAMD51_DFP/1.0.70/gcc/gcc/samd51j18a_flash.ld
+
+OPT_DEFS += -DPROTOCOL_ARM_ATSAM
+
+MCUFLAGS = -mcpu=$(MCU)
+MCUFLAGS += -D__$(ARM_ATSAM)__
+
+# List any extra directories to look for libraries here.
+# Each directory must be seperated by a space.
+# Use forward slashes for directory separators.
+# For a directory that has spaces, enclose it in quotes.
+EXTRALIBDIRS =
+
+# Convert hex to bin.
+bin: $(BUILD_DIR)/$(TARGET).hex
+ $(OBJCOPY) -Iihex -Obinary $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin
+ $(COPY) $(BUILD_DIR)/$(TARGET).bin $(TARGET).bin;
diff --git a/tmk_core/common.mk b/tmk_core/common.mk
index 3e407f1573..fd91d29dce 100644
--- a/tmk_core/common.mk
+++ b/tmk_core/common.mk
@@ -3,6 +3,8 @@ ifeq ($(PLATFORM),AVR)
PLATFORM_COMMON_DIR = $(COMMON_DIR)/avr
else ifeq ($(PLATFORM),CHIBIOS)
PLATFORM_COMMON_DIR = $(COMMON_DIR)/chibios
+else ifeq ($(PLATFORM),ARM_ATSAM)
+ PLATFORM_COMMON_DIR = $(COMMON_DIR)/arm_atsam
else
PLATFORM_COMMON_DIR = $(COMMON_DIR)/test
endif
@@ -35,6 +37,10 @@ ifeq ($(PLATFORM),CHIBIOS)
endif
endif
+ifeq ($(PLATFORM),ARM_ATSAM)
+ TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/eeprom.c
+endif
+
ifeq ($(PLATFORM),TEST)
TMK_COMMON_SRC += $(PLATFORM_COMMON_DIR)/eeprom.c
endif
diff --git a/tmk_core/common/arm_atsam/bootloader.c b/tmk_core/common/arm_atsam/bootloader.c
new file mode 100644
index 0000000000..5155d9ff04
--- /dev/null
+++ b/tmk_core/common/arm_atsam/bootloader.c
@@ -0,0 +1,19 @@
+/* Copyright 2017 Fred Sundvik
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "bootloader.h"
+
+void bootloader_jump(void) {}
diff --git a/tmk_core/common/arm_atsam/eeprom.c b/tmk_core/common/arm_atsam/eeprom.c
new file mode 100644
index 0000000000..61cc039efa
--- /dev/null
+++ b/tmk_core/common/arm_atsam/eeprom.c
@@ -0,0 +1,98 @@
+/* Copyright 2017 Fred Sundvik
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include "eeprom.h"
+
+#define EEPROM_SIZE 32
+
+static uint8_t buffer[EEPROM_SIZE];
+
+uint8_t eeprom_read_byte(const uint8_t *addr) {
+ uintptr_t offset = (uintptr_t)addr;
+ return buffer[offset];
+}
+
+void eeprom_write_byte(uint8_t *addr, uint8_t value) {
+ uintptr_t offset = (uintptr_t)addr;
+ buffer[offset] = value;
+}
+
+uint16_t eeprom_read_word(const uint16_t *addr) {
+ const uint8_t *p = (const uint8_t *)addr;
+ return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8);
+}
+
+uint32_t eeprom_read_dword(const uint32_t *addr) {
+ const uint8_t *p = (const uint8_t *)addr;
+ return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8)
+ | (eeprom_read_byte(p+2) << 16) | (eeprom_read_byte(p+3) << 24);
+}
+
+void eeprom_read_block(void *buf, const void *addr, uint32_t len) {
+ const uint8_t *p = (const uint8_t *)addr;
+ uint8_t *dest = (uint8_t *)buf;
+ while (len--) {
+ *dest++ = eeprom_read_byte(p++);
+ }
+}
+
+void eeprom_write_word(uint16_t *addr, uint16_t value) {
+ uint8_t *p = (uint8_t *)addr;
+ eeprom_write_byte(p++, value);
+ eeprom_write_byte(p, value >> 8);
+}
+
+void eeprom_write_dword(uint32_t *addr, uint32_t value) {
+ uint8_t *p = (uint8_t *)addr;
+ eeprom_write_byte(p++, value);
+ eeprom_write_byte(p++, value >> 8);
+ eeprom_write_byte(p++, value >> 16);
+ eeprom_write_byte(p, value >> 24);
+}
+
+void eeprom_write_block(const void *buf, void *addr, uint32_t len) {
+ uint8_t *p = (uint8_t *)addr;
+ const uint8_t *src = (const uint8_t *)buf;
+ while (len--) {
+ eeprom_write_byte(p++, *src++);
+ }
+}
+
+void eeprom_update_byte(uint8_t *addr, uint8_t value) {
+ eeprom_write_byte(addr, value);
+}
+
+void eeprom_update_word(uint16_t *addr, uint16_t value) {
+ uint8_t *p = (uint8_t *)addr;
+ eeprom_write_byte(p++, value);
+ eeprom_write_byte(p, value >> 8);
+}
+
+void eeprom_update_dword(uint32_t *addr, uint32_t value) {
+ uint8_t *p = (uint8_t *)addr;
+ eeprom_write_byte(p++, value);
+ eeprom_write_byte(p++, value >> 8);
+ eeprom_write_byte(p++, value >> 16);
+ eeprom_write_byte(p, value >> 24);
+}
+
+void eeprom_update_block(const void *buf, void *addr, uint32_t len) {
+ uint8_t *p = (uint8_t *)addr;
+ const uint8_t *src = (const uint8_t *)buf;
+ while (len--) {
+ eeprom_write_byte(p++, *src++);
+ }
+}
diff --git a/tmk_core/common/arm_atsam/printf.h b/tmk_core/common/arm_atsam/printf.h
new file mode 100644
index 0000000000..582c83bf54
--- /dev/null
+++ b/tmk_core/common/arm_atsam/printf.h
@@ -0,0 +1,8 @@
+#ifndef _PRINTF_H_
+#define _PRINTF_H_
+
+#define __xprintf dpf
+int dpf(const char *_Format, ...);
+
+#endif //_PRINTF_H_
+
diff --git a/tmk_core/common/arm_atsam/suspend.c b/tmk_core/common/arm_atsam/suspend.c
new file mode 100644
index 0000000000..01d1930ea5
--- /dev/null
+++ b/tmk_core/common/arm_atsam/suspend.c
@@ -0,0 +1,17 @@
+/* Copyright 2017 Fred Sundvik
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+
diff --git a/tmk_core/common/arm_atsam/timer.c b/tmk_core/common/arm_atsam/timer.c
new file mode 100644
index 0000000000..bcfe5002c3
--- /dev/null
+++ b/tmk_core/common/arm_atsam/timer.c
@@ -0,0 +1,59 @@
+#include "samd51j18a.h"
+#include "timer.h"
+#include "tmk_core/protocol/arm_atsam/clks.h"
+
+void set_time(uint64_t tset)
+{
+ ms_clk = tset;
+}
+
+void timer_init(void)
+{
+ ms_clk = 0;
+}
+
+uint16_t timer_read(void)
+{
+ return (uint16_t)ms_clk;
+}
+
+uint32_t timer_read32(void)
+{
+ return (uint32_t)ms_clk;
+}
+
+uint64_t timer_read64(void)
+{
+ return ms_clk;
+}
+
+uint16_t timer_elapsed(uint16_t tlast)
+{
+ return TIMER_DIFF_16(timer_read(), tlast);
+}
+
+uint32_t timer_elapsed32(uint32_t tlast)
+{
+ return TIMER_DIFF_32(timer_read32(), tlast);
+}
+
+uint32_t timer_elapsed64(uint32_t tlast)
+{
+ uint64_t tnow = timer_read64();
+ return (tnow >= tlast ? tnow - tlast : UINT64_MAX - tlast + tnow);
+}
+
+void timer_clear(void)
+{
+ ms_clk = 0;
+}
+
+void wait_ms(uint64_t msec)
+{
+ CLK_delay_ms(msec);
+}
+
+void wait_us(uint16_t usec)
+{
+ CLK_delay_us(usec);
+}
diff --git a/tmk_core/common/print.h b/tmk_core/common/print.h
index 8836c0fc7c..9cbe67bad6 100644
--- a/tmk_core/common/print.h
+++ b/tmk_core/common/print.h
@@ -99,6 +99,34 @@ void print_set_sendchar(int8_t (*print_sendchar_func)(uint8_t));
# endif /* USER_PRINT / NORMAL PRINT */
+#elif defined(PROTOCOL_ARM_ATSAM) /* PROTOCOL_ARM_ATSAM */
+
+# include "arm_atsam/printf.h"
+
+# ifdef USER_PRINT /* USER_PRINT */
+
+// Remove normal print defines
+# define print(s)
+# define println(s)
+# define xprintf(fmt, ...)
+
+// Create user print defines
+# define uprintf(fmt, ...) __xprintf(fmt, ##__VA_ARGS__)
+# define uprint(s) xprintf(s)
+# define uprintln(s) xprintf(s "\r\n")
+
+# else /* NORMAL PRINT */
+
+// Create user & normal print defines
+# define xprintf(fmt, ...) __xprintf(fmt, ##__VA_ARGS__)
+# define print(s) xprintf(s)
+# define println(s) xprintf(s "\r\n")
+# define uprint(s) print(s)
+# define uprintln(s) println(s)
+# define uprintf(fmt, ...) xprintf(fmt, ...)
+
+# endif /* USER_PRINT / NORMAL PRINT */
+
#elif defined(__arm__) /* __arm__ */
# include "mbed/xprintf.h"
@@ -130,7 +158,7 @@ void print_set_sendchar(int8_t (*print_sendchar_func)(uint8_t));
/* TODO: to select output destinations: UART/USBSerial */
# define print_set_sendchar(func)
-#endif /* __AVR__ / PROTOCOL_CHIBIOS / __arm__ */
+#endif /* __AVR__ / PROTOCOL_CHIBIOS / PROTOCOL_ARM_ATSAM / __arm__ */
// User print disables the normal print messages in the body of QMK/TMK code and
// is meant as a lightweight alternative to NOPRINT. Use it when you only want to do
diff --git a/tmk_core/common/report.h b/tmk_core/common/report.h
index 6c27eb9dc6..167f382751 100644
--- a/tmk_core/common/report.h
+++ b/tmk_core/common/report.h
@@ -84,6 +84,11 @@ along with this program. If not, see .
#define KEYBOARD_REPORT_SIZE NKRO_EPSIZE
#define KEYBOARD_REPORT_KEYS (NKRO_EPSIZE - 2)
#define KEYBOARD_REPORT_BITS (NKRO_EPSIZE - 1)
+ #elif defined(PROTOCOL_ARM_ATSAM)
+ #include "protocol/arm_atsam/usb/udi_device_epsize.h"
+ #define KEYBOARD_REPORT_SIZE NKRO_EPSIZE
+ #define KEYBOARD_REPORT_KEYS (NKRO_EPSIZE - 2)
+ #define KEYBOARD_REPORT_BITS (NKRO_EPSIZE - 1)
#else
#error "NKRO not supported with this protocol"
#endif
diff --git a/tmk_core/protocol/arm_atsam.mk b/tmk_core/protocol/arm_atsam.mk
new file mode 100644
index 0000000000..d535b64cd7
--- /dev/null
+++ b/tmk_core/protocol/arm_atsam.mk
@@ -0,0 +1,26 @@
+ARM_ATSAM_DIR = protocol/arm_atsam
+
+SRC += $(ARM_ATSAM_DIR)/adc.c
+SRC += $(ARM_ATSAM_DIR)/clks.c
+SRC += $(ARM_ATSAM_DIR)/d51_util.c
+SRC += $(ARM_ATSAM_DIR)/i2c_master.c
+SRC += $(ARM_ATSAM_DIR)/led_matrix.c
+SRC += $(ARM_ATSAM_DIR)/main_arm_atsam.c
+SRC += $(ARM_ATSAM_DIR)/spi.c
+SRC += $(ARM_ATSAM_DIR)/startup.c
+
+SRC += $(ARM_ATSAM_DIR)/usb/main_usb.c
+SRC += $(ARM_ATSAM_DIR)/usb/spfssf.c
+SRC += $(ARM_ATSAM_DIR)/usb/udc.c
+SRC += $(ARM_ATSAM_DIR)/usb/udi_cdc.c
+SRC += $(ARM_ATSAM_DIR)/usb/udi_hid.c
+SRC += $(ARM_ATSAM_DIR)/usb/udi_hid_kbd.c
+SRC += $(ARM_ATSAM_DIR)/usb/udi_hid_kbd_desc.c
+SRC += $(ARM_ATSAM_DIR)/usb/ui.c
+SRC += $(ARM_ATSAM_DIR)/usb/usb2422.c
+SRC += $(ARM_ATSAM_DIR)/usb/usb.c
+SRC += $(ARM_ATSAM_DIR)/usb/usb_device_udd.c
+SRC += $(ARM_ATSAM_DIR)/usb/usb_util.c
+
+# Search Path
+VPATH += $(TMK_DIR)/$(ARM_ATSAM_DIR)
diff --git a/tmk_core/protocol/arm_atsam/adc.c b/tmk_core/protocol/arm_atsam/adc.c
new file mode 100644
index 0000000000..ab77f92402
--- /dev/null
+++ b/tmk_core/protocol/arm_atsam/adc.c
@@ -0,0 +1,99 @@
+/*
+Copyright 2018 Massdrop Inc.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+#include "arm_atsam_protocol.h"
+
+uint16_t v_5v;
+uint16_t v_5v_avg;
+uint16_t v_con_1;
+uint16_t v_con_2;
+uint16_t v_con_1_boot;
+uint16_t v_con_2_boot;
+
+void ADC0_clock_init(void)
+{
+ DBGC(DC_ADC0_CLOCK_INIT_BEGIN);
+
+ MCLK->APBDMASK.bit.ADC0_ = 1; //ADC0 Clock Enable
+
+ GCLK->PCHCTRL[ADC0_GCLK_ID].bit.GEN = GEN_OSC0; //Select generator clock
+ GCLK->PCHCTRL[ADC0_GCLK_ID].bit.CHEN = 1; //Enable peripheral clock
+
+ DBGC(DC_ADC0_CLOCK_INIT_COMPLETE);
+}
+
+void ADC0_init(void)
+{
+ DBGC(DC_ADC0_INIT_BEGIN);
+
+ //MCU
+ PORT->Group[1].DIRCLR.reg = 1 << 0; //PB00 as input 5V
+ PORT->Group[1].DIRCLR.reg = 1 << 1; //PB01 as input CON2
+ PORT->Group[1].DIRCLR.reg = 1 << 2; //PB02 as input CON1
+ PORT->Group[1].PMUX[0].bit.PMUXE = 1; //PB00 mux select B ADC 5V
+ PORT->Group[1].PMUX[0].bit.PMUXO = 1; //PB01 mux select B ADC CON2
+ PORT->Group[1].PMUX[1].bit.PMUXE = 1; //PB02 mux select B ADC CON1
+ PORT->Group[1].PINCFG[0].bit.PMUXEN = 1; //PB01 mux ADC Enable 5V
+ PORT->Group[1].PINCFG[1].bit.PMUXEN = 1; //PB01 mux ADC Enable CON2
+ PORT->Group[1].PINCFG[2].bit.PMUXEN = 1; //PB02 mux ADC Enable CON1
+
+ //ADC
+ ADC0->CTRLA.bit.SWRST = 1;
+ while (ADC0->SYNCBUSY.bit.SWRST) { DBGC(DC_ADC0_SWRST_SYNCING_1); }
+ while (ADC0->CTRLA.bit.SWRST) { DBGC(DC_ADC0_SWRST_SYNCING_2); }
+
+ //Clock divide
+ ADC0->CTRLA.bit.PRESCALER = ADC_CTRLA_PRESCALER_DIV2_Val;
+
+ //Averaging
+ ADC0->AVGCTRL.bit.SAMPLENUM = ADC_AVGCTRL_SAMPLENUM_4_Val;
+ while (ADC0->SYNCBUSY.bit.AVGCTRL) { DBGC(DC_ADC0_AVGCTRL_SYNCING_1); }
+ if (ADC0->AVGCTRL.bit.SAMPLENUM == ADC_AVGCTRL_SAMPLENUM_1_Val) ADC0->AVGCTRL.bit.ADJRES = 0;
+ else if (ADC0->AVGCTRL.bit.SAMPLENUM == ADC_AVGCTRL_SAMPLENUM_2_Val) ADC0->AVGCTRL.bit.ADJRES = 1;
+ else if (ADC0->AVGCTRL.bit.SAMPLENUM == ADC_AVGCTRL_SAMPLENUM_4_Val) ADC0->AVGCTRL.bit.ADJRES = 2;
+ else if (ADC0->AVGCTRL.bit.SAMPLENUM == ADC_AVGCTRL_SAMPLENUM_8_Val) ADC0->AVGCTRL.bit.ADJRES = 3;
+ else ADC0->AVGCTRL.bit.ADJRES = 4;
+ while (ADC0->SYNCBUSY.bit.AVGCTRL) { DBGC(DC_ADC0_AVGCTRL_SYNCING_2); }
+
+ //Settling
+ ADC0->SAMPCTRL.bit.SAMPLEN = 45; //Sampling Time Length: 1-63, 1 ADC CLK per
+ while (ADC0->SYNCBUSY.bit.SAMPCTRL) { DBGC(DC_ADC0_SAMPCTRL_SYNCING_1); }
+
+ //Load factory calibration data
+ ADC0->CALIB.bit.BIASCOMP = (ADC0_FUSES_BIASCOMP_ADDR >> ADC0_FUSES_BIASCOMP_Pos) & ADC0_FUSES_BIASCOMP_Msk;
+ ADC0->CALIB.bit.BIASR2R = (ADC0_FUSES_BIASR2R_ADDR >> ADC0_FUSES_BIASR2R_Pos) & ADC0_FUSES_BIASR2R_Msk;
+ ADC0->CALIB.bit.BIASREFBUF = (ADC0_FUSES_BIASREFBUF_ADDR >> ADC0_FUSES_BIASREFBUF_Pos) & ADC0_FUSES_BIASREFBUF_Msk;
+
+ //Enable
+ ADC0->CTRLA.bit.ENABLE = 1;
+ while (ADC0->SYNCBUSY.bit.ENABLE) { DBGC(DC_ADC0_ENABLE_SYNCING_1); }
+
+ DBGC(DC_ADC0_INIT_COMPLETE);
+}
+
+uint16_t adc_get(uint8_t muxpos)
+{
+ ADC0->INPUTCTRL.bit.MUXPOS = muxpos;
+ while (ADC0->SYNCBUSY.bit.INPUTCTRL) {}
+
+ ADC0->SWTRIG.bit.START = 1;
+ while (ADC0->SYNCBUSY.bit.SWTRIG) {}
+ while (!ADC0->INTFLAG.bit.RESRDY) {}
+
+ return ADC0->RESULT.reg;
+}
+
diff --git a/tmk_core/protocol/arm_atsam/adc.h b/tmk_core/protocol/arm_atsam/adc.h
new file mode 100644
index 0000000000..5a90ece3fe
--- /dev/null
+++ b/tmk_core/protocol/arm_atsam/adc.h
@@ -0,0 +1,37 @@
+/*
+Copyright 2018 Massdrop Inc.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+#ifndef _ADC_H_
+#define _ADC_H_
+
+#define ADC_5V_START_LEVEL 2365
+
+#define ADC_5V ADC_INPUTCTRL_MUXPOS_AIN12_Val
+#define ADC_CON1 ADC_INPUTCTRL_MUXPOS_AIN14_Val
+#define ADC_CON2 ADC_INPUTCTRL_MUXPOS_AIN13_Val
+
+extern uint16_t v_5v;
+extern uint16_t v_5v_avg;
+extern uint16_t v_con_1;
+extern uint16_t v_con_2;
+extern uint16_t v_con_1_boot;
+extern uint16_t v_con_2_boot;
+
+void ADC0_clock_init(void);
+void ADC0_init(void);
+
+#endif //_ADC_H_
diff --git a/tmk_core/protocol/arm_atsam/arm_atsam_protocol.h b/tmk_core/protocol/arm_atsam/arm_atsam_protocol.h
new file mode 100644
index 0000000000..be73beccd7
--- /dev/null
+++ b/tmk_core/protocol/arm_atsam/arm_atsam_protocol.h
@@ -0,0 +1,45 @@
+/*
+Copyright 2018 Massdrop Inc.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+#ifndef _ARM_ATSAM_PROTOCOL_H_
+#define _ARM_ATSAM_PROTOCOL_H_
+
+#include "samd51j18a.h"
+#include "md_bootloader.h"
+
+#include "d51_util.h"
+#include "clks.h"
+#include "adc.h"
+#include "i2c_master.h"
+#include "spi.h"
+
+#include "./usb/usb2422.h"
+
+#ifndef MD_BOOTLOADER
+
+#include "main_arm_atsam.h"
+#include "led_matrix.h"
+#include "issi3733_driver.h"
+#include "./usb/compiler.h"
+#include "./usb/udc.h"
+#include "./usb/spfssf.h"
+#include "./usb/udi_cdc.h"
+
+#endif //MD_BOOTLOADER
+
+#endif //_ARM_ATSAM_PROTOCOL_H_
+
diff --git a/tmk_core/protocol/arm_atsam/clks.c b/tmk_core/protocol/arm_atsam/clks.c
new file mode 100644
index 0000000000..8768d0a99e
--- /dev/null
+++ b/tmk_core/protocol/arm_atsam/clks.c
@@ -0,0 +1,439 @@
+/*
+Copyright 2018 Massdrop Inc.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+#include "arm_atsam_protocol.h"
+
+#include
+
+volatile clk_t system_clks;
+volatile uint64_t ms_clk;
+
+volatile uint8_t us_delay_done;
+
+const uint32_t sercom_apbbase[] = {(uint32_t)SERCOM0,(uint32_t)SERCOM1,(uint32_t)SERCOM2,(uint32_t)SERCOM3,(uint32_t)SERCOM4,(uint32_t)SERCOM5};
+const uint8_t sercom_pchan[] = {7, 8, 23, 24, 34, 35};
+
+#define USE_DPLL_IND 0
+#define USE_DPLL_DEF GCLK_SOURCE_DPLL0
+
+void CLK_oscctrl_init(void)
+{
+ Oscctrl *posctrl = OSCCTRL;
+ Gclk *pgclk = GCLK;
+
+ DBGC(DC_CLK_OSC_INIT_BEGIN);
+
+ //default setup on por
+ system_clks.freq_dfll = FREQ_DFLL_DEFAULT;
+ system_clks.freq_gclk[0] = system_clks.freq_dfll;
+
+ //configure and startup 16MHz xosc0
+ posctrl->XOSCCTRL[0].bit.ENABLE = 0;
+ posctrl->XOSCCTRL[0].bit.STARTUP = 0xD;
+ posctrl->XOSCCTRL[0].bit.ENALC = 1;
+ posctrl->XOSCCTRL[0].bit.IMULT = 5;
+ posctrl->XOSCCTRL[0].bit.IPTAT = 3;
+ posctrl->XOSCCTRL[0].bit.ONDEMAND = 0;
+ posctrl->XOSCCTRL[0].bit.XTALEN = 1;
+ posctrl->XOSCCTRL[0].bit.ENABLE = 1;
+ while (posctrl->STATUS.bit.XOSCRDY0 == 0) { DBGC(DC_CLK_OSC_INIT_XOSC0_SYNC); }
+ system_clks.freq_xosc0 = FREQ_XOSC0;
+
+ //configure and startup DPLL
+ posctrl->Dpll[USE_DPLL_IND].DPLLCTRLA.bit.ENABLE = 0;
+ while (posctrl->Dpll[USE_DPLL_IND].DPLLSYNCBUSY.bit.ENABLE) { DBGC(DC_CLK_OSC_INIT_DPLL_SYNC_DISABLE); }
+ posctrl->Dpll[USE_DPLL_IND].DPLLCTRLB.bit.REFCLK = 2; //select XOSC0 (16MHz)
+ posctrl->Dpll[USE_DPLL_IND].DPLLCTRLB.bit.DIV = 7; //16 MHz / (2 * (7 + 1)) = 1 MHz
+ posctrl->Dpll[USE_DPLL_IND].DPLLRATIO.bit.LDR = PLL_RATIO; //1 MHz * (PLL_RATIO(47) + 1) = 48MHz
+ while (posctrl->Dpll[USE_DPLL_IND].DPLLSYNCBUSY.bit.DPLLRATIO) { DBGC(DC_CLK_OSC_INIT_DPLL_SYNC_RATIO); }
+ posctrl->Dpll[USE_DPLL_IND].DPLLCTRLA.bit.ONDEMAND = 0;
+ posctrl->Dpll[USE_DPLL_IND].DPLLCTRLA.bit.ENABLE = 1;
+ while (posctrl->Dpll[USE_DPLL_IND].DPLLSYNCBUSY.bit.ENABLE) { DBGC(DC_CLK_OSC_INIT_DPLL_SYNC_ENABLE); }
+ while (posctrl->Dpll[USE_DPLL_IND].DPLLSTATUS.bit.LOCK == 0) { DBGC(DC_CLK_OSC_INIT_DPLL_WAIT_LOCK); }
+ while (posctrl->Dpll[USE_DPLL_IND].DPLLSTATUS.bit.CLKRDY == 0) { DBGC(DC_CLK_OSC_INIT_DPLL_WAIT_CLKRDY); }
+ system_clks.freq_dpll[0] = (system_clks.freq_xosc0 / 2 / (posctrl->Dpll[USE_DPLL_IND].DPLLCTRLB.bit.DIV + 1)) * (posctrl->Dpll[USE_DPLL_IND].DPLLRATIO.bit.LDR + 1);
+
+ //change gclk0 to DPLL
+ pgclk->GENCTRL[GEN_DPLL0].bit.SRC = USE_DPLL_DEF;
+ while (pgclk->SYNCBUSY.bit.GENCTRL0) { DBGC(DC_CLK_OSC_INIT_GCLK_SYNC_GENCTRL0); }
+
+ system_clks.freq_gclk[0] = system_clks.freq_dpll[0];
+
+ DBGC(DC_CLK_OSC_INIT_COMPLETE);
+}
+
+//configure for 1MHz (1 usec timebase)
+//call CLK_set_gclk_freq(GEN_TC45, FREQ_TC45_DEFAULT);
+uint32_t CLK_set_gclk_freq(uint8_t gclkn, uint32_t freq)
+{
+ Gclk *pgclk = GCLK;
+
+ DBGC(DC_CLK_SET_GCLK_FREQ_BEGIN);
+
+ while (pgclk->SYNCBUSY.vec.GENCTRL) { DBGC(DC_CLK_SET_GCLK_FREQ_SYNC_1); }
+ pgclk->GENCTRL[gclkn].bit.SRC = USE_DPLL_DEF;
+ while (pgclk->SYNCBUSY.vec.GENCTRL) { DBGC(DC_CLK_SET_GCLK_FREQ_SYNC_2); }
+ pgclk->GENCTRL[gclkn].bit.DIV = (uint8_t)(system_clks.freq_dpll[0] / freq);
+ while (pgclk->SYNCBUSY.vec.GENCTRL) { DBGC(DC_CLK_SET_GCLK_FREQ_SYNC_3); }
+ pgclk->GENCTRL[gclkn].bit.DIVSEL = 0;
+ while (pgclk->SYNCBUSY.vec.GENCTRL) { DBGC(DC_CLK_SET_GCLK_FREQ_SYNC_4); }
+ pgclk->GENCTRL[gclkn].bit.GENEN = 1;
+ while (pgclk->SYNCBUSY.vec.GENCTRL) { DBGC(DC_CLK_SET_GCLK_FREQ_SYNC_5); }
+ system_clks.freq_gclk[gclkn] = system_clks.freq_dpll[0] / pgclk->GENCTRL[gclkn].bit.DIV;
+
+ DBGC(DC_CLK_SET_GCLK_FREQ_COMPLETE);
+
+ return system_clks.freq_gclk[gclkn];
+}
+
+void CLK_init_osc(void)
+{
+ uint8_t gclkn = GEN_OSC0;
+ Gclk *pgclk = GCLK;
+
+ DBGC(DC_CLK_INIT_OSC_BEGIN);
+
+ while (pgclk->SYNCBUSY.vec.GENCTRL) { DBGC(DC_CLK_INIT_OSC_SYNC_1); }
+ pgclk->GENCTRL[gclkn].bit.SRC = GCLK_SOURCE_XOSC0;
+ while (pgclk->SYNCBUSY.vec.GENCTRL) { DBGC(DC_CLK_INIT_OSC_SYNC_2); }
+ pgclk->GENCTRL[gclkn].bit.DIV = 1;
+ while (pgclk->SYNCBUSY.vec.GENCTRL) { DBGC(DC_CLK_INIT_OSC_SYNC_3); }
+ pgclk->GENCTRL[gclkn].bit.DIVSEL = 0;
+ while (pgclk->SYNCBUSY.vec.GENCTRL) { DBGC(DC_CLK_INIT_OSC_SYNC_4); }
+ pgclk->GENCTRL[gclkn].bit.GENEN = 1;
+ while (pgclk->SYNCBUSY.vec.GENCTRL) { DBGC(DC_CLK_INIT_OSC_SYNC_5); }
+ system_clks.freq_gclk[gclkn] = system_clks.freq_xosc0;
+
+ DBGC(DC_CLK_INIT_OSC_COMPLETE);
+}
+
+void CLK_reset_time(void)
+{
+ Tc *ptc4 = TC4;
+ Tc *ptc0 = TC0;
+
+ ms_clk = 0;
+
+ DBGC(DC_CLK_RESET_TIME_BEGIN);
+
+ //stop counters
+ ptc4->COUNT16.CTRLA.bit.ENABLE = 0;
+ while (ptc4->COUNT16.SYNCBUSY.bit.ENABLE) {}
+ ptc0->COUNT32.CTRLA.bit.ENABLE = 0;
+ while (ptc0->COUNT32.SYNCBUSY.bit.ENABLE) {}
+ //zero counters
+ ptc4->COUNT16.COUNT.reg = 0;
+ while (ptc4->COUNT16.SYNCBUSY.bit.COUNT) {}
+ ptc0->COUNT32.COUNT.reg = 0;
+ while (ptc0->COUNT32.SYNCBUSY.bit.COUNT) {}
+ //start counters
+ ptc0->COUNT32.CTRLA.bit.ENABLE = 1;
+ while (ptc0->COUNT32.SYNCBUSY.bit.ENABLE) {}
+ ptc4->COUNT16.CTRLA.bit.ENABLE = 1;
+ while (ptc4->COUNT16.SYNCBUSY.bit.ENABLE) {}
+
+ DBGC(DC_CLK_RESET_TIME_COMPLETE);
+}
+
+void TC4_Handler()
+{
+ if (TC4->COUNT16.INTFLAG.bit.MC0)
+ {
+ TC4->COUNT16.INTFLAG.reg = TC_INTENCLR_MC0;
+ ms_clk++;
+ }
+}
+
+void TC5_Handler()
+{
+ if (TC5->COUNT16.INTFLAG.bit.MC0)
+ {
+ TC5->COUNT16.INTFLAG.reg = TC_INTENCLR_MC0;
+ us_delay_done = 1;
+ TC5->COUNT16.CTRLA.bit.ENABLE = 0;
+ while (TC5->COUNT16.SYNCBUSY.bit.ENABLE) {}
+ }
+}
+
+uint32_t CLK_enable_timebase(void)
+{
+ Gclk *pgclk = GCLK;
+ Mclk *pmclk = MCLK;
+ Tc *ptc4 = TC4;
+ Tc *ptc5 = TC5;
+ Tc *ptc0 = TC0;
+ Evsys *pevsys = EVSYS;
+
+ DBGC(DC_CLK_ENABLE_TIMEBASE_BEGIN);
+
+ //gclk2 highspeed time base
+ CLK_set_gclk_freq(GEN_TC45, FREQ_TC45_DEFAULT);
+ CLK_init_osc();
+
+ //unmask TC4, sourcegclk2 to TC4
+ pmclk->APBCMASK.bit.TC4_ = 1;
+ pgclk->PCHCTRL[TC4_GCLK_ID].bit.GEN = GEN_TC45;
+ pgclk->PCHCTRL[TC4_GCLK_ID].bit.CHEN = 1;
+
+ //unmask TC5 sourcegclk2 to TC5
+ pmclk->APBCMASK.bit.TC5_ = 1;
+ pgclk->PCHCTRL[TC5_GCLK_ID].bit.GEN = GEN_TC45;
+ pgclk->PCHCTRL[TC5_GCLK_ID].bit.CHEN = 1;
+
+ //configure TC4
+ DBGC(DC_CLK_ENABLE_TIMEBASE_TC4_BEGIN);
+ ptc4->COUNT16.CTRLA.bit.ENABLE = 0;
+ while (ptc4->COUNT16.SYNCBUSY.bit.ENABLE) { DBGC(DC_CLK_ENABLE_TIMEBASE_TC4_SYNC_DISABLE); }
+ ptc4->COUNT16.CTRLA.bit.SWRST = 1;
+ while (ptc4->COUNT16.SYNCBUSY.bit.SWRST) { DBGC(DC_CLK_ENABLE_TIMEBASE_TC4_SYNC_SWRST_1); }
+ while (ptc4->COUNT16.CTRLA.bit.SWRST) { DBGC(DC_CLK_ENABLE_TIMEBASE_TC4_SYNC_SWRST_2); }
+
+ //CTRLA defaults
+ //CTRLB as default, counting up
+ ptc4->COUNT16.CTRLBCLR.reg = 5;
+ while (ptc4->COUNT16.SYNCBUSY.bit.CTRLB) { DBGC(DC_CLK_ENABLE_TIMEBASE_TC4_SYNC_CLTRB); }
+ ptc4->COUNT16.CC[0].reg = 999;
+ while (ptc4->COUNT16.SYNCBUSY.bit.CC0) { DBGC(DC_CLK_ENABLE_TIMEBASE_TC4_SYNC_CC0); }
+ //ptc4->COUNT16.DBGCTRL.bit.DBGRUN = 1;
+
+ //wave mode
+ ptc4->COUNT16.WAVE.bit.WAVEGEN = 1; //MFRQ match frequency mode, toggle each CC match
+ //generate event for next stage
+ ptc4->COUNT16.EVCTRL.bit.MCEO0 = 1;
+
+ NVIC_EnableIRQ(TC4_IRQn);
+ ptc4->COUNT16.INTENSET.bit.MC0 = 1;
+
+ DBGC(DC_CLK_ENABLE_TIMEBASE_TC4_COMPLETE);
+
+ //configure TC5
+ DBGC(DC_CLK_ENABLE_TIMEBASE_TC5_BEGIN);
+ ptc5->COUNT16.CTRLA.bit.ENABLE = 0;
+ while (ptc5->COUNT16.SYNCBUSY.bit.ENABLE) { DBGC(DC_CLK_ENABLE_TIMEBASE_TC5_SYNC_DISABLE); }
+ ptc5->COUNT16.CTRLA.bit.SWRST = 1;
+ while (ptc5->COUNT16.SYNCBUSY.bit.SWRST) { DBGC(DC_CLK_ENABLE_TIMEBASE_TC5_SYNC_SWRST_1); }
+ while (ptc5->COUNT16.CTRLA.bit.SWRST) { DBGC(DC_CLK_ENABLE_TIMEBASE_TC5_SYNC_SWRST_2); }
+
+ //CTRLA defaults
+ //CTRLB as default, counting up
+ ptc5->COUNT16.CTRLBCLR.reg = 5;
+ while (ptc5->COUNT16.SYNCBUSY.bit.CTRLB) { DBGC(DC_CLK_ENABLE_TIMEBASE_TC5_SYNC_CLTRB); }
+ //ptc5->COUNT16.DBGCTRL.bit.DBGRUN = 1;
+
+ //wave mode
+ ptc5->COUNT16.WAVE.bit.WAVEGEN = 1; //MFRQ match frequency mode, toggle each CC match
+ //generate event for next stage
+ ptc5->COUNT16.EVCTRL.bit.MCEO0 = 1;
+
+ NVIC_EnableIRQ(TC5_IRQn);
+ ptc5->COUNT16.INTENSET.bit.MC0 = 1;
+
+ DBGC(DC_CLK_ENABLE_TIMEBASE_TC5_COMPLETE);
+
+ //unmask TC0,1, sourcegclk2 to TC0,1
+ pmclk->APBAMASK.bit.TC0_ = 1;
+ pgclk->PCHCTRL[TC0_GCLK_ID].bit.GEN = GEN_TC45;
+ pgclk->PCHCTRL[TC0_GCLK_ID].bit.CHEN = 1;
+
+ pmclk->APBAMASK.bit.TC1_ = 1;
+ pgclk->PCHCTRL[TC1_GCLK_ID].bit.GEN = GEN_TC45;
+ pgclk->PCHCTRL[TC1_GCLK_ID].bit.CHEN = 1;
+
+ //configure TC0
+ DBGC(DC_CLK_ENABLE_TIMEBASE_TC0_BEGIN);
+ ptc0->COUNT32.CTRLA.bit.ENABLE = 0;
+ while (ptc0->COUNT32.SYNCBUSY.bit.ENABLE) { DBGC(DC_CLK_ENABLE_TIMEBASE_TC0_SYNC_DISABLE); }
+ ptc0->COUNT32.CTRLA.bit.SWRST = 1;
+ while (ptc0->COUNT32.SYNCBUSY.bit.SWRST) { DBGC(DC_CLK_ENABLE_TIMEBASE_TC0_SYNC_SWRST_1); }
+ while (ptc0->COUNT32.CTRLA.bit.SWRST) { DBGC(DC_CLK_ENABLE_TIMEBASE_TC0_SYNC_SWRST_2); }
+ //CTRLA as default
+ ptc0->COUNT32.CTRLA.bit.MODE = 2; //32 bit mode
+ ptc0->COUNT32.EVCTRL.bit.TCEI = 1; //enable incoming events
+ ptc0->COUNT32.EVCTRL.bit.EVACT = 2 ; //count events
+
+ DBGC(DC_CLK_ENABLE_TIMEBASE_TC0_COMPLETE);
+
+ DBGC(DC_CLK_ENABLE_TIMEBASE_EVSYS_BEGIN);
+
+ //configure event system
+ pmclk->APBBMASK.bit.EVSYS_ = 1;
+ pgclk->PCHCTRL[EVSYS_GCLK_ID_0].bit.GEN = GEN_TC45;
+ pgclk->PCHCTRL[EVSYS_GCLK_ID_0].bit.CHEN = 1;
+ pevsys->USER[44].reg = EVSYS_ID_USER_PORT_EV_0; //TC0 will get event channel 0
+ pevsys->Channel[0].CHANNEL.bit.EDGSEL = EVSYS_CHANNEL_EDGSEL_RISING_EDGE_Val; //Rising edge
+ pevsys->Channel[0].CHANNEL.bit.PATH = EVSYS_CHANNEL_PATH_SYNCHRONOUS_Val; //Synchronous
+ pevsys->Channel[0].CHANNEL.bit.EVGEN = EVSYS_ID_GEN_TC4_MCX_0; //TC4 MC0
+
+ DBGC(DC_CLK_ENABLE_TIMEBASE_EVSYS_COMPLETE);
+
+ CLK_reset_time();
+
+ ADC0_clock_init();
+
+ DBGC(DC_CLK_ENABLE_TIMEBASE_COMPLETE);
+
+ return 0;
+}
+
+uint32_t CLK_get_ms(void)
+{
+ return ms_clk;
+}
+
+void CLK_delay_us(uint16_t usec)
+{
+ us_delay_done = 0;
+
+ if (TC5->COUNT16.CTRLA.bit.ENABLE)
+ {
+ TC5->COUNT16.CTRLA.bit.ENABLE = 0;
+ while (TC5->COUNT16.SYNCBUSY.bit.ENABLE) {}
+ }
+
+ if (usec < 10) usec = 0;
+ else usec -= 10;
+
+ TC5->COUNT16.CC[0].reg = usec;
+ while (TC5->COUNT16.SYNCBUSY.bit.CC0) {}
+
+ TC5->COUNT16.CTRLA.bit.ENABLE = 1;
+ while (TC5->COUNT16.SYNCBUSY.bit.ENABLE) {}
+
+ while (!us_delay_done) {}
+}
+
+void CLK_delay_ms(uint64_t msec)
+{
+ msec += CLK_get_ms();
+ while (msec > CLK_get_ms()) {}
+}
+
+void clk_enable_sercom_apbmask(int sercomn)
+{
+ Mclk *pmclk = MCLK;
+ switch (sercomn)
+ {
+ case 0:
+ pmclk->APBAMASK.bit.SERCOM0_ = 1;
+ break;
+ case 1:
+ pmclk->APBAMASK.bit.SERCOM1_ = 1;
+ break;
+ case 2:
+ pmclk->APBBMASK.bit.SERCOM2_ = 1;
+ break;
+ case 3:
+ pmclk->APBBMASK.bit.SERCOM3_ = 1;
+ break;
+ default:
+ break;
+ }
+}
+
+//call CLK_oscctrl_init first
+//call CLK_set_spi_freq(CHAN_SERCOM_SPI, FREQ_SPI_DEFAULT);
+uint32_t CLK_set_spi_freq(uint8_t sercomn, uint32_t freq)
+{
+ DBGC(DC_CLK_SET_SPI_FREQ_BEGIN);
+
+ Gclk *pgclk = GCLK;
+ Sercom *psercom = (Sercom *)sercom_apbbase[sercomn];
+ clk_enable_sercom_apbmask(sercomn);
+
+ //all gclk0 for now
+ pgclk->PCHCTRL[sercom_pchan[sercomn]].bit.GEN = 0;
+ pgclk->PCHCTRL[sercom_pchan[sercomn]].bit.CHEN = 1;
+
+ psercom->I2CM.CTRLA.bit.SWRST = 1;
+ while (psercom->I2CM.SYNCBUSY.bit.SWRST) {}
+ while (psercom->I2CM.CTRLA.bit.SWRST) {}
+
+ psercom->SPI.BAUD.reg = (uint8_t) (system_clks.freq_gclk[0]/2/freq-1);
+ system_clks.freq_spi = system_clks.freq_gclk[0]/2/(psercom->SPI.BAUD.reg+1);
+ system_clks.freq_sercom[sercomn] = system_clks.freq_spi;
+
+ DBGC(DC_CLK_SET_SPI_FREQ_COMPLETE);
+
+ return system_clks.freq_spi;
+}
+
+//call CLK_oscctrl_init first
+//call CLK_set_i2c0_freq(CHAN_SERCOM_I2C0, FREQ_I2C0_DEFAULT);
+uint32_t CLK_set_i2c0_freq(uint8_t sercomn, uint32_t freq)
+{
+ DBGC(DC_CLK_SET_I2C0_FREQ_BEGIN);
+
+ Gclk *pgclk = GCLK;
+ Sercom *psercom = (Sercom *)sercom_apbbase[sercomn];
+ clk_enable_sercom_apbmask(sercomn);
+
+ //all gclk0 for now
+ pgclk->PCHCTRL[sercom_pchan[sercomn]].bit.GEN = 0;
+ pgclk->PCHCTRL[sercom_pchan[sercomn]].bit.CHEN = 1;
+
+ psercom->I2CM.CTRLA.bit.SWRST = 1;
+ while (psercom->I2CM.SYNCBUSY.bit.SWRST) {}
+ while (psercom->I2CM.CTRLA.bit.SWRST) {}
+
+ psercom->I2CM.BAUD.bit.BAUD = (uint8_t) (system_clks.freq_gclk[0]/2/freq-1);
+ system_clks.freq_i2c0 = system_clks.freq_gclk[0]/2/(psercom->I2CM.BAUD.bit.BAUD+1);
+ system_clks.freq_sercom[sercomn] = system_clks.freq_i2c0;
+
+ DBGC(DC_CLK_SET_I2C0_FREQ_COMPLETE);
+
+ return system_clks.freq_i2c0;
+}
+
+//call CLK_oscctrl_init first
+//call CLK_set_i2c1_freq(CHAN_SERCOM_I2C1, FREQ_I2C1_DEFAULT);
+uint32_t CLK_set_i2c1_freq(uint8_t sercomn, uint32_t freq)
+{
+ DBGC(DC_CLK_SET_I2C1_FREQ_BEGIN);
+
+ Gclk *pgclk = GCLK;
+ Sercom *psercom = (Sercom *)sercom_apbbase[sercomn];
+ clk_enable_sercom_apbmask(sercomn);
+
+ //all gclk0 for now
+ pgclk->PCHCTRL[sercom_pchan[sercomn]].bit.GEN = 0;
+ pgclk->PCHCTRL[sercom_pchan[sercomn]].bit.CHEN = 1;
+
+ psercom->I2CM.CTRLA.bit.SWRST = 1;
+ while (psercom->I2CM.SYNCBUSY.bit.SWRST) {}
+ while (psercom->I2CM.CTRLA.bit.SWRST) {}
+
+ psercom->I2CM.BAUD.bit.BAUD = (uint8_t) (system_clks.freq_gclk[0]/2/freq-10);
+ system_clks.freq_i2c1 = system_clks.freq_gclk[0]/2/(psercom->I2CM.BAUD.bit.BAUD+10);
+ system_clks.freq_sercom[sercomn] = system_clks.freq_i2c1;
+
+ DBGC(DC_CLK_SET_I2C1_FREQ_COMPLETE);
+
+ return system_clks.freq_i2c1;
+}
+
+void CLK_init(void)
+{
+ DBGC(DC_CLK_INIT_BEGIN);
+
+ memset((void *)&system_clks,0,sizeof(system_clks));
+
+ CLK_oscctrl_init();
+ CLK_enable_timebase();
+
+ DBGC(DC_CLK_INIT_COMPLETE);
+}
+
diff --git a/tmk_core/protocol/arm_atsam/clks.h b/tmk_core/protocol/arm_atsam/clks.h
new file mode 100644
index 0000000000..96819bfdd0
--- /dev/null
+++ b/tmk_core/protocol/arm_atsam/clks.h
@@ -0,0 +1,90 @@
+/*
+Copyright 2018 Massdrop Inc.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+#ifndef _CLKS_H_
+#define _CLKS_H_
+
+#ifndef MD_BOOTLOADER
+
+//From keyboard
+#include "config_led.h"
+#include "config.h"
+
+#endif //MD_BOOTLOADER
+
+#define PLL_RATIO 47 //mcu frequency ((X+1)MHz)
+#define FREQ_DFLL_DEFAULT 48000000 //DFLL frequency / usb clock
+#define FREQ_SPI_DEFAULT 1000000 //spi to 595 shift regs
+#define FREQ_I2C0_DEFAULT 100000 //i2c to hub
+#define FREQ_I2C1_DEFAULT I2C_HZ //i2c to LED drivers
+#define FREQ_TC45_DEFAULT 1000000 //1 usec resolution
+
+//I2C1 Set ~Result PWM Time (2x Drivers)
+// 1000000 1090000
+// 900000 1000000 3.82ms
+// 800000 860000
+// 700000 750000
+// 600000 630000
+// 580000 615000 6.08ms
+// 500000 522000
+
+#define FREQ_XOSC0 16000000
+
+#define CHAN_SERCOM_SPI 2 //shift regs
+#define CHAN_SERCOM_I2C0 0 //hub
+#define CHAN_SERCOM_I2C1 1 //led drivers
+#define CHAN_SERCOM_UART 3 //debug util
+
+//Generator clock channels
+#define GEN_DPLL0 0
+#define GEN_OSC0 1
+#define GEN_TC45 2
+
+#define SERCOM_COUNT 5
+#define GCLK_COUNT 12
+
+typedef struct clk_s {
+ uint32_t freq_dfll;
+ uint32_t freq_dpll[2];
+ uint32_t freq_sercom[SERCOM_COUNT];
+ uint32_t freq_gclk[GCLK_COUNT];
+ uint32_t freq_xosc0;
+ uint32_t freq_spi;
+ uint32_t freq_i2c0;
+ uint32_t freq_i2c1;
+ uint32_t freq_uart;
+ uint32_t freq_adc0;
+} clk_t;
+
+extern volatile clk_t system_clks;
+extern volatile uint64_t ms_clk;
+
+void CLK_oscctrl_init(void);
+void CLK_reset_time(void);
+uint32_t CLK_set_gclk_freq(uint8_t gclkn, uint32_t freq);
+uint32_t CLK_enable_timebase(void);
+uint32_t CLK_get_ms(void);
+uint64_t CLK_get_us(void);
+void CLK_delay_us(uint16_t usec);
+void CLK_delay_ms(uint64_t msec);
+
+uint32_t CLK_set_spi_freq(uint8_t sercomn, uint32_t freq);
+uint32_t CLK_set_i2c0_freq(uint8_t sercomn, uint32_t freq);
+uint32_t CLK_set_i2c1_freq(uint8_t sercomn, uint32_t freq);
+void CLK_init(void);
+
+#endif // _CLKS_H_
diff --git a/tmk_core/protocol/arm_atsam/d51_util.c b/tmk_core/protocol/arm_atsam/d51_util.c
new file mode 100644
index 0000000000..91b58757cf
--- /dev/null
+++ b/tmk_core/protocol/arm_atsam/d51_util.c
@@ -0,0 +1,165 @@
+#include "d51_util.h"
+
+//Display unsigned 32-bit number through m15
+//Read as follows: 1230 = || ||| |||| | (note always ending toggle)
+void m15_print(uint32_t x)
+{
+ int8_t t;
+ uint32_t n;
+ uint32_t p, p2;
+
+ if (x < 10) t = 0;
+ else if (x < 100) t = 1;
+ else if (x < 1000) t = 2;
+ else if (x < 10000) t = 3;
+ else if (x < 100000) t = 4;
+ else if (x < 1000000) t = 5;
+ else if (x < 10000000) t = 6;
+ else if (x < 100000000) t = 7;
+ else if (x < 1000000000) t = 8;
+ else t = 9;
+
+ while (t >= 0)
+ {
+ p2 = t;
+ p = 1;
+ while (p2--) p *= 10;
+ n = x / p;
+ x -= n * p;
+ while (n > 0)
+ {
+ m15_on;
+ n--;
+ m15_off;
+ }
+ //Will always end with an extra toggle
+ m15_on;
+ t--;
+ m15_off;
+ }
+}
+
+//Display unsigned 32-bit number through debug led
+//Read as follows: 1230 = [*] [* *] [* * *] [**] (note zero is fast double flash)
+#define DLED_ONTIME 600000
+#define DLED_PAUSE 1000000
+volatile uint32_t w;
+void dled_print(uint32_t x, uint8_t long_pause)
+{
+ int8_t t;
+ uint32_t n;
+ uint32_t p, p2;
+
+ if (x < 10) t = 0;
+ else if (x < 100) t = 1;
+ else if (x < 1000) t = 2;
+ else if (x < 10000) t = 3;
+ else if (x < 100000) t = 4;
+ else if (x < 1000000) t = 5;
+ else if (x < 10000000) t = 6;
+ else if (x < 100000000) t = 7;
+ else if (x < 1000000000) t = 8;
+ else t = 9;
+
+ while (t >= 0)
+ {
+ p2 = t;
+ p = 1;
+ while (p2--) p *= 10;
+ n = x / p;
+ x -= n * p;
+ if (!n)
+ {
+ led_on;
+ for (w = DLED_ONTIME / 4; w; w--);
+ led_off;
+ for (w = DLED_ONTIME / 4; w; w--);
+ led_on;
+ for (w = DLED_ONTIME / 4; w; w--);
+ led_off;
+ for (w = DLED_ONTIME / 4; w; w--);
+ n--;
+ }
+ else
+ {
+ while (n > 0)
+ {
+ led_on;
+ for (w = DLED_ONTIME; w; w--);
+ led_off;
+ for (w = DLED_ONTIME / 2; w; w--);
+ n--;
+ }
+ }
+
+ for (w = DLED_PAUSE; w; w--);
+ t--;
+ }
+
+ if (long_pause)
+ {
+ for (w = DLED_PAUSE * 4; w; w--);
+ }
+}
+
+#ifdef DEBUG_BOOT_TRACING
+
+volatile uint32_t debug_code;
+
+void EIC_15_Handler()
+{
+ //This is only for non-functional keyboard troubleshooting and should be disabled after boot
+ //Intention is to lock up the keyboard here with repeating debug led code
+ while (1)
+ {
+ dled_print(debug_code, 1);
+ }
+}
+
+void debug_code_init(void)
+{
+ DBGC(DC_UNSET);
+
+ //Configure Ports for EIC on PB31
+ PORT->Group[1].DIRCLR.reg = 1 << 31; //Input
+ PORT->Group[1].OUTSET.reg = 1 << 31; //High
+ PORT->Group[1].PINCFG[31].bit.INEN = 1; //Input Enable
+ PORT->Group[1].PINCFG[31].bit.PULLEN = 1; //Pull Enable
+ PORT->Group[1].PINCFG[31].bit.PMUXEN = 1; //Mux Enable
+ PORT->Group[1].PMUX[15].bit.PMUXO = 0; //Mux A
+
+ //Enable CLK_EIC_APB
+ MCLK->APBAMASK.bit.EIC_ = 1;
+
+ //Configure EIC
+ EIC->CTRLA.bit.SWRST = 1;
+ while (EIC->SYNCBUSY.bit.SWRST) {}
+ EIC->ASYNCH.reg = 1 << 15;
+ EIC->INTENSET.reg = 1 << 15;
+ EIC->CONFIG[1].bit.SENSE7 = 2;
+ EIC->CTRLA.bit.ENABLE = 1;
+ while (EIC->SYNCBUSY.bit.ENABLE) {}
+
+ //Enable EIC IRQ
+ NVIC_EnableIRQ(EIC_15_IRQn);
+}
+
+void debug_code_disable(void)
+{
+ //Disable EIC IRQ
+ NVIC_DisableIRQ(EIC_15_IRQn);
+
+ //Disable EIC
+ EIC->CTRLA.bit.ENABLE = 0;
+ while (EIC->SYNCBUSY.bit.ENABLE) {}
+
+ //Disable CLK_EIC_APB
+ MCLK->APBAMASK.bit.EIC_ = 0;
+}
+
+#else
+
+void debug_code_init(void) {}
+void debug_code_disable(void) {}
+
+#endif //DEBUG_BOOT_TRACING
diff --git a/tmk_core/protocol/arm_atsam/d51_util.h b/tmk_core/protocol/arm_atsam/d51_util.h
new file mode 100644
index 0000000000..465889c7cb
--- /dev/null
+++ b/tmk_core/protocol/arm_atsam/d51_util.h
@@ -0,0 +1,185 @@
+/*
+Copyright 2018 Massdrop Inc.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+#ifndef _D51_UTIL_H_
+#define _D51_UTIL_H_
+
+#include "samd51j18a.h"
+
+//TODO: PS: Should bring these ports out to keyboard level configuration
+
+//Debug LED PA27
+#define led_ena REG_PORT_DIRSET0 = 0x08000000 //PA27 Output
+#define led_on REG_PORT_OUTSET0 = 0x08000000 //PA27 High
+#define led_off REG_PORT_OUTCLR0 = 0x08000000 //PA27 Low
+
+//Debug Port PB30
+#define m15_ena REG_PORT_DIRSET1 = 0x40000000 //PB30 Output
+#define m15_on REG_PORT_OUTSET1 = 0x40000000 //PB30 High
+#define m15_off REG_PORT_OUTCLR1 = 0x40000000 //PB30 Low
+
+#define m15_loop(M15X) {uint8_t M15L=M15X; while(M15L--){m15_on;CLK_delay_us(1);m15_off;}}
+
+void m15_print(uint32_t x);
+void dled_print(uint32_t x, uint8_t long_pause);
+
+void debug_code_init(void);
+void debug_code_disable(void);
+
+#ifdef DEBUG_BOOT_TRACING
+
+#define DBGC(n) debug_code = n
+
+extern volatile uint32_t debug_code;
+
+enum debug_code_list {
+ DC_UNSET = 0,
+ DC_CLK_INIT_BEGIN,
+ DC_CLK_INIT_COMPLETE,
+ DC_CLK_SET_I2C1_FREQ_BEGIN,
+ DC_CLK_SET_I2C1_FREQ_COMPLETE,
+ DC_CLK_SET_I2C0_FREQ_BEGIN,
+ DC_CLK_SET_I2C0_FREQ_COMPLETE,
+ DC_CLK_SET_SPI_FREQ_BEGIN,
+ DC_CLK_SET_SPI_FREQ_COMPLETE,
+ DC_CLK_ENABLE_TIMEBASE_BEGIN,
+ DC_CLK_ENABLE_TIMEBASE_SYNC_ENABLE,
+ DC_CLK_ENABLE_TIMEBASE_SYNC_SWRST_1,
+ DC_CLK_ENABLE_TIMEBASE_SYNC_SWRST_2,
+ DC_CLK_ENABLE_TIMEBASE_TC4_BEGIN,
+ DC_CLK_ENABLE_TIMEBASE_TC4_SYNC_DISABLE,
+ DC_CLK_ENABLE_TIMEBASE_TC4_SYNC_SWRST_1,
+ DC_CLK_ENABLE_TIMEBASE_TC4_SYNC_SWRST_2,
+ DC_CLK_ENABLE_TIMEBASE_TC4_SYNC_CLTRB,
+ DC_CLK_ENABLE_TIMEBASE_TC4_SYNC_CC0,
+ DC_CLK_ENABLE_TIMEBASE_TC4_COMPLETE,
+ DC_CLK_ENABLE_TIMEBASE_TC5_BEGIN,
+ DC_CLK_ENABLE_TIMEBASE_TC5_SYNC_DISABLE,
+ DC_CLK_ENABLE_TIMEBASE_TC5_SYNC_SWRST_1,
+ DC_CLK_ENABLE_TIMEBASE_TC5_SYNC_SWRST_2,
+ DC_CLK_ENABLE_TIMEBASE_TC5_SYNC_CLTRB,
+ DC_CLK_ENABLE_TIMEBASE_TC5_COMPLETE,
+ DC_CLK_ENABLE_TIMEBASE_TC0_BEGIN,
+ DC_CLK_ENABLE_TIMEBASE_TC0_SYNC_DISABLE,
+ DC_CLK_ENABLE_TIMEBASE_TC0_SYNC_SWRST_1,
+ DC_CLK_ENABLE_TIMEBASE_TC0_SYNC_SWRST_2,
+ DC_CLK_ENABLE_TIMEBASE_TC0_COMPLETE,
+ DC_CLK_ENABLE_TIMEBASE_EVSYS_BEGIN,
+ DC_CLK_ENABLE_TIMEBASE_EVSYS_COMPLETE,
+ DC_CLK_ENABLE_TIMEBASE_COMPLETE,
+ DC_CLK_SET_GCLK_FREQ_BEGIN,
+ DC_CLK_SET_GCLK_FREQ_SYNC_1,
+ DC_CLK_SET_GCLK_FREQ_SYNC_2,
+ DC_CLK_SET_GCLK_FREQ_SYNC_3,
+ DC_CLK_SET_GCLK_FREQ_SYNC_4,
+ DC_CLK_SET_GCLK_FREQ_SYNC_5,
+ DC_CLK_SET_GCLK_FREQ_COMPLETE,
+ DC_CLK_INIT_OSC_BEGIN,
+ DC_CLK_INIT_OSC_SYNC_1,
+ DC_CLK_INIT_OSC_SYNC_2,
+ DC_CLK_INIT_OSC_SYNC_3,
+ DC_CLK_INIT_OSC_SYNC_4,
+ DC_CLK_INIT_OSC_SYNC_5,
+ DC_CLK_INIT_OSC_COMPLETE,
+ DC_CLK_RESET_TIME_BEGIN,
+ DC_CLK_RESET_TIME_COMPLETE,
+ DC_CLK_OSC_INIT_BEGIN,
+ DC_CLK_OSC_INIT_XOSC0_SYNC,
+ DC_CLK_OSC_INIT_DPLL_SYNC_DISABLE,
+ DC_CLK_OSC_INIT_DPLL_SYNC_RATIO,
+ DC_CLK_OSC_INIT_DPLL_SYNC_ENABLE,
+ DC_CLK_OSC_INIT_DPLL_WAIT_LOCK,
+ DC_CLK_OSC_INIT_DPLL_WAIT_CLKRDY,
+ DC_CLK_OSC_INIT_GCLK_SYNC_GENCTRL0,
+ DC_CLK_OSC_INIT_COMPLETE,
+ DC_SPI_INIT_BEGIN,
+ DC_SPI_WRITE_DRE,
+ DC_SPI_WRITE_TXC_1,
+ DC_SPI_WRITE_TXC_2,
+ DC_SPI_SYNC_ENABLING,
+ DC_SPI_INIT_COMPLETE,
+ DC_PORT_DETECT_INIT_BEGIN,
+ DC_PORT_DETECT_INIT_FAILED,
+ DC_PORT_DETECT_INIT_COMPLETE,
+ DC_USB_RESET_BEGIN,
+ DC_USB_RESET_COMPLETE,
+ DC_USB_SET_HOST_BY_VOLTAGE_BEGIN,
+ DC_USB_SET_HOST_5V_LOW_WAITING,
+ DC_USB_SET_HOST_BY_VOLTAGE_COMPLETE,
+ DC_USB_CONFIGURE_BEGIN,
+ DC_USB_CONFIGURE_GET_SERIAL,
+ DC_USB_CONFIGURE_COMPLETE,
+ DC_USB_WRITE2422_BLOCK_BEGIN,
+ DC_USB_WRITE2422_BLOCK_SYNC_SYSOP,
+ DC_USB_WRITE2422_BLOCK_COMPLETE,
+ DC_ADC0_CLOCK_INIT_BEGIN,
+ DC_ADC0_CLOCK_INIT_COMPLETE,
+ DC_ADC0_INIT_BEGIN,
+ DC_ADC0_SWRST_SYNCING_1,
+ DC_ADC0_SWRST_SYNCING_2,
+ DC_ADC0_AVGCTRL_SYNCING_1,
+ DC_ADC0_AVGCTRL_SYNCING_2,
+ DC_ADC0_SAMPCTRL_SYNCING_1,
+ DC_ADC0_ENABLE_SYNCING_1,
+ DC_ADC0_INIT_COMPLETE,
+ DC_I2C0_INIT_BEGIN,
+ DC_I2C0_INIT_SYNC_ENABLING,
+ DC_I2C0_INIT_SYNC_SYSOP,
+ DC_I2C0_INIT_WAIT_IDLE,
+ DC_I2C0_INIT_COMPLETE,
+ DC_I2C1_INIT_BEGIN,
+ DC_I2C1_INIT_SYNC_ENABLING,
+ DC_I2C1_INIT_SYNC_SYSOP,
+ DC_I2C1_INIT_WAIT_IDLE,
+ DC_I2C1_INIT_COMPLETE,
+ DC_I2C3733_INIT_CONTROL_BEGIN,
+ DC_I2C3733_INIT_CONTROL_COMPLETE,
+ DC_I2C3733_INIT_DRIVERS_BEGIN,
+ DC_I2C3733_INIT_DRIVERS_COMPLETE,
+ DC_I2C_DMAC_LED_INIT_BEGIN,
+ DC_I2C_DMAC_LED_INIT_COMPLETE,
+ DC_I2C3733_CONTROL_SET_BEGIN,
+ DC_I2C3733_CONTROL_SET_COMPLETE,
+ DC_LED_MATRIX_INIT_BEGIN,
+ DC_LED_MATRIX_INIT_COMPLETE,
+ DC_USB2422_INIT_BEGIN,
+ DC_USB2422_INIT_WAIT_5V_LOW,
+ DC_USB2422_INIT_OSC_SYNC_DISABLING,
+ DC_USB2422_INIT_OSC_SYNC_DFLLCTRLB_1,
+ DC_USB2422_INIT_OSC_SYNC_DFLLCTRLB_2,
+ DC_USB2422_INIT_OSC_SYNC_DFLLCTRLB_3,
+ DC_USB2422_INIT_OSC_SYNC_DFLLCTRLB_4,
+ DC_USB2422_INIT_OSC_SYNC_DFLLMUL,
+ DC_USB2422_INIT_OSC_SYNC_ENABLING,
+ DC_USB2422_INIT_USB_SYNC_SWRST,
+ DC_USB2422_INIT_USB_WAIT_SWRST,
+ DC_USB2422_INIT_USB_SYNC_ENABLING,
+ DC_USB2422_INIT_COMPLETE,
+ DC_MAIN_UDC_START_BEGIN,
+ DC_MAIN_UDC_START_COMPLETE,
+ DC_MAIN_CDC_INIT_BEGIN,
+ DC_MAIN_CDC_INIT_COMPLETE,
+ /* Never change the order of error codes! Only add codes to end! */
+};
+
+#else
+
+#define DBGC(n) {}
+
+#endif //DEBUG_BOOT_TRACING
+
+#endif //_D51_UTIL_H_
diff --git a/tmk_core/protocol/arm_atsam/i2c_master.c b/tmk_core/protocol/arm_atsam/i2c_master.c
new file mode 100644
index 0000000000..bbe909e9bb
--- /dev/null
+++ b/tmk_core/protocol/arm_atsam/i2c_master.c
@@ -0,0 +1,585 @@
+/*
+Copyright 2018 Massdrop Inc.
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+#include "arm_atsam_protocol.h"
+
+#ifndef MD_BOOTLOADER
+
+#include
+
+//From keyboard
+#include "config.h"
+#include "config_led.h"
+#include "matrix.h"
+
+#define I2C_LED_USE_DMA 1 //Set 1 to use background DMA transfers for leds, Set 0 to use inline software transfers
+
+static uint8_t i2c_led_q[I2C_Q_SIZE]; //I2C queue circular buffer
+static uint8_t i2c_led_q_s; //Start of circular buffer
+static uint8_t i2c_led_q_e; //End of circular buffer
+static uint8_t i2c_led_q_full; //Queue full counter for reset
+
+static uint8_t dma_sendbuf[I2C_DMA_MAX_SEND]; //Data being written to I2C
+
+volatile uint8_t i2c_led_q_running;
+
+#endif //MD_BOOTLOADER
+
+void i2c0_init(void)
+{
+ DBGC(DC_I2C0_INIT_BEGIN);
+
+ CLK_set_i2c0_freq(CHAN_SERCOM_I2C0, FREQ_I2C0_DEFAULT);
+
+ //MCU
+ PORT->Group[0].PMUX[4].bit.PMUXE = 2;
+ PORT->Group[0].PMUX[4].bit.PMUXO = 2;
+ PORT->Group[0].PINCFG[8].bit.PMUXEN = 1;
+ PORT->Group[0].PINCFG[9].bit.PMUXEN = 1;
+
+ //I2C
+ //Note: SW Reset handled in CLK_set_i2c0_freq clks.c
+
+ SERCOM0->I2CM.CTRLA.bit.MODE = 5; //Set master mode
+
+ SERCOM0->I2CM.CTRLA.bit.SPEED = 0; //Set to 1 for Fast-mode Plus (FM+) up to 1 MHz
+ SERCOM0->I2CM.CTRLA.bit.RUNSTDBY = 1; //Enabled
+
+ SERCOM0->I2CM.CTRLA.bit.ENABLE = 1; //Enable the device
+ while (SERCOM0->I2CM.SYNCBUSY.bit.ENABLE) { DBGC(DC_I2C0_INIT_SYNC_ENABLING); } //Wait for SYNCBUSY.ENABLE to clear
+
+ SERCOM0->I2CM.STATUS.bit.BUSSTATE = 1; //Force into IDLE state
+ while (SERCOM0->I2CM.SYNCBUSY.bit.SYSOP) { DBGC(DC_I2C0_INIT_SYNC_SYSOP); }
+ while (SERCOM0->I2CM.STATUS.bit.BUSSTATE != 1) { DBGC(DC_I2C0_INIT_WAIT_IDLE); } //Wait while not idle
+
+ DBGC(DC_I2C0_INIT_COMPLETE);
+}
+
+uint8_t i2c0_start(uint8_t address)
+{
+ SERCOM0->I2CM.ADDR.bit.ADDR = address;
+ while (SERCOM0->I2CM.SYNCBUSY.bit.SYSOP) {}
+ while (SERCOM0->I2CM.INTFLAG.bit.MB == 0) {}
+ while (SERCOM0->I2CM.STATUS.bit.RXNACK) {}
+
+ return 1;
+}
+
+uint8_t i2c0_transmit(uint8_t address, uint8_t *data, uint16_t length, uint16_t timeout)
+{
+ if (!length) return 0;
+
+ i2c0_start(address);
+
+ while (length)
+ {
+ SERCOM0->I2CM.DATA.bit.DATA = *data;
+ while (SERCOM0->I2CM.INTFLAG.bit.MB == 0) {}
+ while (SERCOM0->I2CM.STATUS.bit.RXNACK) {}
+
+ data++;
+ length--;
+ }
+
+ i2c0_stop();
+
+ return 1;
+}
+
+void i2c0_stop(void)
+{
+ if (SERCOM0->I2CM.STATUS.bit.CLKHOLD || SERCOM0->I2CM.INTFLAG.bit.MB == 1 || SERCOM0->I2CM.STATUS.bit.BUSSTATE != 1)
+ {
+ SERCOM0->I2CM.CTRLB.bit.CMD = 3;
+ while (SERCOM0->I2CM.SYNCBUSY.bit.SYSOP);
+ while (SERCOM0->I2CM.STATUS.bit.CLKHOLD);
+ while (SERCOM0->I2CM.INTFLAG.bit.MB);
+ while (SERCOM0->I2CM.STATUS.bit.BUSSTATE != 1);
+ }
+}
+
+#ifndef MD_BOOTLOADER
+void i2c1_init(void)
+{
+ DBGC(DC_I2C1_INIT_BEGIN);
+
+ CLK_set_i2c1_freq(CHAN_SERCOM_I2C1, FREQ_I2C1_DEFAULT);
+
+ /* MCU */
+ PORT->Group[0].PMUX[8].bit.PMUXE = 2;
+ PORT->Group[0].PMUX[8].bit.PMUXO = 2;
+ PORT->Group[0].PINCFG[16].bit.PMUXEN = 1;
+ PORT->Group[0].PINCFG[17].bit.PMUXEN = 1;
+
+ /* I2C */
+ //Note: SW Reset handled in CLK_set_i2c1_freq clks.c
+
+ SERCOM1->I2CM.CTRLA.bit.MODE = 5; //MODE: Set master mode (No sync)
+ SERCOM1->I2CM.CTRLA.bit.SPEED = 1; //SPEED: Fm+ up to 1MHz (No sync)
+ SERCOM1->I2CM.CTRLA.bit.RUNSTDBY = 1; //RUNSTBY: Enabled (No sync)
+
+ SERCOM1->I2CM.CTRLB.bit.SMEN = 1; //SMEN: Smart mode enabled (For DMA)(No sync)
+
+ NVIC_EnableIRQ(SERCOM1_0_IRQn);
+ SERCOM1->I2CM.INTENSET.bit.ERROR = 1;
+
+ SERCOM1->I2CM.CTRLA.bit.ENABLE = 1; //ENABLE: Enable the device (sync SYNCBUSY.ENABLE)
+ while (SERCOM1->I2CM.SYNCBUSY.bit.ENABLE) { DBGC(DC_I2C1_INIT_SYNC_ENABLING); } //Wait for SYNCBUSY.ENABLE to clear
+
+ SERCOM1->I2CM.STATUS.bit.BUSSTATE = 1; //BUSSTATE: Force into IDLE state (sync SYNCBUSY.SYSOP)
+ while (SERCOM1->I2CM.SYNCBUSY.bit.SYSOP) { DBGC(DC_I2C1_INIT_SYNC_SYSOP); }
+ while (SERCOM1->I2CM.STATUS.bit.BUSSTATE != 1) { DBGC(DC_I2C1_INIT_WAIT_IDLE); } //Wait while not idle
+
+ DBGC(DC_I2C1_INIT_COMPLETE);
+}
+
+uint8_t i2c1_start(uint8_t address)
+{
+ SERCOM1->I2CM.ADDR.bit.ADDR = address;
+ while (SERCOM1->I2CM.SYNCBUSY.bit.SYSOP) {}
+ while (SERCOM1->I2CM.INTFLAG.bit.MB == 0) {}
+ while (SERCOM1->I2CM.STATUS.bit.RXNACK) {}
+
+ return 1;
+}
+
+uint8_t i2c1_transmit(uint8_t address, uint8_t *data, uint16_t length, uint16_t timeout)
+{
+ if (!length) return 0;
+
+ i2c1_start(address);
+
+ while (length)
+ {
+ SERCOM1->I2CM.DATA.bit.DATA = *data;
+ while (SERCOM1->I2CM.INTFLAG.bit.MB == 0) {}
+ while (SERCOM1->I2CM.STATUS.bit.RXNACK) {}
+
+ data++;
+ length--;
+ }
+
+ i2c1_stop();
+
+ return 1;
+}
+
+void i2c1_stop(void)
+{
+ if (SERCOM1->I2CM.STATUS.bit.CLKHOLD || SERCOM1->I2CM.INTFLAG.bit.MB == 1 || SERCOM1->I2CM.STATUS.bit.BUSSTATE != 1)
+ {
+ SERCOM1->I2CM.CTRLB.bit.CMD = 3;
+ while (SERCOM1->I2CM.SYNCBUSY.bit.SYSOP);
+ while (SERCOM1->I2CM.STATUS.bit.CLKHOLD);
+ while (SERCOM1->I2CM.INTFLAG.bit.MB);
+ while (SERCOM1->I2CM.STATUS.bit.BUSSTATE != 1);
+ }
+}
+
+void i2c_led_send_CRWL(uint8_t drvid)
+{
+ uint8_t i2cdata[] = { ISSI3733_CMDRWL, ISSI3733_CMDRWL_WRITE_ENABLE_ONCE };
+ i2c1_transmit(issidrv[drvid].addr, i2cdata, sizeof(i2cdata), 0);
+}
+
+void i2c_led_select_page(uint8_t drvid, uint8_t pageno)
+{
+ uint8_t i2cdata[] = { ISSI3733_CMDR, pageno };
+ i2c1_transmit(issidrv[drvid