aboutsummaryrefslogtreecommitdiff
path: root/Marlin/src/HAL/SAMD51
diff options
context:
space:
mode:
authorGeorgiy Bondarenko <69736697+nehilo@users.noreply.github.com>2021-03-04 20:54:23 +0300
committerGeorgiy Bondarenko <69736697+nehilo@users.noreply.github.com>2021-03-04 20:54:23 +0300
commite8701195e66f2d27ffe17fb514eae8173795aaf7 (patch)
tree9f519c4abf6556b9ae7190a6210d87ead1dfadde /Marlin/src/HAL/SAMD51
downloadkp3s-lgvl-e8701195e66f2d27ffe17fb514eae8173795aaf7.tar.xz
kp3s-lgvl-e8701195e66f2d27ffe17fb514eae8173795aaf7.zip
Initial commit
Diffstat (limited to 'Marlin/src/HAL/SAMD51')
-rw-r--r--Marlin/src/HAL/SAMD51/HAL.cpp478
-rw-r--r--Marlin/src/HAL/SAMD51/HAL.h169
-rw-r--r--Marlin/src/HAL/SAMD51/HAL_SPI.cpp148
-rw-r--r--Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.cpp54
-rw-r--r--Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.h29
-rw-r--r--Marlin/src/HAL/SAMD51/QSPIFlash.cpp78
-rw-r--r--Marlin/src/HAL/SAMD51/QSPIFlash.h50
-rw-r--r--Marlin/src/HAL/SAMD51/SAMD51.h70
-rw-r--r--Marlin/src/HAL/SAMD51/Servo.cpp224
-rw-r--r--Marlin/src/HAL/SAMD51/ServoTimers.h39
-rw-r--r--Marlin/src/HAL/SAMD51/eeprom_flash.cpp95
-rw-r--r--Marlin/src/HAL/SAMD51/eeprom_qspi.cpp71
-rw-r--r--Marlin/src/HAL/SAMD51/eeprom_wired.cpp74
-rw-r--r--Marlin/src/HAL/SAMD51/endstop_interrupts.h208
-rw-r--r--Marlin/src/HAL/SAMD51/fastio.h253
-rw-r--r--Marlin/src/HAL/SAMD51/inc/Conditionals_LCD.h26
-rw-r--r--Marlin/src/HAL/SAMD51/inc/Conditionals_adv.h22
-rw-r--r--Marlin/src/HAL/SAMD51/inc/Conditionals_post.h28
-rw-r--r--Marlin/src/HAL/SAMD51/inc/SanityCheck.h52
-rw-r--r--Marlin/src/HAL/SAMD51/pinsDebug.h153
-rw-r--r--Marlin/src/HAL/SAMD51/spi_pins.h54
-rw-r--r--Marlin/src/HAL/SAMD51/timers.cpp168
-rw-r--r--Marlin/src/HAL/SAMD51/timers.h143
-rw-r--r--Marlin/src/HAL/SAMD51/watchdog.cpp54
-rw-r--r--Marlin/src/HAL/SAMD51/watchdog.h31
25 files changed, 2771 insertions, 0 deletions
diff --git a/Marlin/src/HAL/SAMD51/HAL.cpp b/Marlin/src/HAL/SAMD51/HAL.cpp
new file mode 100644
index 0000000..a413c4c
--- /dev/null
+++ b/Marlin/src/HAL/SAMD51/HAL.cpp
@@ -0,0 +1,478 @@
+/**
+ * Marlin 3D Printer Firmware
+ *
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician)
+ *
+ * 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 3 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#ifdef __SAMD51__
+
+#include "../../inc/MarlinConfig.h"
+#include <Adafruit_ZeroDMA.h>
+#include <wiring_private.h>
+
+#ifdef ADAFRUIT_GRAND_CENTRAL_M4
+ DefaultSerial MSerial(false, Serial);
+ DefaultSerial1 MSerial1(false, Serial1);
+#endif
+
+// ------------------------
+// Local defines
+// ------------------------
+
+#define GET_TEMP_0_ADC() TERN(HAS_TEMP_ADC_0, PIN_TO_ADC(TEMP_0_PIN), -1)
+#define GET_TEMP_1_ADC() TERN(HAS_TEMP_ADC_1, PIN_TO_ADC(TEMP_1_PIN), -1)
+#define GET_TEMP_2_ADC() TERN(HAS_TEMP_ADC_2, PIN_TO_ADC(TEMP_2_PIN), -1)
+#define GET_TEMP_3_ADC() TERN(HAS_TEMP_ADC_3, PIN_TO_ADC(TEMP_3_PIN), -1)
+#define GET_TEMP_4_ADC() TERN(HAS_TEMP_ADC_4, PIN_TO_ADC(TEMP_4_PIN), -1)
+#define GET_TEMP_5_ADC() TERN(HAS_TEMP_ADC_5, PIN_TO_ADC(TEMP_5_PIN), -1)
+#define GET_TEMP_6_ADC() TERN(HAS_TEMP_ADC_6, PIN_TO_ADC(TEMP_6_PIN), -1)
+#define GET_TEMP_7_ADC() TERN(HAS_TEMP_ADC_7, PIN_TO_ADC(TEMP_7_PIN), -1)
+#define GET_PROBE_ADC() TERN(HAS_TEMP_PROBE, PIN_TO_ADC(TEMP_PROBE_PIN), -1)
+#define GET_BED_ADC() TERN(HAS_TEMP_ADC_BED, PIN_TO_ADC(TEMP_BED_PIN), -1)
+#define GET_CHAMBER_ADC() TERN(HAS_TEMP_ADC_CHAMBER, PIN_TO_ADC(TEMP_CHAMBER_PIN), -1)
+#define GET_FILAMENT_WIDTH_ADC() TERN(FILAMENT_WIDTH_SENSOR, PIN_TO_ADC(FILWIDTH_PIN), -1)
+#define GET_BUTTONS_ADC() TERN(HAS_ADC_BUTTONS, PIN_TO_ADC(ADC_KEYPAD_PIN), -1)
+
+#define IS_ADC_REQUIRED(n) ( \
+ GET_TEMP_0_ADC() == n || GET_TEMP_1_ADC() == n || GET_TEMP_2_ADC() == n || GET_TEMP_3_ADC() == n \
+ || GET_TEMP_4_ADC() == n || GET_TEMP_5_ADC() == n || GET_TEMP_6_ADC() == n || GET_TEMP_7_ADC() == n \
+ || GET_PROBE_ADC() == n \
+ || GET_BED_ADC() == n \
+ || GET_CHAMBER_ADC() == n \
+ || GET_FILAMENT_WIDTH_ADC() == n \
+ || GET_BUTTONS_ADC() == n \
+)
+
+#if IS_ADC_REQUIRED(0)
+ #define ADC0_IS_REQUIRED 1
+ #define FIRST_ADC 0
+#else
+ #define FIRST_ADC 1
+#endif
+#if IS_ADC_REQUIRED(1)
+ #define ADC1_IS_REQUIRED 1
+ #define LAST_ADC 1
+#else
+ #define LAST_ADC 0
+#endif
+#if ADC0_IS_REQUIRED || ADC1_IS_REQUIRED
+ #define ADC_IS_REQUIRED 1
+ #define DMA_IS_REQUIRED 1
+#endif
+
+// ------------------------
+// Types
+// ------------------------
+
+#if DMA_IS_REQUIRED
+
+ // Struct must be 32 bits aligned because of DMA accesses but fields needs to be 8 bits packed
+ typedef struct __attribute__((aligned(4), packed)) {
+ ADC_INPUTCTRL_Type INPUTCTRL;
+ } HAL_DMA_DAC_Registers; // DMA transfered registers
+
+#endif
+
+// ------------------------
+// Private Variables
+// ------------------------
+
+uint16_t HAL_adc_result;
+
+#if ADC_IS_REQUIRED
+
+ // Pins used by ADC inputs. Order must be ADC0 inputs first then ADC1
+ const uint8_t adc_pins[] = {
+ // ADC0 pins
+ #if GET_TEMP_0_ADC() == 0
+ TEMP_0_PIN,
+ #endif
+ #if GET_TEMP_1_ADC() == 0
+ TEMP_1_PIN,
+ #endif
+ #if GET_TEMP_2_ADC() == 0
+ TEMP_2_PIN,
+ #endif
+ #if GET_TEMP_3_ADC() == 0
+ TEMP_3_PIN,
+ #endif
+ #if GET_TEMP_4_ADC() == 0
+ TEMP_4_PIN,
+ #endif
+ #if GET_TEMP_5_ADC() == 0
+ TEMP_5_PIN,
+ #endif
+ #if GET_TEMP_6_ADC() == 0
+ TEMP_6_PIN,
+ #endif
+ #if GET_TEMP_7_ADC() == 0
+ TEMP_7_PIN,
+ #endif
+ #if GET_PROBE_ADC() == 0
+ TEMP_PROBE_PIN,
+ #endif
+ #if GET_BED_ADC() == 0
+ TEMP_BED_PIN,
+ #endif
+ #if GET_CHAMBER_ADC() == 0
+ TEMP_CHAMBER_PIN,
+ #endif
+ #if GET_FILAMENT_WIDTH_ADC() == 0
+ FILWIDTH_PIN,
+ #endif
+ #if GET_BUTTONS_ADC() == 0
+ ADC_KEYPAD_PIN,
+ #endif
+ // ADC1 pins
+ #if GET_TEMP_0_ADC() == 1
+ TEMP_0_PIN,
+ #endif
+ #if GET_TEMP_1_ADC() == 1
+ TEMP_1_PIN,
+ #endif
+ #if GET_TEMP_2_ADC() == 1
+ TEMP_2_PIN,
+ #endif
+ #if GET_TEMP_3_ADC() == 1
+ TEMP_3_PIN,
+ #endif
+ #if GET_TEMP_4_ADC() == 1
+ TEMP_4_PIN,
+ #endif
+ #if GET_TEMP_5_ADC() == 1
+ TEMP_5_PIN,
+ #endif
+ #if GET_TEMP_6_ADC() == 1
+ TEMP_6_PIN,
+ #endif
+ #if GET_TEMP_7_ADC() == 1
+ TEMP_7_PIN,
+ #endif
+ #if GET_PROBE_ADC() == 1
+ TEMP_PROBE_PIN,
+ #endif
+ #if GET_BED_ADC() == 1
+ TEMP_BED_PIN,
+ #endif
+ #if GET_CHAMBER_ADC() == 1
+ TEMP_CHAMBER_PIN,
+ #endif
+ #if GET_FILAMENT_WIDTH_ADC() == 1
+ FILWIDTH_PIN,
+ #endif
+ #if GET_BUTTONS_ADC() == 1
+ ADC_KEYPAD_PIN,
+ #endif
+ };
+
+ uint16_t HAL_adc_results[COUNT(adc_pins)];
+
+ #if ADC0_IS_REQUIRED
+ Adafruit_ZeroDMA adc0DMAProgram,
+ adc0DMARead;
+
+ const HAL_DMA_DAC_Registers adc0_dma_regs_list[] = {
+ #if GET_TEMP_0_ADC() == 0
+ { PIN_TO_INPUTCTRL(TEMP_0_PIN) },
+ #endif
+ #if GET_TEMP_1_ADC() == 0
+ { PIN_TO_INPUTCTRL(TEMP_1_PIN) },
+ #endif
+ #if GET_TEMP_2_ADC() == 0
+ { PIN_TO_INPUTCTRL(TEMP_2_PIN) },
+ #endif
+ #if GET_TEMP_3_ADC() == 0
+ { PIN_TO_INPUTCTRL(TEMP_3_PIN) },
+ #endif
+ #if GET_TEMP_4_ADC() == 0
+ { PIN_TO_INPUTCTRL(TEMP_4_PIN) },
+ #endif
+ #if GET_TEMP_5_ADC() == 0
+ { PIN_TO_INPUTCTRL(TEMP_5_PIN) },
+ #endif
+ #if GET_TEMP_6_ADC() == 0
+ { PIN_TO_INPUTCTRL(TEMP_6_PIN) },
+ #endif
+ #if GET_TEMP_7_ADC() == 0
+ { PIN_TO_INPUTCTRL(TEMP_7_PIN) },
+ #endif
+ #if GET_PROBE_ADC() == 0
+ { PIN_TO_INPUTCTRL(TEMP_PROBE_PIN) },
+ #endif
+ #if GET_BED_ADC() == 0
+ { PIN_TO_INPUTCTRL(TEMP_BED_PIN) },
+ #endif
+ #if GET_CHAMBER_ADC() == 0
+ { PIN_TO_INPUTCTRL(TEMP_CHAMBER_PIN) },
+ #endif
+ #if GET_FILAMENT_WIDTH_ADC() == 0
+ { PIN_TO_INPUTCTRL(FILWIDTH_PIN) },
+ #endif
+ #if GET_BUTTONS_ADC() == 0
+ { PIN_TO_INPUTCTRL(ADC_KEYPAD_PIN) },
+ #endif
+ };
+
+ #define ADC0_AINCOUNT COUNT(adc0_dma_regs_list)
+ #endif // ADC0_IS_REQUIRED
+
+ #if ADC1_IS_REQUIRED
+ Adafruit_ZeroDMA adc1DMAProgram,
+ adc1DMARead;
+
+ const HAL_DMA_DAC_Registers adc1_dma_regs_list[] = {
+ #if GET_TEMP_0_ADC() == 1
+ { PIN_TO_INPUTCTRL(TEMP_0_PIN) },
+ #endif
+ #if GET_TEMP_1_ADC() == 1
+ { PIN_TO_INPUTCTRL(TEMP_1_PIN) },
+ #endif
+ #if GET_TEMP_2_ADC() == 1
+ { PIN_TO_INPUTCTRL(TEMP_2_PIN) },
+ #endif
+ #if GET_TEMP_3_ADC() == 1
+ { PIN_TO_INPUTCTRL(TEMP_3_PIN) },
+ #endif
+ #if GET_TEMP_4_ADC() == 1
+ { PIN_TO_INPUTCTRL(TEMP_4_PIN) },
+ #endif
+ #if GET_TEMP_5_ADC() == 1
+ { PIN_TO_INPUTCTRL(TEMP_5_PIN) },
+ #endif
+ #if GET_TEMP_6_ADC() == 1
+ { PIN_TO_INPUTCTRL(TEMP_6_PIN) },
+ #endif
+ #if GET_TEMP_7_ADC() == 1
+ { PIN_TO_INPUTCTRL(TEMP_7_PIN) },
+ #endif
+ #if GET_PROBE_ADC() == 1
+ { PIN_TO_INPUTCTRL(TEMP_PROBE_PIN) },
+ #endif
+ #if GET_BED_ADC() == 1
+ { PIN_TO_INPUTCTRL(TEMP_BED_PIN) },
+ #endif
+ #if GET_CHAMBER_ADC() == 1
+ { PIN_TO_INPUTCTRL(TEMP_CHAMBER_PIN) },
+ #endif
+ #if GET_FILAMENT_WIDTH_ADC() == 1
+ { PIN_TO_INPUTCTRL(FILWIDTH_PIN) },
+ #endif
+ #if GET_BUTTONS_ADC() == 1
+ { PIN_TO_INPUTCTRL(ADC_KEYPAD_PIN) },
+ #endif
+ };
+
+ #define ADC1_AINCOUNT COUNT(adc1_dma_regs_list)
+ #endif // ADC1_IS_REQUIRED
+
+#endif // ADC_IS_REQUIRED
+
+// ------------------------
+// Private functions
+// ------------------------
+
+#if DMA_IS_REQUIRED
+
+ void dma_init() {
+ DmacDescriptor *descriptor;
+
+ #if ADC0_IS_REQUIRED
+ adc0DMAProgram.setTrigger(ADC0_DMAC_ID_SEQ);
+ adc0DMAProgram.setAction(DMA_TRIGGER_ACTON_BEAT);
+ adc0DMAProgram.loop(true);
+ if (adc0DMAProgram.allocate() == DMA_STATUS_OK) {
+ descriptor = adc0DMAProgram.addDescriptor(
+ (void *)adc0_dma_regs_list, // SRC
+ (void *)&ADC0->DSEQDATA.reg, // DEST
+ sizeof(adc0_dma_regs_list) / 4, // CNT
+ DMA_BEAT_SIZE_WORD,
+ true, // SRCINC
+ false, // DSTINC
+ DMA_ADDRESS_INCREMENT_STEP_SIZE_1, // STEPSIZE
+ DMA_STEPSEL_SRC // STEPSEL
+ );
+ if (descriptor)
+ descriptor->BTCTRL.bit.EVOSEL = DMA_EVENT_OUTPUT_BEAT;
+ adc0DMAProgram.startJob();
+ }
+
+ adc0DMARead.setTrigger(ADC0_DMAC_ID_RESRDY);
+ adc0DMARead.setAction(DMA_TRIGGER_ACTON_BEAT);
+ adc0DMARead.loop(true);
+ if (adc0DMARead.allocate() == DMA_STATUS_OK) {
+ adc0DMARead.addDescriptor(
+ (void *)&ADC0->RESULT.reg, // SRC
+ &HAL_adc_results, // DEST
+ ADC0_AINCOUNT, // CNT
+ DMA_BEAT_SIZE_HWORD,
+ false, // SRCINC
+ true, // DSTINC
+ DMA_ADDRESS_INCREMENT_STEP_SIZE_1, // STEPSIZE
+ DMA_STEPSEL_DST // STEPSEL
+ );
+ adc0DMARead.startJob();
+ }
+ #endif
+ #if ADC1_IS_REQUIRED
+ adc1DMAProgram.setTrigger(ADC1_DMAC_ID_SEQ);
+ adc1DMAProgram.setAction(DMA_TRIGGER_ACTON_BEAT);
+ adc1DMAProgram.loop(true);
+ if (adc1DMAProgram.allocate() == DMA_STATUS_OK) {
+ descriptor = adc1DMAProgram.addDescriptor(
+ (void *)adc1_dma_regs_list, // SRC
+ (void *)&ADC1->DSEQDATA.reg, // DEST
+ sizeof(adc1_dma_regs_list) / 4, // CNT
+ DMA_BEAT_SIZE_WORD,
+ true, // SRCINC
+ false, // DSTINC
+ DMA_ADDRESS_INCREMENT_STEP_SIZE_1, // STEPSIZE
+ DMA_STEPSEL_SRC // STEPSEL
+ );
+ if (descriptor)
+ descriptor->BTCTRL.bit.EVOSEL = DMA_EVENT_OUTPUT_BEAT;
+ adc1DMAProgram.startJob();
+ }
+
+ adc1DMARead.setTrigger(ADC1_DMAC_ID_RESRDY);
+ adc1DMARead.setAction(DMA_TRIGGER_ACTON_BEAT);
+ adc1DMARead.loop(true);
+ if (adc1DMARead.allocate() == DMA_STATUS_OK) {
+ adc1DMARead.addDescriptor(
+ (void *)&ADC1->RESULT.reg, // SRC
+ &HAL_adc_results[ADC0_AINCOUNT], // DEST
+ ADC1_AINCOUNT, // CNT
+ DMA_BEAT_SIZE_HWORD,
+ false, // SRCINC
+ true, // DSTINC
+ DMA_ADDRESS_INCREMENT_STEP_SIZE_1, // STEPSIZE
+ DMA_STEPSEL_DST // STEPSEL
+ );
+ adc1DMARead.startJob();
+ }
+ #endif
+
+ DMAC->PRICTRL0.bit.RRLVLEN0 = true; // Activate round robin for DMA channels required by ADCs
+ }
+
+#endif // DMA_IS_REQUIRED
+
+// ------------------------
+// Public functions
+// ------------------------
+
+// HAL initialization task
+void HAL_init() {
+ TERN_(DMA_IS_REQUIRED, dma_init());
+ #if ENABLED(SDSUPPORT)
+ #if SD_CONNECTION_IS(ONBOARD) && PIN_EXISTS(SD_DETECT)
+ SET_INPUT_PULLUP(SD_DETECT_PIN);
+ #endif
+ OUT_WRITE(SDSS, HIGH); // Try to set SDSS inactive before any other SPI users start up
+ #endif
+}
+
+// HAL idle task
+/*
+void HAL_idletask() {
+}
+*/
+
+void HAL_clear_reset_source() { }
+
+#pragma push_macro("WDT")
+#undef WDT // Required to be able to use '.bit.WDT'. Compiler wrongly replace struct field with WDT define
+uint8_t HAL_get_reset_source() {
+ RSTC_RCAUSE_Type resetCause;
+
+ resetCause.reg = REG_RSTC_RCAUSE;
+ if (resetCause.bit.POR) return RST_POWER_ON;
+ else if (resetCause.bit.EXT) return RST_EXTERNAL;
+ else if (resetCause.bit.BODCORE || resetCause.bit.BODVDD) return RST_BROWN_OUT;
+ else if (resetCause.bit.WDT) return RST_WATCHDOG;
+ else if (resetCause.bit.SYST || resetCause.bit.NVM) return RST_SOFTWARE;
+ else if (resetCause.bit.BACKUP) return RST_BACKUP;
+ return 0;
+}
+#pragma pop_macro("WDT")
+
+extern "C" {
+ void * _sbrk(int incr);
+
+ extern unsigned int __bss_end__; // end of bss section
+}
+
+// Return free memory between end of heap (or end bss) and whatever is current
+int freeMemory() {
+ int free_memory, heap_end = (int)_sbrk(0);
+ return (int)&free_memory - (heap_end ?: (int)&__bss_end__);
+}
+
+// ------------------------
+// ADC
+// ------------------------
+
+void HAL_adc_init() {
+ #if ADC_IS_REQUIRED
+ memset(HAL_adc_results, 0xFF, sizeof(HAL_adc_results)); // Fill result with invalid values
+
+ LOOP_L_N(pi, COUNT(adc_pins))
+ pinPeripheral(adc_pins[pi], PIO_ANALOG);
+
+ LOOP_S_LE_N(ai, FIRST_ADC, LAST_ADC) {
+ Adc* adc = ((Adc*[])ADC_INSTS)[ai];
+
+ // ADC clock setup
+ GCLK->PCHCTRL[ADC0_GCLK_ID + ai].bit.CHEN = false;
+ SYNC(GCLK->PCHCTRL[ADC0_GCLK_ID + ai].bit.CHEN);
+ GCLK->PCHCTRL[ADC0_GCLK_ID + ai].reg = GCLK_PCHCTRL_GEN_GCLK1 | GCLK_PCHCTRL_CHEN; // 48MHz startup code programmed
+ SYNC(!GCLK->PCHCTRL[ADC0_GCLK_ID + ai].bit.CHEN);
+ adc->CTRLA.bit.PRESCALER = ADC_CTRLA_PRESCALER_DIV32_Val; // 1.5MHZ adc clock
+
+ // ADC setup
+ // Preloaded data (fixed for all ADC instances hence not loaded by DMA)
+ adc->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_AREFA_Val; // VRefA pin
+ SYNC(adc->SYNCBUSY.bit.REFCTRL);
+ adc->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_10BIT_Val; // ... ADC_CTRLB_RESSEL_16BIT_Val
+ SYNC(adc->SYNCBUSY.bit.CTRLB);
+ adc->SAMPCTRL.bit.SAMPLEN = (6 - 1); // Sampling clocks
+ //adc->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM_16 | ADC_AVGCTRL_ADJRES(4); // 16 Accumulated conversions and shift 4 to get oversampled 12 bits result
+ //SYNC(adc->SYNCBUSY.bit.AVGCTRL);
+
+ // Registers loaded by DMA
+ adc->DSEQCTRL.bit.INPUTCTRL = true;
+ adc->DSEQCTRL.bit.AUTOSTART = true; // Start conversion after DMA sequence
+
+ adc->CTRLA.bit.ENABLE = true; // Enable ADC
+ SYNC(adc->SYNCBUSY.bit.ENABLE);
+ }
+ #endif // ADC_IS_REQUIRED
+}
+
+void HAL_adc_start_conversion(const uint8_t adc_pin) {
+ #if ADC_IS_REQUIRED
+ LOOP_L_N(pi, COUNT(adc_pins)) {
+ if (adc_pin == adc_pins[pi]) {
+ HAL_adc_result = HAL_adc_results[pi];
+ return;
+ }
+ }
+ #endif
+
+ HAL_adc_result = 0xFFFF;
+}
+
+#endif // __SAMD51__
diff --git a/Marlin/src/HAL/SAMD51/HAL.h b/Marlin/src/HAL/SAMD51/HAL.h
new file mode 100644
index 0000000..f28583c
--- /dev/null
+++ b/Marlin/src/HAL/SAMD51/HAL.h
@@ -0,0 +1,169 @@
+/**
+ * Marlin 3D Printer Firmware
+ *
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician)
+ *
+ * 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 3 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#define CPU_32_BIT
+
+#include "../shared/Marduino.h"
+#include "../shared/math_32bit.h"
+#include "../shared/HAL_SPI.h"
+#include "fastio.h"
+#include "watchdog.h"
+
+#ifdef ADAFRUIT_GRAND_CENTRAL_M4
+ #include "MarlinSerial_AGCM4.h"
+
+ // Serial ports
+ typedef ForwardSerial0Type< decltype(Serial) > DefaultSerial;
+ extern DefaultSerial MSerial;
+ typedef ForwardSerial0Type< decltype(Serial1) > DefaultSerial1;
+ extern DefaultSerial1 MSerial1;
+
+ // MYSERIAL0 required before MarlinSerial includes!
+
+ #define __MSERIAL(X) MSerial##X
+ #define _MSERIAL(X) __MSERIAL(X)
+ #define MSERIAL(X) _MSERIAL(INCREMENT(X))
+
+ #if SERIAL_PORT == -1
+ #define MYSERIAL0 MSerial
+ #elif WITHIN(SERIAL_PORT, 0, 3)
+ #define MYSERIAL0 MSERIAL(SERIAL_PORT)
+ #else
+ #error "SERIAL_PORT must be from -1 to 3. Please update your configuration."
+ #endif
+
+ #ifdef SERIAL_PORT_2
+ #if SERIAL_PORT_2 == -1
+ #define MYSERIAL1 MSerial
+ #elif WITHIN(SERIAL_PORT_2, 0, 3)
+ #define MYSERIAL1 MSERIAL(SERIAL_PORT_2)
+ #else
+ #error "SERIAL_PORT_2 must be from -1 to 3. Please update your configuration."
+ #endif
+ #endif
+
+ #ifdef MMU2_SERIAL_PORT
+ #if MMU2_SERIAL_PORT == -1
+ #define MMU2_SERIAL MSerial
+ #elif WITHIN(MMU2_SERIAL_PORT, 0, 3)
+ #define MMU2_SERIAL MSERIAL(MMU2_SERIAL_PORT)
+ #else
+ #error "MMU2_SERIAL_PORT must be from -1 to 3. Please update your configuration."
+ #endif
+ #endif
+
+ #ifdef LCD_SERIAL_PORT
+ #if LCD_SERIAL_PORT == -1
+ #define LCD_SERIAL MSerial
+ #elif WITHIN(LCD_SERIAL_PORT, 0, 3)
+ #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT)
+ #else
+ #error "LCD_SERIAL_PORT must be from -1 to 3. Please update your configuration."
+ #endif
+ #endif
+
+#endif // ADAFRUIT_GRAND_CENTRAL_M4
+
+typedef int8_t pin_t;
+
+#define SHARED_SERVOS HAS_SERVOS
+#define HAL_SERVO_LIB Servo
+
+//
+// Interrupts
+//
+#define CRITICAL_SECTION_START() uint32_t primask = __get_PRIMASK(); __disable_irq()
+#define CRITICAL_SECTION_END() if (!primask) __enable_irq()
+#define ISRS_ENABLED() (!__get_PRIMASK())
+#define ENABLE_ISRS() __enable_irq()
+#define DISABLE_ISRS() __disable_irq()
+
+#define cli() __disable_irq() // Disable interrupts
+#define sei() __enable_irq() // Enable interrupts
+
+void HAL_clear_reset_source(); // clear reset reason
+uint8_t HAL_get_reset_source(); // get reset reason
+
+inline void HAL_reboot() {} // reboot the board or restart the bootloader
+
+//
+// ADC
+//
+extern uint16_t HAL_adc_result; // Most recent ADC conversion
+
+#define HAL_ANALOG_SELECT(pin)
+
+void HAL_adc_init();
+
+//#define HAL_ADC_FILTERED // Disable Marlin's oversampling. The HAL filters ADC values.
+#define HAL_ADC_VREF 3.3
+#define HAL_ADC_RESOLUTION 10 // ... 12
+#define HAL_START_ADC(pin) HAL_adc_start_conversion(pin)
+#define HAL_READ_ADC() HAL_adc_result
+#define HAL_ADC_READY() true
+
+void HAL_adc_start_conversion(const uint8_t adc_pin);
+
+//
+// Pin Map
+//
+#define GET_PIN_MAP_PIN(index) index
+#define GET_PIN_MAP_INDEX(pin) pin
+#define PARSED_PIN_INDEX(code, dval) parser.intval(code, dval)
+
+//
+// Tone
+//
+void toneInit();
+void tone(const pin_t _pin, const unsigned int frequency, const unsigned long duration=0);
+void noTone(const pin_t _pin);
+
+// Enable hooks into idle and setup for HAL
+void HAL_init();
+/*
+#define HAL_IDLETASK 1
+void HAL_idletask();
+*/
+
+//
+// Utility functions
+//
+FORCE_INLINE void _delay_ms(const int delay_ms) { delay(delay_ms); }
+
+#if GCC_VERSION <= 50000
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wunused-function"
+#endif
+
+int freeMemory();
+
+#if GCC_VERSION <= 50000
+ #pragma GCC diagnostic pop
+#endif
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+char *dtostrf(double __val, signed char __width, unsigned char __prec, char *__s);
+#ifdef __cplusplus
+ }
+#endif
diff --git a/Marlin/src/HAL/SAMD51/HAL_SPI.cpp b/Marlin/src/HAL/SAMD51/HAL_SPI.cpp
new file mode 100644
index 0000000..c3acd38
--- /dev/null
+++ b/Marlin/src/HAL/SAMD51/HAL_SPI.cpp
@@ -0,0 +1,148 @@
+/**
+ * Marlin 3D Printer Firmware
+ *
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician)
+ *
+ * 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 3 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * Hardware and software SPI implementations are included in this file.
+ *
+ * Control of the slave select pin(s) is handled by the calling routines and
+ * SAMD51 let hardware SPI handling to remove SS from its logic.
+ */
+
+#ifdef __SAMD51__
+
+// --------------------------------------------------------------------------
+// Includes
+// --------------------------------------------------------------------------
+
+#include "../../inc/MarlinConfig.h"
+#include <SPI.h>
+
+// --------------------------------------------------------------------------
+// Public functions
+// --------------------------------------------------------------------------
+
+#if EITHER(SOFTWARE_SPI, FORCE_SOFT_SPI)
+
+ // ------------------------
+ // Software SPI
+ // ------------------------
+ #error "Software SPI not supported for SAMD51. Use Hardware SPI."
+
+#else // !SOFTWARE_SPI
+
+ #ifdef ADAFRUIT_GRAND_CENTRAL_M4
+ #if SD_CONNECTION_IS(ONBOARD)
+ #define sdSPI SDCARD_SPI
+ #else
+ #define sdSPI SPI
+ #endif
+ #endif
+
+ static SPISettings spiConfig;
+
+ // ------------------------
+ // Hardware SPI
+ // ------------------------
+ void spiBegin() {
+ spiInit(SPI_HALF_SPEED);
+ }
+
+ void spiInit(uint8_t spiRate) {
+ // Use datarates Marlin uses
+ uint32_t clock;
+ switch (spiRate) {
+ case SPI_FULL_SPEED: clock = 8000000; break;
+ case SPI_HALF_SPEED: clock = 4000000; break;
+ case SPI_QUARTER_SPEED: clock = 2000000; break;
+ case SPI_EIGHTH_SPEED: clock = 1000000; break;
+ case SPI_SIXTEENTH_SPEED: clock = 500000; break;
+ case SPI_SPEED_5: clock = 250000; break;
+ case SPI_SPEED_6: clock = 125000; break;
+ default: clock = 4000000; break; // Default from the SPI library
+ }
+ spiConfig = SPISettings(clock, MSBFIRST, SPI_MODE0);
+ sdSPI.begin();
+ }
+
+ /**
+ * @brief Receives a single byte from the SPI port.
+ *
+ * @return Byte received
+ *
+ * @details
+ */
+ uint8_t spiRec() {
+ sdSPI.beginTransaction(spiConfig);
+ uint8_t returnByte = sdSPI.transfer(0xFF);
+ sdSPI.endTransaction();
+ return returnByte;
+ }
+
+ /**
+ * @brief Receives a number of bytes from the SPI port to a buffer
+ *
+ * @param buf Pointer to starting address of buffer to write to.
+ * @param nbyte Number of bytes to receive.
+ * @return Nothing
+ */
+ void spiRead(uint8_t* buf, uint16_t nbyte) {
+ if (nbyte == 0) return;
+ memset(buf, 0xFF, nbyte);
+ sdSPI.beginTransaction(spiConfig);
+ sdSPI.transfer(buf, nbyte);
+ sdSPI.endTransaction();
+ }
+
+ /**
+ * @brief Sends a single byte on SPI port
+ *
+ * @param b Byte to send
+ *
+ * @details
+ */
+ void spiSend(uint8_t b) {
+ sdSPI.beginTransaction(spiConfig);
+ sdSPI.transfer(b);
+ sdSPI.endTransaction();
+ }
+
+ /**
+ * @brief Write token and then write from 512 byte buffer to SPI (for SD card)
+ *
+ * @param buf Pointer with buffer start address
+ * @return Nothing
+ *
+ * @details Uses DMA
+ */
+ void spiSendBlock(uint8_t token, const uint8_t* buf) {
+ sdSPI.beginTransaction(spiConfig);
+ sdSPI.transfer(token);
+ sdSPI.transfer((uint8_t*)buf, nullptr, 512);
+ sdSPI.endTransaction();
+ }
+
+ void spiBeginTransaction(uint32_t spiClock, uint8_t bitOrder, uint8_t dataMode) {
+ spiConfig = SPISettings(spiClock, (BitOrder)bitOrder, dataMode);
+ sdSPI.beginTransaction(spiConfig);
+ }
+#endif // !SOFTWARE_SPI
+
+#endif // __SAMD51__
diff --git a/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.cpp b/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.cpp
new file mode 100644
index 0000000..ce32eaf
--- /dev/null
+++ b/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.cpp
@@ -0,0 +1,54 @@
+/**
+ * Marlin 3D Printer Firmware
+ *
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician)
+ *
+ * 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 3 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#ifdef ADAFRUIT_GRAND_CENTRAL_M4
+
+/**
+ * Framework doesn't define some serials to save sercom resources
+ * hence if these are used I need to define them
+ */
+
+#include "../../inc/MarlinConfig.h"
+
+#if USING_SERIAL_1
+ UartT Serial2(false, &sercom4, PIN_SERIAL2_RX, PIN_SERIAL2_TX, PAD_SERIAL2_RX, PAD_SERIAL2_TX);
+ void SERCOM4_0_Handler() { Serial2.IrqHandler(); }
+ void SERCOM4_1_Handler() { Serial2.IrqHandler(); }
+ void SERCOM4_2_Handler() { Serial2.IrqHandler(); }
+ void SERCOM4_3_Handler() { Serial2.IrqHandler(); }
+#endif
+
+#if USING_SERIAL_2
+ UartT Serial3(false, &sercom1, PIN_SERIAL3_RX, PIN_SERIAL3_TX, PAD_SERIAL3_RX, PAD_SERIAL3_TX);
+ void SERCOM1_0_Handler() { Serial3.IrqHandler(); }
+ void SERCOM1_1_Handler() { Serial3.IrqHandler(); }
+ void SERCOM1_2_Handler() { Serial3.IrqHandler(); }
+ void SERCOM1_3_Handler() { Serial3.IrqHandler(); }
+#endif
+
+#if USING_SERIAL_3
+ UartT Serial4(false, &sercom5, PIN_SERIAL4_RX, PIN_SERIAL4_TX, PAD_SERIAL4_RX, PAD_SERIAL4_TX);
+ void SERCOM5_0_Handler() { Serial4.IrqHandler(); }
+ void SERCOM5_1_Handler() { Serial4.IrqHandler(); }
+ void SERCOM5_2_Handler() { Serial4.IrqHandler(); }
+ void SERCOM5_3_Handler() { Serial4.IrqHandler(); }
+#endif
+
+#endif // ADAFRUIT_GRAND_CENTRAL_M4
diff --git a/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.h b/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.h
new file mode 100644
index 0000000..b729341
--- /dev/null
+++ b/Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.h
@@ -0,0 +1,29 @@
+/**
+ * Marlin 3D Printer Firmware
+ *
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician)
+ *
+ * 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 3 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include "../../core/serial_hook.h"
+
+typedef Serial0Type<Uart> UartT;
+
+extern UartT Serial2;
+extern UartT Serial3;
+extern UartT Serial4;
diff --git a/Marlin/src/HAL/SAMD51/QSPIFlash.cpp b/Marlin/src/HAL/SAMD51/QSPIFlash.cpp
new file mode 100644
index 0000000..fc21a1a
--- /dev/null
+++ b/Marlin/src/HAL/SAMD51/QSPIFlash.cpp
@@ -0,0 +1,78 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * 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 3 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "../../inc/MarlinConfig.h"
+
+#if ENABLED(QSPI_EEPROM)
+
+#include "QSPIFlash.h"
+
+#define INVALID_ADDR 0xFFFFFFFF
+#define SECTOR_OF(a) (a & ~(SFLASH_SECTOR_SIZE - 1))
+#define OFFSET_OF(a) (a & (SFLASH_SECTOR_SIZE - 1))
+
+Adafruit_SPIFlashBase * QSPIFlash::_flashBase = nullptr;
+uint8_t QSPIFlash::_buf[SFLASH_SECTOR_SIZE];
+uint32_t QSPIFlash::_addr = INVALID_ADDR;
+
+void QSPIFlash::begin() {
+ if (_flashBase) return;
+
+ _flashBase = new Adafruit_SPIFlashBase(new Adafruit_FlashTransport_QSPI());
+ _flashBase->begin(nullptr);
+}
+
+size_t QSPIFlash::size() {
+ return _flashBase->size();
+}
+
+uint8_t QSPIFlash::readByte(const uint32_t address) {
+ if (SECTOR_OF(address) == _addr) return _buf[OFFSET_OF(address)];
+
+ return _flashBase->read8(address);
+}
+
+void QSPIFlash::writeByte(const uint32_t address, const uint8_t value) {
+ uint32_t const sector_addr = SECTOR_OF(address);
+
+ // Page changes, flush old and update new cache
+ if (sector_addr != _addr) {
+ flush();
+ _addr = sector_addr;
+
+ // read a whole page from flash
+ _flashBase->readBuffer(sector_addr, _buf, SFLASH_SECTOR_SIZE);
+ }
+
+ _buf[OFFSET_OF(address)] = value;
+}
+
+void QSPIFlash::flush() {
+ if (_addr == INVALID_ADDR) return;
+
+ _flashBase->eraseSector(_addr / SFLASH_SECTOR_SIZE);
+ _flashBase->writeBuffer(_addr, _buf, SFLASH_SECTOR_SIZE);
+
+ _addr = INVALID_ADDR;
+}
+
+#endif // QSPI_EEPROM
diff --git a/Marlin/src/HAL/SAMD51/QSPIFlash.h b/Marlin/src/HAL/SAMD51/QSPIFlash.h
new file mode 100644
index 0000000..db4abec
--- /dev/null
+++ b/Marlin/src/HAL/SAMD51/QSPIFlash.h
@@ -0,0 +1,50 @@
+/**
+ * @file QSPIFlash.h
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2019 Ha Thach and Dean Miller for Adafruit Industries LLC
+ *
+ * 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.
+ *
+ * Derived from Adafruit_SPIFlash class with no SdFat references
+ */
+
+#pragma once
+
+#include <Adafruit_SPIFlashBase.h>
+
+// This class extends Adafruit_SPIFlashBase by adding caching support.
+//
+// This class will use 4096 Bytes of RAM as a block cache.
+class QSPIFlash {
+ public:
+ static void begin();
+ static size_t size();
+ static uint8_t readByte(const uint32_t address);
+ static void writeByte(const uint32_t address, const uint8_t v);
+ static void flush();
+
+ private:
+ static Adafruit_SPIFlashBase * _flashBase;
+ static uint8_t _buf[SFLASH_SECTOR_SIZE];
+ static uint32_t _addr;
+};
+
+extern QSPIFlash qspi;
diff --git a/Marlin/src/HAL/SAMD51/SAMD51.h b/Marlin/src/HAL/SAMD51/SAMD51.h
new file mode 100644
index 0000000..7839561
--- /dev/null
+++ b/Marlin/src/HAL/SAMD51/SAMD51.h
@@ -0,0 +1,70 @@
+/**
+ * Marlin 3D Printer Firmware
+ *
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician)
+ *
+ * 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 3 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#define SYNC(sc) while (sc) { \
+ asm(""); \
+ }
+
+// Get SAMD port/pin from specified arduino pin
+#define GET_SAMD_PORT(P) _GET_SAMD_PORT(PIN_TO_SAMD_PIN(P))
+#define GET_SAMD_PIN(P) _GET_SAMD_PIN(PIN_TO_SAMD_PIN(P))
+
+// Get external interrupt line associated to specified arduino pin
+#define PIN_TO_EILINE(P) _SAMDPORTPIN_TO_EILINE(GET_SAMD_PORT(P), GET_SAMD_PIN(P))
+
+// Get adc/ain associated to specified arduino pin
+#define PIN_TO_ADC(P) (ANAPIN_TO_ADCAIN(P) >> 8)
+#define PIN_TO_AIN(P) (ANAPIN_TO_ADCAIN(P) & 0xFF)
+
+// Private defines
+#define PIN_TO_SAMD_PIN(P) DIO##P##_PIN
+
+#define _GET_SAMD_PORT(P) ((P) >> 5)
+#define _GET_SAMD_PIN(P) ((P) & 0x1F)
+
+// Get external interrupt line
+#define _SAMDPORTPIN_TO_EILINE(P,B) ((P == 0 && WITHIN(B, 0, 31) && B != 8 && B != 26 && B != 28 && B != 29) ? (B) & 0xF \
+ : (P == 1 && (WITHIN(B, 0, 25) || WITHIN(B, 30, 31))) ? (B) & 0xF \
+ : (P == 1 && WITHIN(B, 26, 29)) ? 12 + (B) - 26 \
+ : (P == 2 && (WITHIN(B, 0, 6) || WITHIN(B, 10, 31)) && B != 29) ? (B) & 0xF \
+ : (P == 2 && B == 7) ? 9 \
+ : (P == 3 && WITHIN(B, 0, 1)) ? (B) \
+ : (P == 3 && WITHIN(B, 8, 12)) ? 3 + (B) - 8 \
+ : (P == 3 && WITHIN(B, 20, 21)) ? 10 + (B) - 20 \
+ : -1)
+
+// Get adc/ain
+#define ANAPIN_TO_ADCAIN(P) _PIN_TO_ADCAIN(ANAPIN_TO_SAMDPIN(P))
+#define _PIN_TO_ADCAIN(P) _SAMDPORTPIN_TO_ADCAIN(_GET_SAMD_PORT(P), _GET_SAMD_PIN(P))
+
+#define _SAMDPORTPIN_TO_ADCAIN(P,B) ((P == 0 && WITHIN(B, 2, 3)) ? 0x000 + (B) - 2 \
+ : (P == 0 && WITHIN(B, 4, 7)) ? 0x000 + (B) \
+ : (P == 0 && WITHIN(B, 8, 9)) ? 0x100 + 2 + (B) - 8 \
+ : (P == 0 && WITHIN(B, 10, 11)) ? 0x000 + (B) \
+ : (P == 1 && WITHIN(B, 0, 3)) ? 0x000 + 12 + (B) \
+ : (P == 1 && WITHIN(B, 4, 7)) ? 0x100 + 6 + (B) - 4 \
+ : (P == 1 && WITHIN(B, 8, 9)) ? 0x100 + (B) - 8 \
+ : (P == 2 && WITHIN(B, 0, 1)) ? 0x100 + 10 + (B) \
+ : (P == 2 && WITHIN(B, 2, 3)) ? 0x100 + 4 + (B) - 2 \
+ : (P == 2 && WITHIN(B, 30, 31)) ? 0x100 + 12 + (B) - 30 \
+ : (P == 3 && WITHIN(B, 0, 1)) ? 0x100 + 14 + (B) \
+ : -1)
diff --git a/Marlin/src/HAL/SAMD51/Servo.cpp b/Marlin/src/HAL/SAMD51/Servo.cpp
new file mode 100644
index 0000000..9bab8e8
--- /dev/null
+++ b/Marlin/src/HAL/SAMD51/Servo.cpp
@@ -0,0 +1,224 @@
+/**
+ * Marlin 3D Printer Firmware
+ *
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician)
+ *
+ * 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 3 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * This comes from Arduino library which at the moment is buggy and uncompilable
+ */
+
+#ifdef __SAMD51__
+
+#include "../../inc/MarlinConfig.h"
+
+#if HAS_SERVOS
+
+#include "../shared/servo.h"
+#include "../shared/servo_private.h"
+#include "SAMD51.h"
+
+#define __TC_GCLK_ID(t) TC##t##_GCLK_ID
+#define _TC_GCLK_ID(t) __TC_GCLK_ID(t)
+#define TC_GCLK_ID _TC_GCLK_ID(SERVO_TC)
+
+#define _TC_PRESCALER(d) TC_CTRLA_PRESCALER_DIV##d##_Val
+#define TC_PRESCALER(d) _TC_PRESCALER(d)
+
+#define __SERVO_IRQn(t) TC##t##_IRQn
+#define _SERVO_IRQn(t) __SERVO_IRQn(t)
+#define SERVO_IRQn _SERVO_IRQn(SERVO_TC)
+
+#define HAL_SERVO_TIMER_ISR() TC_HANDLER(SERVO_TC)
+
+#define TIMER_TCCHANNEL(t) ((t) & 1)
+#define TC_COUNTER_START_VAL 0xFFFF
+
+
+static volatile int8_t currentServoIndex[_Nbr_16timers]; // index for the servo being pulsed for each timer (or -1 if refresh interval)
+
+FORCE_INLINE static uint16_t getTimerCount() {
+ Tc * const tc = TimerConfig[SERVO_TC].pTc;
+
+ tc->COUNT16.CTRLBSET.reg = TC_CTRLBCLR_CMD_READSYNC;
+ SYNC(tc->COUNT16.SYNCBUSY.bit.CTRLB || tc->COUNT16.SYNCBUSY.bit.COUNT);
+
+ return tc->COUNT16.COUNT.reg;
+}
+
+// ----------------------------
+// Interrupt handler for the TC
+// ----------------------------
+HAL_SERVO_TIMER_ISR() {
+ Tc * const tc = TimerConfig[SERVO_TC].pTc;
+ const timer16_Sequence_t timer =
+ #ifndef _useTimer1
+ _timer2
+ #elif !defined(_useTimer2)
+ _timer1
+ #else
+ (tc->COUNT16.INTFLAG.reg & tc->COUNT16.INTENSET.reg & TC_INTFLAG_MC0) ? _timer1 : _timer2
+ #endif
+ ;
+ const uint8_t tcChannel = TIMER_TCCHANNEL(timer);
+
+ if (currentServoIndex[timer] < 0) {
+ #if defined(_useTimer1) && defined(_useTimer2)
+ if (currentServoIndex[timer ^ 1] >= 0) {
+ // Wait for both channels
+ // Clear the interrupt
+ tc->COUNT16.INTFLAG.reg = (tcChannel == 0) ? TC_INTFLAG_MC0 : TC_INTFLAG_MC1;
+ return;
+ }
+ #endif
+ tc->COUNT16.COUNT.reg = TC_COUNTER_START_VAL;
+ SYNC(tc->COUNT16.SYNCBUSY.bit.COUNT);
+ }
+ else if (SERVO_INDEX(timer, currentServoIndex[timer]) < ServoCount && SERVO(timer, currentServoIndex[timer]).Pin.isActive)
+ digitalWrite(SERVO(timer, currentServoIndex[timer]).Pin.nbr, LOW); // pulse this channel low if activated
+
+ // Select the next servo controlled by this timer
+ currentServoIndex[timer]++;
+
+ if (SERVO_INDEX(timer, currentServoIndex[timer]) < ServoCount && currentServoIndex[timer] < SERVOS_PER_TIMER) {
+ if (SERVO(timer, currentServoIndex[timer]).Pin.isActive) // check if activated
+ digitalWrite(SERVO(timer, currentServoIndex[timer]).Pin.nbr, HIGH); // it's an active channel so pulse it high
+
+ tc->COUNT16.CC[tcChannel].reg = getTimerCount() - (uint16_t)SERVO(timer, currentServoIndex[timer]).ticks;
+ }
+ else {
+ // finished all channels so wait for the refresh period to expire before starting over
+ currentServoIndex[timer] = -1; // this will get incremented at the end of the refresh period to start again at the first channel
+
+ const uint16_t tcCounterValue = getTimerCount();
+
+ if ((TC_COUNTER_START_VAL - tcCounterValue) + 4UL < usToTicks(REFRESH_INTERVAL)) // allow a few ticks to ensure the next OCR1A not missed
+ tc->COUNT16.CC[tcChannel].reg = TC_COUNTER_START_VAL - (uint16_t)usToTicks(REFRESH_INTERVAL);
+ else
+ tc->COUNT16.CC[tcChannel].reg = (uint16_t)(tcCounterValue - 4UL); // at least REFRESH_INTERVAL has elapsed
+ }
+ if (tcChannel == 0) {
+ SYNC(tc->COUNT16.SYNCBUSY.bit.CC0);
+ // Clear the interrupt
+ tc->COUNT16.INTFLAG.reg = TC_INTFLAG_MC0;
+ }
+ else {
+ SYNC(tc->COUNT16.SYNCBUSY.bit.CC1);
+ // Clear the interrupt
+ tc->COUNT16.INTFLAG.reg = TC_INTFLAG_MC1;
+ }
+}
+
+void initISR(timer16_Sequence_t timer) {
+ Tc * const tc = TimerConfig[SERVO_TC].pTc;
+ const uint8_t tcChannel = TIMER_TCCHANNEL(timer);
+
+ static bool initialized = false; // Servo TC has been initialized
+ if (!initialized) {
+ NVIC_DisableIRQ(SERVO_IRQn);
+
+ // Disable the timer
+ tc->COUNT16.CTRLA.bit.ENABLE = false;
+ SYNC(tc->COUNT16.SYNCBUSY.bit.ENABLE);
+
+ // Select GCLK0 as timer/counter input clock source
+ GCLK->PCHCTRL[TC_GCLK_ID].bit.CHEN = false;
+ SYNC(GCLK->PCHCTRL[TC_GCLK_ID].bit.CHEN);
+ GCLK->PCHCTRL[TC_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK0 | GCLK_PCHCTRL_CHEN; // 120MHz startup code programmed
+ SYNC(!GCLK->PCHCTRL[TC_GCLK_ID].bit.CHEN);
+
+ // Reset the timer
+ tc->COUNT16.CTRLA.bit.SWRST = true;
+ SYNC(tc->COUNT16.SYNCBUSY.bit.SWRST);
+ SYNC(tc->COUNT16.CTRLA.bit.SWRST);
+
+ // Set timer counter mode to 16 bits
+ tc->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16;
+
+ // Set timer counter mode as normal PWM
+ tc->COUNT16.WAVE.bit.WAVEGEN = TCC_WAVE_WAVEGEN_NPWM_Val;
+
+ // Set the prescaler factor
+ tc->COUNT16.CTRLA.bit.PRESCALER = TC_PRESCALER(SERVO_TIMER_PRESCALER);
+
+ // Count down
+ tc->COUNT16.CTRLBSET.reg = TC_CTRLBCLR_DIR;
+ SYNC(tc->COUNT16.SYNCBUSY.bit.CTRLB);
+
+ // Reset all servo indexes
+ memset((void *)currentServoIndex, 0xFF, sizeof(currentServoIndex));
+
+ // Configure interrupt request
+ NVIC_ClearPendingIRQ(SERVO_IRQn);
+ NVIC_SetPriority(SERVO_IRQn, 5);
+ NVIC_EnableIRQ(SERVO_IRQn);
+
+ initialized = true;
+ }
+
+ if (!tc->COUNT16.CTRLA.bit.ENABLE) {
+ // Reset the timer counter
+ tc->COUNT16.COUNT.reg = TC_COUNTER_START_VAL;
+ SYNC(tc->COUNT16.SYNCBUSY.bit.COUNT);
+
+ // Enable the timer and start it
+ tc->COUNT16.CTRLA.bit.ENABLE = true;
+ SYNC(tc->COUNT16.SYNCBUSY.bit.ENABLE);
+ }
+ // First interrupt request after 1 ms
+ tc->COUNT16.CC[tcChannel].reg = getTimerCount() - (uint16_t)usToTicks(1000UL);
+
+ if (tcChannel == 0 ) {
+ SYNC(tc->COUNT16.SYNCBUSY.bit.CC0);
+
+ // Clear pending match interrupt
+ tc->COUNT16.INTFLAG.reg = TC_INTENSET_MC0;
+ // Enable the match channel interrupt request
+ tc->COUNT16.INTENSET.reg = TC_INTENSET_MC0;
+ }
+ else {
+ SYNC(tc->COUNT16.SYNCBUSY.bit.CC1);
+
+ // Clear pending match interrupt
+ tc->COUNT16.INTFLAG.reg = TC_INTENSET_MC1;
+ // Enable the match channel interrupt request
+ tc->COUNT16.INTENSET.reg = TC_INTENSET_MC1;
+ }
+}
+
+void finISR(timer16_Sequence_t timer) {
+ Tc * const tc = TimerConfig[SERVO_TC].pTc;
+ const uint8_t tcChannel = TIMER_TCCHANNEL(timer);
+
+ // Disable the match channel interrupt request
+ tc->COUNT16.INTENCLR.reg = (tcChannel == 0) ? TC_INTENCLR_MC0 : TC_INTENCLR_MC1;
+
+ if (true
+ #if defined(_useTimer1) && defined(_useTimer2)
+ && (tc->COUNT16.INTENCLR.reg & (TC_INTENCLR_MC0|TC_INTENCLR_MC1)) == 0
+ #endif
+ ) {
+ // Disable the timer if not used
+ tc->COUNT16.CTRLA.bit.ENABLE = false;
+ SYNC(tc->COUNT16.SYNCBUSY.bit.ENABLE);
+ }
+}
+
+#endif // HAS_SERVOS
+
+#endif // __SAMD51__
diff --git a/Marlin/src/HAL/SAMD51/ServoTimers.h b/Marlin/src/HAL/SAMD51/ServoTimers.h
new file mode 100644
index 0000000..948d515
--- /dev/null
+++ b/Marlin/src/HAL/SAMD51/ServoTimers.h
@@ -0,0 +1,39 @@
+/**
+ * Marlin 3D Printer Firmware
+ *
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician)
+ *
+ * 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 3 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#define _useTimer1
+#define _useTimer2
+
+#define TRIM_DURATION 5 // compensation ticks to trim adjust for digitalWrite delays
+#define SERVO_TIMER_PRESCALER 64 // timer prescaler factor to 64 (avoid overflowing 16-bit clock counter, at 120MHz this is 1831 ticks per millisecond
+
+#define SERVO_TC 3
+
+typedef enum {
+ #ifdef _useTimer1
+ _timer1,
+ #endif
+ #ifdef _useTimer2
+ _timer2,
+ #endif
+ _Nbr_16timers
+} timer16_Sequence_t;
diff --git a/Marlin/src/HAL/SAMD51/eeprom_flash.cpp b/Marlin/src/HAL/SAMD51/eeprom_flash.cpp
new file mode 100644
index 0000000..871bf22
--- /dev/null
+++ b/Marlin/src/HAL/SAMD51/eeprom_flash.cpp
@@ -0,0 +1,95 @@
+/**
+ * Marlin 3D Printer Firmware
+ *
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician)
+ *
+ * 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 3 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#ifdef __SAMD51__
+
+#include "../../inc/MarlinConfig.h"
+
+#if ENABLED(FLASH_EEPROM_EMULATION)
+
+#include "../shared/eeprom_api.h"
+
+#define NVMCTRL_CMD(c) do{ \
+ SYNC(!NVMCTRL->STATUS.bit.READY); \
+ NVMCTRL->INTFLAG.bit.DONE = true; \
+ NVMCTRL->CTRLB.reg = c | NVMCTRL_CTRLB_CMDEX_KEY; \
+ SYNC(NVMCTRL->INTFLAG.bit.DONE); \
+ }while(0)
+#define NVMCTRL_FLUSH() do{ \
+ if (NVMCTRL->SEESTAT.bit.LOAD) \
+ NVMCTRL_CMD(NVMCTRL_CTRLB_CMD_SEEFLUSH); \
+ }while(0)
+
+size_t PersistentStore::capacity() {
+ const uint8_t psz = NVMCTRL->SEESTAT.bit.PSZ,
+ sblk = NVMCTRL->SEESTAT.bit.SBLK;
+
+ return (!psz && !sblk) ? 0
+ : (psz <= 2) ? (0x200 << psz)
+ : (sblk == 1 || psz == 3) ? 4096
+ : (sblk == 2 || psz == 4) ? 8192
+ : (sblk <= 4 || psz == 5) ? 16384
+ : (sblk >= 9 && psz == 7) ? 65536
+ : 32768;
+}
+
+bool PersistentStore::access_start() {
+ NVMCTRL->SEECFG.reg = NVMCTRL_SEECFG_WMODE_BUFFERED; // Buffered mode and segment reallocation active
+ if (NVMCTRL->SEESTAT.bit.RLOCK)
+ NVMCTRL_CMD(NVMCTRL_CTRLB_CMD_USEE); // Unlock E2P data write access
+ return true;
+}
+
+bool PersistentStore::access_finish() {
+ NVMCTRL_FLUSH();
+ if (!NVMCTRL->SEESTAT.bit.LOCK)
+ NVMCTRL_CMD(NVMCTRL_CTRLB_CMD_LSEE); // Lock E2P data write access
+ return true;
+}
+
+bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) {
+ while (size--) {
+ const uint8_t v = *value;
+ SYNC(NVMCTRL->SEESTAT.bit.BUSY);
+ if (NVMCTRL->INTFLAG.bit.SEESFULL)
+ NVMCTRL_FLUSH(); // Next write will trigger a sector reallocation. I need to flush 'pagebuffer'
+ ((volatile uint8_t *)SEEPROM_ADDR)[pos] = v;
+ SYNC(!NVMCTRL->INTFLAG.bit.SEEWRC);
+ crc16(crc, &v, 1);
+ pos++;
+ value++;
+ }
+ return false;
+}
+
+bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) {
+ while (size--) {
+ SYNC(NVMCTRL->SEESTAT.bit.BUSY);
+ uint8_t c = ((volatile uint8_t *)SEEPROM_ADDR)[pos];
+ if (writing) *value = c;
+ crc16(crc, &c, 1);
+ pos++;
+ value++;
+ }
+ return false;
+}
+
+#endif // FLASH_EEPROM_EMULATION
+#endif // __SAMD51__
diff --git a/Marlin/src/HAL/SAMD51/eeprom_qspi.cpp b/Marlin/src/HAL/SAMD51/eeprom_qspi.cpp
new file mode 100644
index 0000000..faa7637
--- /dev/null
+++ b/Marlin/src/HAL/SAMD51/eeprom_qspi.cpp
@@ -0,0 +1,71 @@
+/**
+ * Marlin 3D Printer Firmware
+ *
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician)
+ *
+ * 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 3 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#ifdef __SAMD51__
+
+#include "../../inc/MarlinConfig.h"
+
+#if ENABLED(QSPI_EEPROM)
+
+#include "../shared/eeprom_api.h"
+
+#include "QSPIFlash.h"
+
+static bool initialized;
+
+size_t PersistentStore::capacity() { return qspi.size(); }
+
+bool PersistentStore::access_start() {
+ if (!initialized) {
+ qspi.begin();
+ initialized = true;
+ }
+ return true;
+}
+
+bool PersistentStore::access_finish() {
+ qspi.flush();
+ return true;
+}
+
+bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) {
+ while (size--) {
+ const uint8_t v = *value;
+ qspi.writeByte(pos, v);
+ crc16(crc, &v, 1);
+ pos++;
+ value++;
+ }
+ return false;
+}
+
+bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) {
+ while (size--) {
+ uint8_t c = qspi.readByte(pos);
+ if (writing) *value = c;
+ crc16(crc, &c, 1);
+ pos++;
+ value++;
+ }
+ return false;
+}
+
+#endif // QSPI_EEPROM
+#endif // __SAMD51__
diff --git a/Marlin/src/HAL/SAMD51/eeprom_wired.cpp b/Marlin/src/HAL/SAMD51/eeprom_wired.cpp
new file mode 100644
index 0000000..d9a0225
--- /dev/null
+++ b/Marlin/src/HAL/SAMD51/eeprom_wired.cpp
@@ -0,0 +1,74 @@
+/**
+ * Marlin 3D Printer Firmware
+ *
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician)
+ *
+ * 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 3 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#ifdef __SAMD51__
+
+#include "../../inc/MarlinConfig.h"
+
+#if USE_WIRED_EEPROM
+
+/**
+ * PersistentStore for Arduino-style EEPROM interface
+ * with simple implementations supplied by Marlin.
+ */
+
+#include "../shared/eeprom_if.h"
+#include "../shared/eeprom_api.h"
+
+#ifndef MARLIN_EEPROM_SIZE
+ #error "MARLIN_EEPROM_SIZE is required for I2C / SPI EEPROM."
+#endif
+size_t PersistentStore::capacity() { return MARLIN_EEPROM_SIZE; }
+
+bool PersistentStore::access_start() { eeprom_init(); return true; }
+bool PersistentStore::access_finish() { return true; }
+
+bool PersistentStore::write_data(int &pos, const uint8_t *value, size_t size, uint16_t *crc) {
+ while (size--) {
+ const uint8_t v = *value;
+ uint8_t * const p = (uint8_t * const)pos;
+ if (v != eeprom_read_byte(p)) {
+ eeprom_write_byte(p, v);
+ delay(2);
+ if (eeprom_read_byte(p) != v) {
+ SERIAL_ECHO_MSG(STR_ERR_EEPROM_WRITE);
+ return true;
+ }
+ }
+ crc16(crc, &v, 1);
+ pos++;
+ value++;
+ }
+ return false;
+}
+
+bool PersistentStore::read_data(int &pos, uint8_t *value, size_t size, uint16_t *crc, const bool writing/*=true*/) {
+ while (size--) {
+ uint8_t c = eeprom_read_byte((uint8_t*)pos);
+ if (writing) *value = c;
+ crc16(crc, &c, 1);
+ pos++;
+ value++;
+ }
+ return false;
+}
+
+#endif // USE_WIRED_EEPROM
+#endif // __SAMD51__
diff --git a/Marlin/src/HAL/SAMD51/endstop_interrupts.h b/Marlin/src/HAL/SAMD51/endstop_interrupts.h
new file mode 100644
index 0000000..daac773
--- /dev/null
+++ b/Marlin/src/HAL/SAMD51/endstop_interrupts.h
@@ -0,0 +1,208 @@
+/**
+ * Marlin 3D Printer Firmware
+ *
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician)
+ *
+ * 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 3 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+/**
+ * Endstop interrupts for ATMEL SAMD51 based targets.
+ *
+ * On SAMD51, all pins support external interrupt capability.
+ * Any pin can be used for external interrupts, but there are some restrictions.
+ * At most 16 different external interrupts can be used at one time.
+ * Further, you can’t just pick any 16 pins to use. This is because every pin on the SAMD51
+ * connects to what is called an EXTINT line, and only one pin per EXTINT line can be used for external
+ * interrupts at a time
+ */
+
+/**
+ * Endstop Interrupts
+ *
+ * Without endstop interrupts the endstop pins must be polled continually in
+ * the temperature-ISR via endstops.update(), most of the time finding no change.
+ * With this feature endstops.update() is called only when we know that at
+ * least one endstop has changed state, saving valuable CPU cycles.
+ *
+ * This feature only works when all used endstop pins can generate an 'external interrupt'.
+ *
+ * Test whether pins issue interrupts on your board by flashing 'pin_interrupt_test.ino'.
+ * (Located in Marlin/buildroot/share/pin_interrupt_test/pin_interrupt_test.ino)
+ */
+
+#include "../../module/endstops.h"
+
+#define MATCH_EILINE(P1,P2) (P1 != P2 && PIN_TO_EILINE(P1) == PIN_TO_EILINE(P2))
+#if HAS_X_MAX
+ #define MATCH_X_MAX_EILINE(P) MATCH_EILINE(P, X_MAX_PIN)
+#else
+ #define MATCH_X_MAX_EILINE(P) false
+#endif
+#if HAS_X_MIN
+ #define MATCH_X_MIN_EILINE(P) MATCH_EILINE(P, X_MIN_PIN)
+#else
+ #define MATCH_X_MIN_EILINE(P) false
+#endif
+#if HAS_Y_MAX
+ #define MATCH_Y_MAX_EILINE(P) MATCH_EILINE(P, Y_MAX_PIN)
+#else
+ #define MATCH_Y_MAX_EILINE(P) false
+#endif
+#if HAS_Y_MIN
+ #define MATCH_Y_MIN_EILINE(P) MATCH_EILINE(P, Y_MIN_PIN)
+#else
+ #define MATCH_Y_MIN_EILINE(P) false
+#endif
+#if HAS_Z_MAX
+ #define MATCH_Z_MAX_EILINE(P) MATCH_EILINE(P, Z_MAX_PIN)
+#else
+ #define MATCH_Z_MAX_EILINE(P) false
+#endif
+#if HAS_Z_MIN
+ #define MATCH_Z_MIN_EILINE(P) MATCH_EILINE(P, Z_MIN_PIN)
+#else
+ #define MATCH_Z_MIN_EILINE(P) false
+#endif
+#if HAS_Z2_MAX
+ #define MATCH_Z2_MAX_EILINE(P) MATCH_EILINE(P, Z2_MAX_PIN)
+#else
+ #define MATCH_Z2_MAX_EILINE(P) false
+#endif
+#if HAS_Z2_MIN
+ #define MATCH_Z2_MIN_EILINE(P) MATCH_EILINE(P, Z2_MIN_PIN)
+#else
+ #define MATCH_Z2_MIN_EILINE(P) false
+#endif
+#if HAS_Z3_MAX
+ #define MATCH_Z3_MAX_EILINE(P) MATCH_EILINE(P, Z3_MAX_PIN)
+#else
+ #define MATCH_Z3_MAX_EILINE(P) false
+#endif
+#if HAS_Z3_MIN
+ #define MATCH_Z3_MIN_EILINE(P) MATCH_EILINE(P, Z3_MIN_PIN)
+#else
+ #define MATCH_Z3_MIN_EILINE(P) false
+#endif
+#if HAS_Z4_MAX
+ #define MATCH_Z4_MAX_EILINE(P) MATCH_EILINE(P, Z4_MAX_PIN)
+#else
+ #define MATCH_Z4_MAX_EILINE(P) false
+#endif
+#if HAS_Z4_MIN
+ #define MATCH_Z4_MIN_EILINE(P) MATCH_EILINE(P, Z4_MIN_PIN)
+#else
+ #define MATCH_Z4_MIN_EILINE(P) false
+#endif
+#if HAS_Z_MIN_PROBE_PIN
+ #define MATCH_Z_MIN_PROBE_EILINE(P) MATCH_EILINE(P, Z_MIN_PROBE_PIN)
+#else
+ #define MATCH_Z_MIN_PROBE_EILINE(P) false
+#endif
+#define AVAILABLE_EILINE(P) (PIN_TO_EILINE(P) != -1 \
+ && !MATCH_X_MAX_EILINE(P) && !MATCH_X_MIN_EILINE(P) \
+ && !MATCH_Y_MAX_EILINE(P) && !MATCH_Y_MIN_EILINE(P) \
+ && !MATCH_Z_MAX_EILINE(P) && !MATCH_Z_MIN_EILINE(P) \
+ && !MATCH_Z2_MAX_EILINE(P) && !MATCH_Z2_MIN_EILINE(P) \
+ && !MATCH_Z3_MAX_EILINE(P) && !MATCH_Z3_MIN_EILINE(P) \
+ && !MATCH_Z4_MAX_EILINE(P) && !MATCH_Z4_MIN_EILINE(P) \
+ && !MATCH_Z_MIN_PROBE_EILINE(P))
+
+// One ISR for all EXT-Interrupts
+void endstop_ISR() { endstops.update(); }
+
+void setup_endstop_interrupts() {
+ #define _ATTACH(P) attachInterrupt(P, endstop_ISR, CHANGE)
+ #if HAS_X_MAX
+ #if !AVAILABLE_EILINE(X_MAX_PIN)
+ #error "X_MAX_PIN has no EXTINT line available."
+ #endif
+ _ATTACH(X_MAX_PIN);
+ #endif
+ #if HAS_X_MIN
+ #if !AVAILABLE_EILINE(X_MIN_PIN)
+ #error "X_MIN_PIN has no EXTINT line available."
+ #endif
+ _ATTACH(X_MIN_PIN);
+ #endif
+ #if HAS_Y_MAX
+ #if !AVAILABLE_EILINE(Y_MAX_PIN)
+ #error "Y_MAX_PIN has no EXTINT line available."
+ #endif
+ _ATTACH(Y_MAX_PIN);
+ #endif
+ #if HAS_Y_MIN
+ #if !AVAILABLE_EILINE(Y_MIN_PIN)
+ #error "Y_MIN_PIN has no EXTINT line available."
+ #endif
+ _ATTACH(Y_MIN_PIN);
+ #endif
+ #if HAS_Z_MAX
+ #if !AVAILABLE_EILINE(Z_MAX_PIN)
+ #error "Z_MAX_PIN has no EXTINT line available."
+ #endif
+ _ATTACH(Z_MAX_PIN);
+ #endif
+ #if HAS_Z_MIN
+ #if !AVAILABLE_EILINE(Z_MIN_PIN)
+ #error "Z_MIN_PIN has no EXTINT line available."
+ #endif
+ _ATTACH(Z_MIN_PIN);
+ #endif
+ #if HAS_Z2_MAX
+ #if !AVAILABLE_EILINE(Z2_MAX_PIN)
+ #error "Z2_MAX_PIN has no EXTINT line available."
+ #endif
+ _ATTACH(Z2_MAX_PIN);
+ #endif
+ #if HAS_Z2_MIN
+ #if !AVAILABLE_EILINE(Z2_MIN_PIN)
+ #error "Z2_MIN_PIN has no EXTINT line available."
+ #endif
+ _ATTACH(Z2_MIN_PIN);
+ #endif
+ #if HAS_Z3_MAX
+ #if !AVAILABLE_EILINE(Z3_MAX_PIN)
+ #error "Z3_MAX_PIN has no EXTINT line available."
+ #endif
+ _ATTACH(Z3_MAX_PIN);
+ #endif
+ #if HAS_Z3_MIN
+ #if !AVAILABLE_EILINE(Z3_MIN_PIN)
+ #error "Z3_MIN_PIN has no EXTINT line available."
+ #endif
+ _ATTACH(Z3_MIN_PIN);
+ #endif
+ #if HAS_Z4_MAX
+ #if !AVAILABLE_EILINE(Z4_MAX_PIN)
+ #error "Z4_MAX_PIN has no EXTINT line available."
+ #endif
+ _ATTACH(Z4_MAX_PIN);
+ #endif
+ #if HAS_Z4_MIN
+ #if !AVAILABLE_EILINE(Z4_MIN_PIN)
+ #error "Z4_MIN_PIN has no EXTINT line available."
+ #endif
+ _ATTACH(Z4_MIN_PIN);
+ #endif
+ #if HAS_Z_MIN_PROBE_PIN
+ #if !AVAILABLE_EILINE(Z_MIN_PROBE_PIN)
+ #error "Z_MIN_PROBE_PIN has no EXTINT line available."
+ #endif
+ _ATTACH(Z_MIN_PROBE_PIN);
+ #endif
+}
diff --git a/Marlin/src/HAL/SAMD51/fastio.h b/Marlin/src/HAL/SAMD51/fastio.h
new file mode 100644
index 0000000..a95b7ca
--- /dev/null
+++ b/Marlin/src/HAL/SAMD51/fastio.h
@@ -0,0 +1,253 @@
+/**
+ * Marlin 3D Printer Firmware
+ *
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician)
+ *
+ * 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 3 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+/**
+ * Fast IO functions for SAMD51
+ */
+
+#include "SAMD51.h"
+
+/**
+ * Utility functions
+ */
+
+#ifndef MASK
+ #define MASK(PIN) _BV(PIN)
+#endif
+
+/**
+ * Magic I/O routines
+ *
+ * Now you can simply SET_OUTPUT(IO); WRITE(IO, HIGH); WRITE(IO, LOW);
+ */
+
+// Read a pin
+#define READ(IO) ((PORT->Group[(EPortType)GET_SAMD_PORT(IO)].IN.reg & MASK(GET_SAMD_PIN(IO))) != 0)
+
+// Write to a pin
+#define WRITE(IO,V) do{ \
+ const EPortType port = (EPortType)GET_SAMD_PORT(IO); \
+ const uint32_t mask = MASK(GET_SAMD_PIN(IO)); \
+ \
+ if (V) PORT->Group[port].OUTSET.reg = mask; \
+ else PORT->Group[port].OUTCLR.reg = mask; \
+ }while(0)
+
+// Toggle a pin
+#define TOGGLE(IO) PORT->Group[(EPortType)GET_SAMD_PORT(IO)].OUTTGL.reg = MASK(GET_SAMD_PIN(IO));
+
+// Set pin as input
+#define SET_INPUT(IO) do{ \
+ const EPortType port = (EPortType)GET_SAMD_PORT(IO); \
+ const uint32_t pin = GET_SAMD_PIN(IO); \
+ \
+ PORT->Group[port].PINCFG[pin].reg = (uint8_t)(PORT_PINCFG_INEN); \
+ PORT->Group[port].DIRCLR.reg = MASK(pin); \
+ }while(0)
+// Set pin as input with pullup
+#define SET_INPUT_PULLUP(IO) do{ \
+ const EPortType port = (EPortType)GET_SAMD_PORT(IO); \
+ const uint32_t pin = GET_SAMD_PIN(IO); \
+ const uint32_t mask = MASK(pin); \
+ \
+ PORT->Group[port].PINCFG[pin].reg = (uint8_t)(PORT_PINCFG_INEN | PORT_PINCFG_PULLEN); \
+ PORT->Group[port].DIRCLR.reg = mask; \
+ PORT->Group[port].OUTSET.reg = mask; \
+ }while(0)
+// Set pin as input with pulldown
+#define SET_INPUT_PULLDOWN(IO) do{ \
+ const EPortType port = (EPortType)GET_SAMD_PORT(IO); \
+ const uint32_t pin = GET_SAMD_PIN(IO); \
+ const uint32_t mask = MASK(pin); \
+ \
+ PORT->Group[port].PINCFG[pin].reg = (uint8_t)(PORT_PINCFG_INEN | PORT_PINCFG_PULLEN); \
+ PORT->Group[port].DIRCLR.reg = mask; \
+ PORT->Group[port].OUTCLR.reg = mask; \
+ }while(0)
+// Set pin as output (push pull)
+#define SET_OUTPUT(IO) do{ \
+ const EPortType port = (EPortType)GET_SAMD_PORT(IO); \
+ const uint32_t pin = GET_SAMD_PIN(IO); \
+ \
+ PORT->Group[port].DIRSET.reg = MASK(pin); \
+ PORT->Group[port].PINCFG[pin].reg = 0; \
+ }while(0)
+// Set pin as output (open drain)
+#define SET_OUTPUT_OD(IO) do{ \
+ const EPortType port = (EPortType)GET_SAMD_PORT(IO); \
+ const uint32_t pin = GET_SAMD_PIN(IO); \
+ \
+ PORT->Group[port].PINCFG[pin].reg = (uint8_t)(PORT_PINCFG_PULLEN); \
+ PORT->Group[port].DIRCLR.reg = MASK(pin); \
+ }while(0)
+// Set pin as PWM (push pull)
+#define SET_PWM SET_OUTPUT
+// Set pin as PWM (open drain)
+#define SET_PWM_OD SET_OUTPUT_OD
+
+// check if pin is an output
+#define IS_OUTPUT(IO) ((PORT->Group[(EPortType)GET_SAMD_PORT(IO)].DIR.reg & MASK(GET_SAMD_PIN(IO))) \
+ || (PORT->Group[(EPortType)GET_SAMD_PORT(IO)].PINCFG[GET_SAMD_PIN(IO)].reg & (PORT_PINCFG_INEN | PORT_PINCFG_PULLEN)) == PORT_PINCFG_PULLEN)
+// check if pin is an input
+#define IS_INPUT(IO) !IS_OUTPUT(IO)
+
+// Shorthand
+#define OUT_WRITE(IO,V) do{ SET_OUTPUT(IO); WRITE(IO,V); }while(0)
+#define OUT_WRITE_OD(IO,V) do{ SET_OUTPUT_OD(IO); WRITE(IO,V); }while(0)
+
+// digitalRead/Write wrappers
+#define extDigitalRead(IO) digitalRead(IO)
+#define extDigitalWrite(IO,V) digitalWrite(IO,V)
+
+/**
+ * Ports and functions
+ * Added as necessary or if I feel like it- not a comprehensive list!
+ */
+
+#ifdef ADAFRUIT_GRAND_CENTRAL_M4
+
+ /*
+ * Adafruit Grand Central M4 has a lot of PWMs the availables are listed here.
+ * Some of these share the same source and so can't be used in the same time
+ */
+ #define PWM_PIN(P) (WITHIN(P, 2, 13) || WITHIN(P, 22, 23) || WITHIN(P, 44, 45) || P == 48)
+
+ // Return fullfilled ADCx->INPUTCTRL.reg
+ #define PIN_TO_INPUTCTRL(P) ( (PIN_TO_AIN(P) == 0) ? ADC_INPUTCTRL_MUXPOS_AIN0 \
+ : (PIN_TO_AIN(P) == 1) ? ADC_INPUTCTRL_MUXPOS_AIN1 \
+ : (PIN_TO_AIN(P) == 2) ? ADC_INPUTCTRL_MUXPOS_AIN2 \
+ : (PIN_TO_AIN(P) == 3) ? ADC_INPUTCTRL_MUXPOS_AIN3 \
+ : (PIN_TO_AIN(P) == 4) ? ADC_INPUTCTRL_MUXPOS_AIN4 \
+ : (PIN_TO_AIN(P) == 5) ? ADC_INPUTCTRL_MUXPOS_AIN5 \
+ : (PIN_TO_AIN(P) == 6) ? ADC_INPUTCTRL_MUXPOS_AIN6 \
+ : (PIN_TO_AIN(P) == 7) ? ADC_INPUTCTRL_MUXPOS_AIN7 \
+ : (PIN_TO_AIN(P) == 8) ? ADC_INPUTCTRL_MUXPOS_AIN8 \
+ : (PIN_TO_AIN(P) == 9) ? ADC_INPUTCTRL_MUXPOS_AIN9 \
+ : (PIN_TO_AIN(P) == 10) ? ADC_INPUTCTRL_MUXPOS_AIN10 \
+ : (PIN_TO_AIN(P) == 11) ? ADC_INPUTCTRL_MUXPOS_AIN11 \
+ : (PIN_TO_AIN(P) == 12) ? ADC_INPUTCTRL_MUXPOS_AIN12 \
+ : (PIN_TO_AIN(P) == 13) ? ADC_INPUTCTRL_MUXPOS_AIN13 \
+ : (PIN_TO_AIN(P) == 14) ? ADC_INPUTCTRL_MUXPOS_AIN14 \
+ : ADC_INPUTCTRL_MUXPOS_AIN15)
+
+ #define ANAPIN_TO_SAMDPIN(P) ( (P == 0) ? PIN_TO_SAMD_PIN(67) \
+ : (P == 1) ? PIN_TO_SAMD_PIN(68) \
+ : (P == 2) ? PIN_TO_SAMD_PIN(69) \
+ : (P == 3) ? PIN_TO_SAMD_PIN(70) \
+ : (P == 4) ? PIN_TO_SAMD_PIN(71) \
+ : (P == 5) ? PIN_TO_SAMD_PIN(72) \
+ : (P == 6) ? PIN_TO_SAMD_PIN(73) \
+ : (P == 7) ? PIN_TO_SAMD_PIN(74) \
+ : (P == 8) ? PIN_TO_SAMD_PIN(54) \
+ : (P == 9) ? PIN_TO_SAMD_PIN(55) \
+ : (P == 10) ? PIN_TO_SAMD_PIN(56) \
+ : (P == 11) ? PIN_TO_SAMD_PIN(57) \
+ : (P == 12) ? PIN_TO_SAMD_PIN(58) \
+ : (P == 13) ? PIN_TO_SAMD_PIN(59) \
+ : (P == 14) ? PIN_TO_SAMD_PIN(60) \
+ : (P == 15) ? PIN_TO_SAMD_PIN(61) \
+ : (P == 16) ? PIN_TO_SAMD_PIN(12) \
+ : (P == 17) ? PIN_TO_SAMD_PIN(13) \
+ : PIN_TO_SAMD_PIN(9))
+
+ #define digitalPinToAnalogInput(P) (WITHIN(P, 67, 74) ? (P) - 67 : WITHIN(P, 54, 61) ? 8 + (P) - 54 : WITHIN(P, 12, 13) ? 16 + (P) - 12 : P == 9 ? 18 : -1)
+
+ /*
+ * pins
+ */
+
+ // PORTA
+ #define DIO67_PIN PIN_PA02 // A0
+ #define DIO59_PIN PIN_PA04 // A13
+ #define DIO68_PIN PIN_PA05 // A1
+ #define DIO60_PIN PIN_PA06 // A14
+ #define DIO61_PIN PIN_PA07 // A15
+ #define DIO26_PIN PIN_PA12
+ #define DIO27_PIN PIN_PA13
+ #define DIO28_PIN PIN_PA14
+ #define DIO23_PIN PIN_PA15
+ #define DIO37_PIN PIN_PA16
+ #define DIO36_PIN PIN_PA17
+ #define DIO35_PIN PIN_PA18
+ #define DIO34_PIN PIN_PA19
+ #define DIO33_PIN PIN_PA20
+ #define DIO32_PIN PIN_PA21
+ #define DIO31_PIN PIN_PA22
+ #define DIO30_PIN PIN_PA23
+ // PORTB
+ #define DIO12_PIN PIN_PB00 // A16
+ #define DIO13_PIN PIN_PB01 // A17
+ #define DIO9_PIN PIN_PB02 // A18
+ #define DIO69_PIN PIN_PB03 // A2
+ #define DIO74_PIN PIN_PB04 // A7
+ #define DIO54_PIN PIN_PB05 // A8
+ #define DIO55_PIN PIN_PB06 // A9
+ #define DIO56_PIN PIN_PB07 // A10
+ #define DIO57_PIN PIN_PB08 // A11
+ #define DIO58_PIN PIN_PB09 // A12
+ #define DIO18_PIN PIN_PB12
+ #define DIO19_PIN PIN_PB13
+ #define DIO39_PIN PIN_PB14
+ #define DIO38_PIN PIN_PB15
+ #define DIO14_PIN PIN_PB16
+ #define DIO15_PIN PIN_PB17
+ #define DIO8_PIN PIN_PB18
+ #define DIO29_PIN PIN_PB19
+ #define DIO20_PIN PIN_PB20
+ #define DIO21_PIN PIN_PB21
+ #define DIO10_PIN PIN_PB22
+ #define DIO11_PIN PIN_PB23
+ #define DIO1_PIN PIN_PB24
+ #define DIO0_PIN PIN_PB25
+ #define DIO83_PIN PIN_PB28 // SD_CS
+ #define DIO95_PIN PIN_PB31 // SD_CD
+ // PORTC
+ #define DIO70_PIN PIN_PC00 // A3
+ #define DIO71_PIN PIN_PC01 // A4
+ #define DIO72_PIN PIN_PC02 // A5
+ #define DIO73_PIN PIN_PC03 // A6
+ #define DIO48_PIN PIN_PC04
+ #define DIO49_PIN PIN_PC05
+ #define DIO46_PIN PIN_PC06
+ #define DIO47_PIN PIN_PC07
+ #define DIO45_PIN PIN_PC10
+ #define DIO44_PIN PIN_PC11
+ #define DIO41_PIN PIN_PC12
+ #define DIO40_PIN PIN_PC13
+ #define DIO43_PIN PIN_PC14
+ #define DIO42_PIN PIN_PC15
+ #define DIO25_PIN PIN_PC16
+ #define DIO24_PIN PIN_PC17
+ #define DIO2_PIN PIN_PC18
+ #define DIO3_PIN PIN_PC19
+ #define DIO4_PIN PIN_PC20
+ #define DIO5_PIN PIN_PC21
+ #define DIO16_PIN PIN_PC22
+ #define DIO17_PIN PIN_PC23
+ #define DIO88_PIN PIN_PC24 // NEOPIXEL
+ // PORTD
+ #define DIO53_PIN PIN_PD10
+ #define DIO22_PIN PIN_PD12
+ #define DIO6_PIN PIN_PD20
+ #define DIO7_PIN PIN_PD21
+
+#endif // ADAFRUIT_GRAND_CENTRAL_M4
diff --git a/Marlin/src/HAL/SAMD51/inc/Conditionals_LCD.h b/Marlin/src/HAL/SAMD51/inc/Conditionals_LCD.h
new file mode 100644
index 0000000..932348c
--- /dev/null
+++ b/Marlin/src/HAL/SAMD51/inc/Conditionals_LCD.h
@@ -0,0 +1,26 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * 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 3 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#if HAS_SPI_TFT || HAS_FSMC_TFT
+ #error "Sorry! TFT displays are not available for HAL/SAMD51."
+#endif
diff --git a/Marlin/src/HAL/SAMD51/inc/Conditionals_adv.h b/Marlin/src/HAL/SAMD51/inc/Conditionals_adv.h
new file mode 100644
index 0000000..5f1c4b1
--- /dev/null
+++ b/Marlin/src/HAL/SAMD51/inc/Conditionals_adv.h
@@ -0,0 +1,22 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * 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 3 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
diff --git a/Marlin/src/HAL/SAMD51/inc/Conditionals_post.h b/Marlin/src/HAL/SAMD51/inc/Conditionals_post.h
new file mode 100644
index 0000000..ce6d3fd
--- /dev/null
+++ b/Marlin/src/HAL/SAMD51/inc/Conditionals_post.h
@@ -0,0 +1,28 @@
+/**
+ * Marlin 3D Printer Firmware
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ *
+ * Based on Sprinter and grbl.
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
+ *
+ * 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 3 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#if USE_FALLBACK_EEPROM
+ #define FLASH_EEPROM_EMULATION
+#elif EITHER(I2C_EEPROM, SPI_EEPROM)
+ #define USE_SHARED_EEPROM 1
+#endif
diff --git a/Marlin/src/HAL/SAMD51/inc/SanityCheck.h b/Marlin/src/HAL/SAMD51/inc/SanityCheck.h
new file mode 100644
index 0000000..5d610ac
--- /dev/null
+++ b/Marlin/src/HAL/SAMD51/inc/SanityCheck.h
@@ -0,0 +1,52 @@
+/**
+ * Marlin 3D Printer Firmware
+ *
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician)
+ *
+ * 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 3 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+
+/**
+ * Test SAMD51 specific configuration values for errors at compile-time.
+ */
+
+#if ENABLED(FLASH_EEPROM_EMULATION)
+ #warning "Did you activate the SmartEEPROM? See https://github.com/GMagician/SAMD51-SmartEEprom-Manager/releases"
+#endif
+
+#if defined(ADAFRUIT_GRAND_CENTRAL_M4) && SD_CONNECTION_IS(CUSTOM_CABLE)
+ #error "No custom SD drive cable defined for this board."
+#endif
+
+#if defined(MAX6675_SCK_PIN) && defined(MAX6675_DO_PIN) && (MAX6675_SCK_PIN == SCK1 || MAX6675_DO_PIN == MISO1)
+ #error "OnBoard SPI BUS can't be shared with other devices."
+#endif
+
+#if SERVO_TC == RTC_TIMER_NUM
+ #error "Servos can't use RTC timer"
+#endif
+
+#if ENABLED(EMERGENCY_PARSER)
+ #error "EMERGENCY_PARSER is not yet implemented for SAMD51. Disable EMERGENCY_PARSER to continue."
+#endif
+
+#if ENABLED(SDIO_SUPPORT)
+ #error "SDIO_SUPPORT is not supported on SAMD51."
+#endif
+
+#if ENABLED(FAST_PWM_FAN) || SPINDLE_LASER_FREQUENCY
+ #error "Features requiring Hardware PWM (FAST_PWM_FAN, SPINDLE_LASER_FREQUENCY) are not yet supported on SAMD51."
+#endif
diff --git a/Marlin/src/HAL/SAMD51/pinsDebug.h b/Marlin/src/HAL/SAMD51/pinsDebug.h
new file mode 100644
index 0000000..81376db
--- /dev/null
+++ b/Marlin/src/HAL/SAMD51/pinsDebug.h
@@ -0,0 +1,153 @@
+/**
+ * Marlin 3D Printer Firmware
+ *
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician)
+ *
+ * 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 3 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#define NUMBER_PINS_TOTAL PINS_COUNT
+
+#define digitalRead_mod(p) extDigitalRead(p)
+#define PRINT_PORT(p) do{ SERIAL_ECHOPGM(" Port: "); sprintf_P(buffer, PSTR("%c%02ld"), 'A' + g_APinDescription[p].ulPort, g_APinDescription[p].ulPin); SERIAL_ECHO(buffer); }while (0)
+#define PRINT_ARRAY_NAME(x) do{ sprintf_P(buffer, PSTR("%-" STRINGIFY(MAX_NAME_LENGTH) "s"), pin_array[x].name); SERIAL_ECHO(buffer); }while(0)
+#define PRINT_PIN(p) do{ sprintf_P(buffer, PSTR("%3d "), p); SERIAL_ECHO(buffer); }while(0)
+#define GET_ARRAY_PIN(p) pin_array[p].pin
+#define GET_ARRAY_IS_DIGITAL(p) pin_array[p].is_digital
+#define VALID_PIN(pin) (pin >= 0 && pin < (int8_t)NUMBER_PINS_TOTAL)
+#define DIGITAL_PIN_TO_ANALOG_PIN(p) digitalPinToAnalogInput(p)
+#define IS_ANALOG(P) (DIGITAL_PIN_TO_ANALOG_PIN(P)!=-1)
+#define pwm_status(pin) digitalPinHasPWM(pin)
+#define MULTI_NAME_PAD 27 // space needed to be pretty if not first name assigned to a pin
+
+// pins that will cause hang/reset/disconnect in M43 Toggle and Watch utilities
+// uses pin index
+#define M43_NEVER_TOUCH(Q) ((Q) >= 75)
+
+bool GET_PINMODE(int8_t pin) { // 1: output, 0: input
+ const EPortType samdport = g_APinDescription[pin].ulPort;
+ const uint32_t samdpin = g_APinDescription[pin].ulPin;
+ return PORT->Group[samdport].DIR.reg & MASK(samdpin) || (PORT->Group[samdport].PINCFG[samdpin].reg & (PORT_PINCFG_INEN | PORT_PINCFG_PULLEN)) == PORT_PINCFG_PULLEN;
+}
+
+void pwm_details(int32_t pin) {
+ if (pwm_status(pin)) {
+ //uint32_t chan = g_APinDescription[pin].ulPWMChannel TODO when fast pwm is operative;
+ //SERIAL_ECHOPAIR("PWM = ", duty);
+ }
+}
+
+/**
+ * AGCM4 Board pin | PORT | Label
+ * ----------------+--------+-------
+ * 0 | PB25 | "RX0"
+ * 1 | PB24 | "TX0"
+ * 2 | PC18 |
+ * 3 | PC19 |
+ * 4 | PC20 |
+ * 5 | PC21 |
+ * 6 | PD20 |
+ * 7 | PD21 |
+ * 8 | PB18 |
+ * 9 | PB2 |
+ * 10 | PB22 |
+ * 11 | PB23 |
+ * 12 | PB0 | "A16"
+ * 13 | PB1 | LED AMBER "L" / "A17"
+ * 14 | PB16 | "TX3"
+ * 15 | PB17 | "RX3"
+ * 16 | PC22 | "TX2"
+ * 17 | PC23 | "RX2"
+ * 18 | PB12 | "TX1" / "A18"
+ * 19 | PB13 | "RX1"
+ * 20 | PB20 | "SDA"
+ * 21 | PB21 | "SCL"
+ * 22 | PD12 |
+ * 23 | PA15 |
+ * 24 | PC17 |
+ * 25 | PC16 |
+ * 26 | PA12 |
+ * 27 | PA13 |
+ * 28 | PA14 |
+ * 29 | PB19 |
+ * 30 | PA23 |
+ * 31 | PA22 |
+ * 32 | PA21 |
+ * 33 | PA20 |
+ * 34 | PA19 |
+ * 35 | PA18 |
+ * 36 | PA17 |
+ * 37 | PA16 |
+ * 38 | PB15 |
+ * 39 | PB14 |
+ * 40 | PC13 |
+ * 41 | PC12 |
+ * 42 | PC15 |
+ * 43 | PC14 |
+ * 44 | PC11 |
+ * 45 | PC10 |
+ * 46 | PC6 |
+ * 47 | PC7 |
+ * 48 | PC4 |
+ * 49 | PC5 |
+ * 50 | PD11 |
+ * 51 | PD8 |
+ * 52 | PD9 |
+ * 53 | PD10 |
+ * 54 | PB5 | "A8"
+ * 55 | PB6 | "A9"
+ * 56 | PB7 | "A10"
+ * 57 | PB8 | "A11"
+ * 58 | PB9 | "A12"
+ * 69 | PA4 | "A13"
+ * 60 | PA6 | "A14"
+ * 61 | PA7 | "A15"
+ * 62 | PB17 |
+ * 63 | PB20 |
+ * 64 | PD11 |
+ * 65 | PD8 |
+ * 66 | PD9 |
+ * 67 | PA2 | "A0" / "DAC0"
+ * 68 | PA5 | "A1" / "DAC1"
+ * 69 | PB3 | "A2"
+ * 70 | PC0 | "A3"
+ * 71 | PC1 | "A4"
+ * 72 | PC2 | "A5"
+ * 73 | PC3 | "A6"
+ * 74 | PB4 | "A7"
+ * 75 | PC31 | LED GREEN "RX"
+ * 76 | PC30 | LED GREEN "TX"
+ * 77 | PA27 | USB: Host enable
+ * 78 | PA24 | USB: D-
+ * 79 | PA25 | USB: D+
+ * 80 | PB29 | SD: MISO
+ * 81 | PB27 | SD: SCK
+ * 82 | PB26 | SD: MOSI
+ * 83 | PB28 | SD: CS
+ * 84 | PA3 | AREF
+ * 85 | PA2 | DAC0 (Duplicate)
+ * 86 | PA5 | DAC1 (Duplicate)
+ * 87 | PB1 | LED AMBER "L" (Duplicate)
+ * 88 | PC24 | NeoPixel
+ * 89 | PB10 | QSPI: SCK
+ * 90 | PB11 | QSPI: CS
+ * 91 | PA8 | QSPI: IO0
+ * 92 | PA9 | QSPI: IO1
+ * 93 | PA10 | QSPI: IO2
+ * 94 | PA11 | QSPI: IO3
+ * 95 | PB31 | SD: DETECT
+ */
diff --git a/Marlin/src/HAL/SAMD51/spi_pins.h b/Marlin/src/HAL/SAMD51/spi_pins.h
new file mode 100644
index 0000000..2a667bc
--- /dev/null
+++ b/Marlin/src/HAL/SAMD51/spi_pins.h
@@ -0,0 +1,54 @@
+/**
+ * Marlin 3D Printer Firmware
+ *
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician)
+ *
+ * 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 3 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#ifdef ADAFRUIT_GRAND_CENTRAL_M4
+
+ /*
+ * AGCM4 Default SPI Pins
+ *
+ * SS SCK MISO MOSI
+ * +-------------------------+
+ * SPI | 53 52 50 51 |
+ * SPI1 | 83 81 80 82 |
+ * +-------------------------+
+ * Any pin can be used for Chip Select (SD_SS_PIN)
+ */
+ #ifndef SD_SCK_PIN
+ #define SD_SCK_PIN 52
+ #endif
+ #ifndef SD_MISO_PIN
+ #define SD_MISO_PIN 50
+ #endif
+ #ifndef SD_MOSI_PIN
+ #define SD_MOSI_PIN 51
+ #endif
+ #ifndef SDSS
+ #define SDSS 53
+ #endif
+
+#else
+
+ #error "Unsupported board!"
+
+#endif
+
+#define SD_SS_PIN SDSS
diff --git a/Marlin/src/HAL/SAMD51/timers.cpp b/Marlin/src/HAL/SAMD51/timers.cpp
new file mode 100644
index 0000000..5c55d32
--- /dev/null
+++ b/Marlin/src/HAL/SAMD51/timers.cpp
@@ -0,0 +1,168 @@
+/**
+ * Marlin 3D Printer Firmware
+ *
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician)
+ *
+ * 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 3 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#ifdef __SAMD51__
+
+// --------------------------------------------------------------------------
+// Includes
+// --------------------------------------------------------------------------
+
+#include "../../inc/MarlinConfig.h"
+#include "ServoTimers.h" // for SERVO_TC
+
+// --------------------------------------------------------------------------
+// Local defines
+// --------------------------------------------------------------------------
+
+#define NUM_HARDWARE_TIMERS 8
+
+// --------------------------------------------------------------------------
+// Private Variables
+// --------------------------------------------------------------------------
+
+const tTimerConfig TimerConfig[NUM_HARDWARE_TIMERS+1] = {
+ { {.pTc=TC0}, TC0_IRQn, TC_PRIORITY(0) }, // 0 - stepper (assigned priority 2)
+ { {.pTc=TC1}, TC1_IRQn, TC_PRIORITY(1) }, // 1 - stepper (needed by 32 bit timers)
+ { {.pTc=TC2}, TC2_IRQn, 5 }, // 2 - tone (reserved by framework and fixed assigned priority 5)
+ { {.pTc=TC3}, TC3_IRQn, TC_PRIORITY(3) }, // 3 - servo (assigned priority 1)
+ { {.pTc=TC4}, TC4_IRQn, TC_PRIORITY(4) }, // 4 - software serial (no interrupts used)
+ { {.pTc=TC5}, TC5_IRQn, TC_PRIORITY(5) },
+ { {.pTc=TC6}, TC6_IRQn, TC_PRIORITY(6) },
+ { {.pTc=TC7}, TC7_IRQn, TC_PRIORITY(7) },
+ { {.pRtc=RTC}, RTC_IRQn, TC_PRIORITY(8) } // 8 - temperature (assigned priority 6)
+};
+
+// --------------------------------------------------------------------------
+// Private functions
+// --------------------------------------------------------------------------
+
+FORCE_INLINE void Disable_Irq(IRQn_Type irq) {
+ NVIC_DisableIRQ(irq);
+
+ // We NEED memory barriers to ensure Interrupts are actually disabled!
+ // ( https://dzone.com/articles/nvic-disabling-interrupts-on-arm-cortex-m-and-the )
+ __DSB();
+ __ISB();
+}
+
+// --------------------------------------------------------------------------
+// Public functions
+// --------------------------------------------------------------------------
+
+void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency) {
+ IRQn_Type irq = TimerConfig[timer_num].IRQ_Id;
+
+ // Disable interrupt, just in case it was already enabled
+ Disable_Irq(irq);
+
+ if (timer_num == RTC_TIMER_NUM) {
+ Rtc * const rtc = TimerConfig[timer_num].pRtc;
+
+ // Disable timer interrupt
+ rtc->MODE0.INTENCLR.reg = RTC_MODE0_INTENCLR_CMP0;
+
+ // RTC clock setup
+ OSC32KCTRL->RTCCTRL.reg = OSC32KCTRL_RTCCTRL_RTCSEL_XOSC32K; // External 32.768KHz oscillator
+
+ // Stop timer, just in case, to be able to reconfigure it
+ rtc->MODE0.CTRLA.bit.ENABLE = false;
+ SYNC(rtc->MODE0.SYNCBUSY.bit.ENABLE);
+
+ // Mode, reset counter on match
+ rtc->MODE0.CTRLA.reg = RTC_MODE0_CTRLA_MODE_COUNT32 | RTC_MODE0_CTRLA_MATCHCLR;
+
+ // Set compare value
+ rtc->MODE0.COMP[0].reg = (32768 + frequency / 2) / frequency;
+ SYNC(rtc->MODE0.SYNCBUSY.bit.COMP0);
+
+ // Enable interrupt on compare
+ rtc->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP0; // reset pending interrupt
+ rtc->MODE0.INTENSET.reg = RTC_MODE0_INTENSET_CMP0; // enable compare 0 interrupt
+
+ // And start timer
+ rtc->MODE0.CTRLA.bit.ENABLE = true;
+ SYNC(rtc->MODE0.SYNCBUSY.bit.ENABLE);
+ }
+ else {
+ Tc * const tc = TimerConfig[timer_num].pTc;
+
+ // Disable timer interrupt
+ tc->COUNT32.INTENCLR.reg = TC_INTENCLR_OVF; // disable overflow interrupt
+
+ // TCn clock setup
+ const uint8_t clockID = GCLK_CLKCTRL_IDs[TCC_INST_NUM + timer_num]; // TC clock are preceeded by TCC ones
+ GCLK->PCHCTRL[clockID].bit.CHEN = false;
+ SYNC(GCLK->PCHCTRL[clockID].bit.CHEN);
+ GCLK->PCHCTRL[clockID].reg = GCLK_PCHCTRL_GEN_GCLK0 | GCLK_PCHCTRL_CHEN; // 120MHz startup code programmed
+ SYNC(!GCLK->PCHCTRL[clockID].bit.CHEN);
+
+ // Stop timer, just in case, to be able to reconfigure it
+ tc->COUNT32.CTRLA.bit.ENABLE = false;
+ SYNC(tc->COUNT32.SYNCBUSY.bit.ENABLE);
+
+ // Reset timer
+ tc->COUNT32.CTRLA.bit.SWRST = true;
+ SYNC(tc->COUNT32.SYNCBUSY.bit.SWRST);
+
+ // Wave mode, reset counter on compare match
+ tc->COUNT32.WAVE.reg = TC_WAVE_WAVEGEN_MFRQ;
+ tc->COUNT32.CTRLA.reg = TC_CTRLA_MODE_COUNT32 | TC_CTRLA_PRESCALER_DIV1;
+ tc->COUNT32.CTRLBCLR.reg = TC_CTRLBCLR_DIR;
+ SYNC(tc->COUNT32.SYNCBUSY.bit.CTRLB);
+
+ // Set compare value
+ tc->COUNT32.CC[0].reg = (HAL_TIMER_RATE) / frequency;
+ tc->COUNT32.COUNT.reg = 0;
+
+ // Enable interrupt on compare
+ tc->COUNT32.INTFLAG.reg = TC_INTFLAG_OVF; // reset pending interrupt
+ tc->COUNT32.INTENSET.reg = TC_INTENSET_OVF; // enable overflow interrupt
+
+ // And start timer
+ tc->COUNT32.CTRLA.bit.ENABLE = true;
+ SYNC(tc->COUNT32.SYNCBUSY.bit.ENABLE);
+ }
+
+ // Finally, enable IRQ
+ NVIC_SetPriority(irq, TimerConfig[timer_num].priority);
+ NVIC_EnableIRQ(irq);
+}
+
+void HAL_timer_enable_interrupt(const uint8_t timer_num) {
+ const IRQn_Type irq = TimerConfig[timer_num].IRQ_Id;
+ NVIC_EnableIRQ(irq);
+}
+
+void HAL_timer_disable_interrupt(const uint8_t timer_num) {
+ const IRQn_Type irq = TimerConfig[timer_num].IRQ_Id;
+ Disable_Irq(irq);
+}
+
+// missing from CMSIS: Check if interrupt is enabled or not
+static bool NVIC_GetEnabledIRQ(IRQn_Type IRQn) {
+ return TEST(NVIC->ISER[uint32_t(IRQn) >> 5], uint32_t(IRQn) & 0x1F);
+}
+
+bool HAL_timer_interrupt_enabled(const uint8_t timer_num) {
+ const IRQn_Type irq = TimerConfig[timer_num].IRQ_Id;
+ return NVIC_GetEnabledIRQ(irq);
+}
+
+#endif // __SAMD51__
diff --git a/Marlin/src/HAL/SAMD51/timers.h b/Marlin/src/HAL/SAMD51/timers.h
new file mode 100644
index 0000000..dc6e38b
--- /dev/null
+++ b/Marlin/src/HAL/SAMD51/timers.h
@@ -0,0 +1,143 @@
+/**
+ * Marlin 3D Printer Firmware
+ *
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician)
+ *
+ * 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 3 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+#include <stdint.h>
+
+// --------------------------------------------------------------------------
+// Defines
+// --------------------------------------------------------------------------
+#define RTC_TIMER_NUM 8 // This is not a TC but a RTC
+
+typedef uint32_t hal_timer_t;
+#define HAL_TIMER_TYPE_MAX 0xFFFFFFFF
+
+#define HAL_TIMER_RATE F_CPU // frequency of timers peripherals
+
+#ifndef STEP_TIMER_NUM
+ #define STEP_TIMER_NUM 0 // Timer Index for Stepper
+#endif
+#ifndef PULSE_TIMER_NUM
+ #define PULSE_TIMER_NUM STEP_TIMER_NUM
+#endif
+#ifndef TEMP_TIMER_NUM
+ #define TEMP_TIMER_NUM RTC_TIMER_NUM // Timer Index for Temperature
+#endif
+
+#define TEMP_TIMER_FREQUENCY 1000 // temperature interrupt frequency
+
+#define STEPPER_TIMER_RATE HAL_TIMER_RATE // frequency of stepper timer (HAL_TIMER_RATE / STEPPER_TIMER_PRESCALE)
+#define STEPPER_TIMER_TICKS_PER_US (STEPPER_TIMER_RATE / 1000000) // stepper timer ticks per µs
+#define STEPPER_TIMER_PRESCALE (CYCLES_PER_MICROSECOND / STEPPER_TIMER_TICKS_PER_US)
+
+#define PULSE_TIMER_RATE STEPPER_TIMER_RATE
+#define PULSE_TIMER_PRESCALE STEPPER_TIMER_PRESCALE
+#define PULSE_TIMER_TICKS_PER_US STEPPER_TIMER_TICKS_PER_US
+
+#define ENABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_enable_interrupt(STEP_TIMER_NUM)
+#define DISABLE_STEPPER_DRIVER_INTERRUPT() HAL_timer_disable_interrupt(STEP_TIMER_NUM)
+#define STEPPER_ISR_ENABLED() HAL_timer_interrupt_enabled(STEP_TIMER_NUM)
+
+#define ENABLE_TEMPERATURE_INTERRUPT() HAL_timer_enable_interrupt(TEMP_TIMER_NUM)
+#define DISABLE_TEMPERATURE_INTERRUPT() HAL_timer_disable_interrupt(TEMP_TIMER_NUM)
+
+#define TC_PRIORITY(t) t == SERVO_TC ? 1 \
+ : (t == STEP_TIMER_NUM || t == PULSE_TIMER_NUM) ? 2 \
+ : (t == TEMP_TIMER_NUM) ? 6 \
+ : 7
+
+#define _TC_HANDLER(t) void TC##t##_Handler()
+#define TC_HANDLER(t) _TC_HANDLER(t)
+#ifndef HAL_STEP_TIMER_ISR
+ #define HAL_STEP_TIMER_ISR() TC_HANDLER(STEP_TIMER_NUM)
+#endif
+#if STEP_TIMER_NUM != PULSE_TIMER_NUM
+ #define HAL_PULSE_TIMER_ISR() TC_HANDLER(PULSE_TIMER_NUM)
+#endif
+#if TEMP_TIMER_NUM == RTC_TIMER_NUM
+ #define HAL_TEMP_TIMER_ISR() void RTC_Handler()
+#else
+ #define HAL_TEMP_TIMER_ISR() TC_HANDLER(TEMP_TIMER_NUM)
+#endif
+
+// --------------------------------------------------------------------------
+// Types
+// --------------------------------------------------------------------------
+
+typedef struct {
+ union {
+ Tc *pTc;
+ Rtc *pRtc;
+ };
+ IRQn_Type IRQ_Id;
+ uint8_t priority;
+} tTimerConfig;
+
+// --------------------------------------------------------------------------
+// Public Variables
+// --------------------------------------------------------------------------
+
+extern const tTimerConfig TimerConfig[];
+
+// --------------------------------------------------------------------------
+// Public functions
+// --------------------------------------------------------------------------
+
+void HAL_timer_start(const uint8_t timer_num, const uint32_t frequency);
+
+FORCE_INLINE static void HAL_timer_set_compare(const uint8_t timer_num, const hal_timer_t compare) {
+ // Should never be called with timer RTC_TIMER_NUM
+ Tc * const tc = TimerConfig[timer_num].pTc;
+ tc->COUNT32.CC[0].reg = compare;
+}
+
+FORCE_INLINE static hal_timer_t HAL_timer_get_compare(const uint8_t timer_num) {
+ // Should never be called with timer RTC_TIMER_NUM
+ Tc * const tc = TimerConfig[timer_num].pTc;
+ return (hal_timer_t)tc->COUNT32.CC[0].reg;
+}
+
+FORCE_INLINE static hal_timer_t HAL_timer_get_count(const uint8_t timer_num) {
+ // Should never be called with timer RTC_TIMER_NUM
+ Tc * const tc = TimerConfig[timer_num].pTc;
+ tc->COUNT32.CTRLBSET.reg = TC_CTRLBCLR_CMD_READSYNC;
+ SYNC(tc->COUNT32.SYNCBUSY.bit.CTRLB || tc->COUNT32.SYNCBUSY.bit.COUNT);
+ return tc->COUNT32.COUNT.reg;
+}
+
+void HAL_timer_enable_interrupt(const uint8_t timer_num);
+void HAL_timer_disable_interrupt(const uint8_t timer_num);
+bool HAL_timer_interrupt_enabled(const uint8_t timer_num);
+
+FORCE_INLINE static void HAL_timer_isr_prologue(const uint8_t timer_num) {
+ if (timer_num == RTC_TIMER_NUM) {
+ Rtc * const rtc = TimerConfig[timer_num].pRtc;
+ // Clear interrupt flag
+ rtc->MODE0.INTFLAG.reg = RTC_MODE0_INTFLAG_CMP0;
+ }
+ else {
+ Tc * const tc = TimerConfig[timer_num].pTc;
+ // Clear interrupt flag
+ tc->COUNT32.INTFLAG.reg = TC_INTFLAG_OVF;
+ }
+}
+
+#define HAL_timer_isr_epilogue(timer_num)
diff --git a/Marlin/src/HAL/SAMD51/watchdog.cpp b/Marlin/src/HAL/SAMD51/watchdog.cpp
new file mode 100644
index 0000000..9de4518
--- /dev/null
+++ b/Marlin/src/HAL/SAMD51/watchdog.cpp
@@ -0,0 +1,54 @@
+/**
+ * Marlin 3D Printer Firmware
+ *
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician)
+ *
+ * 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 3 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#ifdef __SAMD51__
+
+#include "../../inc/MarlinConfig.h"
+
+#if ENABLED(USE_WATCHDOG)
+
+#include "watchdog.h"
+
+#define WDT_TIMEOUT_REG TERN(WATCHDOG_DURATION_8S, WDT_CONFIG_PER_CYC8192, WDT_CONFIG_PER_CYC4096) // 4 or 8 second timeout
+
+void watchdog_init() {
+ // The low-power oscillator used by the WDT runs at 32,768 Hz with
+ // a 1:32 prescale, thus 1024 Hz, though probably not super precise.
+
+ // Setup WDT clocks
+ MCLK->APBAMASK.bit.OSC32KCTRL_ = true;
+ MCLK->APBAMASK.bit.WDT_ = true;
+ OSC32KCTRL->OSCULP32K.bit.EN1K = true; // Enable out 1K (this is what WDT uses)
+
+ WDT->CTRLA.bit.ENABLE = false; // Disable watchdog for config
+ SYNC(WDT->SYNCBUSY.bit.ENABLE);
+
+ WDT->INTENCLR.reg = WDT_INTENCLR_EW; // Disable early warning interrupt
+ WDT->CONFIG.reg = WDT_TIMEOUT_REG; // Set a 4s or 8s period for chip reset
+
+ HAL_watchdog_refresh();
+
+ WDT->CTRLA.reg = WDT_CTRLA_ENABLE; // Start watchdog now in normal mode
+ SYNC(WDT->SYNCBUSY.bit.ENABLE);
+}
+
+#endif // USE_WATCHDOG
+
+#endif // __SAMD51__
diff --git a/Marlin/src/HAL/SAMD51/watchdog.h b/Marlin/src/HAL/SAMD51/watchdog.h
new file mode 100644
index 0000000..2cd4788
--- /dev/null
+++ b/Marlin/src/HAL/SAMD51/watchdog.h
@@ -0,0 +1,31 @@
+/**
+ * Marlin 3D Printer Firmware
+ *
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
+ * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician)
+ *
+ * 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 3 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 <https://www.gnu.org/licenses/>.
+ *
+ */
+#pragma once
+
+// Initialize watchdog with a 4 second interrupt time
+void watchdog_init();
+
+// Reset watchdog. MUST be called at least every 4 seconds after the
+// first watchdog_init or SAMD will go into emergency procedures.
+inline void HAL_watchdog_refresh() {
+ SYNC(WDT->SYNCBUSY.bit.CLEAR); // Test first if previous is 'ongoing' to save time waiting for command execution
+ WDT->CLEAR.reg = WDT_CLEAR_CLEAR_KEY;
+}