aboutsummaryrefslogtreecommitdiff
path: root/Marlin/src/HAL/SAMD51/HAL.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Marlin/src/HAL/SAMD51/HAL.cpp')
-rw-r--r--Marlin/src/HAL/SAMD51/HAL.cpp478
1 files changed, 478 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__