PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
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.

152 line
4.8KB

  1. /* Copyright (c) 2009 by Alex Leone <acleone ~AT~ gmail.com>
  2. This file is part of the Arduino TLC5940 Library.
  3. The Arduino TLC5940 Library is free software: you can redistribute it
  4. and/or modify it under the terms of the GNU General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. The Arduino TLC5940 Library is distributed in the hope that it will be
  8. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with The Arduino TLC5940 Library. If not, see
  13. <http://www.gnu.org/licenses/>. */
  14. #ifndef TLC_SERVOS_H
  15. #define TLC_SERVOS_H
  16. /** \file
  17. TLC servo functions. */
  18. #include "Tlc5940.h"
  19. #ifndef SERVO_MAX_ANGLE
  20. /** The maximum angle of the servo. */
  21. #define SERVO_MAX_ANGLE 180
  22. #endif
  23. #ifndef SERVO_MIN_WIDTH
  24. /** The 1ms pulse width for zero degrees (0 - 4095). */
  25. #define SERVO_MIN_WIDTH 204
  26. #endif
  27. #ifndef SERVO_MAX_WIDTH
  28. /** The 2ms pulse width for 180 degrees (0 - 4095). */
  29. #define SERVO_MAX_WIDTH 410
  30. #endif
  31. #ifndef SERVO_TIMER1_TOP
  32. /** The top value for XLAT and BLANK pulses. This is with the div8 prescale,
  33. so
  34. \f$\displaystyle f_{PWM} = \frac{f_{osc}}{2 * 8 * SERVO\_TIMER1\_TOP} \f$
  35. The default is 20000, which corresponds to 50Hz. */
  36. #define SERVO_TIMER1_TOP 20000
  37. #endif
  38. #ifndef SERVO_TIMER2_TOP
  39. /** The top value for GSCLK pulses. Related to SERVO_TIMER1_TOP by
  40. \f$\displaystyle SERVO\_TIMER2\_TOP =
  41. \frac{2 * 8 * SERVO\_TIMER1\_TOP}{4096} - 1 \f$
  42. The default is 77. */
  43. #define SERVO_TIMER2_TOP 77
  44. #endif
  45. void tlc_initServos(uint8_t initAngle = 0);
  46. void tlc_setServo(TLC_CHANNEL_TYPE channel, uint8_t angle);
  47. uint8_t tlc_getServo(TLC_CHANNEL_TYPE channel);
  48. uint16_t tlc_angleToVal(uint8_t angle);
  49. uint8_t tlc_valToAngle(uint16_t value);
  50. /** \addtogroup ExtendedFunctions
  51. \code #include "tlc_servos.h" \endcode
  52. - void tlc_initServos(uint8_t initAngle = 0) - initializes the tlc for
  53. servos.
  54. - void tlc_setServo(TLC_CHANNEL_TYPE channel, uint8_t angle) - sets a
  55. servo to an angle
  56. - uint8_t tlc_getServo(TLC_CHANNEL_TYPE channel) - gets the currently set
  57. servo angle */
  58. /* @{ */
  59. /** Initializes the tlc.
  60. \param initAngle the initial angle to set all servos to
  61. (0 - SERVO_MAX_ANGLE). */
  62. void tlc_initServos(uint8_t initAngle)
  63. {
  64. Tlc.init(tlc_angleToVal(initAngle));
  65. #if defined(__AVR__)
  66. TCCR1B &= ~(_BV(CS12) | _BV(CS11) | _BV(CS10)); // stop timer1
  67. ICR1 = SERVO_TIMER1_TOP;
  68. TCNT1 = 0;
  69. #ifdef TLC_ATMEGA_8_H
  70. uint8_t oldTCCR2 = TCCR2;
  71. TCCR2 = 0;
  72. TCNT2 = 0;
  73. OCR2 = SERVO_TIMER2_TOP / 2;
  74. TCCR2 = oldTCCR2;
  75. #elif defined(TLC_TIMER3_GSCLK)
  76. // TODO: timer3 implementation needed...
  77. // pull requests would be most welcome! ;-)
  78. #else
  79. uint8_t oldTCCR2B = TCCR2B;
  80. TCCR2B = 0;
  81. TCNT2 = 0;
  82. OCR2A = SERVO_TIMER2_TOP;
  83. TCCR2B = oldTCCR2B;
  84. #endif
  85. TCCR1B |= _BV(CS11); // start timer1 with div 8 prescale
  86. #elif defined(__arm__) && defined(TEENSYDUINO)
  87. //clear_XLAT_interrupt();
  88. uint32_t sc __attribute__ ((unused)) = FTM1_SC;
  89. FTM1_SC = 0; // stop timer
  90. CMT_MSC = 0;
  91. CMT_CGH1 = TLC_TIMER_TEENSY3_SERVO_CGH1;
  92. CMT_CGL1 = TLC_TIMER_TEENSY3_SERVO_CGL1;
  93. CMT_MSC = 0x01; // GSCLK target is 204800 Hz
  94. // TODO: this reconfiguration of FTM1 crashes... why?
  95. // pull requests would be most welcome! ;-)
  96. FTM1_CNT = 0;
  97. FTM1_MOD = TLC_TIMER_TEENSY3_SERVO_MOD;
  98. FTM1_C0V = TLC_TIMER_TEENSY3_SERVO_MOD - TLC_TIMER_TEENSY3_SERVO_CV;
  99. FTM1_C1V = TLC_TIMER_TEENSY3_SERVO_MOD - TLC_TIMER_TEENSY3_SERVO_CV - 1;
  100. FTM1_SC = FTM_SC_CLKS(1) | FTM_SC_CPWMS | TLC_TIMER_TEENSY3_SERVO_PS;
  101. #endif
  102. }
  103. /** Sets a servo on channel to angle.
  104. \param channel which channel to set
  105. \param angle (0 - SERVO_MAX_ANGLE) */
  106. void tlc_setServo(TLC_CHANNEL_TYPE channel, uint8_t angle)
  107. {
  108. Tlc.set(channel, tlc_angleToVal(angle));
  109. }
  110. /** Gets the current angle that channel is set to.
  111. \param channel which channel to get */
  112. uint8_t tlc_getServo(TLC_CHANNEL_TYPE channel)
  113. {
  114. return tlc_valToAngle(Tlc.get(channel));
  115. }
  116. /** Converts and angle (0 - SERVO_MAX_ANGLE) to the inverted tlc channel value
  117. (4095 - 0). */
  118. uint16_t tlc_angleToVal(uint8_t angle)
  119. {
  120. return 4095 - SERVO_MIN_WIDTH - (
  121. ((uint16_t)(angle) * (uint16_t)(SERVO_MAX_WIDTH - SERVO_MIN_WIDTH))
  122. / SERVO_MAX_ANGLE);
  123. }
  124. /** Converts an inverted tlc channel value (4095 - 0) into an angle (0 -
  125. SERVO_MAX_ANGLE). */
  126. uint8_t tlc_valToAngle(uint16_t value)
  127. {
  128. return SERVO_MAX_ANGLE * (4095 - SERVO_MIN_WIDTH - value)
  129. / (SERVO_MAX_WIDTH - SERVO_MIN_WIDTH);
  130. }
  131. /* @} */
  132. #endif