audio_pwm_hardware.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /* Copyright 2016 Jack Humbert
  2. * Copyright 2020 JohSchneider
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  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. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #if defined(__AVR__)
  18. # include <avr/pgmspace.h>
  19. # include <avr/interrupt.h>
  20. # include <avr/io.h>
  21. #endif
  22. #include "audio.h"
  23. extern bool playing_note;
  24. extern bool playing_melody;
  25. extern uint8_t note_timbre;
  26. #define CPU_PRESCALER 8
  27. /*
  28. Audio Driver: PWM
  29. drive up to two speakers through the AVR PWM hardware-peripheral, using timer1 and/or timer3 on Atmega32U4.
  30. the primary channel_1 can be connected to either pin PC4 PC5 or PC6 (the later being used by most AVR based keyboards) with a PMW signal generated by timer3
  31. and an optional secondary channel_2 on either pin PB5, PB6 or PB7, with a PWM signal from timer1
  32. alternatively, the PWM pins on PORTB can be used as only/primary speaker
  33. */
  34. #if defined(AUDIO_PIN) && (AUDIO_PIN != C4) && (AUDIO_PIN != C5) && (AUDIO_PIN != C6) && (AUDIO_PIN != B5) && (AUDIO_PIN != B6) && (AUDIO_PIN != B7) && (AUDIO_PIN != D5)
  35. # error "Audio feature enabled, but no suitable pin selected as AUDIO_PIN - see docs/feature_audio under the AVR settings for available options."
  36. #endif
  37. #if (AUDIO_PIN == C4) || (AUDIO_PIN == C5) || (AUDIO_PIN == C6)
  38. # define AUDIO1_PIN_SET
  39. # define AUDIO1_TIMSKx TIMSK3
  40. # define AUDIO1_TCCRxA TCCR3A
  41. # define AUDIO1_TCCRxB TCCR3B
  42. # define AUDIO1_ICRx ICR3
  43. # define AUDIO1_WGMx0 WGM30
  44. # define AUDIO1_WGMx1 WGM31
  45. # define AUDIO1_WGMx2 WGM32
  46. # define AUDIO1_WGMx3 WGM33
  47. # define AUDIO1_CSx0 CS30
  48. # define AUDIO1_CSx1 CS31
  49. # define AUDIO1_CSx2 CS32
  50. # if (AUDIO_PIN == C6)
  51. # define AUDIO1_COMxy0 COM3A0
  52. # define AUDIO1_COMxy1 COM3A1
  53. # define AUDIO1_OCIExy OCIE3A
  54. # define AUDIO1_OCRxy OCR3A
  55. # define AUDIO1_PIN C6
  56. # define AUDIO1_TIMERx_COMPy_vect TIMER3_COMPA_vect
  57. # elif (AUDIO_PIN == C5)
  58. # define AUDIO1_COMxy0 COM3B0
  59. # define AUDIO1_COMxy1 COM3B1
  60. # define AUDIO1_OCIExy OCIE3B
  61. # define AUDIO1_OCRxy OCR3B
  62. # define AUDIO1_PIN C5
  63. # define AUDIO1_TIMERx_COMPy_vect TIMER3_COMPB_vect
  64. # elif (AUDIO_PIN == C4)
  65. # define AUDIO1_COMxy0 COM3C0
  66. # define AUDIO1_COMxy1 COM3C1
  67. # define AUDIO1_OCIExy OCIE3C
  68. # define AUDIO1_OCRxy OCR3C
  69. # define AUDIO1_PIN C4
  70. # define AUDIO1_TIMERx_COMPy_vect TIMER3_COMPC_vect
  71. # endif
  72. #endif
  73. #if defined(AUDIO_PIN) && defined(AUDIO_PIN_ALT) && (AUDIO_PIN == AUDIO_PIN_ALT)
  74. # error "Audio feature: AUDIO_PIN and AUDIO_PIN_ALT on the same pin makes no sense."
  75. #endif
  76. #if ((AUDIO_PIN == B5) && ((AUDIO_PIN_ALT == B6) || (AUDIO_PIN_ALT == B7))) || ((AUDIO_PIN == B6) && ((AUDIO_PIN_ALT == B5) || (AUDIO_PIN_ALT == B7))) || ((AUDIO_PIN == B7) && ((AUDIO_PIN_ALT == B5) || (AUDIO_PIN_ALT == B6)))
  77. # error "Audio feature: PORTB as AUDIO_PIN and AUDIO_PIN_ALT at the same time is not supported."
  78. #endif
  79. #if defined(AUDIO_PIN_ALT) && (AUDIO_PIN_ALT != B5) && (AUDIO_PIN_ALT != B6) && (AUDIO_PIN_ALT != B7)
  80. # error "Audio feature: the pin selected as AUDIO_PIN_ALT is not supported."
  81. #endif
  82. #if (AUDIO_PIN == B5) || (AUDIO_PIN == B6) || (AUDIO_PIN == B7) || (AUDIO_PIN_ALT == B5) || (AUDIO_PIN_ALT == B6) || (AUDIO_PIN_ALT == B7) || (AUDIO_PIN == D5)
  83. # define AUDIO2_PIN_SET
  84. # define AUDIO2_TIMSKx TIMSK1
  85. # define AUDIO2_TCCRxA TCCR1A
  86. # define AUDIO2_TCCRxB TCCR1B
  87. # define AUDIO2_ICRx ICR1
  88. # define AUDIO2_WGMx0 WGM10
  89. # define AUDIO2_WGMx1 WGM11
  90. # define AUDIO2_WGMx2 WGM12
  91. # define AUDIO2_WGMx3 WGM13
  92. # define AUDIO2_CSx0 CS10
  93. # define AUDIO2_CSx1 CS11
  94. # define AUDIO2_CSx2 CS12
  95. # if (AUDIO_PIN == B5) || (AUDIO_PIN_ALT == B5)
  96. # define AUDIO2_COMxy0 COM1A0
  97. # define AUDIO2_COMxy1 COM1A1
  98. # define AUDIO2_OCIExy OCIE1A
  99. # define AUDIO2_OCRxy OCR1A
  100. # define AUDIO2_PIN B5
  101. # define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPA_vect
  102. # elif (AUDIO_PIN == B6) || (AUDIO_PIN_ALT == B6)
  103. # define AUDIO2_COMxy0 COM1B0
  104. # define AUDIO2_COMxy1 COM1B1
  105. # define AUDIO2_OCIExy OCIE1B
  106. # define AUDIO2_OCRxy OCR1B
  107. # define AUDIO2_PIN B6
  108. # define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPB_vect
  109. # elif (AUDIO_PIN == B7) || (AUDIO_PIN_ALT == B7)
  110. # define AUDIO2_COMxy0 COM1C0
  111. # define AUDIO2_COMxy1 COM1C1
  112. # define AUDIO2_OCIExy OCIE1C
  113. # define AUDIO2_OCRxy OCR1C
  114. # define AUDIO2_PIN B7
  115. # define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPC_vect
  116. # elif (AUDIO_PIN == D5) && defined(__AVR_ATmega32A__)
  117. # pragma message "Audio support for ATmega32A is experimental and can cause crashes."
  118. # undef AUDIO2_TIMSKx
  119. # define AUDIO2_TIMSKx TIMSK
  120. # define AUDIO2_COMxy0 COM1A0
  121. # define AUDIO2_COMxy1 COM1A1
  122. # define AUDIO2_OCIExy OCIE1A
  123. # define AUDIO2_OCRxy OCR1A
  124. # define AUDIO2_PIN D5
  125. # define AUDIO2_TIMERx_COMPy_vect TIMER1_COMPA_vect
  126. # endif
  127. #endif
  128. // C6 seems to be the assumed default by many existing keyboard - but sill warn the user
  129. #if !defined(AUDIO1_PIN_SET) && !defined(AUDIO2_PIN_SET)
  130. # pragma message "Audio feature enabled, but no suitable pin selected - see docs/feature_audio under the AVR settings for available options. Don't expect to hear anything... :-)"
  131. // TODO: make this an error - go through the breaking-change-process and change all keyboards to the new define
  132. #endif
  133. // -----------------------------------------------------------------------------
  134. #ifdef AUDIO1_PIN_SET
  135. static float channel_1_frequency = 0.0f;
  136. void channel_1_set_frequency(float freq) {
  137. if (freq == 0.0f) // a pause/rest is a valid "note" with freq=0
  138. {
  139. // disable the output, but keep the pwm-ISR going (with the previous
  140. // frequency) so the audio-state keeps getting updated
  141. // Note: setting the duty-cycle 0 is not possible on non-inverting PWM mode - see the AVR data-sheet
  142. AUDIO1_TCCRxA &= ~(_BV(AUDIO1_COMxy1) | _BV(AUDIO1_COMxy0));
  143. return;
  144. } else {
  145. AUDIO1_TCCRxA |= _BV(AUDIO1_COMxy1); // enable output, PWM mode
  146. }
  147. channel_1_frequency = freq;
  148. // set pwm period
  149. AUDIO1_ICRx = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
  150. // and duty cycle
  151. AUDIO1_OCRxy = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre / 100);
  152. }
  153. void channel_1_start(void) {
  154. // enable timer-counter ISR
  155. AUDIO1_TIMSKx |= _BV(AUDIO1_OCIExy);
  156. // enable timer-counter output
  157. AUDIO1_TCCRxA |= _BV(AUDIO1_COMxy1);
  158. }
  159. void channel_1_stop(void) {
  160. // disable timer-counter ISR
  161. AUDIO1_TIMSKx &= ~_BV(AUDIO1_OCIExy);
  162. // disable timer-counter output
  163. AUDIO1_TCCRxA &= ~(_BV(AUDIO1_COMxy1) | _BV(AUDIO1_COMxy0));
  164. }
  165. #endif
  166. #ifdef AUDIO2_PIN_SET
  167. static float channel_2_frequency = 0.0f;
  168. void channel_2_set_frequency(float freq) {
  169. if (freq == 0.0f) {
  170. AUDIO2_TCCRxA &= ~(_BV(AUDIO2_COMxy1) | _BV(AUDIO2_COMxy0));
  171. return;
  172. } else {
  173. AUDIO2_TCCRxA |= _BV(AUDIO2_COMxy1);
  174. }
  175. channel_2_frequency = freq;
  176. AUDIO2_ICRx = (uint16_t)(((float)F_CPU) / (freq * CPU_PRESCALER));
  177. AUDIO2_OCRxy = (uint16_t)((((float)F_CPU) / (freq * CPU_PRESCALER)) * note_timbre / 100);
  178. }
  179. float channel_2_get_frequency(void) { return channel_2_frequency; }
  180. void channel_2_start(void) {
  181. AUDIO2_TIMSKx |= _BV(AUDIO2_OCIExy);
  182. AUDIO2_TCCRxA |= _BV(AUDIO2_COMxy1);
  183. }
  184. void channel_2_stop(void) {
  185. AUDIO2_TIMSKx &= ~_BV(AUDIO2_OCIExy);
  186. AUDIO2_TCCRxA &= ~(_BV(AUDIO2_COMxy1) | _BV(AUDIO2_COMxy0));
  187. }
  188. #endif
  189. void audio_driver_initialize() {
  190. #ifdef AUDIO1_PIN_SET
  191. channel_1_stop();
  192. setPinOutput(AUDIO1_PIN);
  193. #endif
  194. #ifdef AUDIO2_PIN_SET
  195. channel_2_stop();
  196. setPinOutput(AUDIO2_PIN);
  197. #endif
  198. // TCCR3A / TCCR3B: Timer/Counter #3 Control Registers TCCR3A/TCCR3B, TCCR1A/TCCR1B
  199. // Compare Output Mode (COM3An and COM1An) = 0b00 = Normal port operation
  200. // OC3A -- PC6
  201. // OC3B -- PC5
  202. // OC3C -- PC4
  203. // OC1A -- PB5
  204. // OC1B -- PB6
  205. // OC1C -- PB7
  206. // Waveform Generation Mode (WGM3n) = 0b1110 = Fast PWM Mode 14. Period = ICR3, Duty Cycle OCR3A)
  207. // OCR3A - PC6
  208. // OCR3B - PC5
  209. // OCR3C - PC4
  210. // OCR1A - PB5
  211. // OCR1B - PB6
  212. // OCR1C - PB7
  213. // Clock Select (CS3n) = 0b010 = Clock / 8
  214. #ifdef AUDIO1_PIN_SET
  215. // initialize timer-counter
  216. AUDIO1_TCCRxA = (0 << AUDIO1_COMxy1) | (0 << AUDIO1_COMxy0) | (1 << AUDIO1_WGMx1) | (0 << AUDIO1_WGMx0);
  217. AUDIO1_TCCRxB = (1 << AUDIO1_WGMx3) | (1 << AUDIO1_WGMx2) | (0 << AUDIO1_CSx2) | (1 << AUDIO1_CSx1) | (0 << AUDIO1_CSx0);
  218. #endif
  219. #ifdef AUDIO2_PIN_SET
  220. AUDIO2_TCCRxA = (0 << AUDIO2_COMxy1) | (0 << AUDIO2_COMxy0) | (1 << AUDIO2_WGMx1) | (0 << AUDIO2_WGMx0);
  221. AUDIO2_TCCRxB = (1 << AUDIO2_WGMx3) | (1 << AUDIO2_WGMx2) | (0 << AUDIO2_CSx2) | (1 << AUDIO2_CSx1) | (0 << AUDIO2_CSx0);
  222. #endif
  223. }
  224. void audio_driver_stop() {
  225. #ifdef AUDIO1_PIN_SET
  226. channel_1_stop();
  227. #endif
  228. #ifdef AUDIO2_PIN_SET
  229. channel_2_stop();
  230. #endif
  231. }
  232. void audio_driver_start(void) {
  233. #ifdef AUDIO1_PIN_SET
  234. channel_1_start();
  235. if (playing_note) {
  236. channel_1_set_frequency(audio_get_processed_frequency(0));
  237. }
  238. #endif
  239. #if !defined(AUDIO1_PIN_SET) && defined(AUDIO2_PIN_SET)
  240. channel_2_start();
  241. if (playing_note) {
  242. channel_2_set_frequency(audio_get_processed_frequency(0));
  243. }
  244. #endif
  245. }
  246. static volatile uint32_t isr_counter = 0;
  247. #ifdef AUDIO1_PIN_SET
  248. ISR(AUDIO1_TIMERx_COMPy_vect) {
  249. isr_counter++;
  250. if (isr_counter < channel_1_frequency / (CPU_PRESCALER * 8)) return;
  251. isr_counter = 0;
  252. bool state_changed = audio_update_state();
  253. if (!playing_note && !playing_melody) {
  254. channel_1_stop();
  255. # ifdef AUDIO2_PIN_SET
  256. channel_2_stop();
  257. # endif
  258. return;
  259. }
  260. if (state_changed) {
  261. channel_1_set_frequency(audio_get_processed_frequency(0));
  262. # ifdef AUDIO2_PIN_SET
  263. if (audio_get_number_of_active_tones() > 1) {
  264. channel_2_set_frequency(audio_get_processed_frequency(1));
  265. } else {
  266. channel_2_stop();
  267. }
  268. # endif
  269. }
  270. }
  271. #endif
  272. #if !defined(AUDIO1_PIN_SET) && defined(AUDIO2_PIN_SET)
  273. ISR(AUDIO2_TIMERx_COMPy_vect) {
  274. isr_counter++;
  275. if (isr_counter < channel_2_frequency / (CPU_PRESCALER * 8)) return;
  276. isr_counter = 0;
  277. bool state_changed = audio_update_state();
  278. if (!playing_note && !playing_melody) {
  279. channel_2_stop();
  280. return;
  281. }
  282. if (state_changed) {
  283. channel_2_set_frequency(audio_get_processed_frequency(0));
  284. }
  285. }
  286. #endif