SAMD51 Servo class (#14781)
This commit is contained in:
		
				
					committed by
					
						 Scott Lahteine
						Scott Lahteine
					
				
			
			
				
	
			
			
			
						parent
						
							8efa3455c2
						
					
				
				
					commit
					21993b75f4
				
			| @@ -53,8 +53,8 @@ | ||||
|  * -------------------- | ||||
|  */ | ||||
|  | ||||
| #define TRIM_DURATION       2   // compensation ticks to trim adjust for digitalWrite delays | ||||
| #define PRESCALER           8   // timer prescaler | ||||
| #define TRIM_DURATION           2   // compensation ticks to trim adjust for digitalWrite delays | ||||
| #define SERVO_TIMER_PRESCALER   8   // timer prescaler | ||||
|  | ||||
| // Say which 16 bit timers can be used and in what order | ||||
| #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) | ||||
|   | ||||
| @@ -36,8 +36,8 @@ | ||||
| //!#define _useTimer4 | ||||
| #define _useTimer5 | ||||
|  | ||||
| #define TRIM_DURATION       2    // compensation ticks to trim adjust for digitalWrite delays | ||||
| #define PRESCALER           32   // timer prescaler | ||||
| #define TRIM_DURATION             2   // compensation ticks to trim adjust for digitalWrite delays | ||||
| #define SERVO_TIMER_PRESCALER     32  // timer prescaler | ||||
|  | ||||
| /* | ||||
|   TC0, chan 0 => TC0_Handler | ||||
|   | ||||
| @@ -193,8 +193,8 @@ uint16_t HAL_adc_result; | ||||
|   uint16_t HAL_adc_results[COUNT(adc_pins)]; | ||||
|  | ||||
|   #if ADC0_IS_REQUIRED | ||||
|     Adafruit_ZeroDMA adc0ProgramDMA, | ||||
|                      adc0ReadDMA; | ||||
|     Adafruit_ZeroDMA adc0DMAProgram, | ||||
|                      adc0DMARead; | ||||
|  | ||||
|     const HAL_DMA_DAC_Registers adc0_dma_regs_list[] = { | ||||
|       #if GET_TEMP_0_ADC() == 0 | ||||
| @@ -233,8 +233,8 @@ uint16_t HAL_adc_result; | ||||
|   #endif // ADC0_IS_REQUIRED | ||||
|  | ||||
|   #if ADC1_IS_REQUIRED | ||||
|     Adafruit_ZeroDMA adc1ProgramDMA, | ||||
|                      adc1ReadDMA; | ||||
|     Adafruit_ZeroDMA adc1DMAProgram, | ||||
|                      adc1DMARead; | ||||
|  | ||||
|     const HAL_DMA_DAC_Registers adc1_dma_regs_list[] = { | ||||
|       #if GET_TEMP_0_ADC() == 1 | ||||
| @@ -284,11 +284,11 @@ uint16_t HAL_adc_result; | ||||
|     DmacDescriptor *descriptor; | ||||
|  | ||||
|     #if ADC0_IS_REQUIRED | ||||
|       adc0ProgramDMA.setTrigger(ADC0_DMAC_ID_SEQ); | ||||
|       adc0ProgramDMA.setAction(DMA_TRIGGER_ACTON_BEAT); | ||||
|       adc0ProgramDMA.loop(true); | ||||
|       if (adc0ProgramDMA.allocate() == DMA_STATUS_OK) { | ||||
|         descriptor = adc0ProgramDMA.addDescriptor( | ||||
|       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 | ||||
| @@ -300,14 +300,14 @@ uint16_t HAL_adc_result; | ||||
|         ); | ||||
|         if (descriptor != nullptr) | ||||
|           descriptor->BTCTRL.bit.EVOSEL = DMA_EVENT_OUTPUT_BEAT; | ||||
|         adc0ProgramDMA.startJob(); | ||||
|         adc0DMAProgram.startJob(); | ||||
|       } | ||||
|  | ||||
|       adc0ReadDMA.setTrigger(ADC0_DMAC_ID_RESRDY); | ||||
|       adc0ReadDMA.setAction(DMA_TRIGGER_ACTON_BEAT); | ||||
|       adc0ReadDMA.loop(true); | ||||
|       if (adc0ReadDMA.allocate() == DMA_STATUS_OK) { | ||||
|         adc0ReadDMA.addDescriptor( | ||||
|       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 | ||||
| @@ -317,15 +317,15 @@ uint16_t HAL_adc_result; | ||||
|           DMA_ADDRESS_INCREMENT_STEP_SIZE_1,  // STEPSIZE | ||||
|           DMA_STEPSEL_DST                     // STEPSEL | ||||
|         ); | ||||
|         adc0ReadDMA.startJob(); | ||||
|         adc0DMARead.startJob(); | ||||
|       } | ||||
|     #endif | ||||
|     #if ADC1_IS_REQUIRED | ||||
|       adc1ProgramDMA.setTrigger(ADC1_DMAC_ID_SEQ); | ||||
|       adc1ProgramDMA.setAction(DMA_TRIGGER_ACTON_BEAT); | ||||
|       adc1ProgramDMA.loop(true); | ||||
|       if (adc1ProgramDMA.allocate() == DMA_STATUS_OK) { | ||||
|         descriptor = adc1ProgramDMA.addDescriptor( | ||||
|       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 | ||||
| @@ -337,14 +337,14 @@ uint16_t HAL_adc_result; | ||||
|         ); | ||||
|         if (descriptor != nullptr) | ||||
|           descriptor->BTCTRL.bit.EVOSEL = DMA_EVENT_OUTPUT_BEAT; | ||||
|         adc1ProgramDMA.startJob(); | ||||
|         adc1DMAProgram.startJob(); | ||||
|       } | ||||
|  | ||||
|       adc1ReadDMA.setTrigger(ADC1_DMAC_ID_RESRDY); | ||||
|       adc1ReadDMA.setAction(DMA_TRIGGER_ACTON_BEAT); | ||||
|       adc1ReadDMA.loop(true); | ||||
|       if (adc1ReadDMA.allocate() == DMA_STATUS_OK) { | ||||
|         adc1ReadDMA.addDescriptor( | ||||
|       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 | ||||
| @@ -354,11 +354,11 @@ uint16_t HAL_adc_result; | ||||
|           DMA_ADDRESS_INCREMENT_STEP_SIZE_1,  // STEPSIZE | ||||
|           DMA_STEPSEL_DST                     // STEPSEL | ||||
|         ); | ||||
|         adc1ReadDMA.startJob(); | ||||
|         adc1DMARead.startJob(); | ||||
|       } | ||||
|     #endif | ||||
|  | ||||
|     DMAC->PRICTRL0.bit.RRLVLEN0 = true;                         // Activate round robin for DMA channels used by ADCs | ||||
|     DMAC->PRICTRL0.bit.RRLVLEN0 = true;                         // Activate round robin for DMA channels required by ADCs | ||||
|   } | ||||
|  | ||||
| #endif // DMA_IS_REQUIRED | ||||
|   | ||||
| @@ -76,7 +76,8 @@ | ||||
|  | ||||
| typedef int8_t pin_t; | ||||
|  | ||||
| //#define HAL_SERVO_LIB Servo | ||||
| #define SHARED_SERVOS HAS_SERVOS | ||||
| #define HAL_SERVO_LIB Servo | ||||
|  | ||||
| // | ||||
| // Interrupts | ||||
|   | ||||
| @@ -40,8 +40,8 @@ | ||||
| const tTimerConfig TimerConfig[NUM_HARDWARE_TIMERS] = { | ||||
|   { TC0, TC0_IRQn, TC_PRIORITY(0) }, | ||||
|   { TC1, TC1_IRQn, TC_PRIORITY(1) }, | ||||
|   { TC2, TC2_IRQn, TC_PRIORITY(2) }, | ||||
|   { TC3, TC3_IRQn, TC_PRIORITY(3) }, | ||||
|   { TC2, TC2_IRQn, TC_PRIORITY(2) },  // Reserved by framework tone function | ||||
|   { TC3, TC3_IRQn, TC_PRIORITY(3) },  // Reserved by servo library | ||||
|   { TC4, TC4_IRQn, TC_PRIORITY(4) }, | ||||
|   { TC5, TC5_IRQn, TC_PRIORITY(5) }, | ||||
|   { TC6, TC6_IRQn, TC_PRIORITY(6) }, | ||||
|   | ||||
| @@ -33,7 +33,6 @@ typedef uint32_t hal_timer_t; | ||||
|  | ||||
| #define STEP_TIMER_NUM      0  // index of timer to use for stepper (also +1 for 32bits counter) | ||||
| #define PULSE_TIMER_NUM     STEP_TIMER_NUM | ||||
| #define TONE_TIMER_NUM      2  // index of timer to use for beeper tones (also +1 for 32bits counter) | ||||
| #define TEMP_TIMER_NUM      4  // index of timer to use for temperature (also +1 for 32bits counter) | ||||
|  | ||||
| #define TEMP_TIMER_FREQUENCY   1000 // temperature interrupt frequency | ||||
| @@ -53,9 +52,10 @@ typedef uint32_t hal_timer_t; | ||||
| #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 == STEP_TIMER_NUM || t == PULSE_TIMER_NUM) ? 2     \ | ||||
|                                : (t == TEMP_TIMER_NUM) ? 6                          \ | ||||
|                                : (t == TONE_TIMER_NUM) ? 5 : 7 | ||||
| #define TC_PRIORITY(t)        (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) | ||||
| #define HAL_STEP_TIMER_ISR()  TC_HANDLER(STEP_TIMER_NUM) | ||||
| @@ -63,7 +63,6 @@ typedef uint32_t hal_timer_t; | ||||
|   #define HAL_PULSE_TIMER_ISR()  TC_HANDLER(PULSE_TIMER_NUM) | ||||
| #endif | ||||
| #define HAL_TEMP_TIMER_ISR()  TC_HANDLER(TEMP_TIMER_NUM) | ||||
| #define HAL_TONE_TIMER_ISR()  TC_HANDLER(TONE_TIMER_NUM) | ||||
|  | ||||
| // -------------------------------------------------------------------------- | ||||
| // Types | ||||
|   | ||||
| @@ -20,8 +20,8 @@ | ||||
|  */ | ||||
| #pragma once | ||||
|  | ||||
| #define SYNC(sc)    while (sc) {   \ | ||||
|                       asm("");     \ | ||||
| #define SYNC(sc)    while (sc) {  \ | ||||
|                       asm("");    \ | ||||
|                     } | ||||
|  | ||||
| // Get SAMD port/pin from specified arduino pin | ||||
|   | ||||
							
								
								
									
										39
									
								
								Marlin/src/HAL/HAL_SAMD51/ServoTimers.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								Marlin/src/HAL/HAL_SAMD51/ServoTimers.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| /** | ||||
|  * Marlin 3D Printer Firmware | ||||
|  * | ||||
|  * Copyright (C) 2019 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/>. | ||||
|  * | ||||
|  */ | ||||
| #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; | ||||
							
								
								
									
										226
									
								
								Marlin/src/HAL/HAL_SAMD51/Servo_SAMD51.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										226
									
								
								Marlin/src/HAL/HAL_SAMD51/Servo_SAMD51.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,226 @@ | ||||
| /** | ||||
|  * Marlin 3D Printer Firmware | ||||
|  * | ||||
|  * Copyright (C) 2019 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/>. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * This comes from Arduino library which at the moment is buggy and uncompilable | ||||
|  */ | ||||
|  | ||||
| #ifdef __SAMD51__ | ||||
|  | ||||
| #include "../../inc/MarlinConfig.h" | ||||
|  | ||||
| #if HAS_SERVOS | ||||
|  | ||||
| #include "../shared/Marduino.h" | ||||
| #include "../shared/servo.h" | ||||
| #include "../shared/servo_private.h" | ||||
| #include "SAMD51.h" | ||||
| #include "HAL_timers_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].pTimer; | ||||
|  | ||||
|   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].pTimer; | ||||
|   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].pTimer; | ||||
|   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(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].pTimer; | ||||
|   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__ | ||||
| @@ -1,59 +0,0 @@ | ||||
| /** | ||||
|  * Marlin 3D Printer Firmware | ||||
|  * | ||||
|  * Copyright (C) 2019 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/>. | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| /** | ||||
|  * Description: Tone function for Arduino Due and compatible (SAM3X8E) | ||||
|  * Derived from http://forum.arduino.cc/index.php?topic=136500.msg2903012#msg2903012 | ||||
|  */ | ||||
|  | ||||
| #ifdef __SAMD51__ | ||||
|  | ||||
| #include "../../inc/MarlinConfig.h" | ||||
| #include "HAL_timers_SAMD51.h" | ||||
|  | ||||
| static pin_t tone_pin; | ||||
| volatile static int32_t toggles; | ||||
|  | ||||
| void tone(const pin_t _pin, const unsigned int frequency, const unsigned long duration) { | ||||
|   tone_pin = _pin; | ||||
|   toggles = 2 * frequency * duration / 1000; | ||||
|   HAL_timer_start(TONE_TIMER_NUM, 2 * frequency); | ||||
| } | ||||
|  | ||||
| void noTone(const pin_t _pin) { | ||||
|   HAL_timer_disable_interrupt(TONE_TIMER_NUM); | ||||
|   extDigitalWrite(_pin, LOW); | ||||
| } | ||||
|  | ||||
| HAL_TONE_TIMER_ISR() { | ||||
|   static bool pin_state = false; | ||||
|   HAL_timer_isr_prologue(TONE_TIMER_NUM); | ||||
|  | ||||
|   if (toggles) { | ||||
|     toggles--; | ||||
|     extDigitalWrite(tone_pin, (pin_state = !pin_state)); | ||||
|   } | ||||
|   else noTone(tone_pin);                         // turn off interrupt | ||||
|  | ||||
|   HAL_timer_isr_epilogue(TONE_TIMER_NUM); | ||||
| } | ||||
|  | ||||
| #endif // __SAMD51__ | ||||
| @@ -32,8 +32,6 @@ | ||||
|  | ||||
| #define NUM_HARDWARE_TIMERS 2 | ||||
|  | ||||
| //#define PRESCALER 1 | ||||
|  | ||||
| // ------------------------ | ||||
| // Private Variables | ||||
| // ------------------------ | ||||
|   | ||||
| @@ -33,8 +33,6 @@ | ||||
| #define STEP_TIMER_IRQ_ID TIM5_IRQn | ||||
| #define TEMP_TIMER_IRQ_ID TIM7_IRQn | ||||
|  | ||||
| //#define PRESCALER 1 | ||||
|  | ||||
| // ------------------------ | ||||
| // Private Variables | ||||
| // ------------------------ | ||||
|   | ||||
| @@ -116,9 +116,8 @@ void Servo::detach() { | ||||
| } | ||||
|  | ||||
| void Servo::write(int value) { | ||||
|   if (value < MIN_PULSE_WIDTH) { // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds) | ||||
|   if (value < MIN_PULSE_WIDTH)    // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds) | ||||
|     value = map(constrain(value, 0, 180), 0, 180, SERVO_MIN(), SERVO_MAX()); | ||||
|   } | ||||
|   this->writeMicroseconds(value); | ||||
| } | ||||
|  | ||||
| @@ -140,7 +139,7 @@ void Servo::writeMicroseconds(int value) { | ||||
| int Servo::read() { return map(this->readMicroseconds() + 1, SERVO_MIN(), SERVO_MAX(), 0, 180); } | ||||
|  | ||||
| int Servo::readMicroseconds() { | ||||
|   return (this->servoIndex == INVALID_SERVO) ? 0 : ticksToUs(servo_info[this->servoIndex].ticks) + TRIM_DURATION; | ||||
|   return (this->servoIndex == INVALID_SERVO) ? 0 : ticksToUs(servo_info[this->servoIndex].ticks) + (TRIM_DURATION); | ||||
| } | ||||
|  | ||||
| bool Servo::attached() { return servo_info[this->servoIndex].Pin.isActive; } | ||||
|   | ||||
| @@ -84,10 +84,10 @@ | ||||
| #else | ||||
|   #include <stdint.h> | ||||
|  | ||||
|   #if defined(__AVR__) || defined(ARDUINO_ARCH_SAM) | ||||
|   #if defined(__AVR__) || defined(ARDUINO_ARCH_SAM) || defined (__SAMD51__) | ||||
|     // we're good to go | ||||
|   #else | ||||
|     #error "This library only supports boards with an AVR or SAM3X processor." | ||||
|     #error "This library only supports boards with an AVR, SAM3X or SAMD51 processor." | ||||
|   #endif | ||||
|  | ||||
|   #define Servo_VERSION           2     // software version of this library | ||||
|   | ||||
| @@ -47,8 +47,10 @@ | ||||
|   #include "../HAL_AVR/ServoTimers.h" | ||||
| #elif defined(ARDUINO_ARCH_SAM) | ||||
|   #include "../HAL_DUE/ServoTimers.h" | ||||
| #elif defined(__SAMD51__) | ||||
|   #include "../HAL_SAMD51/ServoTimers.h" | ||||
| #else | ||||
|   #error "This library only supports boards with an AVR or SAM3X processor." | ||||
|   #error "This library only supports boards with an AVR, SAM3X or SAMD51 processor." | ||||
| #endif | ||||
|  | ||||
| // Macros | ||||
| @@ -64,10 +66,8 @@ | ||||
| #define INVALID_SERVO         255     // flag indicating an invalid servo index | ||||
|  | ||||
| // Convert microseconds to ticks and back (PRESCALER depends on architecture) | ||||
| #define usToTicks(_us)    (clockCyclesPerMicrosecond() * (_us) / (PRESCALER)) | ||||
| #define ticksToUs(_ticks) (unsigned(_ticks) * (PRESCALER) / clockCyclesPerMicrosecond()) | ||||
|  | ||||
| //#define NBR_TIMERS        ((MAX_SERVOS) / (SERVOS_PER_TIMER)) | ||||
| #define usToTicks(_us)    (clockCyclesPerMicrosecond() * (_us) / (SERVO_TIMER_PRESCALER)) | ||||
| #define ticksToUs(_ticks) (unsigned(_ticks) * (SERVO_TIMER_PRESCALER) / clockCyclesPerMicrosecond()) | ||||
|  | ||||
| // convenience macros | ||||
| #define SERVO_INDEX_TO_TIMER(_servo_nbr) ((timer16_Sequence_t)(_servo_nbr / (SERVOS_PER_TIMER))) // returns the timer controlling this servo | ||||
| @@ -78,7 +78,7 @@ | ||||
| // Types | ||||
|  | ||||
| typedef struct { | ||||
|   uint8_t nbr        : 6 ;            // a pin number from 0 to 63 | ||||
|   uint8_t nbr        : 7 ;            // a pin number from 0 to 127 | ||||
|   uint8_t isActive   : 1 ;            // true if this channel is enabled, pin not pulsed if false | ||||
| } ServoPin_t; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user