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.

Tone.cpp 6.8KB

3 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. /* Tone generation for the Teensy and Teensy++
  2. * http://www.pjrc.com/teensy/
  3. * Copyright (c) 2010 PJRC.COM, LLC
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining a copy
  6. * of this software and associated documentation files (the "Software"), to deal
  7. * in the Software without restriction, including without limitation the rights
  8. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. * copies of the Software, and to permit persons to whom the Software is
  10. * furnished to do so, subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be included in
  13. * all copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. * THE SOFTWARE.
  22. */
  23. #include <avr/interrupt.h>
  24. #include "wiring.h"
  25. #include "core_pins.h"
  26. #include "pins_arduino.h"
  27. static uint8_t timer_acquired = 0;
  28. static uint8_t *tone1_reg = (uint8_t *)0;
  29. static uint8_t tone1_mask = 0;
  30. static uint16_t tone1_inc = 0;
  31. static uint32_t tone1_count = 0;
  32. static uint8_t *tone2_reg = (uint8_t *)0;
  33. static uint8_t tone2_mask = 0;
  34. static uint16_t tone2_inc = 0;
  35. static uint32_t tone2_count = 0;
  36. static uint8_t *tone3_reg = (uint8_t *)0;
  37. static uint8_t tone3_mask = 0;
  38. static uint16_t tone3_inc = 0;
  39. static uint32_t tone3_count = 0;
  40. #define MAX_FREQ (F_CPU / 16 / 25)
  41. #define MIN_FREQ (F_CPU / 16 / 65535 + 1)
  42. #define PIN_REG_AND_MASK_LOOKUP(pin, reg, mask) \
  43. asm volatile( \
  44. "lsl %2" "\n\t" \
  45. "add %A3, %2" "\n\t" \
  46. "adc %B3, __zero_reg__" "\n\n" \
  47. "lpm %1, Z+" "\n\t" \
  48. "lpm %A0, Z" "\n\t" \
  49. "ldi %B0, 0" "\n" \
  50. : "=z" (reg), "=r" (mask), "+r" (pin) \
  51. : "z" (digital_pin_table_PGM), "2" (pin))
  52. #if defined(__AVR_ATmega32U4__)
  53. //#define TONE_USE_TIMER1
  54. #define TONE_USE_TIMER3
  55. #elif defined(__AVR_AT90USB1286__)
  56. //#define TONE_USE_TIMER1
  57. #define TONE_USE_TIMER3
  58. #elif defined(__AVR_AT90USB162__)
  59. #define TONE_USE_TIMER1
  60. #elif defined(__AVR_AT90USB646__)
  61. //#define TONE_USE_TIMER1
  62. #define TONE_USE_TIMER3
  63. #endif
  64. #ifdef TONE_USE_TIMER3
  65. #define TIMSKx TIMSK3
  66. #define OCIExA OCIE3A
  67. #define OCIExB OCIE3B
  68. #define OCIExC OCIE3C
  69. #define TCCRxA TCCR3A
  70. #define WGMx0 WGM30
  71. #define TCCRxB TCCR3B
  72. #define CSx1 CS31
  73. #define TCNTx TCNT3
  74. #define OCRxA OCR3A
  75. #define OCRxB OCR3B
  76. #define OCRxC OCR3C
  77. #define TIFRx TIFR3
  78. #define OCFxA OCF3A
  79. #define OCFxB OCF3B
  80. #define OCFxC OCF3C
  81. #define VECTxA TIMER3_COMPA_vect
  82. #define VECTxB TIMER3_COMPB_vect
  83. #define VECTxC TIMER3_COMPC_vect
  84. #endif
  85. #ifdef TONE_USE_TIMER1
  86. #define TIMSKx TIMSK1
  87. #define OCIExA OCIE1A
  88. #define OCIExB OCIE1B
  89. #define OCIExC OCIE1C
  90. #define TCCRxA TCCR1A
  91. #define WGMx0 WGM10
  92. #define TCCRxB TCCR1B
  93. #define CSx1 CS11
  94. #define TCNTx TCNT1
  95. #define OCRxA OCR1A
  96. #define OCRxB OCR1B
  97. #define OCRxC OCR1C
  98. #define TIFRx TIFR1
  99. #define OCFxA OCF1A
  100. #define OCFxB OCF1B
  101. #define OCFxC OCF1C
  102. #define VECTxA TIMER1_COMPA_vect
  103. #define VECTxB TIMER1_COMPB_vect
  104. #define VECTxC TIMER1_COMPC_vect
  105. #endif
  106. void tone(uint8_t pin, uint16_t frequency, uint32_t duration)
  107. {
  108. uint8_t *reg;
  109. uint8_t mask;
  110. uint16_t inc;
  111. uint32_t count;
  112. if (pin >= CORE_NUM_TOTAL_PINS) return;
  113. if (frequency < MIN_FREQ) {
  114. frequency = MIN_FREQ;
  115. } else if (frequency > MAX_FREQ) {
  116. frequency = MAX_FREQ;
  117. }
  118. inc = (F_CPU / 16 + frequency / 2) / frequency;
  119. if (duration) {
  120. count = duration * frequency / 500;
  121. } else {
  122. count = 0;
  123. }
  124. if (!timer_acquired) {
  125. TIMSKx = 0; // disable all interrupts
  126. TCCRxA = 0;
  127. TCCRxB = (1<<CSx1); // normal mode, div8 prescale
  128. timer_acquired = 1;
  129. }
  130. PIN_REG_AND_MASK_LOOKUP(pin, reg, mask);
  131. if (!tone1_mask || (tone1_mask == mask && tone1_reg == reg)) {
  132. TIMSKx &= ~(1<<OCIExA); // disable compare interrupt
  133. tone1_reg = reg;
  134. tone1_mask = mask;
  135. tone1_count = count;
  136. tone1_inc = inc;
  137. cli();
  138. *(reg + 2) &= ~mask; // clear pin
  139. *(reg + 1) |= mask; // output mode
  140. OCRxA = TCNTx + inc;
  141. TIFRx |= (1<<OCFxA); // clear any pending compare match
  142. sei();
  143. TIMSKx |= (1<<OCIExA); // enable compare interrupt
  144. return;
  145. }
  146. if (!tone2_mask || (tone2_mask == mask && tone2_reg == reg)) {
  147. TIMSKx &= ~(1<<OCIExB); // disable compare interrupt
  148. tone2_reg = reg;
  149. tone2_mask = mask;
  150. tone2_count = count;
  151. tone2_inc = inc;
  152. cli();
  153. *(reg + 2) &= ~mask; // clear pin
  154. *(reg + 1) |= mask; // output mode
  155. OCRxB = TCNTx + inc;
  156. TIFRx |= (1<<OCFxB); // clear any pending compare match
  157. sei();
  158. TIMSKx |= (1<<OCIExB); // enable compare interrupt
  159. return;
  160. }
  161. if (!tone3_mask || (tone3_mask == mask && tone3_reg == reg)) {
  162. TIMSKx &= ~(1<<OCIExC); // disable compare interrupt
  163. tone3_reg = reg;
  164. tone3_mask = mask;
  165. tone3_count = count;
  166. tone3_inc = inc;
  167. cli();
  168. *(reg + 2) &= ~mask; // clear pin
  169. *(reg + 1) |= mask; // output mode
  170. OCRxC = TCNTx + inc;
  171. TIFRx |= (1<<OCFxC); // clear any pending compare match
  172. sei();
  173. TIMSKx |= (1<<OCIExC); // enable compare interrupt
  174. return;
  175. }
  176. }
  177. void noTone(uint8_t pin)
  178. {
  179. uint8_t *reg;
  180. uint8_t mask;
  181. if (pin >= CORE_NUM_TOTAL_PINS) return;
  182. PIN_REG_AND_MASK_LOOKUP(pin, reg, mask);
  183. if (tone1_mask == mask && tone1_reg == reg) {
  184. TIMSKx &= ~(1<<OCIExA);
  185. tone1_mask = 0;
  186. } else if (tone2_mask == mask && tone2_reg == reg) {
  187. TIMSKx &= ~(1<<OCIExB);
  188. tone2_mask = 0;
  189. } else if (tone3_mask == mask && tone3_reg == reg) {
  190. TIMSKx &= ~(1<<OCIExC);
  191. tone3_mask = 0;
  192. }
  193. if (!tone1_mask && !tone2_mask && !tone3_mask) {
  194. TCCRxA = (1<<WGMx0); // restore timer
  195. timer_acquired = 0;
  196. }
  197. }
  198. ISR(VECTxA)
  199. {
  200. OCRxA += tone1_inc;
  201. *(tone1_reg) = tone1_mask;
  202. if (tone1_count > 0) {
  203. if ((--tone1_count) == 0) {
  204. *(tone1_reg + 2) &= ~tone1_mask;
  205. TIMSKx &= ~(1<<OCIExA);
  206. tone1_mask = 0;
  207. if (!tone2_mask && !tone3_mask) {
  208. TCCRxA = (1<<WGMx0);
  209. timer_acquired = 0;
  210. }
  211. }
  212. }
  213. }
  214. ISR(VECTxB)
  215. {
  216. OCRxB += tone2_inc;
  217. *(tone2_reg) = tone2_mask;
  218. if (tone2_count > 0) {
  219. if ((--tone2_count) == 0) {
  220. *(tone2_reg + 2) &= ~tone2_mask;
  221. TIMSKx &= ~(1<<OCIExB);
  222. tone2_mask = 0;
  223. if (!tone1_mask && !tone3_mask) {
  224. TCCRxA = (1<<WGMx0);
  225. timer_acquired = 0;
  226. }
  227. }
  228. }
  229. }
  230. ISR(VECTxC)
  231. {
  232. OCRxC += tone3_inc;
  233. *(tone3_reg) = tone3_mask;
  234. if (tone3_count > 0) {
  235. if ((--tone3_count) == 0) {
  236. *(tone3_reg + 2) &= ~tone3_mask;
  237. TIMSKx &= ~(1<<OCIExC);
  238. tone3_mask = 0;
  239. if (!tone1_mask && !tone2_mask) {
  240. TCCRxA = (1<<WGMx0);
  241. timer_acquired = 0;
  242. }
  243. }
  244. }
  245. }