My Marlin configs for Fabrikator Mini and CTC i3 Pro B
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Servo.cpp 7.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. /**
  2. * Marlin 3D Printer Firmware
  3. *
  4. * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
  5. * SAMD51 HAL developed by Giuliano Zaro (AKA GMagician)
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. *
  20. */
  21. /**
  22. * This comes from Arduino library which at the moment is buggy and uncompilable
  23. */
  24. #ifdef __SAMD51__
  25. #include "../../inc/MarlinConfig.h"
  26. #if HAS_SERVOS
  27. #include "../shared/servo.h"
  28. #include "../shared/servo_private.h"
  29. #include "SAMD51.h"
  30. #include "timers.h"
  31. #define __TC_GCLK_ID(t) TC##t##_GCLK_ID
  32. #define _TC_GCLK_ID(t) __TC_GCLK_ID(t)
  33. #define TC_GCLK_ID _TC_GCLK_ID(SERVO_TC)
  34. #define _TC_PRESCALER(d) TC_CTRLA_PRESCALER_DIV##d##_Val
  35. #define TC_PRESCALER(d) _TC_PRESCALER(d)
  36. #define __SERVO_IRQn(t) TC##t##_IRQn
  37. #define _SERVO_IRQn(t) __SERVO_IRQn(t)
  38. #define SERVO_IRQn _SERVO_IRQn(SERVO_TC)
  39. #define HAL_SERVO_TIMER_ISR() TC_HANDLER(SERVO_TC)
  40. #define TIMER_TCCHANNEL(t) ((t) & 1)
  41. #define TC_COUNTER_START_VAL 0xFFFF
  42. static volatile int8_t currentServoIndex[_Nbr_16timers]; // index for the servo being pulsed for each timer (or -1 if refresh interval)
  43. FORCE_INLINE static uint16_t getTimerCount() {
  44. Tc * const tc = TimerConfig[SERVO_TC].pTc;
  45. tc->COUNT16.CTRLBSET.reg = TC_CTRLBCLR_CMD_READSYNC;
  46. SYNC(tc->COUNT16.SYNCBUSY.bit.CTRLB || tc->COUNT16.SYNCBUSY.bit.COUNT);
  47. return tc->COUNT16.COUNT.reg;
  48. }
  49. // ----------------------------
  50. // Interrupt handler for the TC
  51. // ----------------------------
  52. HAL_SERVO_TIMER_ISR() {
  53. Tc * const tc = TimerConfig[SERVO_TC].pTc;
  54. const timer16_Sequence_t timer =
  55. #ifndef _useTimer1
  56. _timer2
  57. #elif !defined(_useTimer2)
  58. _timer1
  59. #else
  60. (tc->COUNT16.INTFLAG.reg & tc->COUNT16.INTENSET.reg & TC_INTFLAG_MC0) ? _timer1 : _timer2
  61. #endif
  62. ;
  63. const uint8_t tcChannel = TIMER_TCCHANNEL(timer);
  64. if (currentServoIndex[timer] < 0) {
  65. #if defined(_useTimer1) && defined(_useTimer2)
  66. if (currentServoIndex[timer ^ 1] >= 0) {
  67. // Wait for both channels
  68. // Clear the interrupt
  69. tc->COUNT16.INTFLAG.reg = (tcChannel == 0) ? TC_INTFLAG_MC0 : TC_INTFLAG_MC1;
  70. return;
  71. }
  72. #endif
  73. tc->COUNT16.COUNT.reg = TC_COUNTER_START_VAL;
  74. SYNC(tc->COUNT16.SYNCBUSY.bit.COUNT);
  75. }
  76. else if (SERVO_INDEX(timer, currentServoIndex[timer]) < ServoCount && SERVO(timer, currentServoIndex[timer]).Pin.isActive)
  77. digitalWrite(SERVO(timer, currentServoIndex[timer]).Pin.nbr, LOW); // pulse this channel low if activated
  78. // Select the next servo controlled by this timer
  79. currentServoIndex[timer]++;
  80. if (SERVO_INDEX(timer, currentServoIndex[timer]) < ServoCount && currentServoIndex[timer] < SERVOS_PER_TIMER) {
  81. if (SERVO(timer, currentServoIndex[timer]).Pin.isActive) // check if activated
  82. digitalWrite(SERVO(timer, currentServoIndex[timer]).Pin.nbr, HIGH); // it's an active channel so pulse it high
  83. tc->COUNT16.CC[tcChannel].reg = getTimerCount() - (uint16_t)SERVO(timer, currentServoIndex[timer]).ticks;
  84. }
  85. else {
  86. // finished all channels so wait for the refresh period to expire before starting over
  87. currentServoIndex[timer] = -1; // this will get incremented at the end of the refresh period to start again at the first channel
  88. const uint16_t tcCounterValue = getTimerCount();
  89. if ((TC_COUNTER_START_VAL - tcCounterValue) + 4UL < usToTicks(REFRESH_INTERVAL)) // allow a few ticks to ensure the next OCR1A not missed
  90. tc->COUNT16.CC[tcChannel].reg = TC_COUNTER_START_VAL - (uint16_t)usToTicks(REFRESH_INTERVAL);
  91. else
  92. tc->COUNT16.CC[tcChannel].reg = (uint16_t)(tcCounterValue - 4UL); // at least REFRESH_INTERVAL has elapsed
  93. }
  94. if (tcChannel == 0) {
  95. SYNC(tc->COUNT16.SYNCBUSY.bit.CC0);
  96. // Clear the interrupt
  97. tc->COUNT16.INTFLAG.reg = TC_INTFLAG_MC0;
  98. }
  99. else {
  100. SYNC(tc->COUNT16.SYNCBUSY.bit.CC1);
  101. // Clear the interrupt
  102. tc->COUNT16.INTFLAG.reg = TC_INTFLAG_MC1;
  103. }
  104. }
  105. void initISR(timer16_Sequence_t timer) {
  106. Tc * const tc = TimerConfig[SERVO_TC].pTc;
  107. const uint8_t tcChannel = TIMER_TCCHANNEL(timer);
  108. static bool initialized = false; // Servo TC has been initialized
  109. if (!initialized) {
  110. NVIC_DisableIRQ(SERVO_IRQn);
  111. // Disable the timer
  112. tc->COUNT16.CTRLA.bit.ENABLE = false;
  113. SYNC(tc->COUNT16.SYNCBUSY.bit.ENABLE);
  114. // Select GCLK0 as timer/counter input clock source
  115. GCLK->PCHCTRL[TC_GCLK_ID].bit.CHEN = false;
  116. SYNC(GCLK->PCHCTRL[TC_GCLK_ID].bit.CHEN);
  117. GCLK->PCHCTRL[TC_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK0 | GCLK_PCHCTRL_CHEN; // 120MHz startup code programmed
  118. SYNC(!GCLK->PCHCTRL[TC_GCLK_ID].bit.CHEN);
  119. // Reset the timer
  120. tc->COUNT16.CTRLA.bit.SWRST = true;
  121. SYNC(tc->COUNT16.SYNCBUSY.bit.SWRST);
  122. SYNC(tc->COUNT16.CTRLA.bit.SWRST);
  123. // Set timer counter mode to 16 bits
  124. tc->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16;
  125. // Set timer counter mode as normal PWM
  126. tc->COUNT16.WAVE.bit.WAVEGEN = TCC_WAVE_WAVEGEN_NPWM_Val;
  127. // Set the prescaler factor
  128. tc->COUNT16.CTRLA.bit.PRESCALER = TC_PRESCALER(SERVO_TIMER_PRESCALER);
  129. // Count down
  130. tc->COUNT16.CTRLBSET.reg = TC_CTRLBCLR_DIR;
  131. SYNC(tc->COUNT16.SYNCBUSY.bit.CTRLB);
  132. // Reset all servo indexes
  133. memset((void *)currentServoIndex, 0xFF, sizeof(currentServoIndex));
  134. // Configure interrupt request
  135. NVIC_ClearPendingIRQ(SERVO_IRQn);
  136. NVIC_SetPriority(SERVO_IRQn, 5);
  137. NVIC_EnableIRQ(SERVO_IRQn);
  138. initialized = true;
  139. }
  140. if (!tc->COUNT16.CTRLA.bit.ENABLE) {
  141. // Reset the timer counter
  142. tc->COUNT16.COUNT.reg = TC_COUNTER_START_VAL;
  143. SYNC(tc->COUNT16.SYNCBUSY.bit.COUNT);
  144. // Enable the timer and start it
  145. tc->COUNT16.CTRLA.bit.ENABLE = true;
  146. SYNC(tc->COUNT16.SYNCBUSY.bit.ENABLE);
  147. }
  148. // First interrupt request after 1 ms
  149. tc->COUNT16.CC[tcChannel].reg = getTimerCount() - (uint16_t)usToTicks(1000UL);
  150. if (tcChannel == 0 ) {
  151. SYNC(tc->COUNT16.SYNCBUSY.bit.CC0);
  152. // Clear pending match interrupt
  153. tc->COUNT16.INTFLAG.reg = TC_INTENSET_MC0;
  154. // Enable the match channel interrupt request
  155. tc->COUNT16.INTENSET.reg = TC_INTENSET_MC0;
  156. }
  157. else {
  158. SYNC(tc->COUNT16.SYNCBUSY.bit.CC1);
  159. // Clear pending match interrupt
  160. tc->COUNT16.INTFLAG.reg = TC_INTENSET_MC1;
  161. // Enable the match channel interrupt request
  162. tc->COUNT16.INTENSET.reg = TC_INTENSET_MC1;
  163. }
  164. }
  165. void finISR(timer16_Sequence_t timer) {
  166. Tc * const tc = TimerConfig[SERVO_TC].pTc;
  167. const uint8_t tcChannel = TIMER_TCCHANNEL(timer);
  168. // Disable the match channel interrupt request
  169. tc->COUNT16.INTENCLR.reg = (tcChannel == 0) ? TC_INTENCLR_MC0 : TC_INTENCLR_MC1;
  170. if (true
  171. #if defined(_useTimer1) && defined(_useTimer2)
  172. && (tc->COUNT16.INTENCLR.reg & (TC_INTENCLR_MC0|TC_INTENCLR_MC1)) == 0
  173. #endif
  174. ) {
  175. // Disable the timer if not used
  176. tc->COUNT16.CTRLA.bit.ENABLE = false;
  177. SYNC(tc->COUNT16.SYNCBUSY.bit.ENABLE);
  178. }
  179. }
  180. #endif // HAS_SERVOS
  181. #endif // __SAMD51__