diff options
author | Georgiy Bondarenko <69736697+nehilo@users.noreply.github.com> | 2021-03-04 20:54:23 +0300 |
---|---|---|
committer | Georgiy Bondarenko <69736697+nehilo@users.noreply.github.com> | 2021-03-04 20:54:23 +0300 |
commit | e8701195e66f2d27ffe17fb514eae8173795aaf7 (patch) | |
tree | 9f519c4abf6556b9ae7190a6210d87ead1dfadde /Marlin/src/HAL/SAMD51 | |
download | kp3s-lgvl-e8701195e66f2d27ffe17fb514eae8173795aaf7.tar.xz kp3s-lgvl-e8701195e66f2d27ffe17fb514eae8173795aaf7.zip |
Initial commit
Diffstat (limited to 'Marlin/src/HAL/SAMD51')
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; +} |