28 #include "FrequencyTimer2.h" 32 #include "IntervalTimer.h" 35 #include "HardwareTimer.h" 40 uint16_t output_buffer_size = 0;
42 #include <driver/i2s.h> 43 #include <driver/timer.h> 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." 57 uint8_t stm32_current_adc_pin;
83 #if BYPASS_MOZZI_OUTPUT_BUFFER == true 84 uint64_t samples_written_to_buffer = 0;
89 CircularBuffer<StereoOutput> output_buffer;
101 static uint8_t pre_mozzi_TCCR1A, pre_mozzi_TCCR1B, pre_mozzi_OCR1A,
104 #if (AUDIO_MODE == HIFI) 106 static uint8_t pre_mozzi_TCCR2A, pre_mozzi_TCCR2B, pre_mozzi_OCR2A,
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;
116 static void backupPreMozziTimer1() {
118 pre_mozzi_TCCR1A = TCCR1A;
119 pre_mozzi_TCCR1B = TCCR1B;
120 pre_mozzi_OCR1A = OCR1A;
121 pre_mozzi_TIMSK1 = TIMSK1;
126 #if (AUDIO_MODE == HIFI) 128 static uint8_t mozzi_TCCR2A, mozzi_TCCR2B, mozzi_OCR2A, mozzi_TIMSK2;
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;
141 #if (USE_AUDIO_INPUT == true) 144 CircularBuffer<
unsigned int> input_buffer;
146 static boolean audio_input_is_available;
147 static int audio_input;
148 uint8_t adc_count = 0;
150 int getAudioInput() {
return audio_input; }
152 static void startFirstAudioADC() {
154 adc->startSingleRead(
157 uint8_t dummy = AUDIO_INPUT_PIN;
158 adc.setPins(&dummy, 1);
159 adc.startConversion();
161 adcStartConversion(adcPinToChannelNum(AUDIO_INPUT_PIN));
172 static void startSecondAudioADC() {
174 adc->startSingleRead(AUDIO_INPUT_PIN);
176 uint8_t dummy = AUDIO_INPUT_PIN;
177 adc.setPins(&dummy, 1);
178 adc.startConversion();
180 ADCSRA |= (1 << ADSC);
184 static void receiveSecondAudioADC() {
185 if (!input_buffer.isFull())
187 input_buffer.write(adc->readSingle());
189 input_buffer.write(adc.getData());
191 input_buffer.write(ADC);
195 #if IS_TEENSY3() || IS_STM32() || IS_AVR() 199 void stm32_adc_eoc_handler()
201 ISR(ADC_vect, ISR_BLOCK)
207 receiveSecondAudioADC();
208 adcReadSelectedChannels();
214 startSecondControlADC();
219 receiveSecondControlADC();
220 startFirstAudioADC();
237 static bool tcIsSyncing() {
238 return TC5->COUNT16.STATUS.reg & TC_STATUS_SYNCBUSY;
241 static void tcReset() {
243 TC5->COUNT16.CTRLA.reg = TC_CTRLA_SWRST;
244 while (tcIsSyncing())
246 while (TC5->COUNT16.CTRLA.bit.SWRST)
259 static void tcConfigure(uint32_t sampleRate) {
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)
269 TC5->COUNT16.CTRLA.reg |= TC_CTRLA_MODE_COUNT16;
272 TC5->COUNT16.CTRLA.reg |= TC_CTRLA_WAVEGEN_MFRQ;
274 TC5->COUNT16.CTRLA.reg |= TC_CTRLA_PRESCALER_DIV1 | TC_CTRLA_ENABLE;
276 TC5->COUNT16.CC[0].reg = (uint16_t)(SystemCoreClock / sampleRate - 1);
277 while (tcIsSyncing())
281 NVIC_DisableIRQ(TC5_IRQn);
282 NVIC_ClearPendingIRQ(TC5_IRQn);
283 NVIC_SetPriority(TC5_IRQn, 0);
284 NVIC_EnableIRQ(TC5_IRQn);
287 TC5->COUNT16.INTENSET.bit.MC0 = 1;
288 while (tcIsSyncing())
294 void CACHED_FUNCTION_ATTR esp8266_serial_audio_output() {
296 while ((UART_TX_FIFO_SIZE - ((U1S >> USTXC) & 0xff)) > (PDM_RESOLUTION * 4)) {
297 audioOutput(output_buffer.read());
302 #if BYPASS_MOZZI_OUTPUT_BUFFER == true 303 inline void bufferAudioOutput(
const AudioOutput_t f) {
305 ++samples_written_to_buffer;
308 #define canBufferAudioOutput() (!output_buffer.isFull()) 309 #define bufferAudioOutput(f) output_buffer.write(f) 312 static uint16_t update_control_timeout;
313 static uint16_t update_control_counter;
315 inline void advanceControlLoop() {
316 if (!update_control_counter) {
317 update_control_counter = update_control_timeout;
321 --update_control_counter;
328 #if (USE_AUDIO_INPUT == true) 329 if (!input_buffer.isEmpty())
330 audio_input = input_buffer.read();
333 if (canBufferAudioOutput()) {
334 advanceControlLoop();
337 bufferAudioOutput(StereoOutput(audio_out_1, audio_out_2));
339 bufferAudioOutput(updateAudio());
350 void TC5_Handler(
void)
__attribute__((weak, alias(
"samd21AudioOutput")));
356 IntervalTimer timer1;
358 HardwareTimer audio_update_timer(2);
360 HardwareTimer audio_update_timer(AUDIO_UPDATE_TIMER);
361 HardwareTimer audio_pwm_timer(AUDIO_PWM_TIMER);
364 #if (BYPASS_MOZZI_OUTPUT_BUFFER != true) 366 #if (USE_AUDIO_INPUT == true) 368 startSecondAudioADC();
370 audioOutput(output_buffer.read());
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();
386 void samd21AudioOutput() {
387 defaultAudioOutput();
388 TC5->COUNT16.INTFLAG.bit.MC0 = 1;
396 static void startAudioStandard() {
399 adc->setAveraging(0);
400 adc->setConversionSpeed(
401 ADC_CONVERSION_SPEED::MED_SPEED);
403 analogWriteResolution(12);
404 timer1.begin(defaultAudioOutput, 1000000UL / AUDIO_RATE);
406 #ifdef ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS 408 static const int CPLAY_SPEAKER_SHUTDOWN = 11;
409 pinMode(CPLAY_SPEAKER_SHUTDOWN, OUTPUT);
410 digitalWrite(CPLAY_SPEAKER_SHUTDOWN, HIGH);
414 analogWriteResolution(10);
415 #if (EXTERNAL_AUDIO_OUTPUT != true) 416 analogWrite(AUDIO_CHANNEL_1_PIN, 0);
418 tcConfigure(AUDIO_RATE);
420 #elif IS_ESP32() && (BYPASS_MOZZI_OUTPUT_BUFFER != true) 421 static intr_handle_t s_timer_handle;
422 timer_config_t config = {
425 .intr_type = TIMER_INTR_LEVEL,
426 .counter_dir = TIMER_COUNT_UP,
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);
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),
444 .sample_rate = AUDIO_RATE * PDM_RESOLUTION,
445 .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
446 .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
447 .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_LSB),
448 .intr_alloc_flags = 0,
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,
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);
467 i2s_zero_dma_buffer((i2s_port_t)i2s_num);
470 audio_update_timer.pause();
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,
481 audio_update_timer.attachCompare1Interrupt(defaultAudioOutput);
482 audio_update_timer.refresh();
483 audio_update_timer.resume();
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);
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) 500 #if MAX_CARRIER_FREQ < (AUDIO_RATE * 5
) 502 audio_pwm_timer.setPrescaleFactor(1);
507 audio_pwm_timer.setPrescaleFactor((
int)MAX_CARRIER_FREQ / (AUDIO_RATE * 5));
509 audio_pwm_timer.setOverflow(
510 1 << AUDIO_BITS_PER_CHANNEL);
516 timer1_attachInterrupt(defaultAudioOutput);
517 timer1_enable(TIM_DIV1, TIM_EDGE, TIM_LOOP);
518 timer1_write(F_CPU / AUDIO_RATE);
520 #if (ESP_AUDIO_OUT_MODE == PDM_VIA_SERIAL) 522 AUDIO_RATE * (PDM_RESOLUTION * 40), SERIAL_8N1,
530 timer1_attachInterrupt(esp8266_serial_audio_output);
534 timer1_enable(TIM_DIV16, TIM_EDGE, TIM_LOOP);
535 timer1_write(F_CPU / (AUDIO_RATE * PDM_RESOLUTION));
538 #if (ESP_AUDIO_OUT_MODE == PDM_VIA_I2S) 543 i2s_set_rate(AUDIO_RATE * PDM_RESOLUTION);
544 if (output_buffer_size == 0)
551 #elif IS_AVR() && (EXTERNAL_AUDIO_OUTPUT == true) 552 static void startAudioStandard() {
553 backupPreMozziTimer1();
554 Timer1.initializeCPUCycles(
561 ISR(TIMER1_OVF_vect, ISR_BLOCK) {
562 defaultAudioOutput();
568 static void startAudioStandard() {
569 backupPreMozziTimer1();
571 pinMode(AUDIO_CHANNEL_1_PIN, OUTPUT);
573 #if (AUDIO_MODE == STANDARD) 574 Timer1.initializeCPUCycles(
578 Timer1.initializeCPUCycles(F_CPU / PWM_RATE,
581 Timer1.pwm(AUDIO_CHANNEL_1_PIN,
583 #if (STEREO_HACK == true) 584 Timer1.pwm(AUDIO_CHANNEL_2_PIN, AUDIO_BIAS);
593 ISR(TIMER1_OVF_vect, ISR_BLOCK) {
595 #if (AUDIO_MODE == STANDARD_PLUS) && 596 (AUDIO_RATE == 16384
) 597 static boolean alternate;
598 alternate = !alternate;
599 if (alternate)
return;
602 defaultAudioOutput();
609 #elif IS_AVR() && (AUDIO_MODE == HIFI) 611 static void startAudioHiFi() {
612 backupPreMozziTimer1();
614 pinMode(AUDIO_CHANNEL_1_highByte_PIN,
616 pinMode(AUDIO_CHANNEL_1_lowByte_PIN,
618 Timer1.initializeCPUCycles(
621 Timer1.pwm(AUDIO_CHANNEL_1_highByte_PIN,
623 Timer1.pwm(AUDIO_CHANNEL_1_lowByte_PIN,
632 static void backupPreMozziTimer2() {
635 pre_mozzi_TCCR2A = TCCR2A;
636 pre_mozzi_TCCR2B = TCCR2B;
637 pre_mozzi_OCR2A = OCR2A;
638 pre_mozzi_TIMSK2 = TIMSK2;
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;
656 static void setupTimer2() {
657 backupPreMozziTimer2();
658 unsigned long period = F_CPU / AUDIO_RATE;
659 FrequencyTimer2::setPeriodCPUCycles(period);
660 FrequencyTimer2::setOnOverflow(dummy);
661 FrequencyTimer2::enable();
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)
672 "This board does not have a hardware timer which is compatible with FrequencyTimer2" 673 void dummy_function(
void)
676 defaultAudioOutput();
685 static void startControl(
unsigned int control_rate_hz) {
686 update_control_timeout =
AUDIO_RATE / control_rate_hz;
693 startControl(control_rate_hz);
698 startAudioStandard();
699 #elif (AUDIO_MODE == HIFI) 708 audio_update_timer.pause();
710 #if (ESP_AUDIO_OUT_MODE != PDM_VIA_SERIAL) 722 TCCR1A = pre_mozzi_TCCR1A;
723 TCCR1B = pre_mozzi_TCCR1B;
724 OCR1A = pre_mozzi_OCR1A;
726 TIMSK1 = pre_mozzi_TIMSK1;
730 TCCR2A = pre_mozzi_TCCR2A;
731 TCCR2B = pre_mozzi_TCCR2B;
732 OCR2A = pre_mozzi_OCR2A;
733 TIMSK2 = pre_mozzi_TIMSK2;
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;
753 #if (BYPASS_MOZZI_OUTPUT_BUFFER != true) 754 return output_buffer.count();
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));
764 return (samples_written_to_buffer - (output_buffer_size - i2s_available()));
unsigned long mozziMicros()
An alternative for Arduino time functions like micros() and millis().
void stopMozzi()
Stops audio and control interrupts and restores the timers to the values they had before Mozzi was st...
#define AUDIO_MODE
AUDIO_MODE holds the audio mode setting.
#define STEREO_HACK
This sets an option for stereo output, a hack which requires variables audio_signal_1 and audio_signa...
void updateControl()
This is where you put your control code.
#define AUDIO_RATE
Holds the audio rate setting.
void audioHook()
This is required in Arduino's loop().
unsigned long audioTicks()
An alternative for Arduino time functions like micros() and millis().
#define MICROS_PER_AUDIO_TICK
#define CACHED_FUNCTION_ATTR
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...
#define STANDARD
Used to set AUDIO_MODE to STANDARD, STANDARD_PLUS, or HIFI.
#define EXTERNAL_AUDIO_OUTPUT
Defining this option as true in mozzi_config.h allows to completely customize the audio output...