Skip to content

Commit

Permalink
Also compiles for ESP32, now, in default config.
Browse files Browse the repository at this point in the history
  • Loading branch information
tfry-git committed Nov 14, 2023
1 parent b19df2a commit 4b03226
Show file tree
Hide file tree
Showing 8 changed files with 176 additions and 114 deletions.
45 changes: 0 additions & 45 deletions AudioConfigESP32.h

This file was deleted.

72 changes: 71 additions & 1 deletion MozziConfigExample.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@
* - MOZZI_OUTPUT_EXTERNAL_TIMED
* - MOZZI_OUTPUT_EXTERNAL_CUSTOM
*
* In all cases, Timer 1 is claimed, and is not available for any other purpose.
* In all cases, except MOZZI_OUTPUT_EXTERNAL_CUSTOM, Timer 1 is claimed, and is not available for any other purpose.
*
* @section avr_pwm MOZZI_OUTPUT_PWM
* For MOZZI_OUTPUT_PWM, output is restricted to pins that are hardware-attached to Timer 1, but can be configured
Expand Down Expand Up @@ -356,3 +356,73 @@
* some 8 bit boards!
*/
//#define MOZZI_AUDIO_BITS 16




/***************************************** ADVANCED SETTTINGS -- ESP32 ***********************************************************
*
* The settings in the following section applies to the ESP32 architecture.
*
* It is generally not recommended to change anything, here, unless you really know, what you are doing and/or
* are willing to rough it out by yourself.
*
********************************************************************************************************************************/


/** @ingroup hardware
* @page hardware_esp32 Mozzi on ESP32-based boards.
*
* The following audio modes (see @ref MOZZI_AUDIO_MODE) are currently supported on this hardware:
* - MOZZI_OUTPUT_EXTERNAL_TIMED
* - MOZZI_OUTPUT_EXTERNAL_CUSTOM
* - MOZZI_OUTPUT_PDM_VIA_I2S
* - MOZZI_OUTPUT_I2S_DAC
* - MOZZI_OUTPUT_INTERNAL_DAC
*
* The default mode is @ref esp32_internal_dac .
*
* @note
* This port really does not currently come with a PWM mode!
*
* @section esp32_internal_dac MOZZI_OUTPUT_INTERNAL_DAC
* The internal DAC has 8 bit resolution, and outputs to GPIO pins 25 and 26 (non-configurable). For simplicity of code, both pins are always used.
* In a mono configuration, both pins output the same sample.
*
* TODO: We could really use this to hack in a 2 PIN mode!
*
* @note
* The number 25 refers to "GPIO 25" or sometimes labelled "D25". Confusingly, many boards come with an additional, totally different numbering scheme on top of that.
*
* Internally, the inbuilt DAC is connected via an I2S interface. Which interface number to use can be configured using:
*
* @code
* #define MOZZI_I2S_PORT ... // (default: I2S_NUM_0)
* @endcode
*
* @section esp32_i2s_dac MOZZI_OUTPUT_I2S_DAC
* This mode outputs to a PT8211 (or compatible) I2S DAC, which allows for very high quality (mono or stereo) output. Communication needs the BCK, WS, and DATA(out) pins
* of one I2S interface. Presumably, any pins qualify, and you can configure this using:
* @code
* #define MOZZI_I2S_PIN_BCK ... // (default: 26)
* #define MOZZI_I2S_PIN_WS ... // (default: 15)
* #define MOZZI_I2S_PIN_DATA ... // (default: 33)
* #define MOZZI_I2S_PORT ... // (default: I2S_NUM_0)
* @endcode
*
* See the note above (@ref esp_internal_dac) regarding pin numbering. Also, please always test the default pinout, should a custom setting fail!
*
* As a technical note, I2S support in the ESP32 SDK has been reworked since this was implemented in Mozzi, and Mozzi uses the "legacy" implementation "i2s.h".
* This should not be an issue, unless you want to connect additional I2S components, yourself. In which case contributions are certainly welcome!
*
* @section esp32_pdm_via_i2s MOZZI_OUTPUT_PDM_VIA_I2S
* This mode uses the same setup as @ref esp32_i2s_dac, but rather than using an external DAC, the communication signal itself is modulated in PDM
* (pulse density modulation) encoded form. Thus not extra hardware is needed, and the signal is output on the DATA pin (see above). The BCK and
* WS pins are also claimed, but should be left non-connected, and do not produce anything meaningful. This can only be used in mono mode.
*
* Output resolution may be adjusted by defining MOZZI_PDM_RESOLUTION , where the default value of 4 means that each audio sample is encoded into four 32 bit blocks
* of ones and zeros. Obviously, more is potentially better, but at the cost of considerable computation power.
*
* @section esp32_external MOZZI_OUTPUT_EXTERNAL_TIMED and MOZZI_OUTPUT_EXTERNAL_CUSTOM
* See @ref external_audio
*/
31 changes: 0 additions & 31 deletions MozziGuts.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,37 +32,6 @@

#include "internal/config_check_generic.h"


#if (EXTERNAL_AUDIO_OUTPUT != true)
#if IS_TEENSY3()
#include "AudioConfigTeensy3_12bit.h"
#elif IS_TEENSY4()
#include "AudioConfigTeensy4.h"
#elif IS_STM32()
#include "AudioConfigSTM32.h"
#elif IS_STM32DUINO()
#include "AudioConfigSTM32duino.h"
#elif IS_ESP8266()
#include "AudioConfigESP.h"
#elif IS_ESP32()
#include "AudioConfigESP32.h"
#elif IS_SAMD21()
#include "AudioConfigSAMD21.h"
#elif IS_RP2040()
#include "AudioConfigRP2040.h"
#elif IS_MBED()
#include "AudioConfigMBED.h"
#elif IS_RENESAS()
#include "AudioConfigRenesas.h"
#endif
#else // EXTERNAL_AUDIO_OUTPUT==true
#if !defined(EXTERNAL_AUDIO_BITS)
#define EXTERNAL_AUDIO_BITS 16
#endif
#define AUDIO_BITS EXTERNAL_AUDIO_BITS
#define AUDIO_BIAS (1 << (AUDIO_BITS - 1))
#endif

#if (STEREO_HACK == true)
extern int audio_out_1, audio_out_2;
#endif
Expand Down
52 changes: 27 additions & 25 deletions MozziGuts_impl_ESP32.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,21 @@ void setupMozziADC(int8_t speed) {


//// BEGIN AUDIO OUTPUT code ///////
#include <driver/i2s.h> // for I2S-based output modes
#include <driver/timer.h> // for EXTERNAL_AUDIO_OUTPUT
#if MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_INTERNAL_DAC) || MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_I2S_DAC) || MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_PDM_VIA_I2S)
# include <driver/i2s.h> // for I2S-based output modes, including - technically - internal DAC
const i2s_port_t i2s_num = MOZZI_I2S_PORT;

#if (EXTERNAL_AUDIO_OUTPUT != true)
# include "AudioConfigESP32.h"
// On ESP32 we cannot test wether the DMA buffer has room. Instead, we have to use a one-sample mini buffer. In each iteration we
// _try_ to write that sample to the DMA buffer, and if successful, we can buffer the next sample. Somewhat cumbersome, but works.
// TODO: Should ESP32 gain an implemenation of i2s_available(), we should switch to using that, instead.
static bool _esp32_can_buffer_next = true;
# if (ESP32_AUDIO_OUT_MODE == INTERNAL_DAC)
# if MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_INTERNAL_DAC)
static uint16_t _esp32_prev_sample[2];
# define ESP_SAMPLE_SIZE (2*sizeof(uint16_t))
# elif (ESP32_AUDIO_OUT_MODE == PT8211_DAC)
# elif MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_I2S_DAC)
static int16_t _esp32_prev_sample[2];
# define ESP_SAMPLE_SIZE (2*sizeof(int16_t))
# elif (ESP32_AUDIO_OUT_MODE == PDM_VIA_I2S)
# elif MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_PDM_VIA_I2S)
static uint32_t _esp32_prev_sample[PDM_RESOLUTION];
# define ESP_SAMPLE_SIZE (PDM_RESOLUTION*sizeof(uint32_t))
# endif
Expand All @@ -72,17 +71,17 @@ inline bool canBufferAudioOutput() {
}

inline void audioOutput(const AudioOutput f) {
# if (ESP32_AUDIO_OUT_MODE == INTERNAL_DAC)
_esp32_prev_sample[0] = (f.l() + AUDIO_BIAS) << 8;
# if (AUDIO_CHANNELS > 1)
_esp32_prev_sample[1] = (f.r() + AUDIO_BIAS) << 8;
# if MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_INTERNAL_DAC)
_esp32_prev_sample[0] = (f.l() + MOZZI_AUDIO_BIAS) << 8;
# if (MOZZI_AUDIO_CHANNELS > 1)
_esp32_prev_sample[1] = (f.r() + MOZZI_AUDIO_BIAS) << 8;
# else
// For simplicity of code, even in mono, we're writing stereo samples
_esp32_prev_sample[1] = _esp32_prev_sample[0];
# endif
# elif (ESP32_AUDIO_OUT_MODE == PDM_VIA_I2S)
for (uint8_t i=0; i<PDM_RESOLUTION; ++i) {
_esp32_prev_sample[i] = pdmCode32(f.l() + AUDIO_BIAS);
# elif MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_PDM_VIA_I2S)
for (uint8_t i=0; i<MOZZI_PDM_RESOLUTION; ++i) {
_esp32_prev_sample[i] = pdmCode32(f.l() + MOZZI_AUDIO_BIAS);
}
# else
// PT8211 takes signed samples
Expand All @@ -93,7 +92,8 @@ inline void audioOutput(const AudioOutput f) {
}
#endif

#if (BYPASS_MOZZI_OUTPUT_BUFFER != true)
#if MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_EXTERNAL_TIMED)
# include <driver/timer.h>
void CACHED_FUNCTION_ATTR timer0_audio_output_isr(void *) {
TIMERG0.int_clr_timers.t0 = 1;
TIMERG0.hw_timer[0].config.alarm_en = 1;
Expand All @@ -102,7 +102,7 @@ void CACHED_FUNCTION_ATTR timer0_audio_output_isr(void *) {
#endif

static void startAudio() {
#if (BYPASS_MOZZI_OUTPUT_BUFFER != true) // for external audio output, set up a timer running a audio rate
#if MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_EXTERNAL_TIMED) // for external audio output, set up a timer running a audio rate
static intr_handle_t s_timer_handle;
const int div = 2;
timer_config_t config = {
Expand All @@ -116,19 +116,19 @@ static void startAudio() {
};
timer_init(TIMER_GROUP_0, TIMER_0, &config);
timer_set_counter_value(TIMER_GROUP_0, TIMER_0, 0);
timer_set_alarm_value(TIMER_GROUP_0, TIMER_0, 80000000UL / AUDIO_RATE / div);
timer_set_alarm_value(TIMER_GROUP_0, TIMER_0, 80000000UL / MOZZI_AUDIO_RATE / div);
timer_enable_intr(TIMER_GROUP_0, TIMER_0);
timer_isr_register(TIMER_GROUP_0, TIMER_0, &timer0_audio_output_isr, nullptr, 0, &s_timer_handle);
timer_start(TIMER_GROUP_0, TIMER_0);

#else
static const i2s_config_t i2s_config = {
# if (ESP32_AUDIO_OUT_MODE == PT8211_DAC) || (ESP32_AUDIO_OUT_MODE == PDM_VIA_I2S)
# if MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_I2S_DAC) || MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_PDM_VIA_I2S)
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
# elif (ESP32_AUDIO_OUT_MODE == INTERNAL_DAC)
# elif MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_INTERNAL_DAC)
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN),
# endif
.sample_rate = AUDIO_RATE * PDM_RESOLUTION,
.sample_rate = MOZZI_AUDIO_RATE * MOZZI_PDM_RESOLUTION,
.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
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, // always use stereo output. mono seems to be buggy, and the overhead is insignifcant on the ESP32
.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
Expand All @@ -139,15 +139,15 @@ static void startAudio() {
};

i2s_driver_install(i2s_num, &i2s_config, 0, NULL);
# if (ESP32_AUDIO_OUT_MODE == PT8211_DAC) || (ESP32_AUDIO_OUT_MODE == PDM_VIA_I2S)
# if MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_I2S_DAC) || MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_PDM_VIA_I2S)
static const i2s_pin_config_t pin_config = {
.bck_io_num = ESP32_I2S_BCK_PIN,
.ws_io_num = ESP32_I2S_WS_PIN,
.data_out_num = ESP32_I2S_DATA_PIN,
.bck_io_num = MOZZI_I2S_PIN_BCK,
.ws_io_num = MOZZI_I2S_PIN_WS,
.data_out_num = MOZZI_I2S_PIN_DATA,
.data_in_num = -1
};
i2s_set_pin((i2s_port_t)i2s_num, &pin_config);
# elif (ESP32_AUDIO_OUT_MODE == INTERNAL_DAC)
# elif MOZZI_IS(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_INTERNAL_DAC)
i2s_set_pin((i2s_port_t)i2s_num, NULL);
i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN);
# endif
Expand All @@ -160,3 +160,5 @@ void stopMozzi() {
// TODO: implement me
}
//// END AUDIO OUTPUT code ///////

#undef ESP_SAMPLE_SIZE // only used inside this file
3 changes: 2 additions & 1 deletion Readme_Mozzi_2_0.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ all new
- MOZZI_ANALOG_READS
- MOZZI_COMPATIBILITY_LEVEL


general:
- Added many config sanity checks. Some may be too strict, if so please mention

Other removed stuff:
- pauseMozzi() - was still declared but not defined -> not usable, anyway
Expand Down
6 changes: 0 additions & 6 deletions hardware_defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,6 @@
#define NUM_ANALOG_INPUTS 1
#endif

#if IS_AVR()
#define AUDIO_RATE_PLATFORM_DEFAULT 16384
#else
#define AUDIO_RATE_PLATFORM_DEFAULT 32768
#endif

#if IS_ESP8266()
#define CACHED_FUNCTION_ATTR ICACHE_RAM_ATTR
#elif IS_ESP32()
Expand Down
13 changes: 8 additions & 5 deletions internal/config_check_generic.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
#include "../MozziConfigValues.h" // in case not user-included
#include "mozzi_macros.h"

/// Step 0: Check for some stuff that user should never configure directly (but may be set, indirectly from the hardware-specific setups)
#if defined(BYPASS_MOZZI_OUTPUT_BUFFER)
#error "BYPASS_MOZZI_OUTPUT_BUFFER may not be customized via config"
#endif


//// Step 1: Apply missing defaults for generic config options (not the hardware specific ones)
#if not defined(MOZZI_COMPATIBILITY_LEVEL)
#define MOZZI_COMPATIBILITY_LEVEL MOZZI_COMPATIBILITY_2_0
Expand Down Expand Up @@ -45,10 +51,11 @@
//MOZZI_AUDIO_PIN_2_LOW -> hardware specific



/// Step 2: Include the hardware specific checks-and-defaults-header
#if IS_AVR()
#include "config_checks_avr.h"
#elif IS_ESP32()
#include "config_checks_esp32.h"
#else
// TODO
#error oops
Expand Down Expand Up @@ -82,10 +89,6 @@ MOZZI_CHECK_POW2(MOZZI_CONTROL_RATE)
#warning "Mozzi is configured to use an external void 'audioOutput(const AudioOutput f)' function. Please define one in your sketch"
#endif

#if defined(BYPASS_MOZZI_OUTPUT_BUFFER)
#error "BYPASS_MOZZI_OUTPUT_BUFFER may not be customized via config"
#endif

// Hardware-specific checks file should have more narrow checks for most options, below, but is not required to, so let's check for anything that is wildly out of scope:
MOZZI_CHECK_SUPPORTED(MOZZI_AUDIO_MODE, MOZZI_OUTPUT_PWM, MOZZI_OUTPUT_2PIN_PWM, MOZZI_OUTPUT_EXTERNAL_TIMED, MOZZI_OUTPUT_EXTERNAL_CUSTOM, MOZZI_OUTPUT_PDM_VIA_I2S, MOZZI_OUTPUT_PDM_VIA_SERIAL, MOZZI_OUTPUT_I2S_DAC, MOZZI_OUTPUT_INTERNAL_DAC)
MOZZI_CHECK_SUPPORTED(MOZZI_ANALOG_READ, MOZZI_ANALOG_READ_NONE, MOZZI_ANALOG_READ_STANDARD)
Expand Down
Loading

0 comments on commit 4b03226

Please sign in to comment.