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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  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 <https://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. #define __TC_GCLK_ID(t) TC##t##_GCLK_ID
  31. #define _TC_GCLK_ID(t) __TC_GCLK_ID(t)
  32. #define TC_GCLK_ID _TC_GCLK_ID(SERVO_TC)
  33. #define _TC_PRESCALER(d) TC_CTRLA_PRESCALER_DIV##d##_Val
  34. #define TC_PRESCALER(d) _TC_PRESCALER(d)
  35. #define __SERVO_IRQn(t) TC##t##_IRQn
  36. #define _SERVO_IRQn(t) __SERVO_IRQn(t)
  37. #define SERVO_IRQn _SERVO_IRQn(SERVO_TC)
  38. #define HAL_SERVO_TIMER_ISR() TC_HANDLER(SERVO_TC)
  39. #define TIMER_TCCHANNEL(t) ((t) & 1)
  40. #define TC_COUNTER_START_VAL 0xFFFF
  41. static volatile int8_t currentServoIndex[_Nbr_16timers]; // index for the servo being pulsed for each timer (or -1 if refresh interval)
  42. FORCE_INLINE static uint16_t getTimerCount() {
  43. Tc * const tc = timer_config[SERVO_TC].pTc;
  44. tc->COUNT16.CTRLBSET.reg = TC_CTRLBCLR_CMD_READSYNC;
  45. SYNC(tc->COUNT16.SYNCBUSY.bit.CTRLB || tc->COUNT16.SYNCBUSY.bit.COUNT);
  46. return tc->COUNT16.COUNT.reg;
  47. }
  48. // ----------------------------
  49. // Interrupt handler for the TC
  50. // ----------------------------
  51. HAL_SERVO_TIMER_ISR() {
  52. Tc * const tc = timer_config[SERVO_TC].pTc;
  53. const timer16_Sequence_t timer =
  54. #ifndef _useTimer1
  55. _timer2
  56. #elif !defined(_useTimer2)
  57. _timer1
  58. #else
  59. (tc->COUNT16.INTFLAG.reg & tc->COUNT16.INTENSET.reg & TC_INTFLAG_MC0) ? _timer1 : _timer2
  60. #endif
  61. ;
  62. const uint8_t tcChannel = TIMER_TCCHANNEL(timer);
  63. int8_t cho = currentServoIndex[timer]; // Handle the prior servo first
  64. if (cho < 0) { // Servo -1 indicates the refresh interval completed...
  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; // ...so reset the timer
  74. SYNC(tc->COUNT16.SYNCBUSY.bit.COUNT);
  75. }
  76. else if (SERVO_INDEX(timer, cho) < ServoCount) // prior channel handled?
  77. digitalWrite(SERVO(timer, cho).Pin.nbr, LOW); // pulse the prior channel LOW
  78. currentServoIndex[timer] = ++cho; // go to the next channel (or 0)
  79. if (cho < SERVOS_PER_TIMER && SERVO_INDEX(timer, cho) < ServoCount) {
  80. if (SERVO(timer, cho).Pin.isActive) // activated?
  81. digitalWrite(SERVO(timer, cho).Pin.nbr, HIGH); // yes: pulse HIGH
  82. tc->COUNT16.CC[tcChannel].reg = getTimerCount() - (uint16_t)SERVO(timer, cho).ticks;
  83. }
  84. else {
  85. // finished all channels so wait for the refresh period to expire before starting over
  86. currentServoIndex[timer] = -1; // reset the timer COUNT.reg on the next call
  87. const uint16_t cval = getTimerCount() - 256 / (SERVO_TIMER_PRESCALER), // allow 256 cycles to ensure the next CV not missed
  88. ival = (TC_COUNTER_START_VAL) - (uint16_t)usToTicks(REFRESH_INTERVAL); // at least REFRESH_INTERVAL has elapsed
  89. tc->COUNT16.CC[tcChannel].reg = min(cval, ival);
  90. }
  91. if (tcChannel == 0) {
  92. SYNC(tc->COUNT16.SYNCBUSY.bit.CC0);
  93. tc->COUNT16.INTFLAG.reg = TC_INTFLAG_MC0; // Clear the interrupt
  94. }
  95. else {
  96. SYNC(tc->COUNT16.SYNCBUSY.bit.CC1);
  97. tc->COUNT16.INTFLAG.reg = TC_INTFLAG_MC1; // Clear the interrupt
  98. }
  99. }
  100. void initISR(const timer16_Sequence_t timer) {
  101. Tc * const tc = timer_config[SERVO_TC].pTc;
  102. const uint8_t tcChannel = TIMER_TCCHANNEL(timer);
  103. static bool initialized = false; // Servo TC has been initialized
  104. if (!initialized) {
  105. NVIC_DisableIRQ(SERVO_IRQn);
  106. // Disable the timer
  107. tc->COUNT16.CTRLA.bit.ENABLE = false;
  108. SYNC(tc->COUNT16.SYNCBUSY.bit.ENABLE);
  109. // Select GCLK0 as timer/counter input clock source
  110. GCLK->PCHCTRL[TC_GCLK_ID].bit.CHEN = false;
  111. SYNC(GCLK->PCHCTRL[TC_GCLK_ID].bit.CHEN);
  112. GCLK->PCHCTRL[TC_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK0 | GCLK_PCHCTRL_CHEN; // 120MHz startup code programmed
  113. SYNC(!GCLK->PCHCTRL[TC_GCLK_ID].bit.CHEN);
  114. // Reset the timer
  115. tc->COUNT16.CTRLA.bit.SWRST = true;
  116. SYNC(tc->COUNT16.SYNCBUSY.bit.SWRST);
  117. SYNC(tc->COUNT16.CTRLA.bit.SWRST);
  118. // Set timer counter mode to 16 bits
  119. tc->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16;
  120. // Set timer counter mode as normal PWM
  121. tc->COUNT16.WAVE.bit.WAVEGEN = TCC_WAVE_WAVEGEN_NPWM_Val;
  122. // Set the prescaler factor
  123. tc->COUNT16.CTRLA.bit.PRESCALER = TC_PRESCALER(SERVO_TIMER_PRESCALER);
  124. // Count down
  125. tc->COUNT16.CTRLBSET.reg = TC_CTRLBCLR_DIR;
  126. SYNC(tc->COUNT16.SYNCBUSY.bit.CTRLB);
  127. // Reset all servo indexes
  128. memset((void *)currentServoIndex, 0xFF, sizeof(currentServoIndex));
  129. // Configure interrupt request
  130. NVIC_ClearPendingIRQ(SERVO_IRQn);
  131. NVIC_SetPriority(SERVO_IRQn, 5);
  132. NVIC_EnableIRQ(SERVO_IRQn);
  133. initialized = true;
  134. }
  135. if (!tc->COUNT16.CTRLA.bit.ENABLE) {
  136. // Reset the timer counter
  137. tc->COUNT16.COUNT.reg = TC_COUNTER_START_VAL;
  138. SYNC(tc->COUNT16.SYNCBUSY.bit.COUNT);
  139. // Enable the timer and start it
  140. tc->COUNT16.CTRLA.bit.ENABLE = true;
  141. SYNC(tc->COUNT16.SYNCBUSY.bit.ENABLE);
  142. }
  143. // First interrupt request after 1 ms
  144. tc->COUNT16.CC[tcChannel].reg = getTimerCount() - (uint16_t)usToTicks(1000UL);
  145. if (tcChannel == 0 ) {
  146. SYNC(tc->COUNT16.SYNCBUSY.bit.CC0);
  147. // Clear pending match interrupt
  148. tc->COUNT16.INTFLAG.reg = TC_INTENSET_MC0;
  149. // Enable the match channel interrupt request
  150. tc->COUNT16.INTENSET.reg = TC_INTENSET_MC0;
  151. }
  152. else {
  153. SYNC(tc->COUNT16.SYNCBUSY.bit.CC1);
  154. // Clear pending match interrupt
  155. tc->COUNT16.INTFLAG.reg = TC_INTENSET_MC1;
  156. // Enable the match channel interrupt request
  157. tc->COUNT16.INTENSET.reg = TC_INTENSET_MC1;
  158. }
  159. }
  160. void finISR(const timer16_Sequence_t timer_index) {
  161. Tc * const tc = timer_config[SERVO_TC].pTc;
  162. const uint8_t tcChannel = TIMER_TCCHANNEL(timer_index);
  163. // Disable the match channel interrupt request
  164. tc->COUNT16.INTENCLR.reg = (tcChannel == 0) ? TC_INTENCLR_MC0 : TC_INTENCLR_MC1;
  165. if (true
  166. #if defined(_useTimer1) && defined(_useTimer2)
  167. && (tc->COUNT16.INTENCLR.reg & (TC_INTENCLR_MC0|TC_INTENCLR_MC1)) == 0
  168. #endif
  169. ) {
  170. // Disable the timer if not used
  171. tc->COUNT16.CTRLA.bit.ENABLE = false;
  172. SYNC(tc->COUNT16.SYNCBUSY.bit.ENABLE);
  173. }
  174. }
  175. #endif // HAS_SERVOS
  176. #endif // __SAMD51__