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.

241 lines
6.6KB

  1. // Copyright 2009 Olivier Gillet.
  2. //
  3. // Author: Olivier Gillet (ol.gillet@gmail.com)
  4. //
  5. // This program is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. //
  16. // -----------------------------------------------------------------------------
  17. //
  18. // Definitions of timer and related PWM registers.
  19. #ifndef AVRLIB_TIMER_H_
  20. #define AVRLIB_TIMER_H_
  21. // interrupt.h is not strictly needed here, but .cc files including the timer
  22. // classes are likely to also define interrupt handlers (and we have macros for
  23. // that).
  24. #include <avr/interrupt.h>
  25. #include <avr/io.h>
  26. #include "avrlib/avrlib.h"
  27. namespace avrlib {
  28. SpecialFunctionRegister(TCCR0A);
  29. SpecialFunctionRegister(TCCR0B);
  30. SpecialFunctionRegister(TCCR1A);
  31. SpecialFunctionRegister(TCCR1B);
  32. SpecialFunctionRegister(TCCR2A);
  33. SpecialFunctionRegister(TCCR2B);
  34. SpecialFunctionRegister(TIMSK0);
  35. SpecialFunctionRegister(TIMSK1);
  36. SpecialFunctionRegister(TIMSK2);
  37. SpecialFunctionRegister(TCNT0);
  38. SpecialFunctionRegister16(TCNT1);
  39. SpecialFunctionRegister(TCNT2);
  40. SpecialFunctionRegister(OCR0A);
  41. SpecialFunctionRegister(OCR0B);
  42. SpecialFunctionRegister(OCR1A);
  43. SpecialFunctionRegister(OCR1B);
  44. SpecialFunctionRegister(OCR2A);
  45. SpecialFunctionRegister(OCR2B);
  46. #ifdef HAS_TIMER3
  47. SpecialFunctionRegister(TCCR3A);
  48. SpecialFunctionRegister(TCCR3B);
  49. SpecialFunctionRegister(TIMSK3);
  50. SpecialFunctionRegister(TCNT3);
  51. SpecialFunctionRegister(OCR3A);
  52. SpecialFunctionRegister(OCR3B);
  53. #endif // HAS_TIMER3
  54. enum TimerMode {
  55. TIMER_NORMAL = 0,
  56. TIMER_PWM_PHASE_CORRECT = 1,
  57. TIMER_CTC = 2,
  58. TIMER_FAST_PWM = 3,
  59. };
  60. template<typename ControlRegisterA,
  61. typename ControlRegisterB,
  62. typename InterruptRegister,
  63. typename ValueRegister>
  64. struct TimerImpl {
  65. typedef ControlRegisterA A;
  66. typedef ControlRegisterB B;
  67. static inline uint8_t value() {
  68. return *ValueRegister::ptr();
  69. }
  70. static inline void Start() {
  71. *InterruptRegister::ptr() |= _BV(0);
  72. }
  73. static inline void Stop() {
  74. *InterruptRegister::ptr() &= ~(_BV(0));
  75. }
  76. static inline void StartInputCapture() {
  77. *InterruptRegister::ptr() |= _BV(5);
  78. }
  79. static inline void StopInputCapture() {
  80. *InterruptRegister::ptr() &= ~(_BV(5));
  81. }
  82. static inline void StartCompare() {
  83. *InterruptRegister::ptr() |= _BV(1);
  84. }
  85. static inline void StopCompare() {
  86. *InterruptRegister::ptr() &= ~(_BV(1));
  87. }
  88. static inline void set_mode(TimerMode mode) {
  89. // Sets the mode registers.
  90. *ControlRegisterA::ptr() = (*ControlRegisterA::ptr() & 0xfc) | mode;
  91. }
  92. static inline void set_mode(
  93. uint8_t wg_mode_1,
  94. uint8_t wg_mode_2,
  95. uint8_t prescaler) {
  96. // Sets the mode registers.
  97. *ControlRegisterA::ptr() = wg_mode_1;
  98. *ControlRegisterB::ptr() = wg_mode_2 | prescaler;
  99. }
  100. static inline void set_value(uint16_t value) {
  101. *ValueRegister::ptr() = value;
  102. }
  103. // These are the values for MCUs clocked at 20 MHz
  104. //
  105. // Timer speed
  106. // value | fast | accurate
  107. // --------------------------------------
  108. // 1 | 78.125 kHz | 39.215 kHz
  109. // 2 | 9.765 kHz | 4.901 kHz
  110. // 3 | 1220.7 Hz | 612.7 Hz
  111. // 4 | 305.2 Hz | 153.2 Hz
  112. // 5 | 76.3 Hz | 38.3 Hz
  113. static inline void set_prescaler(uint8_t prescaler) {
  114. *ControlRegisterB::ptr() = (*ControlRegisterB::ptr() & 0xf8) | prescaler;
  115. }
  116. };
  117. template<int n>
  118. struct NumberedTimer { };
  119. template<> struct NumberedTimer<0> {
  120. typedef TimerImpl<
  121. TCCR0ARegister,
  122. TCCR0BRegister,
  123. TIMSK0Register,
  124. TCNT0Register> Impl;
  125. };
  126. template<> struct NumberedTimer<1> {
  127. typedef TimerImpl<
  128. TCCR1ARegister,
  129. TCCR1BRegister,
  130. TIMSK1Register,
  131. TCNT1Register> Impl;
  132. };
  133. template<> struct NumberedTimer<2> {
  134. typedef TimerImpl<
  135. TCCR2ARegister,
  136. TCCR2BRegister,
  137. TIMSK2Register,
  138. TCNT2Register> Impl;
  139. };
  140. #ifdef HAS_TIMER3
  141. template<> struct NumberedTimer<3> {
  142. typedef TimerImpl<
  143. TCCR3ARegister,
  144. TCCR3BRegister,
  145. TIMSK3Register,
  146. TCNT3Register> Impl;
  147. };
  148. #endif // HAS_TIMER3
  149. template<int n>
  150. struct Timer {
  151. typedef typename NumberedTimer<n>::Impl Impl;
  152. static inline uint8_t value() { return Impl::value(); }
  153. static inline void Start() { Impl::Start(); }
  154. static inline void Stop() { Impl::Stop(); }
  155. static inline void StartInputCapture() { Impl::StartInputCapture(); }
  156. static inline void StopInputCapture() { Impl::StopInputCapture(); }
  157. static inline void StartCompare() { Impl::StartCompare(); }
  158. static inline void StopCompare() { Impl::StopCompare(); }
  159. static inline void set_mode(TimerMode mode) { Impl::set_mode(mode); }
  160. static inline void set_mode(uint8_t a, uint8_t b, uint8_t c) {
  161. Impl::set_mode(a, b, c);
  162. }
  163. static inline void set_prescaler(uint8_t prescaler) {
  164. Impl::set_prescaler(prescaler);
  165. }
  166. };
  167. template<typename Timer, uint8_t enabled_flag, typename PwmRegister>
  168. struct PwmChannel {
  169. typedef BitInRegister<typename Timer::Impl::A, enabled_flag> EnabledBit;
  170. enum {
  171. has_pwm = 1
  172. };
  173. static inline void Start() {
  174. EnabledBit::set();
  175. }
  176. static inline void Stop() {
  177. EnabledBit::clear();
  178. }
  179. static inline void Write(uint8_t value) {
  180. *PwmRegister::ptr() = value;
  181. }
  182. static inline void set_frequency(uint16_t f) {
  183. OCR1A = f;
  184. OCR1B = f >> 1;
  185. }
  186. static inline void set_frequency_pulse(uint16_t f) {
  187. OCR1A = f;
  188. OCR1B = f - (f >> 2);
  189. }
  190. };
  191. struct NoPwmChannel {
  192. enum {
  193. has_pwm = 0
  194. };
  195. static inline void Start() { }
  196. static inline void Stop() { }
  197. static inline void Write(uint8_t value) { }
  198. };
  199. typedef PwmChannel<Timer<0>, COM0A1, OCR0ARegister> PwmChannel0A;
  200. typedef PwmChannel<Timer<0>, COM0B1, OCR0BRegister> PwmChannel0B;
  201. typedef PwmChannel<Timer<1>, COM1A1, OCR1ARegister> PwmChannel1A;
  202. typedef PwmChannel<Timer<1>, COM1B1, OCR1BRegister> PwmChannel1B;
  203. typedef PwmChannel<Timer<2>, COM2A1, OCR2ARegister> PwmChannel2A;
  204. typedef PwmChannel<Timer<2>, COM2B1, OCR2BRegister> PwmChannel2B;
  205. // Readable aliases for timer interrupts.
  206. #define TIMER_0_TICK ISR(TIMER0_OVF_vect)
  207. #define TIMER_1_TICK ISR(TIMER1_OVF_vect)
  208. #define TIMER_2_TICK ISR(TIMER2_OVF_vect)
  209. #ifdef HAS_TIMER3
  210. #define TIMER_3_TICK ISR(TIMER3_OVF_vect)
  211. #endif // HAS_TIMER3
  212. } // namespace avrlib
  213. #endif // AVRLIB_TIMER_H_