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.4KB

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