2022-06-08 21:14:01 +02:00
# pragma once
# include "wled.h"
# include <driver/i2s.h>
2022-07-07 19:29:36 +02:00
# include <driver/adc.h>
2022-09-16 16:58:04 +02:00
# include <soc/i2s_reg.h> // needed for SPH0465 timing workaround (classic ESP32)
2022-07-07 19:27:22 +02:00
# if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)
2022-09-11 00:12:51 +02:00
# if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32C3)
2022-07-07 19:27:22 +02:00
# include <driver/adc_deprecated.h>
# include <driver/adc_types_deprecated.h>
# endif
2022-09-11 14:32:00 +02:00
// type of i2s_config_t.SampleRate was changed from "int" to "unsigned" in IDF 4.4.x
# define SRate_t uint32_t
# else
# define SRate_t int
2022-09-11 00:12:51 +02:00
# endif
2022-07-07 19:27:22 +02:00
//#include <driver/i2s_std.h>
//#include <driver/i2s_pdm.h>
2022-09-11 14:32:00 +02:00
//#include <driver/i2s_tdm.h>
2022-07-07 19:27:22 +02:00
//#include <driver/gpio.h>
2022-09-11 00:12:51 +02:00
// see https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/hw-reference/chip-series-comparison.html#related-documents
// and https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-reference/peripherals/i2s.html#overview-of-all-modes
2022-11-28 20:52:33 +01:00
# if defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C5) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32H2) || defined(ESP8266) || defined(ESP8265)
2022-09-17 22:00:33 +02:00
// there are two things in these MCUs that could lead to problems with audio processing:
// * no floating point hardware (FPU) support - FFT uses float calculations. If done in software, a strong slow-down can be expected (between 8x and 20x)
// * single core, so FFT task might slow down other things like LED updates
2022-11-28 20:52:33 +01:00
# if !defined(SOC_I2S_NUM) || (SOC_I2S_NUM < 1)
# error This audio reactive usermod does not support ESP32-C2, ESP32-C3 or ESP32-S2.
# else
2022-09-17 22:00:33 +02:00
# warning This audio reactive usermod does not support ESP32-C2, ESP32-C3 or ESP32-S2.
2022-11-28 20:52:33 +01:00
# endif
2022-09-11 00:12:51 +02:00
# endif
2022-06-08 21:14:01 +02:00
/* ToDo: remove. ES7243 is controlled via compiler defines
Until this configuration is moved to the webinterface
*/
2022-08-10 17:18:43 +02:00
// if you have problems to get your microphone work on the left channel, uncomment the following line
//#define I2S_USE_RIGHT_CHANNEL // (experimental) define this to use right channel (digital mics only)
// Uncomment the line below to utilize ADC1 _exclusively_ for I2S sound input.
// benefit: analog mic inputs will be sampled contiously -> better response times and less "glitches"
// WARNING: this option WILL lock-up your device in case that any other analogRead() operation is performed;
// for example if you want to read "analog buttons"
//#define I2S_GRAB_ADC1_COMPLETELY // (experimental) continously sample analog ADC microphone. WARNING will cause analogRead() lock-up
2022-06-08 21:14:01 +02:00
// data type requested from the I2S driver - currently we always use 32bit
//#define I2S_USE_16BIT_SAMPLES // (experimental) define this to request 16bit - more efficient but possibly less compatible
2022-09-16 16:58:04 +02:00
2022-06-08 21:14:01 +02:00
# ifdef I2S_USE_16BIT_SAMPLES
# define I2S_SAMPLE_RESOLUTION I2S_BITS_PER_SAMPLE_16BIT
# define I2S_datatype int16_t
2022-08-10 17:18:43 +02:00
# define I2S_unsigned_datatype uint16_t
2022-09-16 16:58:04 +02:00
# define I2S_data_size I2S_BITS_PER_CHAN_16BIT
2022-06-08 21:14:01 +02:00
# undef I2S_SAMPLE_DOWNSCALE_TO_16BIT
# else
# define I2S_SAMPLE_RESOLUTION I2S_BITS_PER_SAMPLE_32BIT
2022-09-16 16:58:04 +02:00
//#define I2S_SAMPLE_RESOLUTION I2S_BITS_PER_SAMPLE_24BIT
2022-06-08 21:14:01 +02:00
# define I2S_datatype int32_t
2022-08-10 17:18:43 +02:00
# define I2S_unsigned_datatype uint32_t
2022-09-16 16:58:04 +02:00
# define I2S_data_size I2S_BITS_PER_CHAN_32BIT
2022-06-08 21:14:01 +02:00
# define I2S_SAMPLE_DOWNSCALE_TO_16BIT
# endif
2022-09-16 16:58:04 +02:00
/* There are several (confusing) options in IDF 4.4.x:
* I2S_CHANNEL_FMT_RIGHT_LEFT , I2S_CHANNEL_FMT_ALL_RIGHT and I2S_CHANNEL_FMT_ALL_LEFT stands for stereo mode , which means two channels will transport different data .
* I2S_CHANNEL_FMT_ONLY_RIGHT and I2S_CHANNEL_FMT_ONLY_LEFT they are mono mode , both channels will only transport same data .
* I2S_CHANNEL_FMT_MULTIPLE means TDM channels , up to 16 channel will available , and they are stereo as default .
* if you want to receive two channels , one is the actual data from microphone and another channel is suppose to receive 0 , it ' s different data in two channels , you need to choose I2S_CHANNEL_FMT_RIGHT_LEFT in this case .
*/
# if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)) && (ESP_IDF_VERSION <= ESP_IDF_VERSION_VAL(4, 4, 3))
// espressif bug: only_left has no sound, left and right are swapped
// https://github.com/espressif/esp-idf/issues/9635 I2S mic not working since 4.4 (IDFGH-8138)
// https://github.com/espressif/esp-idf/issues/8538 I2S channel selection issue? (IDFGH-6918)
// https://github.com/espressif/esp-idf/issues/6625 I2S: left/right channels are swapped for read (IDFGH-4826)
# ifdef I2S_USE_RIGHT_CHANNEL
# define I2S_MIC_CHANNEL I2S_CHANNEL_FMT_ONLY_LEFT
# define I2S_MIC_CHANNEL_TEXT "right channel only (work-around swapped channel bug in IDF 4.4)."
2022-11-28 20:52:33 +01:00
# define I2S_PDM_MIC_CHANNEL I2S_CHANNEL_FMT_ONLY_RIGHT
# define I2S_PDM_MIC_CHANNEL_TEXT "right channel only"
2022-09-16 16:58:04 +02:00
# else
//#define I2S_MIC_CHANNEL I2S_CHANNEL_FMT_ALL_LEFT
//#define I2S_MIC_CHANNEL I2S_CHANNEL_FMT_RIGHT_LEFT
# define I2S_MIC_CHANNEL I2S_CHANNEL_FMT_ONLY_RIGHT
# define I2S_MIC_CHANNEL_TEXT "left channel only (work-around swapped channel bug in IDF 4.4)."
2022-11-28 20:52:33 +01:00
# define I2S_PDM_MIC_CHANNEL I2S_CHANNEL_FMT_ONLY_LEFT
# define I2S_PDM_MIC_CHANNEL_TEXT "left channel only."
2022-09-16 16:58:04 +02:00
# endif
# else
// not swapped
# ifdef I2S_USE_RIGHT_CHANNEL
# define I2S_MIC_CHANNEL I2S_CHANNEL_FMT_ONLY_RIGHT
# define I2S_MIC_CHANNEL_TEXT "right channel only."
# else
# define I2S_MIC_CHANNEL I2S_CHANNEL_FMT_ONLY_LEFT
# define I2S_MIC_CHANNEL_TEXT "left channel only."
# endif
2022-11-28 20:52:33 +01:00
# define I2S_PDM_MIC_CHANNEL I2S_MIC_CHANNEL
# define I2S_PDM_MIC_CHANNEL_TEXT I2S_MIC_CHANNEL_TEXT
2022-09-16 16:58:04 +02:00
# endif
2022-06-08 21:14:01 +02:00
/* Interface class
AudioSource serves as base class for all microphone types
This enables accessing all microphones with one single interface
which simplifies the caller code
*/
class AudioSource {
2022-06-11 00:50:29 +02:00
public :
2022-06-08 21:14:01 +02:00
/* All public methods are virtual, so they can be overridden
Everything but the destructor is also removed , to make sure each mic
Implementation provides its version of this function
*/
virtual ~ AudioSource ( ) { } ;
/* Initialize
This function needs to take care of anything that needs to be done
before samples can be obtained from the microphone .
*/
2022-06-13 17:34:49 +02:00
virtual void initialize ( int8_t = I2S_PIN_NO_CHANGE , int8_t = I2S_PIN_NO_CHANGE , int8_t = I2S_PIN_NO_CHANGE , int8_t = I2S_PIN_NO_CHANGE , int8_t = I2S_PIN_NO_CHANGE , int8_t = I2S_PIN_NO_CHANGE ) = 0 ;
2022-06-08 21:14:01 +02:00
/* Deinitialize
Release all resources and deactivate any functionality that is used
by this microphone
*/
virtual void deinitialize ( ) = 0 ;
/* getSamples
Read num_samples from the microphone , and store them in the provided
buffer
*/
2022-07-03 23:00:32 +02:00
virtual void getSamples ( float * buffer , uint16_t num_samples ) = 0 ;
2022-06-08 21:14:01 +02:00
2022-08-10 17:18:43 +02:00
/* check if the audio source driver was initialized successfully */
virtual bool isInitialized ( void ) { return ( _initialized ) ; }
/* identify Audiosource type - I2S-ADC or I2S-digital */
typedef enum { Type_unknown = 0 , Type_I2SAdc = 1 , Type_I2SDigital = 2 } AudioSourceType ;
virtual AudioSourceType getType ( void ) { return ( Type_I2SDigital ) ; } // default is "I2S digital source" - ADC type overrides this method
2022-06-11 00:50:29 +02:00
protected :
2022-08-10 17:18:43 +02:00
/* Post-process audio sample - currently on needed for I2SAdcSource*/
virtual I2S_datatype postProcessSample ( I2S_datatype sample_in ) { return ( sample_in ) ; } // default method can be overriden by instances (ADC) that need sample postprocessing
2022-06-08 21:14:01 +02:00
// Private constructor, to make sure it is not callable except from derived classes
2022-11-28 20:52:33 +01:00
AudioSource ( SRate_t sampleRate , int blockSize , float sampleScale ) :
2022-06-11 00:50:29 +02:00
_sampleRate ( sampleRate ) ,
_blockSize ( blockSize ) ,
2022-11-28 20:52:33 +01:00
_initialized ( false ) ,
_sampleScale ( sampleScale )
2022-06-11 00:50:29 +02:00
{ } ;
2022-09-11 14:32:00 +02:00
SRate_t _sampleRate ; // Microphone sampling rate
2022-06-11 00:50:29 +02:00
int _blockSize ; // I2S block size
bool _initialized ; // Gets set to true if initialization is successful
2022-11-28 20:52:33 +01:00
float _sampleScale ; // pre-scaling factor for I2S samples
2022-06-08 21:14:01 +02:00
} ;
/* Basic I2S microphone source
All functions are marked virtual , so derived classes can replace them
*/
class I2SSource : public AudioSource {
2022-06-11 00:50:29 +02:00
public :
2022-11-28 20:52:33 +01:00
I2SSource ( SRate_t sampleRate , int blockSize , float sampleScale = 1.0f ) :
AudioSource ( sampleRate , blockSize , sampleScale ) {
2022-06-11 00:50:29 +02:00
_config = {
. mode = i2s_mode_t ( I2S_MODE_MASTER | I2S_MODE_RX ) ,
. sample_rate = _sampleRate ,
. bits_per_sample = I2S_SAMPLE_RESOLUTION ,
2022-08-10 17:18:43 +02:00
. channel_format = I2S_MIC_CHANNEL ,
2022-07-07 19:27:22 +02:00
# if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0)
2022-07-07 19:29:36 +02:00
. communication_format = i2s_comm_format_t ( I2S_COMM_FORMAT_STAND_I2S ) ,
2022-09-16 16:58:04 +02:00
//.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
. intr_alloc_flags = ESP_INTR_FLAG_LEVEL2 ,
. dma_buf_count = 8 ,
. dma_buf_len = _blockSize ,
. use_apll = 0 ,
. bits_per_chan = I2S_data_size ,
2022-07-07 19:27:22 +02:00
# else
2022-06-11 00:50:29 +02:00
. communication_format = i2s_comm_format_t ( I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB ) ,
. intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 ,
. dma_buf_count = 8 ,
2022-09-16 16:58:04 +02:00
. dma_buf_len = _blockSize ,
. use_apll = false
# endif
2022-06-11 00:50:29 +02:00
} ;
}
2022-06-08 21:14:01 +02:00
2022-06-13 17:34:49 +02:00
virtual void initialize ( int8_t i2swsPin = I2S_PIN_NO_CHANGE , int8_t i2ssdPin = I2S_PIN_NO_CHANGE , int8_t i2sckPin = I2S_PIN_NO_CHANGE , int8_t mclkPin = I2S_PIN_NO_CHANGE , int8_t = I2S_PIN_NO_CHANGE , int8_t = I2S_PIN_NO_CHANGE ) {
2022-06-11 00:50:29 +02:00
if ( i2swsPin ! = I2S_PIN_NO_CHANGE & & i2ssdPin ! = I2S_PIN_NO_CHANGE ) {
2022-06-11 12:35:29 +02:00
if ( ! pinManager . allocatePin ( i2swsPin , true , PinOwner : : UM_Audioreactive ) | |
2022-06-14 11:26:52 +02:00
! pinManager . allocatePin ( i2ssdPin , false , PinOwner : : UM_Audioreactive ) ) { // #206
2022-09-16 16:58:04 +02:00
DEBUGSR_PRINTF ( " \n AR: Failed to allocate I2S pins: ws=%d, sd=%d \n " , i2swsPin , i2ssdPin ) ;
2022-06-11 00:50:29 +02:00
return ;
2022-06-08 21:14:01 +02:00
}
2022-06-11 00:50:29 +02:00
}
// i2ssckPin needs special treatment, since it might be unused on PDM mics
if ( i2sckPin ! = I2S_PIN_NO_CHANGE ) {
2022-09-16 16:58:04 +02:00
if ( ! pinManager . allocatePin ( i2sckPin , true , PinOwner : : UM_Audioreactive ) ) {
DEBUGSR_PRINTF ( " \n AR: Failed to allocate I2S pins: sck=%d \n " , i2sckPin ) ;
return ;
}
2022-06-13 17:34:49 +02:00
} else {
2022-11-28 20:52:33 +01:00
# if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0)
# if !defined(SOC_I2S_SUPPORTS_PDM_RX)
# warning this MCU does not support PDM microphones
# endif
# endif
2022-09-11 00:12:51 +02:00
# if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
2022-06-13 17:34:49 +02:00
// This is an I2S PDM microphone, these microphones only use a clock and
2022-11-28 20:52:33 +01:00
// data line, to make it simpler to debug, use the WS pin as CLK and SD pin as DATA
// example from espressif: https://github.com/espressif/esp-idf/blob/release/v4.4/examples/peripherals/i2s/i2s_audio_recorder_sdcard/main/i2s_recorder_main.c
// note to self: PDM has known bugs on S3, and does not work on C3
// * S3: PDM sample rate only at 50% of expected rate: https://github.com/espressif/esp-idf/issues/9893
// * S3: I2S PDM has very low amplitude: https://github.com/espressif/esp-idf/issues/8660
// * C3: does not support PDM to PCM input. SoC would allow PDM RX, but there is no hardware to directly convert to PCM so it will not work. https://github.com/espressif/esp-idf/issues/8796
2022-09-11 00:12:51 +02:00
_config . mode = i2s_mode_t ( I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM ) ; // Change mode to pdm if clock pin not provided. PDM is not supported on ESP32-S2. PDM RX not supported on ESP32-C3
2022-11-28 20:52:33 +01:00
_config . channel_format = I2S_PDM_MIC_CHANNEL ; // seems that PDM mono mode always uses left channel.
_config . use_apll = true ; // experimental - use aPLL clock source to improve sampling quality
2022-09-11 00:12:51 +02:00
# endif
2022-06-13 17:34:49 +02:00
}
2022-11-28 20:52:33 +01:00
# if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0)
if ( mclkPin ! = I2S_PIN_NO_CHANGE ) {
_config . use_apll = true ; // experimental - use aPLL clock source to improve sampling quality, and to avoid glitches.
// //_config.fixed_mclk = 512 * _sampleRate;
// //_config.fixed_mclk = 256 * _sampleRate;
}
# if !defined(SOC_I2S_SUPPORTS_APLL)
# warning this MCU does not have an APLL high accuracy clock for audio
// S3: not supported; S2: supported; C3: not supported
_config . use_apll = false ; // APLL not supported on this MCU
# endif
# if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
if ( ESP . getChipRevision ( ) = = 0 ) _config . use_apll = false ; // APLL is broken on ESP32 revision 0
# endif
# endif
2022-06-13 17:34:49 +02:00
// Reserve the master clock pin if provided
_mclkPin = mclkPin ;
if ( mclkPin ! = I2S_PIN_NO_CHANGE ) {
2022-11-28 20:52:33 +01:00
if ( ! pinManager . allocatePin ( mclkPin , true , PinOwner : : UM_Audioreactive ) ) {
DEBUGSR_PRINTF ( " \n AR: Failed to allocate I2S pin: MCLK=%d \n " , mclkPin ) ;
return ;
} else
2022-06-13 17:34:49 +02:00
_routeMclk ( mclkPin ) ;
2022-06-11 00:50:29 +02:00
}
_pinConfig = {
2022-09-16 16:58:04 +02:00
# if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0)
. mck_io_num = mclkPin , // "classic" ESP32 supports setting MCK on GPIO0/GPIO1/GPIO3 only. i2s_set_pin() will fail if wrong mck_io_num is provided.
# endif
2022-06-11 00:50:29 +02:00
. bck_io_num = i2sckPin ,
. ws_io_num = i2swsPin ,
. data_out_num = I2S_PIN_NO_CHANGE ,
. data_in_num = i2ssdPin
} ;
2022-11-28 20:52:33 +01:00
//DEBUGSR_PRINTF("[AR] I2S: SD=%d, WS=%d, SCK=%d, MCLK=%d\n", i2ssdPin, i2swsPin, i2sckPin, mclkPin);
2022-06-11 00:50:29 +02:00
esp_err_t err = i2s_driver_install ( I2S_NUM_0 , & _config , 0 , nullptr ) ;
if ( err ! = ESP_OK ) {
2022-11-28 20:52:33 +01:00
DEBUGSR_PRINTF ( " AR: Failed to install i2s driver: %d \n " , err ) ;
2022-06-11 00:50:29 +02:00
return ;
}
2022-11-28 20:52:33 +01:00
DEBUGSR_PRINTF ( " AR: I2S#0 driver %s aPLL; fixed_mclk=%d. \n " , _config . use_apll ? " uses " : " without " , _config . fixed_mclk ) ;
DEBUGSR_PRINTF ( " AR: %d bits, Sample scaling factor = %6.4f \n " , _config . bits_per_sample , _sampleScale ) ;
if ( _config . mode & I2S_MODE_PDM ) {
DEBUGSR_PRINTLN ( F ( " AR: I2S#0 driver installed in PDM MASTER mode. " ) ) ;
} else {
DEBUGSR_PRINTLN ( F ( " AR: I2S#0 driver installed in MASTER mode. " ) ) ;
}
2022-06-11 00:50:29 +02:00
err = i2s_set_pin ( I2S_NUM_0 , & _pinConfig ) ;
if ( err ! = ESP_OK ) {
2022-11-28 20:52:33 +01:00
DEBUGSR_PRINTF ( " AR: Failed to set i2s pin config: %d \n " , err ) ;
2022-09-16 16:58:04 +02:00
i2s_driver_uninstall ( I2S_NUM_0 ) ; // uninstall already-installed driver
2022-06-11 00:50:29 +02:00
return ;
}
2022-09-16 16:58:04 +02:00
# if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0)
err = i2s_set_clk ( I2S_NUM_0 , _sampleRate , I2S_SAMPLE_RESOLUTION , I2S_CHANNEL_MONO ) ; // set bit clocks. Also takes care of MCLK routing if needed.
if ( err ! = ESP_OK ) {
2022-11-28 20:52:33 +01:00
DEBUGSR_PRINTF ( " AR: Failed to configure i2s clocks: %d \n " , err ) ;
2022-09-16 16:58:04 +02:00
i2s_driver_uninstall ( I2S_NUM_0 ) ; // uninstall already-installed driver
return ;
}
# endif
2022-06-11 00:50:29 +02:00
_initialized = true ;
}
2022-06-08 21:14:01 +02:00
2022-06-11 12:35:29 +02:00
virtual void deinitialize ( ) {
2022-06-11 00:50:29 +02:00
_initialized = false ;
esp_err_t err = i2s_driver_uninstall ( I2S_NUM_0 ) ;
if ( err ! = ESP_OK ) {
DEBUGSR_PRINTF ( " Failed to uninstall i2s driver: %d \n " , err ) ;
return ;
}
2022-06-11 12:35:29 +02:00
if ( _pinConfig . ws_io_num ! = I2S_PIN_NO_CHANGE ) pinManager . deallocatePin ( _pinConfig . ws_io_num , PinOwner : : UM_Audioreactive ) ;
if ( _pinConfig . data_in_num ! = I2S_PIN_NO_CHANGE ) pinManager . deallocatePin ( _pinConfig . data_in_num , PinOwner : : UM_Audioreactive ) ;
if ( _pinConfig . bck_io_num ! = I2S_PIN_NO_CHANGE ) pinManager . deallocatePin ( _pinConfig . bck_io_num , PinOwner : : UM_Audioreactive ) ;
2022-06-13 17:34:49 +02:00
// Release the master clock pin
if ( _mclkPin ! = I2S_PIN_NO_CHANGE ) pinManager . deallocatePin ( _mclkPin , PinOwner : : UM_Audioreactive ) ;
2022-06-11 00:50:29 +02:00
}
2022-06-08 21:14:01 +02:00
2022-07-03 23:00:32 +02:00
virtual void getSamples ( float * buffer , uint16_t num_samples ) {
2022-06-11 00:50:29 +02:00
if ( _initialized ) {
esp_err_t err ;
size_t bytes_read = 0 ; /* Counter variable to check if we actually got enough data */
I2S_datatype newSamples [ num_samples ] ; /* Intermediary sample storage */
2022-06-08 21:14:01 +02:00
2022-06-11 00:50:29 +02:00
err = i2s_read ( I2S_NUM_0 , ( void * ) newSamples , sizeof ( newSamples ) , & bytes_read , portMAX_DELAY ) ;
2022-06-08 21:14:01 +02:00
if ( err ! = ESP_OK ) {
2022-06-11 00:50:29 +02:00
DEBUGSR_PRINTF ( " Failed to get samples: %d \n " , err ) ;
return ;
2022-06-08 21:14:01 +02:00
}
2022-06-11 00:50:29 +02:00
// For correct operation, we need to read exactly sizeof(samples) bytes from i2s
if ( bytes_read ! = sizeof ( newSamples ) ) {
DEBUGSR_PRINTF ( " Failed to get enough samples: wanted: %d read: %d \n " , sizeof ( newSamples ) , bytes_read ) ;
return ;
2022-06-08 21:14:01 +02:00
}
2022-06-11 00:50:29 +02:00
// Store samples in sample buffer and update DC offset
for ( int i = 0 ; i < num_samples ; i + + ) {
2022-08-10 17:18:43 +02:00
2022-08-14 14:47:03 +02:00
newSamples [ i ] = postProcessSample ( newSamples [ i ] ) ; // perform postprocessing (needed for ADC samples)
2022-07-03 23:00:32 +02:00
float currSample = 0.0f ;
2022-06-08 21:14:01 +02:00
# ifdef I2S_SAMPLE_DOWNSCALE_TO_16BIT
2022-08-10 17:18:43 +02:00
currSample = ( float ) newSamples [ i ] / 65536.0f ; // 32bit input -> 16bit; keeping lower 16bits as decimal places
2022-06-08 21:14:01 +02:00
# else
2022-08-10 17:18:43 +02:00
currSample = ( float ) newSamples [ i ] ; // 16bit input -> use as-is
2022-06-08 21:14:01 +02:00
# endif
2022-06-11 00:50:29 +02:00
buffer [ i ] = currSample ;
2022-11-28 20:52:33 +01:00
buffer [ i ] * = _sampleScale ; // scale samples
2022-06-08 21:14:01 +02:00
}
2022-06-11 00:50:29 +02:00
}
2022-06-08 21:14:01 +02:00
}
2022-06-11 00:50:29 +02:00
protected :
void _routeMclk ( int8_t mclkPin ) {
2022-09-11 00:12:51 +02:00
# if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
2022-09-16 16:58:04 +02:00
// MCLK routing by writing registers is not needed any more with IDF > 4.4.0
# if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(4, 4, 0)
2022-09-11 00:12:51 +02:00
// this way of MCLK routing only works on "classic" ESP32
2022-09-16 16:58:04 +02:00
/* Enable the mclk routing depending on the selected mclk pin (ESP32: only 0,1,3)
2022-06-11 00:50:29 +02:00
Only I2S_NUM_0 is supported
*/
if ( mclkPin = = GPIO_NUM_0 ) {
PIN_FUNC_SELECT ( PERIPHS_IO_MUX_GPIO0_U , FUNC_GPIO0_CLK_OUT1 ) ;
WRITE_PERI_REG ( PIN_CTRL , 0xFFF0 ) ;
} else if ( mclkPin = = GPIO_NUM_1 ) {
PIN_FUNC_SELECT ( PERIPHS_IO_MUX_U0TXD_U , FUNC_U0TXD_CLK_OUT3 ) ;
WRITE_PERI_REG ( PIN_CTRL , 0xF0F0 ) ;
} else {
PIN_FUNC_SELECT ( PERIPHS_IO_MUX_U0RXD_U , FUNC_U0RXD_CLK_OUT2 ) ;
WRITE_PERI_REG ( PIN_CTRL , 0xFF00 ) ;
}
2022-09-16 16:58:04 +02:00
# endif
2022-09-11 00:12:51 +02:00
# endif
2022-06-08 21:14:01 +02:00
}
2022-06-11 00:50:29 +02:00
2022-06-13 17:34:49 +02:00
i2s_config_t _config ;
i2s_pin_config_t _pinConfig ;
2022-06-11 00:50:29 +02:00
int8_t _mclkPin ;
2022-06-08 21:14:01 +02:00
} ;
/* ES7243 Microphone
This is an I2S microphone that requires ininitialization over
I2C before I2S data can be received
*/
2022-06-11 00:50:29 +02:00
class ES7243 : public I2SSource {
private :
2022-06-08 21:14:01 +02:00
void _es7243I2cWrite ( uint8_t reg , uint8_t val ) {
2023-05-30 19:36:14 +02:00
# ifndef ES7243_ADDR
# define ES7243_ADDR 0x13 // default address
# endif
2022-06-11 00:50:29 +02:00
Wire . beginTransmission ( ES7243_ADDR ) ;
Wire . write ( ( uint8_t ) reg ) ;
Wire . write ( ( uint8_t ) val ) ;
2022-11-28 20:52:33 +01:00
uint8_t i2cErr = Wire . endTransmission ( ) ; // i2cErr == 0 means OK
if ( i2cErr ! = 0 ) {
DEBUGSR_PRINTF ( " AR: ES7243 I2C write failed with error=%d (addr=0x%X, reg 0x%X, val 0x%X). \n " , i2cErr , ES7243_ADDR , reg , val ) ;
}
2022-06-08 21:14:01 +02:00
}
void _es7243InitAdc ( ) {
2022-06-11 00:50:29 +02:00
_es7243I2cWrite ( 0x00 , 0x01 ) ;
_es7243I2cWrite ( 0x06 , 0x00 ) ;
_es7243I2cWrite ( 0x05 , 0x1B ) ;
_es7243I2cWrite ( 0x01 , 0x00 ) ; // 0x00 for 24 bit to match INMP441 - not sure if this needs adjustment to get 16bit samples from I2S
_es7243I2cWrite ( 0x08 , 0x43 ) ;
_es7243I2cWrite ( 0x05 , 0x13 ) ;
2022-06-08 21:14:01 +02:00
}
public :
2022-11-28 20:52:33 +01:00
ES7243 ( SRate_t sampleRate , int blockSize , float sampleScale = 1.0f ) :
I2SSource ( sampleRate , blockSize , sampleScale ) {
2022-06-11 00:50:29 +02:00
_config . channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT ;
2022-06-08 21:14:01 +02:00
} ;
2022-06-11 00:50:29 +02:00
2023-05-30 19:36:14 +02:00
void initialize ( int8_t i2swsPin , int8_t i2ssdPin , int8_t i2sckPin , int8_t mclkPin ) {
2022-11-28 20:52:33 +01:00
if ( ( i2sckPin < 0 ) | | ( mclkPin < 0 ) ) {
DEBUGSR_PRINTF ( " \n AR: invalid I2S pin: SCK=%d, MCLK=%d \n " , i2sckPin , mclkPin ) ;
return ;
}
2022-06-11 00:50:29 +02:00
// First route mclk, then configure ADC over I2C, then configure I2S
_es7243InitAdc ( ) ;
2022-06-13 17:34:49 +02:00
I2SSource : : initialize ( i2swsPin , i2ssdPin , i2sckPin , mclkPin ) ;
2022-06-08 21:14:01 +02:00
}
void deinitialize ( ) {
2022-06-11 00:50:29 +02:00
I2SSource : : deinitialize ( ) ;
2022-06-08 21:14:01 +02:00
}
} ;
2022-11-28 20:52:33 +01:00
# if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0)
# if !defined(SOC_I2S_SUPPORTS_ADC) && !defined(SOC_I2S_SUPPORTS_ADC_DAC)
# warning this MCU does not support analog sound input
# endif
# endif
2022-09-11 00:12:51 +02:00
# if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
// ADC over I2S is only availeable in "classic" ESP32
2022-06-08 21:14:01 +02:00
/* ADC over I2S Microphone
This microphone is an ADC pin sampled via the I2S interval
This allows to use the I2S API to obtain ADC samples with high sample rates
without the need of manual timing of the samples
*/
class I2SAdcSource : public I2SSource {
2022-06-11 00:50:29 +02:00
public :
2022-11-28 20:52:33 +01:00
I2SAdcSource ( SRate_t sampleRate , int blockSize , float sampleScale = 1.0f ) :
I2SSource ( sampleRate , blockSize , sampleScale ) {
2022-06-11 00:50:29 +02:00
_config = {
. mode = i2s_mode_t ( I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN ) ,
. sample_rate = _sampleRate ,
. bits_per_sample = I2S_SAMPLE_RESOLUTION ,
. channel_format = I2S_CHANNEL_FMT_ONLY_LEFT ,
2022-07-07 19:27:22 +02:00
# if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0)
2022-07-07 19:29:36 +02:00
. communication_format = i2s_comm_format_t ( I2S_COMM_FORMAT_STAND_I2S ) ,
2022-07-07 19:27:22 +02:00
# else
2022-06-11 00:50:29 +02:00
. communication_format = i2s_comm_format_t ( I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB ) ,
2022-07-07 19:27:22 +02:00
# endif
2022-08-14 13:58:07 +02:00
. intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 ,
2022-06-11 00:50:29 +02:00
. dma_buf_count = 8 ,
2022-08-14 13:58:07 +02:00
. dma_buf_len = _blockSize ,
. use_apll = false ,
. tx_desc_auto_clear = false ,
. fixed_mclk = 0
2022-06-11 00:50:29 +02:00
} ;
2022-06-08 21:14:01 +02:00
}
2022-08-10 17:18:43 +02:00
/* identify Audiosource type - I2S-ADC*/
AudioSourceType getType ( void ) { return ( Type_I2SAdc ) ; }
2022-06-13 17:34:49 +02:00
void initialize ( int8_t audioPin , int8_t = I2S_PIN_NO_CHANGE , int8_t = I2S_PIN_NO_CHANGE , int8_t = I2S_PIN_NO_CHANGE , int8_t = I2S_PIN_NO_CHANGE , int8_t = I2S_PIN_NO_CHANGE ) {
2022-08-14 16:17:34 +02:00
_myADCchannel = 0x0F ;
2022-06-11 12:35:29 +02:00
if ( ! pinManager . allocatePin ( audioPin , false , PinOwner : : UM_Audioreactive ) ) {
2022-08-14 13:58:07 +02:00
DEBUGSR_PRINTF ( " failed to allocate GPIO for audio analog input: %d \n " , audioPin ) ;
2022-06-11 00:50:29 +02:00
return ;
}
_audioPin = audioPin ;
// Determine Analog channel. Only Channels on ADC1 are supported
int8_t channel = digitalPinToAnalogChannel ( _audioPin ) ;
if ( channel > 9 ) {
2022-11-28 20:52:33 +01:00
DEBUGSR_PRINTF ( " Incompatible GPIO used for analog audio input: %d \n " , _audioPin ) ;
2022-06-11 00:50:29 +02:00
return ;
} else {
adc_gpio_init ( ADC_UNIT_1 , adc_channel_t ( channel ) ) ;
2022-08-14 16:17:34 +02:00
_myADCchannel = channel ;
2022-06-11 00:50:29 +02:00
}
// Install Driver
esp_err_t err = i2s_driver_install ( I2S_NUM_0 , & _config , 0 , nullptr ) ;
if ( err ! = ESP_OK ) {
DEBUGSR_PRINTF ( " Failed to install i2s driver: %d \n " , err ) ;
return ;
}
2022-09-19 13:30:13 +02:00
adc1_config_width ( ADC_WIDTH_BIT_12 ) ; // ensure that ADC runs with 12bit resolution
2022-06-11 00:50:29 +02:00
// Enable I2S mode of ADC
err = i2s_set_adc_mode ( ADC_UNIT_1 , adc1_channel_t ( channel ) ) ;
if ( err ! = ESP_OK ) {
DEBUGSR_PRINTF ( " Failed to set i2s adc mode: %d \n " , err ) ;
return ;
}
2022-09-19 13:30:13 +02:00
// see example in https://github.com/espressif/arduino-esp32/blob/master/libraries/ESP32/examples/I2S/HiFreq_ADC/HiFreq_ADC.ino
adc1_config_channel_atten ( adc1_channel_t ( channel ) , ADC_ATTEN_DB_11 ) ; // configure ADC input amplification
2022-08-14 16:17:34 +02:00
# if defined(I2S_GRAB_ADC1_COMPLETELY)
2022-06-11 00:50:29 +02:00
// according to docs from espressif, the ADC needs to be started explicitly
// fingers crossed
2022-08-14 16:17:34 +02:00
err = i2s_adc_enable ( I2S_NUM_0 ) ;
if ( err ! = ESP_OK ) {
DEBUGSR_PRINTF ( " Failed to enable i2s adc: %d \n " , err ) ;
//return;
}
# else
2022-11-28 20:52:33 +01:00
// bugfix: do not disable ADC initially - its already disabled after driver install.
//err = i2s_adc_disable(I2S_NUM_0);
// //err = i2s_stop(I2S_NUM_0);
//if (err != ESP_OK) {
// DEBUGSR_PRINTF("Failed to initially disable i2s adc: %d\n", err);
//}
2022-08-14 16:17:34 +02:00
# endif
2022-06-08 21:14:01 +02:00
2022-06-11 00:50:29 +02:00
_initialized = true ;
2022-06-08 21:14:01 +02:00
}
2022-08-14 16:17:34 +02:00
I2S_datatype postProcessSample ( I2S_datatype sample_in ) {
static I2S_datatype lastADCsample = 0 ; // last good sample
static unsigned int broken_samples_counter = 0 ; // number of consecutive broken (and fixed) ADC samples
I2S_datatype sample_out = 0 ;
// bring sample down down to 16bit unsigned
I2S_unsigned_datatype rawData = * reinterpret_cast < I2S_unsigned_datatype * > ( & sample_in ) ; // C++ acrobatics to get sample as "unsigned"
# ifndef I2S_USE_16BIT_SAMPLES
rawData = ( rawData > > 16 ) & 0xFFFF ; // scale input down from 32bit -> 16bit
I2S_datatype lastGoodSample = lastADCsample / 16384 ; // prepare "last good sample" accordingly (26bit-> 12bit with correct sign handling)
# else
rawData = rawData & 0xFFFF ; // input is already in 16bit, just mask off possible junk
I2S_datatype lastGoodSample = lastADCsample * 4 ; // prepare "last good sample" accordingly (10bit-> 12bit)
# endif
// decode ADC sample data fields
uint16_t the_channel = ( rawData > > 12 ) & 0x000F ; // upper 4 bit = ADC channel
uint16_t the_sample = rawData & 0x0FFF ; // lower 12bit -> ADC sample (unsigned)
I2S_datatype finalSample = ( int ( the_sample ) - 2048 ) ; // convert unsigned sample to signed (centered at 0);
if ( ( the_channel ! = _myADCchannel ) & & ( _myADCchannel ! = 0x0F ) ) { // 0x0F means "don't know what my channel is"
// fix bad sample
finalSample = lastGoodSample ; // replace with last good ADC sample
broken_samples_counter + + ;
if ( broken_samples_counter > 256 ) _myADCchannel = 0x0F ; // too many bad samples in a row -> disable sample corrections
//Serial.print("\n!ADC rogue sample 0x"); Serial.print(rawData, HEX); Serial.print("\tchannel:");Serial.println(the_channel);
} else broken_samples_counter = 0 ; // good sample - reset counter
// back to original resolution
# ifndef I2S_USE_16BIT_SAMPLES
finalSample = finalSample < < 16 ; // scale up from 16bit -> 32bit;
# endif
finalSample = finalSample / 4 ; // mimic old analog driver behaviour (12bit -> 10bit)
sample_out = ( 3 * finalSample + lastADCsample ) / 4 ; // apply low-pass filter (2-tap FIR)
//sample_out = (finalSample + lastADCsample) / 2; // apply stronger low-pass filter (2-tap FIR)
lastADCsample = sample_out ; // update ADC last sample
return ( sample_out ) ;
}
2022-07-03 23:00:32 +02:00
void getSamples ( float * buffer , uint16_t num_samples ) {
2022-06-11 00:50:29 +02:00
/* Enable ADC. This has to be enabled and disabled directly before and
* after sampling , otherwise Wifi dies
*/
if ( _initialized ) {
2022-08-14 16:17:34 +02:00
# if !defined(I2S_GRAB_ADC1_COMPLETELY)
// old code - works for me without enable/disable, at least on ESP32.
//esp_err_t err = i2s_start(I2S_NUM_0);
esp_err_t err = i2s_adc_enable ( I2S_NUM_0 ) ;
if ( err ! = ESP_OK ) {
DEBUGSR_PRINTF ( " Failed to enable i2s adc: %d \n " , err ) ;
return ;
}
# endif
2022-06-11 00:50:29 +02:00
I2SSource : : getSamples ( buffer , num_samples ) ;
2022-06-08 21:14:01 +02:00
2022-08-14 16:17:34 +02:00
# if !defined(I2S_GRAB_ADC1_COMPLETELY)
// old code - works for me without enable/disable, at least on ESP32.
err = i2s_adc_disable ( I2S_NUM_0 ) ; //i2s_adc_disable() may cause crash with IDF 4.4 (https://github.com/espressif/arduino-esp32/issues/6832)
//err = i2s_stop(I2S_NUM_0);
if ( err ! = ESP_OK ) {
DEBUGSR_PRINTF ( " Failed to disable i2s adc: %d \n " , err ) ;
return ;
}
# endif
2022-06-11 00:50:29 +02:00
}
2022-06-08 21:14:01 +02:00
}
void deinitialize ( ) {
2022-06-11 12:35:29 +02:00
pinManager . deallocatePin ( _audioPin , PinOwner : : UM_Audioreactive ) ;
2022-06-11 00:50:29 +02:00
_initialized = false ;
2022-08-14 16:17:34 +02:00
_myADCchannel = 0x0F ;
2022-06-11 00:50:29 +02:00
esp_err_t err ;
2022-08-14 16:17:34 +02:00
# if defined(I2S_GRAB_ADC1_COMPLETELY)
// according to docs from espressif, the ADC needs to be stopped explicitly
// fingers crossed
err = i2s_adc_disable ( I2S_NUM_0 ) ;
if ( err ! = ESP_OK ) {
DEBUGSR_PRINTF ( " Failed to disable i2s adc: %d \n " , err ) ;
}
# endif
i2s_stop ( I2S_NUM_0 ) ;
2022-06-11 00:50:29 +02:00
err = i2s_driver_uninstall ( I2S_NUM_0 ) ;
if ( err ! = ESP_OK ) {
DEBUGSR_PRINTF ( " Failed to uninstall i2s driver: %d \n " , err ) ;
return ;
}
2022-06-08 21:14:01 +02:00
}
2022-06-11 00:50:29 +02:00
private :
int8_t _audioPin ;
2022-08-14 16:17:34 +02:00
int8_t _myADCchannel = 0x0F ; // current ADC channel for analog input. 0x0F means "undefined"
2022-06-08 21:14:01 +02:00
} ;
2022-09-11 00:12:51 +02:00
# endif
2022-06-08 21:14:01 +02:00
/* SPH0645 Microphone
This is an I2S microphone with some timing quirks that need
special consideration .
*/
2022-09-16 16:58:04 +02:00
// https://github.com/espressif/esp-idf/issues/7192 SPH0645 i2s microphone issue when migrate from legacy esp-idf version (IDFGH-5453)
// a user recommended this: Try to set .communication_format to I2S_COMM_FORMAT_STAND_I2S and call i2s_set_clk() after i2s_set_pin().
2022-06-08 21:14:01 +02:00
class SPH0654 : public I2SSource {
2022-06-11 00:50:29 +02:00
public :
2022-11-28 20:52:33 +01:00
SPH0654 ( SRate_t sampleRate , int blockSize , float sampleScale = 1.0f ) :
I2SSource ( sampleRate , blockSize , sampleScale )
2022-06-13 17:34:49 +02:00
{ }
2022-06-08 21:14:01 +02:00
2022-06-13 17:34:49 +02:00
void initialize ( uint8_t i2swsPin , uint8_t i2ssdPin , uint8_t i2sckPin , int8_t = I2S_PIN_NO_CHANGE , int8_t = I2S_PIN_NO_CHANGE , int8_t = I2S_PIN_NO_CHANGE ) {
2022-06-11 00:50:29 +02:00
I2SSource : : initialize ( i2swsPin , i2ssdPin , i2sckPin ) ;
2022-09-11 00:12:51 +02:00
# if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
// these registers are only existing in "classic" ESP32
2022-06-11 00:50:29 +02:00
REG_SET_BIT ( I2S_TIMING_REG ( I2S_NUM_0 ) , BIT ( 9 ) ) ;
REG_SET_BIT ( I2S_CONF_REG ( I2S_NUM_0 ) , I2S_RX_MSB_SHIFT ) ;
2022-09-11 00:12:51 +02:00
# else
# warning FIX ME! Please.
# endif
2022-06-08 21:14:01 +02:00
}
} ;