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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  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. * Copyright (c) 2017 Victor Perez
  8. *
  9. * This program is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License as published by
  11. * the Free Software Foundation, either version 3 of the License, or
  12. * (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. *
  22. */
  23. #ifdef __STM32F1__
  24. #include "../../inc/MarlinConfig.h"
  25. #if HAS_SERVOS
  26. uint8_t ServoCount = 0;
  27. #include "Servo.h"
  28. #include "timers.h"
  29. //#include "Servo.h"
  30. #include <boards.h>
  31. #include <io.h>
  32. #include <pwm.h>
  33. #include <wirish_math.h>
  34. /**
  35. * 20 millisecond period config. For a 1-based prescaler,
  36. *
  37. * (prescaler * overflow / CYC_MSEC) msec = 1 timer cycle = 20 msec
  38. * => prescaler * overflow = 20 * CYC_MSEC
  39. *
  40. * This uses the smallest prescaler that allows an overflow < 2^16.
  41. */
  42. #define MAX_OVERFLOW UINT16_MAX //((1 << 16) - 1)
  43. #define CYC_MSEC (1000 * CYCLES_PER_MICROSECOND)
  44. #define TAU_MSEC 20
  45. #define TAU_USEC (TAU_MSEC * 1000)
  46. #define TAU_CYC (TAU_MSEC * CYC_MSEC)
  47. #define SERVO_PRESCALER (TAU_CYC / MAX_OVERFLOW + 1)
  48. #define SERVO_OVERFLOW ((uint16_t)round((double)TAU_CYC / SERVO_PRESCALER))
  49. // Unit conversions
  50. #define US_TO_COMPARE(us) uint16_t(map((us), 0, TAU_USEC, 0, SERVO_OVERFLOW))
  51. #define COMPARE_TO_US(c) uint32_t(map((c), 0, SERVO_OVERFLOW, 0, TAU_USEC))
  52. #define ANGLE_TO_US(a) uint16_t(map((a), minAngle, maxAngle, SERVO_DEFAULT_MIN_PW, SERVO_DEFAULT_MAX_PW))
  53. #define US_TO_ANGLE(us) int16_t(map((us), SERVO_DEFAULT_MIN_PW, SERVO_DEFAULT_MAX_PW, minAngle, maxAngle))
  54. void libServo::servoWrite(uint8_t inPin, uint16_t duty_cycle) {
  55. #ifdef SERVO0_TIMER_NUM
  56. if (servoIndex == 0) {
  57. pwmSetDuty(duty_cycle);
  58. return;
  59. }
  60. #endif
  61. timer_dev *tdev = PIN_MAP[inPin].timer_device;
  62. uint8_t tchan = PIN_MAP[inPin].timer_channel;
  63. if (tdev) timer_set_compare(tdev, tchan, duty_cycle);
  64. }
  65. libServo::libServo() {
  66. servoIndex = ServoCount < MAX_SERVOS ? ServoCount++ : INVALID_SERVO;
  67. }
  68. bool libServo::attach(const int32_t inPin, const int32_t inMinAngle, const int32_t inMaxAngle) {
  69. if (servoIndex >= MAX_SERVOS) return false;
  70. if (inPin >= BOARD_NR_GPIO_PINS) return false;
  71. minAngle = inMinAngle;
  72. maxAngle = inMaxAngle;
  73. angle = -1;
  74. #ifdef SERVO0_TIMER_NUM
  75. if (servoIndex == 0 && setupSoftPWM(inPin)) {
  76. pin = inPin; // set attached()
  77. return true;
  78. }
  79. #endif
  80. if (!PWM_PIN(inPin)) return false;
  81. timer_dev *tdev = PIN_MAP[inPin].timer_device;
  82. //uint8_t tchan = PIN_MAP[inPin].timer_channel;
  83. SET_PWM(inPin);
  84. servoWrite(inPin, 0);
  85. timer_pause(tdev);
  86. timer_set_prescaler(tdev, SERVO_PRESCALER - 1); // prescaler is 1-based
  87. timer_set_reload(tdev, SERVO_OVERFLOW);
  88. timer_generate_update(tdev);
  89. timer_resume(tdev);
  90. pin = inPin; // set attached()
  91. return true;
  92. }
  93. bool libServo::detach() {
  94. if (!attached()) return false;
  95. angle = -1;
  96. servoWrite(pin, 0);
  97. return true;
  98. }
  99. int32_t libServo::read() const {
  100. if (attached()) {
  101. #ifdef SERVO0_TIMER_NUM
  102. if (servoIndex == 0) return angle;
  103. #endif
  104. timer_dev *tdev = PIN_MAP[pin].timer_device;
  105. uint8_t tchan = PIN_MAP[pin].timer_channel;
  106. return US_TO_ANGLE(COMPARE_TO_US(timer_get_compare(tdev, tchan)));
  107. }
  108. return 0;
  109. }
  110. void libServo::move(const int32_t value) {
  111. constexpr uint16_t servo_delay[] = SERVO_DELAY;
  112. static_assert(COUNT(servo_delay) == NUM_SERVOS, "SERVO_DELAY must be an array NUM_SERVOS long.");
  113. if (attached()) {
  114. angle = constrain(value, minAngle, maxAngle);
  115. servoWrite(pin, US_TO_COMPARE(ANGLE_TO_US(angle)));
  116. safe_delay(servo_delay[servoIndex]);
  117. #if ENABLED(DEACTIVATE_SERVOS_AFTER_MOVE)
  118. detach();
  119. #endif
  120. }
  121. }
  122. #ifdef SERVO0_TIMER_NUM
  123. extern "C" void Servo_IRQHandler() {
  124. static timer_dev *tdev = get_timer_dev(SERVO0_TIMER_NUM);
  125. uint16_t SR = timer_get_status(tdev);
  126. if (SR & TIMER_SR_CC1IF) { // channel 1 off
  127. #ifdef SERVO0_PWM_OD
  128. OUT_WRITE_OD(SERVO0_PIN, 1); // off
  129. #else
  130. OUT_WRITE(SERVO0_PIN, 0);
  131. #endif
  132. timer_reset_status_bit(tdev, TIMER_SR_CC1IF_BIT);
  133. }
  134. if (SR & TIMER_SR_CC2IF) { // channel 2 resume
  135. #ifdef SERVO0_PWM_OD
  136. OUT_WRITE_OD(SERVO0_PIN, 0); // on
  137. #else
  138. OUT_WRITE(SERVO0_PIN, 1);
  139. #endif
  140. timer_reset_status_bit(tdev, TIMER_SR_CC2IF_BIT);
  141. }
  142. }
  143. bool libServo::setupSoftPWM(const int32_t inPin) {
  144. timer_dev *tdev = get_timer_dev(SERVO0_TIMER_NUM);
  145. if (!tdev) return false;
  146. #ifdef SERVO0_PWM_OD
  147. OUT_WRITE_OD(inPin, 1);
  148. #else
  149. OUT_WRITE(inPin, 0);
  150. #endif
  151. timer_pause(tdev);
  152. timer_set_mode(tdev, 1, TIMER_OUTPUT_COMPARE); // counter with isr
  153. timer_oc_set_mode(tdev, 1, TIMER_OC_MODE_FROZEN, 0); // no pin output change
  154. timer_oc_set_mode(tdev, 2, TIMER_OC_MODE_FROZEN, 0); // no pin output change
  155. timer_set_prescaler(tdev, SERVO_PRESCALER - 1); // prescaler is 1-based
  156. timer_set_reload(tdev, SERVO_OVERFLOW);
  157. timer_set_compare(tdev, 1, SERVO_OVERFLOW);
  158. timer_set_compare(tdev, 2, SERVO_OVERFLOW);
  159. timer_attach_interrupt(tdev, 1, Servo_IRQHandler);
  160. timer_attach_interrupt(tdev, 2, Servo_IRQHandler);
  161. timer_generate_update(tdev);
  162. timer_resume(tdev);
  163. return true;
  164. }
  165. void libServo::pwmSetDuty(const uint16_t duty_cycle) {
  166. timer_dev *tdev = get_timer_dev(SERVO0_TIMER_NUM);
  167. timer_set_compare(tdev, 1, duty_cycle);
  168. timer_generate_update(tdev);
  169. if (duty_cycle) {
  170. timer_enable_irq(tdev, 1);
  171. timer_enable_irq(tdev, 2);
  172. }
  173. else {
  174. timer_disable_irq(tdev, 1);
  175. timer_disable_irq(tdev, 2);
  176. #ifdef SERVO0_PWM_OD
  177. OUT_WRITE_OD(pin, 1); // off
  178. #else
  179. OUT_WRITE(pin, 0);
  180. #endif
  181. }
  182. }
  183. void libServo::pauseSoftPWM() { // detach
  184. timer_dev *tdev = get_timer_dev(SERVO0_TIMER_NUM);
  185. timer_pause(tdev);
  186. pwmSetDuty(0);
  187. }
  188. #else
  189. bool libServo::setupSoftPWM(const int32_t inPin) { return false; }
  190. void libServo::pwmSetDuty(const uint16_t duty_cycle) {}
  191. void libServo::pauseSoftPWM() {}
  192. #endif
  193. #endif // HAS_SERVOS
  194. #endif // __STM32F1__