| Mozzi version v1.1.0 sound synthesis library for Arduino |

MozziGuts.cpp
1 /*
2 * MozziGuts.cpp
3 *
4 * Copyright 2012 Tim Barrass.
5 *
6 * This file is part of Mozzi.
7 *
8 * Mozzi by Tim Barrass is licensed under a Creative Commons
9 * Attribution-NonCommercial-ShareAlike 4.0 International License.
10 *
11 */
12
13 #if ARDUINO >= 100
14 #include "Arduino.h"
15 #else
16 #include "WProgram.h"
17 #endif
18
19 #include "CircularBuffer.h"
20 #include "MozziGuts.h"
21 #include "mozzi_analog.h"
22 #include "mozzi_config.h" // at the top of all MozziGuts and analog files
23 //#include "mozzi_utils.h"
24 #include "AudioOutput.h"
25
26
27 #if IS_AVR()
28 #include "FrequencyTimer2.h"
29 #include "TimerOne.h"
30 #elif IS_TEENSY3()
31 // required from http://github.com/pedvide/ADC for Teensy 3.*
32 #include "IntervalTimer.h"
33 #include <ADC.h>
34 #elif IS_STM32()
35 #include "HardwareTimer.h"
36 //#include <STM32ADC.h> // Disabled, here. See AudioConfigSTM32.h
37 #elif IS_ESP8266()
38 #include <uart.h>
39 #include <i2s.h>
40 uint16_t output_buffer_size = 0;
41 #elif IS_ESP32()
42 #include <driver/i2s.h> // for I2S-based output modes
43 #include <driver/timer.h> // for EXTERNAL_AUDIO_OUTPUT
44 #endif
45
46
47 #if (IS_TEENSY3() && F_CPU != 48000000) || (IS_AVR() && F_CPU != 16000000)
48 #warning
49 "Mozzi has been tested with a cpu clock speed of 16MHz on Arduino and 48MHz on Teensy 3! Results may vary with other speeds."
50 #endif
51
52 #if IS_TEENSY3()
53 ADC *adc; // adc object
54 uint8_t teensy_pin;
55 #elif IS_STM32()
56 STM32ADC adc(ADC1);
57 uint8_t stm32_current_adc_pin;
58 #endif
59
60 /*
61 ATmega328 technical manual, Section 12.7.4:
62 The dual-slope operation [of phase correct pwm] has lower maximum operation
63 frequency than single slope operation. However, due to the symmetric feature
64 of the dual-slope PWM modes, these modes are preferred for motor control
65 applications.
66 Due to the single-slope operation, the operating frequency of the
67 fast PWM mode can be twice as high as the phase correct PWM mode that use
68 dual-slope operation. This high frequency makes the fast PWM mode well suited
69 for power regulation, rectification, and DAC applications. High frequency allows
70 physically small sized external components (coils, capacitors)..
71
72 DAC, that's us! Fast PWM.
73
74 PWM frequency tests
75 62500Hz, single 8 or dual 16 bits, bad aliasing
76 125000Hz dual 14 bits, sweet
77 250000Hz dual 12 bits, gritty, if you're gonna have 2 pins, have 14 bits
78 500000Hz dual 10 bits, grittier
79 16384Hz single nearly 9 bits (original mode) not bad for a single pin, but
80 carrier freq noise can be an issue
81 */
82
83 #if BYPASS_MOZZI_OUTPUT_BUFFER == true
84 uint64_t samples_written_to_buffer = 0;
85 #else
86 //-----------------------------------------------------------------------------------------------------------------
87 // ring buffer for audio output
88 #if (STEREO_HACK == true)
89 CircularBuffer<StereoOutput> output_buffer; // fixed size 256
90 #else
91 CircularBuffer<AudioOutput_t> output_buffer; // fixed size 256
92 #endif
93 //-----------------------------------------------------------------------------------------------------------------
94 #endif
95
96 #if IS_AVR() // not storing backups, just turning timer on and off for pause for
97 // teensy 3.*, other ARMs
98
99 // to store backups of timer registers so Mozzi can be stopped and pre_mozzi
100 // timer values can be restored
101 static uint8_t pre_mozzi_TCCR1A, pre_mozzi_TCCR1B, pre_mozzi_OCR1A,
102 pre_mozzi_TIMSK1;
103
104 #if (AUDIO_MODE == HIFI)
105 #if defined(TCCR2A)
106 static uint8_t pre_mozzi_TCCR2A, pre_mozzi_TCCR2B, pre_mozzi_OCR2A,
107 pre_mozzi_TIMSK2;
108 #elif defined(TCCR2)
109 static uint8_t pre_mozzi_TCCR2, pre_mozzi_OCR2, pre_mozzi_TIMSK;
110 #elif defined(TCCR4A)
111 static uint8_t pre_mozzi_TCCR4A, pre_mozzi_TCCR4B, pre_mozzi_TCCR4C,
112 pre_mozzi_TCCR4D, pre_mozzi_TCCR4E, pre_mozzi_OCR4C, pre_mozzi_TIMSK4;
113 #endif
114 #endif
115
116 static void backupPreMozziTimer1() {
117 // backup pre-mozzi register values for pausing later
118 pre_mozzi_TCCR1A = TCCR1A;
119 pre_mozzi_TCCR1B = TCCR1B;
120 pre_mozzi_OCR1A = OCR1A;
121 pre_mozzi_TIMSK1 = TIMSK1;
122 }
123
124 //-----------------------------------------------------------------------------------------------------------------
125
126 #if (AUDIO_MODE == HIFI)
127 #if defined(TCCR2A)
128 static uint8_t mozzi_TCCR2A, mozzi_TCCR2B, mozzi_OCR2A, mozzi_TIMSK2;
129 #elif defined(TCCR2)
130 static uint8_t mozzi_TCCR2, mozzi_OCR2, mozzi_TIMSK;
131 #elif defined(TCCR4A)
132 static uint8_t mozzi_TCCR4A, mozzi_TCCR4B, mozzi_TCCR4C, mozzi_TCCR4D,
133 mozzi_TCCR4E, mozzi_OCR4C, mozzi_TIMSK4;
134 #endif
135 #endif
136
137 #endif // end of timer backups for non-Teensy 3 boards
138 //-----------------------------------------------------------------------------------------------------------------
139
140 ////// BEGIN AUDIO INPUT code ////////
141 #if (USE_AUDIO_INPUT == true)
142
143 // ring buffer for audio input
144 CircularBuffer<unsigned int> input_buffer; // fixed size 256
145
146 static boolean audio_input_is_available;
147 static int audio_input; // holds the latest audio from input_buffer
148 uint8_t adc_count = 0;
149
150 int getAudioInput() { return audio_input; }
151
152 static void startFirstAudioADC() {
153 #if IS_TEENSY3()
154 adc->startSingleRead(
155 AUDIO_INPUT_PIN); // ADC lib converts pin/channel in startSingleRead
156 #elif IS_STM32()
157 uint8_t dummy = AUDIO_INPUT_PIN;
158 adc.setPins(&dummy, 1);
159 adc.startConversion();
160 #else
161 adcStartConversion(adcPinToChannelNum(AUDIO_INPUT_PIN));
162 #endif
163 }
164
165 /*
166 static void receiveFirstAudioADC()
167 {
168 // nothing
169 }
170 */
171
172 static void startSecondAudioADC() {
173 #if IS_TEENSY3()
174 adc->startSingleRead(AUDIO_INPUT_PIN);
175 #elif IS_STM32()
176 uint8_t dummy = AUDIO_INPUT_PIN;
177 adc.setPins(&dummy, 1);
178 adc.startConversion();
179 #else
180 ADCSRA |= (1 << ADSC); // start a second conversion on the current channel
181 #endif
182 }
183
184 static void receiveSecondAudioADC() {
185 if (!input_buffer.isFull())
186 #if IS_TEENSY3()
187 input_buffer.write(adc->readSingle());
188 #elif IS_STM32()
189 input_buffer.write(adc.getData());
190 #else
191 input_buffer.write(ADC);
192 #endif
193 }
194
195 #if IS_TEENSY3() || IS_STM32() || IS_AVR()
196 #if IS_TEENSY3()
197 void adc0_isr(void)
198 #elif IS_STM32()
199 void stm32_adc_eoc_handler()
200 #else
201 ISR(ADC_vect, ISR_BLOCK)
202 #endif
203 {
204 switch (adc_count) {
205 case 0:
206 // 6us
207 receiveSecondAudioADC();
208 adcReadSelectedChannels();
209 break;
210
211 case 1:
212 // <2us, <1us w/o receive
213 // receiveFirstControlADC();
214 startSecondControlADC();
215 break;
216
217 case 2:
218 // 3us
219 receiveSecondControlADC();
220 startFirstAudioADC();
221 break;
222
223 // case 3:
224 // invisible
225 // receiveFirstAudioADC();
226 // break;
227 }
228 adc_count++;
229 }
230 #endif // end main audio input section
231 #endif
232 ////// END AUDIO INPUT code ////////
233
234
235 #if IS_SAMD21()
236 // These are ARM SAMD21 Timer 5 routines to establish a sample rate interrupt
237 static bool tcIsSyncing() {
238 return TC5->COUNT16.STATUS.reg & TC_STATUS_SYNCBUSY;
239 }
240
241 static void tcReset() {
242 // Reset TCx
243 TC5->COUNT16.CTRLA.reg = TC_CTRLA_SWRST;
244 while (tcIsSyncing())
245 ;
246 while (TC5->COUNT16.CTRLA.bit.SWRST)
247 ;
248 }
249 /* Not currently used, and does not compile with EXTERNAL_AUDIO_OUTPUT
250 static void tcEnd() {
251 // Disable TC5
252 TC5->COUNT16.CTRLA.reg &= ~TC_CTRLA_ENABLE;
253 while (tcIsSyncing())
254 ;
255 tcReset();
256 analogWrite(AUDIO_CHANNEL_1_PIN, 0);
257 } */
258
259 static void tcConfigure(uint32_t sampleRate) {
260 // Enable GCLK for TCC2 and TC5 (timer counter input clock)
261 GCLK->CLKCTRL.reg = (uint16_t)(GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 |
262 GCLK_CLKCTRL_ID(GCM_TC4_TC5));
263 while (GCLK->STATUS.bit.SYNCBUSY)
264 ;
265
266 tcReset();
267
268 // Set Timer counter Mode to 16 bits
269 TC5->COUNT16.CTRLA.reg |= TC_CTRLA_MODE_COUNT16;
270
271 // Set TC5 mode as match frequency
272 TC5->COUNT16.CTRLA.reg |= TC_CTRLA_WAVEGEN_MFRQ;
273
274 TC5->COUNT16.CTRLA.reg |= TC_CTRLA_PRESCALER_DIV1 | TC_CTRLA_ENABLE;
275
276 TC5->COUNT16.CC[0].reg = (uint16_t)(SystemCoreClock / sampleRate - 1);
277 while (tcIsSyncing())
278 ;
279
280 // Configure interrupt request
281 NVIC_DisableIRQ(TC5_IRQn);
282 NVIC_ClearPendingIRQ(TC5_IRQn);
283 NVIC_SetPriority(TC5_IRQn, 0);
284 NVIC_EnableIRQ(TC5_IRQn);
285
286 // Enable the TC5 interrupt request
287 TC5->COUNT16.INTENSET.bit.MC0 = 1;
288 while (tcIsSyncing())
289 ;
290 }
291 #endif
292
293 #if (IS_ESP8266() && (ESP_AUDIO_OUT_MODE == PDM_VIA_SERIAL) && (EXTERNAL_AUDIO_OUTPUT != true))
294 void CACHED_FUNCTION_ATTR esp8266_serial_audio_output() {
295 // Note: That unreadble mess is an optimized version of Serial1.availableForWrite()
296 while ((UART_TX_FIFO_SIZE - ((U1S >> USTXC) & 0xff)) > (PDM_RESOLUTION * 4)) {
297 audioOutput(output_buffer.read());
298 }
299 }
300 #endif
301
302 #if BYPASS_MOZZI_OUTPUT_BUFFER == true
303 inline void bufferAudioOutput(const AudioOutput_t f) {
304 audioOutput(f);
305 ++samples_written_to_buffer;
306 }
307 #else
308 #define canBufferAudioOutput() (!output_buffer.isFull())
309 #define bufferAudioOutput(f) output_buffer.write(f)
310 #endif
311
312 static uint16_t update_control_timeout;
313 static uint16_t update_control_counter;
314
315 inline void advanceControlLoop() {
316 if (!update_control_counter) {
317 update_control_counter = update_control_timeout;
318 updateControl();
319 adcStartReadCycle();
320 } else {
321 --update_control_counter;
322 }
323 }
324
325 void audioHook() // 2us on AVR excluding updateAudio()
326 {
327 // setPin13High();
328 #if (USE_AUDIO_INPUT == true)
329 if (!input_buffer.isEmpty())
330 audio_input = input_buffer.read();
331 #endif
332
333 if (canBufferAudioOutput()) {
334 advanceControlLoop();
335 #if (STEREO_HACK == true)
336 updateAudio(); // in hacked version, this returns void
337 bufferAudioOutput(StereoOutput(audio_out_1, audio_out_2));
338 #else
339 bufferAudioOutput(updateAudio());
340 #endif
341
342 #if IS_ESP8266()
343 yield();
344 #endif
345 }
346 // setPin13Low();
347 }
348
349 #if IS_SAMD21()
350 void TC5_Handler(void) __attribute__((weak, alias("samd21AudioOutput")));
351 #endif
352
353 //-----------------------------------------------------------------------------------------------------------------
354 #if (AUDIO_MODE == STANDARD) || (AUDIO_MODE == STANDARD_PLUS) || IS_STM32()
355 #if IS_TEENSY3()
356 IntervalTimer timer1;
357 #elif IS_STM32() && (EXTERNAL_AUDIO_OUTPUT == true)
358 HardwareTimer audio_update_timer(2);
359 #elif IS_STM32()
360 HardwareTimer audio_update_timer(AUDIO_UPDATE_TIMER);
361 HardwareTimer audio_pwm_timer(AUDIO_PWM_TIMER);
362 #endif
363
364 #if (BYPASS_MOZZI_OUTPUT_BUFFER != true)
365 static void CACHED_FUNCTION_ATTR defaultAudioOutput() {
366 #if (USE_AUDIO_INPUT == true)
367 adc_count = 0;
368 startSecondAudioADC();
369 #endif
370 audioOutput(output_buffer.read());
371 }
372 #endif
373
374 #if (IS_ESP32() && (BYPASS_MOZZI_OUTPUT_BUFFER != true))
375 void CACHED_FUNCTION_ATTR timer0_audio_output_isr(void *) {
376 TIMERG0.int_clr_timers.t0 = 1;
377 TIMERG0.hw_timer[0].config.alarm_en = 1;
378 defaultAudioOutput();
379 }
380 #endif
381
382 #if IS_SAMD21()
383 #ifdef __cplusplus
384 extern "C" {
385 #endif
386 void samd21AudioOutput() {
387 defaultAudioOutput();
388 TC5->COUNT16.INTFLAG.bit.MC0 = 1;
389 }
390 #ifdef __cplusplus
391 }
392 #endif
393 #endif
394
395 #if !IS_AVR()
396 static void startAudioStandard() {
397
398 #if IS_TEENSY3()
399 adc->setAveraging(0);
400 adc->setConversionSpeed(
401 ADC_CONVERSION_SPEED::MED_SPEED); // could be HIGH_SPEED, noisier
402
403 analogWriteResolution(12);
404 timer1.begin(defaultAudioOutput, 1000000UL / AUDIO_RATE);
405 #elif IS_SAMD21()
406 #ifdef ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS
407 {
408 static const int CPLAY_SPEAKER_SHUTDOWN = 11;
409 pinMode(CPLAY_SPEAKER_SHUTDOWN, OUTPUT);
410 digitalWrite(CPLAY_SPEAKER_SHUTDOWN, HIGH);
411 }
412
413 #endif
414 analogWriteResolution(10);
415 #if (EXTERNAL_AUDIO_OUTPUT != true)
416 analogWrite(AUDIO_CHANNEL_1_PIN, 0);
417 #endif
418 tcConfigure(AUDIO_RATE);
419
420 #elif IS_ESP32() && (BYPASS_MOZZI_OUTPUT_BUFFER != true) // for external audio output, set up a timer running a audio rate
421 static intr_handle_t s_timer_handle;
422 timer_config_t config = {
423 .alarm_en = true,
424 .counter_en = false,
425 .intr_type = TIMER_INTR_LEVEL,
426 .counter_dir = TIMER_COUNT_UP,
427 .auto_reload = true,
428 .divider = 1 // For max available precision: The APB_CLK clock signal is running at 80 MHz, i.e. 1/80 uS per tick
429 };
430 timer_init(TIMER_GROUP_0, TIMER_0, &config);
431 timer_set_counter_value(TIMER_GROUP_0, TIMER_0, 0);
432 timer_set_alarm_value(TIMER_GROUP_0, TIMER_0, 80000000UL / AUDIO_RATE);
433 timer_enable_intr(TIMER_GROUP_0, TIMER_0);
434 timer_isr_register(TIMER_GROUP_0, TIMER_0, &timer0_audio_output_isr, nullptr, 0, &s_timer_handle);
435 timer_start(TIMER_GROUP_0, TIMER_0);
436
437 #elif IS_ESP32()
438 static const i2s_config_t i2s_config = {
439 #if (ESP32_AUDIO_OUT_MODE == PT8211_DAC) || (ESP32_AUDIO_OUT_MODE == PDM_VIA_I2S)
440 .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
441 #elif (ESP32_AUDIO_OUT_MODE == INTERNAL_DAC)
442 .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN),
443 #endif
444 .sample_rate = AUDIO_RATE * PDM_RESOLUTION,
445 .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // only the top 8 bits will actually be used by the internal DAC, but using 8 bits straight away seems buggy
446 .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, // always use stereo output. mono seems to be buggy, and the overhead is insignifcant on the ESP32
447 .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_LSB), // this appears to be the correct setting for internal DAC and PT8211, but not for other dacs
448 .intr_alloc_flags = 0, // default interrupt priority
449 .dma_buf_count = 8, // 8*128 bytes of buffer corresponds to 256 samples (2 channels, see above, 2 bytes per sample per channel)
450 .dma_buf_len = 128,
451 .use_apll = false
452 };
453
454 i2s_driver_install(i2s_num, &i2s_config, 0, NULL);
455 #if (ESP32_AUDIO_OUT_MODE == PT8211_DAC) || (ESP32_AUDIO_OUT_MODE == PDM_VIA_I2S)
456 static const i2s_pin_config_t pin_config = {
457 .bck_io_num = ESP32_I2S_BCK_PIN,
458 .ws_io_num = ESP32_I2S_WS_PIN,
459 .data_out_num = ESP32_I2S_DATA_PIN,
460 .data_in_num = -1
461 };
462 i2s_set_pin((i2s_port_t)i2s_num, &pin_config);
463 #elif (ESP32_AUDIO_OUT_MODE == INTERNAL_DAC)
464 i2s_set_pin((i2s_port_t)i2s_num, NULL);
465 i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN);
466 #endif
467 i2s_zero_dma_buffer((i2s_port_t)i2s_num);
468
469 #elif IS_STM32()
470 audio_update_timer.pause();
471 //audio_update_timer.setPeriod(1000000UL / AUDIO_RATE);
472 // Manually calculate prescaler and overflow instead of using setPeriod, to avoid rounding errors
473 uint32_t period_cyc = F_CPU / AUDIO_RATE;
474 uint16_t prescaler = (uint16_t)(period_cyc / 65535 + 1);
475 uint16_t overflow = (uint16_t)((period_cyc + (prescaler / 2)) / prescaler);
476 audio_update_timer.setPrescaleFactor(prescaler);
477 audio_update_timer.setOverflow(overflow);
478 audio_update_timer.setChannel1Mode(TIMER_OUTPUT_COMPARE);
479 audio_update_timer.setCompare(TIMER_CH1,
480 1); // Interrupt 1 count after each update
481 audio_update_timer.attachCompare1Interrupt(defaultAudioOutput);
482 audio_update_timer.refresh();
483 audio_update_timer.resume();
484
485 #if (EXTERNAL_AUDIO_OUTPUT != true)
486 pinMode(AUDIO_CHANNEL_1_PIN, PWM);
487 #if (AUDIO_MODE == HIFI)
488 pinMode(AUDIO_CHANNEL_1_PIN_HIGH, PWM);
489 #elif (STEREO_HACK == true)
490 pinMode(AUDIO_CHANNEL_2_PIN, PWM);
491 #endif
492
493 #define MAX_CARRIER_FREQ (F_CPU / (1 << AUDIO_BITS_PER_CHANNEL))
494 #if MAX_CARRIER_FREQ < AUDIO_RATE
495 #error Configured audio resolution is definitely too high at the configured audio rate (and the given CPU speed)
496 #elif MAX_CARRIER_FREQ < (AUDIO_RATE * 3)
497 #warning Configured audio resolution may be higher than optimal at the configured audio rate (and the given CPU speed)
498 #endif
499
500 #if MAX_CARRIER_FREQ < (AUDIO_RATE * 5)
501 // Generate as fast a carrier as possible
502 audio_pwm_timer.setPrescaleFactor(1);
503 #else
504 // No point in generating arbitrarily high carrier frequencies. In fact, if
505 // there _is_ any headroom, give the PWM pin more time to swing from HIGH to
506 // LOW and BACK, cleanly
507 audio_pwm_timer.setPrescaleFactor((int)MAX_CARRIER_FREQ / (AUDIO_RATE * 5));
508 #endif
509 audio_pwm_timer.setOverflow(
510 1 << AUDIO_BITS_PER_CHANNEL); // Allocate enough room to write all
511 // intended bits
512 #endif
513
514 #elif IS_ESP8266() && (EXTERNAL_AUDIO_OUTPUT == true) && (BYPASS_MOZZI_OUTPUT_BUFFER != true) // for external audio output, set up a timer running a audio rate
515 timer1_isr_init();
516 timer1_attachInterrupt(defaultAudioOutput);
517 timer1_enable(TIM_DIV1, TIM_EDGE, TIM_LOOP);
518 timer1_write(F_CPU / AUDIO_RATE);
519 #elif IS_ESP8266()
520 #if (ESP_AUDIO_OUT_MODE == PDM_VIA_SERIAL)
521 Serial1.begin(
522 AUDIO_RATE * (PDM_RESOLUTION * 40), SERIAL_8N1,
523 SERIAL_TX_ONLY); // Note: PDM_RESOLUTION corresponds to packets of 32
524 // encoded bits However, the UART (unfortunately) adds a
525 // start and stop bit each around each byte, thus sending
526 // a total to 40 bits per audio sample per
527 // PDM_RESOLUTION.
528 // set up a timer to copy from Mozzi output_buffer into Serial TX buffer
529 timer1_isr_init();
530 timer1_attachInterrupt(esp8266_serial_audio_output);
531 // UART FIFO buffer size is 128 bytes. To be on the safe side, we keep the
532 // interval to the time needed to write half of that. PDM_RESOLUTION * 4 bytes
533 // per sample written.
534 timer1_enable(TIM_DIV16, TIM_EDGE, TIM_LOOP);
535 timer1_write(F_CPU / (AUDIO_RATE * PDM_RESOLUTION));
536 #else
537 i2s_begin();
538 #if (ESP_AUDIO_OUT_MODE == PDM_VIA_I2S)
539 pinMode(2, INPUT); // Set the two unneeded I2S pins to input mode, to reduce
540 // side effects
541 pinMode(15, INPUT);
542 #endif
543 i2s_set_rate(AUDIO_RATE * PDM_RESOLUTION);
544 if (output_buffer_size == 0)
545 output_buffer_size =
546 i2s_available(); // Do not reset count when stopping / restarting
547 #endif
548 #endif
549 }
550
551 #elif IS_AVR() && (EXTERNAL_AUDIO_OUTPUT == true)
552 static void startAudioStandard() {
553 backupPreMozziTimer1();
554 Timer1.initializeCPUCycles(
555 F_CPU / AUDIO_RATE,
556 PHASE_FREQ_CORRECT); // set period, phase and frequency correct
557 TIMSK1 = _BV(TOIE1); // Overflow Interrupt Enable (when not using
558 // Timer1.attachInterrupt())
559 }
560
561 ISR(TIMER1_OVF_vect, ISR_BLOCK) {
562 defaultAudioOutput();
563 }
564
565 #else
566
567 // avr architecture
568 static void startAudioStandard() {
569 backupPreMozziTimer1();
570
571 pinMode(AUDIO_CHANNEL_1_PIN, OUTPUT); // set pin to output for audio
572 // pinMode(AUDIO_CHANNEL_2_PIN, OUTPUT); // set pin to output for audio
573 #if (AUDIO_MODE == STANDARD)
574 Timer1.initializeCPUCycles(
575 F_CPU / AUDIO_RATE,
576 PHASE_FREQ_CORRECT); // set period, phase and frequency correct
577 #else // (AUDIO_MODE == STANDARD_PLUS)
578 Timer1.initializeCPUCycles(F_CPU / PWM_RATE,
579 FAST); // fast mode enables higher PWM rate
580 #endif
581 Timer1.pwm(AUDIO_CHANNEL_1_PIN,
582 AUDIO_BIAS); // pwm pin, 50% of Mozzi's duty cycle, ie. 0 signal
583 #if (STEREO_HACK == true)
584 Timer1.pwm(AUDIO_CHANNEL_2_PIN, AUDIO_BIAS); // sets pin to output
585 #endif
586 TIMSK1 = _BV(TOIE1); // Overflow Interrupt Enable (when not using
587 // Timer1.attachInterrupt())
588 }
589
590 /* Interrupt service routine moves sound data from the output buffer to the
591 Arduino output register, running at AUDIO_RATE. */
592
593 ISR(TIMER1_OVF_vect, ISR_BLOCK) {
594
595 #if (AUDIO_MODE == STANDARD_PLUS) &&
596 (AUDIO_RATE == 16384) // only update every second ISR, if lower audio rate
597 static boolean alternate;
598 alternate = !alternate;
599 if (alternate) return;
600 #endif
601
602 defaultAudioOutput();
603 }
604 // end avr
605 #endif
606 // end STANDARD
607
608 //-----------------------------------------------------------------------------------------------------------------
609 #elif IS_AVR() && (AUDIO_MODE == HIFI)
610
611 static void startAudioHiFi() {
612 backupPreMozziTimer1();
613 // pwm on timer 1
614 pinMode(AUDIO_CHANNEL_1_highByte_PIN,
615 OUTPUT); // set pin to output for audio, use 3.9k resistor
616 pinMode(AUDIO_CHANNEL_1_lowByte_PIN,
617 OUTPUT); // set pin to output for audio, use 499k resistor
618 Timer1.initializeCPUCycles(
619 F_CPU / 125000,
620 FAST); // set period for 125000 Hz fast pwm carrier frequency = 14 bits
621 Timer1.pwm(AUDIO_CHANNEL_1_highByte_PIN,
622 0); // pwm pin, 0% duty cycle, ie. 0 signal
623 Timer1.pwm(AUDIO_CHANNEL_1_lowByte_PIN,
624 0); // pwm pin, 0% duty cycle, ie. 0 signal
625 // audio output interrupt on timer 2, sets the pwm levels of timer 1
626 setupTimer2();
627 }
628
629 /* set up Timer 2 using modified FrequencyTimer2 library */
630 void dummy() {}
631
632 static void backupPreMozziTimer2() {
633 // backup Timer2 register values
634 #if defined(TCCR2A)
635 pre_mozzi_TCCR2A = TCCR2A;
636 pre_mozzi_TCCR2B = TCCR2B;
637 pre_mozzi_OCR2A = OCR2A;
638 pre_mozzi_TIMSK2 = TIMSK2;
639 #elif defined(TCCR2)
640 pre_mozzi_TCCR2 = TCCR2;
641 pre_mozzi_OCR2 = OCR2;
642 pre_mozzi_TIMSK = TIMSK;
643 #elif defined(TCCR4A)
644 pre_mozzi_TCCR4B = TCCR4A;
645 pre_mozzi_TCCR4B = TCCR4B;
646 pre_mozzi_TCCR4B = TCCR4C;
647 pre_mozzi_TCCR4B = TCCR4D;
648 pre_mozzi_TCCR4B = TCCR4E;
649 pre_mozzi_OCR4C = OCR4C;
650 pre_mozzi_TIMSK4 = TIMSK4;
651 #endif
652 }
653
654 // audio output interrupt on timer 2 (or 4 on ATMEGA32U4 cpu), sets the pwm
655 // levels of timer 2
656 static void setupTimer2() {
657 backupPreMozziTimer2(); // to reset while pausing
658 unsigned long period = F_CPU / AUDIO_RATE;
659 FrequencyTimer2::setPeriodCPUCycles(period);
660 FrequencyTimer2::setOnOverflow(dummy);
661 FrequencyTimer2::enable();
662 }
663
664 #if defined(TIMER2_COMPA_vect)
665 ISR(TIMER2_COMPA_vect)
666 #elif defined(TIMER2_COMP_vect)
667 ISR(TIMER2_COMP_vect)
668 #elif defined(TIMER4_COMPA_vect)
669 ISR(TIMER4_COMPA_vect)
670 #else
671 #error
672 "This board does not have a hardware timer which is compatible with FrequencyTimer2"
673 void dummy_function(void)
674 #endif
675 {
676 defaultAudioOutput();
677 }
678
679 // end of HIFI
680
681 #endif
682
683 //-----------------------------------------------------------------------------------------------------------------
684
685 static void startControl(unsigned int control_rate_hz) {
686 update_control_timeout = AUDIO_RATE / control_rate_hz;
687 }
688
689 void startMozzi(int control_rate_hz) {
690 setupMozziADC(); // you can use setupFastAnalogRead() with FASTER or FASTEST
691 // in setup() if desired (not for Teensy 3.* )
692 // delay(200); // so AutoRange doesn't read 0 to start with
693 startControl(control_rate_hz);
694 #if (AUDIO_MODE == STANDARD) || (AUDIO_MODE == STANDARD_PLUS) ||
695 IS_STM32() // Sorry, this is really hacky. But on STM32 regular and HIFI
696 // audio modes are so similar to set up, that we do it all in one
697 // function.
698 startAudioStandard();
699 #elif (AUDIO_MODE == HIFI)
700 startAudioHiFi();
701 #endif
702 }
703
704 void stopMozzi() {
705 #if IS_TEENSY3()
706 timer1.end();
707 #elif IS_STM32()
708 audio_update_timer.pause();
709 #elif IS_ESP8266()
710 #if (ESP_AUDIO_OUT_MODE != PDM_VIA_SERIAL)
711 i2s_end();
712 #else
713 timer1_disable();
714 #endif
715 #elif IS_SAMD21()
716 #elif IS_ESP32()
717 #else
718
719 noInterrupts();
720
721 // restore backed up register values
722 TCCR1A = pre_mozzi_TCCR1A;
723 TCCR1B = pre_mozzi_TCCR1B;
724 OCR1A = pre_mozzi_OCR1A;
725
726 TIMSK1 = pre_mozzi_TIMSK1;
727
728 #if (AUDIO_MODE == HIFI)
729 #if defined(TCCR2A)
730 TCCR2A = pre_mozzi_TCCR2A;
731 TCCR2B = pre_mozzi_TCCR2B;
732 OCR2A = pre_mozzi_OCR2A;
733 TIMSK2 = pre_mozzi_TIMSK2;
734 #elif defined(TCCR2)
735 TCCR2 = pre_mozzi_TCCR2;
736 OCR2 = pre_mozzi_OCR2;
737 TIMSK = pre_mozzi_TIMSK;
738 #elif defined(TCCR4A)
739 TCCR4B = pre_mozzi_TCCR4A;
740 TCCR4B = pre_mozzi_TCCR4B;
741 TCCR4B = pre_mozzi_TCCR4C;
742 TCCR4B = pre_mozzi_TCCR4D;
743 TCCR4B = pre_mozzi_TCCR4E;
744 OCR4C = pre_mozzi_OCR4C;
745 TIMSK4 = pre_mozzi_TIMSK4;
746 #endif
747 #endif
748 #endif
749 interrupts();
750 }
751
752 unsigned long audioTicks() {
753 #if (BYPASS_MOZZI_OUTPUT_BUFFER != true)
754 return output_buffer.count();
755 #elif IS_ESP32()
756 // TODO: This is not entirely accurate, as it does not account for samples still in the buffer
757 // and not yet written to output. There does not seem to be an API to retrieve I2S-buffer
758 // fill state on ESP32.
759 return samples_written_to_buffer;
760 #elif (IS_ESP8266() && (ESP_AUDIO_OUT_MODE == PDM_VIA_I2S) && (PDM_RESOLUTION != 1))
761 return (samples_written_to_buffer -
762 ((output_buffer_size - i2s_available()) / PDM_RESOLUTION));
763 #else
764 return (samples_written_to_buffer - (output_buffer_size - i2s_available()));
765 #endif
766 }
767
768 unsigned long mozziMicros() { return audioTicks() * MICROS_PER_AUDIO_TICK; }
769
770 // Unmodified TimerOne.cpp has TIMER3_OVF_vect.
771 // Watch out if you update the library file.
772 // The symptom will be no sound.
773 // ISR(TIMER1_OVF_vect)
774 // {
775 // Timer1.isrCallback();
776 // }
mozziMicros
unsigned long mozziMicros()
An alternative for Arduino time functions like micros() and millis().
Definition: MozziGuts.cpp:768
stopMozzi
void stopMozzi()
Stops audio and control interrupts and restores the timers to the values they had before Mozzi was st...
Definition: MozziGuts.cpp:704
AUDIO_MODE
#define AUDIO_MODE
AUDIO_MODE holds the audio mode setting.
Definition: mozzi_config.h:28
HIFI
#define HIFI
Definition: MozziGuts.h:155
STEREO_HACK
#define STEREO_HACK
This sets an option for stereo output, a hack which requires variables audio_signal_1 and audio_signa...
Definition: mozzi_config.h:92
IS_SAMD21
#define IS_SAMD21()
Definition: hardware_defines.h:16
updateControl
void updateControl()
This is where you put your control code.
AUDIO_RATE
#define AUDIO_RATE
Holds the audio rate setting.
Definition: mozzi_config.h:62
CircularBuffer
Circular buffer object.
Definition: CircularBuffer.h:12
IS_STM32
#define IS_STM32()
Definition: hardware_defines.h:18
STANDARD_PLUS
#define STANDARD_PLUS
Definition: MozziGuts.h:154
audioHook
void audioHook()
This is required in Arduino&#39;s loop().
Definition: MozziGuts.cpp:325
IS_AVR
#define IS_AVR()
Definition: hardware_defines.h:15
IS_TEENSY3
#define IS_TEENSY3()
Definition: hardware_defines.h:17
audioTicks
unsigned long audioTicks()
An alternative for Arduino time functions like micros() and millis().
Definition: MozziGuts.cpp:752
AudioOutput_t
#define AudioOutput_t
Definition: AudioOutput.h:59
MICROS_PER_AUDIO_TICK
#define MICROS_PER_AUDIO_TICK
Definition: MozziGuts.h:172
CACHED_FUNCTION_ATTR
#define CACHED_FUNCTION_ATTR
Definition: hardware_defines.h:44
startMozzi
void startMozzi(int control_rate_hz=CONTROL_RATE)
Sets up the timers for audio and control rate processes, storing the timer registers so they can be r...
Definition: MozziGuts.cpp:689
STANDARD
#define STANDARD
Used to set AUDIO_MODE to STANDARD, STANDARD_PLUS, or HIFI.
Definition: MozziGuts.h:153
EXTERNAL_AUDIO_OUTPUT
#define EXTERNAL_AUDIO_OUTPUT
Defining this option as true in mozzi_config.h allows to completely customize the audio output...
Definition: mozzi_config.h:99
IS_ESP8266
#define IS_ESP8266()
Definition: hardware_defines.h:19
IS_ESP32
#define IS_ESP32()
Definition: hardware_defines.h:20