123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527 |
- /**
- * 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 <http://www.gnu.org/licenses/>.
- *
- */
-
- #ifdef __SAMD51__
-
- #include "../../inc/MarlinConfig.h"
- #include <Adafruit_ZeroDMA.h>
- #include <wiring_private.h>
-
- // ------------------------
- // Local defines
- // ------------------------
-
- #if HAS_TEMP_ADC_0
- #define GET_TEMP_0_ADC() PIN_TO_ADC(TEMP_0_PIN)
- #else
- #define GET_TEMP_0_ADC() -1
- #endif
- #if HAS_TEMP_ADC_1
- #define GET_TEMP_1_ADC() PIN_TO_ADC(TEMP_1_PIN)
- #else
- #define GET_TEMP_1_ADC() -1
- #endif
- #if HAS_TEMP_ADC_2
- #define GET_TEMP_2_ADC() PIN_TO_ADC(TEMP_2_PIN)
- #else
- #define GET_TEMP_2_ADC() -1
- #endif
- #if HAS_TEMP_ADC_3
- #define GET_TEMP_3_ADC() PIN_TO_ADC(TEMP_3_PIN)
- #else
- #define GET_TEMP_3_ADC() -1
- #endif
- #if HAS_TEMP_ADC_4
- #define GET_TEMP_4_ADC() PIN_TO_ADC(TEMP_4_PIN)
- #else
- #define GET_TEMP_4_ADC() -1
- #endif
- #if HAS_TEMP_ADC_5
- #define GET_TEMP_5_ADC() PIN_TO_ADC(TEMP_5_PIN)
- #else
- #define GET_TEMP_5_ADC() -1
- #endif
- #if HAS_TEMP_ADC_6
- #define GET_TEMP_6_ADC() PIN_TO_ADC(TEMP_6_PIN)
- #else
- #define GET_TEMP_6_ADC() -1
- #endif
- #if HAS_TEMP_ADC_7
- #define GET_TEMP_7_ADC() PIN_TO_ADC(TEMP_7_PIN)
- #else
- #define GET_TEMP_7_ADC() -1
- #endif
- #if HAS_TEMP_PROBE
- #define GET_PROBE_ADC() PIN_TO_ADC(TEMP_PROBE_PIN)
- #else
- #define GET_PROBE_ADC() -1
- #endif
- #if HAS_TEMP_ADC_BED
- #define GET_BED_ADC() PIN_TO_ADC(TEMP_BED_PIN)
- #else
- #define GET_BED_ADC() -1
- #endif
- #if HAS_TEMP_ADC_CHAMBER
- #define GET_CHAMBER_ADC() PIN_TO_ADC(TEMP_CHAMBER_PIN)
- #else
- #define GET_CHAMBER_ADC() -1
- #endif
- #if ENABLED(FILAMENT_WIDTH_SENSOR)
- #define GET_FILAMENT_WIDTH_ADC() PIN_TO_ADC(FILWIDTH_PIN)
- #else
- #define GET_FILAMENT_WIDTH_ADC() -1
- #endif
- #if HAS_ADC_BUTTONS
- #define GET_BUTTONS_ADC() PIN_TO_ADC(ADC_KEYPAD_PIN)
- #else
- #define GET_BUTTONS_ADC() -1
- #endif
-
- #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 \
- )
-
- #define ADC0_IS_REQUIRED IS_ADC_REQUIRED(0)
- #define ADC1_IS_REQUIRED IS_ADC_REQUIRED(1)
- #define ADC_IS_REQUIRED (ADC0_IS_REQUIRED || ADC1_IS_REQUIRED)
- #if ADC0_IS_REQUIRED
- #define FIRST_ADC 0
- #else
- #define FIRST_ADC 1
- #endif
- #if ADC1_IS_REQUIRED
- #define LAST_ADC 1
- #else
- #define LAST_ADC 0
- #endif
-
- #define DMA_IS_REQUIRED ADC_IS_REQUIRED
-
- // ------------------------
- // 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 != nullptr)
- 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 != nullptr)
- 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() {
- #if DMA_IS_REQUIRED
- dma_init();
- #endif
- #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__
|