Unverified Commit 11496501 authored by Lucas Saavedra Vaz's avatar Lucas Saavedra Vaz Committed by GitHub

Add I2S examples and documentation (#9030)

* feat(i2s): Add I2S examples

- ES8388 loopback example using the LyraT board
- ESP32-S3-EYE record WAV to SD card example
- Simple tone example

* docs(i2s): Add I2S API docs
parent dd712db3
......@@ -16,142 +16,142 @@ The I²S bus consists of at least three lines:
.. note:: All lines can be attached to almost any pin and this change can occur even during operation.
* **Bit clock line**
* Officially "continuous serial clock (SCK)". Typically written "bit clock (BCLK)".
* In this library function parameter ``sckPin`` or constant ``PIN_I2S_SCK``.
* In this library function parameter ``sck``.
* **Word clock line**
* Officially "word select (WS)". Typically called "left-right clock (LRCLK)" or "frame sync (FS)".
* 0 = Left channel, 1 = Right channel
* In this library function parameter ``fsPin`` or constant ``PIN_I2S_FS``.
* In this library function parameter ``ws``.
* **Data line**
* Officially "serial data (SD)", but can be called SDATA, SDIN, SDOUT, DACDAT, ADCDAT, etc.
* Unlike Arduino I2S with single data pin switching between input and output, in ESP core driver use separate data line for input and output.
* For backward compatibility, the shared data pin is ``sdPin`` or constant ``PIN_I2S_SD`` when using simplex mode.
* When using in duplex mode, there are two data lines:
* Output data line is called ``outSdPin`` for function parameter, or constant ``PIN_I2S_SD_OUT``
* Input data line is called ``inSdPin`` for function parameter, or constant ``PIN_I2S_SD_IN``
* Output data line is called ``dout`` for function parameter.
* Input data line is called ``din`` for function parameter.
It may also include a **Master clock** line:
I2S Modes
---------
* **Master clock**
The I2S can be set up in three groups of modes:
* Officially "master clock (MCLK)".
* This is not a part of I2S bus, but is used to synchronize multiple I2S devices.
* In this library function parameter ``mclk``.
* Master (default) or Slave.
* Simplex (default) or Duplex.
* Operation modes (Philips standard, ADC/DAC, PDM)
* Most of them are dual-channel, some can be single channel
.. note:: Please check the `ESP-IDF documentation <https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/i2s.html>`_ for more details on the I2S peripheral for each ESP32 chip.
.. note:: Officially supported operation mode is only ``I2S_PHILIPS_MODE``. Other modes are implemented, but we cannot guarantee flawless execution and behavior.
I2S Configuration
-----------------
Master / Slave Mode
*******************
In **Master mode** (default) the device is generating clock signal ``sckPin`` and word select signal on ``fsPin``.
In **Master mode** (default) the device is generating clock signal ``sck`` and word select signal on ``ws``.
In **Slave mode** the device listens on attached pins for the clock signal and word select - i.e. unless externally driven the pins will remain LOW.
How to enter either mode is described in the function section.
This mode is not supported yet.
Operation Modes
***************
Setting the operation mode is done with function ``begin`` (see API section)
Setting the operation mode is done with function ``begin`` and is set by function parameter ``mode``.
* ``I2S_PHILIPS_MODE``
* Currently the only official* ``PIN_I2S_SCK``
* ``PIN_I2S_FS``
* ``PIN_I2S_SD``
* ``PIN_I2S_SD_OUT`` only need to send one channel data but the data will be copied for another channel automatically, then both channels will transmit same data.
* ``I2S_MODE_STD``
In standard mode, there are always two sound channels, i.e., the left and right channels, which are called "slots".
These slots support 8/16/24/32-bit width sample data.
The communication format for the slots follows the Philips standard.
* ``ADC_DAC_MODE``
The output will be an analog signal on pins ``25`` (L or R?) and ``26`` (L or R?).
Input will be received on pin ``_inSdPin``.
The data are sampled in 12 bits and stored in a 16 bits, with the 4 most significant bits set to zero.
* ``I2S_MODE_TDM``
In Time Division Multiplexing mode (TDM), the number of sound channels is variable, and the width of each channel
is fixed.
* ``PDM_STEREO_MODE``
Pulse-density-modulation is similar to PWM, but instead, the pulses have constant width. The signal is modulated with the number of ones or zeroes in sequence.
* ``I2S_MODE_PDM_TX``
PDM (Pulse-density Modulation) mode for the TX channel can convert PCM data into PDM format which always
has left and right slots.
PDM TX is only supported on I2S0 and it only supports 16-bit width sample data.
It needs at least a CLK pin for clock signal and a DOUT pin for data signal.
* ``PDM_MONO_MODE``
Single-channel version of PDM mode described above.
* ``I2S_MODE_PDM_RX``
PDM (Pulse-density Modulation) mode for RX channel can receive PDM-format data and convert the data
into PCM format. PDM RX is only supported on I2S0, and it only supports 16-bit width sample data.
PDM RX needs at least a CLK pin for clock signal and a DIN pin for data signal.
Simplex / Duplex Mode
*********************
The **Simplex** mode is the default after driver initialization. Simplex mode uses the shared data pin ``sdPin`` or constant ``PIN_I2S_SD`` for both output and input, but can only read or write. This is the same behavior as in original Arduino library.
Due to the different clock sources the PDM modes are always in **Simplex** mode, using only one data pin.
The **Duplex** mode uses two separate data pins:
The STD and TDM modes operate in the **Duplex** mode, using two separate data pins:
* Output pin ``outSdPin`` for function parameter, or constant ``PIN_I2S_SD_OUT``
* Input pin ``inSdPin`` for function parameter, or constant ``PIN_I2S_SD_IN``
* Output pin ``dout`` for function parameter
* Input pin ``din`` for function parameter
In this mode, the driver is able to read and write simultaneously on each line and is suitable for applications like walkie-talkie or phone.
Switching between these modes is performed simply by calling setDuplex() or setSimplex() (see APi section for details and more functions).
Data Bit Width
**************
Arduino-ESP32 I2S API
---------------------
The ESP32 I2S library is based on the Arduino I2S Library and implements a few more APIs, described in this `documentation <https://www.arduino.cc/en/Reference/I2S>`_.
This is the number of bits in a channel sample. The data bit width is set by function parameter ``bits_cfg``.
The current supported values are:
Initialization and deinitialization
***********************************
* ``I2S_DATA_BIT_WIDTH_8BIT``
* ``I2S_DATA_BIT_WIDTH_16BIT``
* ``I2S_DATA_BIT_WIDTH_24BIT``, requires the MCLK multiplier to be manually set to 384
* ``I2S_DATA_BIT_WIDTH_32BIT``
Before initialization, choose which pins you want to use. In DAC mode you can use only pins `25` and `26` for the output.
begin (Master Mode)
^^^^^^^^^^^^^^^^^^^
Before usage choose which pins you want to use. In DAC mode you can use only pins 25 and 26 as output.
.. code-block:: arduino
Sample Rate
***********
int begin(int mode, int sampleRate, int bitsPerSample)
The sample rate is set by function parameter ``rate``. It is the number of samples per second in Hz.
Parameters:
* [in] ``mode`` one of above mentioned operation mode, for example ``I2S_PHILIPS_MODE``.
Slot Mode
*********
* [in] ``sampleRate`` is the sampling rate in Hz. Currently officially supported value is only 16000 - other than this value will print warning, but continue to operate, however the resulting audio quality may suffer and the app may crash.
The slot mode is set by function parameter ``ch``. The current supported values are:
* [in] ``bitsPerSample`` is the number of bits in a channel sample.
Currently, the supported value is only 16 - other than this value will print a warning, but continues to operate, however, the resulting audio quality may suffer and the application may crash.
* ``I2S_SLOT_MODE_MONO``
I2S channel slot format mono. Transmit the same data in all slots for TX mode.
Only receive the data in the first slots for RX mode.
For ``ADC_DAC_MODE`` the only possible value will remain 16.
* ``I2S_SLOT_MODE_STEREO``
I2S channel slot format stereo. Transmit different data in different slots for TX mode.
Receive the data in all slots for RX mode.
This function will return ``true`` on success or ``fail`` in case of failure.
Arduino-ESP32 I2S API
---------------------
When failed, an error message will be printed if subscribed.
Initialization and deinitialization
***********************************
begin (Slave Mode)
^^^^^^^^^^^^^^^^^^
Before initialization, set which pins you want to use.
Performs initialization before use - creates buffers, task handling underlying driver messages, configuring and starting the driver operation.
begin (Master Mode)
^^^^^^^^^^^^^^^^^^^
This version initializes I2S in SLAVE mode (see previous entry for MASTER mode).
Before usage choose which pins you want to use.
.. code-block:: arduino
int begin(int mode, int bitsPerSample)
bool begin(i2s_mode_t mode, uint32_t rate, i2s_data_bit_width_t bits_cfg, i2s_slot_mode_t ch, int8_t slot_mask=-1)
Parameters:
* [in] ``mode`` one of above mentioned modes for example ``I2S_PHILIPS_MODE``.
* [in] ``mode`` one of above mentioned operation mode, for example ``I2S_MODE_STD``.
* [in] ``bitsPerSample`` is the umber of bits in a channel sample. Currently, the only supported value is only 16 - other than this value will print warning, but continue to operate, however the resulting audio quality may suffer and the app may crash.
* [in] ``rate`` is the sampling rate in Hz, for example ``16000``.
For ``ADC_DAC_MODE`` the only possible value will remain 16.
* [in] ``bits_cfg`` is the number of bits in a channel sample, for example ``I2S_DATA_BIT_WIDTH_16BIT``.
* [in] ``ch`` is the slot mode, for example ``I2S_SLOT_MODE_STEREO``.
* [in] ``slot_mask`` is the slot mask, for example ``0b11``. This parameter is optional and defaults to ``-1`` (not used).
This function will return ``true`` on success or ``fail`` in case of failure.
When failed, an error message will be printed if subscribed.
When failed, an error message will be printed if the correct log level is set.
end
^^^
......@@ -165,402 +165,393 @@ Performs safe deinitialization - free buffers, destroy task, end driver operatio
Pin setup
*********
Pins can be changed in two ways- 1st constants, 2nd functions.
The function to set the pins will depend on the operation mode.
.. note:: Shared data pin can be equal to any other data pin, but must not be equal to clock pin nor frame sync pin! Input and Output pins must not be equal, but one of them can be equal to shared data pin!
.. code-block:: arduino
setPins
^^^^^^^
sckPin != fsPin != outSdPin != inSdPin
Set the pins for the I2S interface when using the standard or TDM mode.
.. code-block:: arduino
sckPin != fsPin != sdPin
void setPins(int8_t bclk, int8_t ws, int8_t dout, int8_t din=-1, int8_t mclk=-1)
By default, the pin numbers are defined in constants in the header file. You can redefine any of those constants before including ``I2S.h``. This way the driver will use these new default values and you will not need to specify pins in your code. The constants and their default values are:
Parameters:
* ``PIN_I2S_SCK`` 14
* ``PIN_I2S_FS`` 25
* ``PIN_I2S_SD`` 26
* ``PIN_I2S_SD_OUT`` 26
* ``PIN_I2S_SD_IN`` 35
* [in] ``bclk`` is the bit clock pin.
The second option to change pins is using the following functions. These functions can be called on either on initialized or uninitialized object.
* [in] ``ws`` is the word select pin.
If called on the initialized object (after calling ``begin``) the pins will change during operation.
If called on the uninitialized object (before calling ``begin``, or after calling ``end``) the new pin setup will be used on next initialization.
* [in] ``dout`` is the data output pin. Can be set to ``-1`` if not used.
setSckPin
^^^^^^^^^
* [in] ``din`` is the data input pin. This parameter is optional and defaults to ``-1`` (not used).
Set and apply clock pin.
* [in] ``mclk`` is the master clock pin. This parameter is optional and defaults to ``-1`` (not used).
.. code-block:: arduino
setPinsPdmTx
^^^^^^^^^^^^
int setSckPin(int sckPin)
Set the pins for the I2S interface when using the PDM TX mode.
This function will return ``true`` on success or ``fail`` in case of failure.
.. code-block:: arduino
setFsPin
^^^^^^^^
void setPinsPdmTx(int8_t clk, int8_t dout0, int8_t dout1=-1)
Set and apply frame sync pin.
Parameters:
.. code-block:: arduino
* [in] ``clk`` is the clock pin.
int setFsPin(int fsPin)
* [in] ``dout0`` is the data output pin 0.
This function will return ``true`` on success or ``fail`` in case of failure.
* [in] ``dout1`` is the data output pin 1. This parameter is optional and defaults to ``-1`` (not used).
setDataPin
^^^^^^^^^^
setPinsPdmRx
^^^^^^^^^^^^
Set and apply shared data pin used in simplex mode.
Set the pins for the I2S interface when using the PDM RX mode.
.. code-block:: arduino
int setDataPin(int sdPin)
void setPinsPdmRx(int8_t clk, int8_t din0, int8_t din1=-1, int8_t din2=-1, int8_t din3=-1)
This function will return ``true`` on success or ``fail`` in case of failure.
Parameters:
setDataInPin
^^^^^^^^^^^^
* [in] ``clk`` is the clock pin.
Set and apply data input pin.
* [in] ``din0`` is the data input pin 0.
.. code-block:: arduino
* [in] ``din1`` is the data input pin 1. This parameter is optional and defaults to ``-1`` (not used).
int setDataInPin(int inSdPin)
* [in] ``din2`` is the data input pin 2. This parameter is optional and defaults to ``-1`` (not used).
This function will return ``true`` on success or ``fail`` in case of failure.
* [in] ``din3`` is the data input pin 3. This parameter is optional and defaults to ``-1`` (not used).
setDataOutPin
^^^^^^^^^^^^^
setInverted
^^^^^^^^^^^
Set and apply data output pin.
Set which pins have inverted logic when using the standard or TDM mode. Data pins cannot be inverted.
.. code-block:: arduino
int setDataOutPin(int outSdPin)
void setInverted(bool bclk, bool ws, bool mclk=false)
This function will return ``true`` on success or ``fail`` in case of failure.
setAllPins
^^^^^^^^^^
Parameters:
Set all pins using given values in parameters. This is simply a wrapper of four functions mentioned above.
* [in] ``bclk`` true if the bit clock pin is inverted. False otherwise.
.. code-block:: arduino
* [in] ``ws`` true if the word select pin is inverted. False otherwise.
int setAllPins(int sckPin, int fsPin, int sdPin, int outSdPin, int inSdPin)
* [in] ``mclk`` true if the master clock pin is inverted. False otherwise. This parameter is optional and defaults to ``false``.
Set all pins to default i.e. take values from constants mentioned above. This simply calls the the function with the following constants.
setInvertedPdm
^^^^^^^^^^^^^^
* ``PIN_I2S_SCK`` 14
* ``PIN_I2S_FS`` 25
* ``PIN_I2S_SD`` 26
* ``PIN_I2S_SD_OUT`` 26
* ``PIN_I2S_SD_IN`` 35
Set which pins have inverted logic when using the PDM mode. Data pins cannot be inverted.
.. code-block:: arduino
int setAllPins()
void setInvertedPdm(bool clk)
getSckPin
^^^^^^^^^
Parameters:
Get the current value of the clock pin.
* [in] ``clk`` true if the clock pin is inverted. False otherwise.
.. code-block:: arduino
I2S Configuration
*****************
int getSckPin()
The I2S configuration can be changed during operation.
getFsPin
^^^^^^^^
configureTX
^^^^^^^^^^^
Get the current value of frame sync pin.
Configure the I2S TX channel.
.. code-block:: arduino
int getFsPin()
getDataPin
^^^^^^^^^^
bool configureTX(uint32_t rate, i2s_data_bit_width_t bits_cfg, i2s_slot_mode_t ch, int8_t slot_mask=-1)
Get the current value of shared data pin.
Parameters:
.. code-block:: arduino
* [in] ``rate`` is the sampling rate in Hz, for example ``16000``.
int getDataPin()
* [in] ``bits_cfg`` is the number of bits in a channel sample, for example ``I2S_DATA_BIT_WIDTH_16BIT``.
getDataInPin
^^^^^^^^^^^^
* [in] ``ch`` is the slot mode, for example ``I2S_SLOT_MODE_STEREO``.
Get the current value of data input pin.
* [in] ``slot_mask`` is the slot mask, for example ``0b11``. This parameter is optional and defaults to ``-1`` (not used).
.. code-block:: arduino
This function will return ``true`` on success or ``fail`` in case of failure.
int getDataInPin()
When failed, an error message will be printed if the correct log level is set.
getDataOutPin
^^^^^^^^^^^^^
configureRX
^^^^^^^^^^^
Get the current value of data output pin.
Configure the I2S RX channel.
.. code-block:: arduino
int getDataOutPin()
bool configureRX(uint32_t rate, i2s_data_bit_width_t bits_cfg, i2s_slot_mode_t ch, i2s_rx_transform_t transform=I2S_RX_TRANSFORM_NONE)
onTransmit
^^^^^^^^^^
Parameters:
Register the function to be called on each successful transmit event.
* [in] ``rate`` is the sampling rate in Hz, for example ``16000``.
.. code-block:: arduino
* [in] ``bits_cfg`` is the number of bits in a channel sample, for example ``I2S_DATA_BIT_WIDTH_16BIT``.
void onTransmit(void(*)(void))
* [in] ``ch`` is the slot mode, for example ``I2S_SLOT_MODE_STEREO``.
onReceive
^^^^^^^^^
Register the function to be called on each successful receives event.
* [in] ``transform`` is the transform mode, for example ``I2S_RX_TRANSFORM_NONE``.
This can be used to apply a transformation/conversion to the received data.
The supported values are: ``I2S_RX_TRANSFORM_NONE`` (no transformation),
``I2S_RX_TRANSFORM_32_TO_16`` (convert from 32 bits of data width to 16 bits) and
``I2S_RX_TRANSFORM_16_STEREO_TO_MONO`` (convert from stereo to mono when using 16 bits of data width).
.. code-block:: arduino
This function will return ``true`` on success or ``fail`` in case of failure.
void onReceive(void(*)(void))
When failed, an error message will be printed if the correct log level is set.
setBufferSize
^^^^^^^^^^^^^
txChan
^^^^^^
Set the size of buffer.
Get the TX channel handler pointer.
.. code-block:: arduino
int setBufferSize(int bufferSize)
i2s_chan_handle_t txChan()
This function can be called on both the initialized or uninitialized driver.
txSampleRate
^^^^^^^^^^^^
If called on initialized, it will change internal values for buffer size and re-initialize driver with new value.
If called on uninitialized, it will only change the internal values which will be used for next initialization.
Get the TX sample rate.
Parameter ``bufferSize`` must be in range from 8 to 1024 and the unit is sample words. The default value is 128.
.. code-block:: arduino
Example: 16 bit sample, dual channel, buffer size for input:
uint32_t txSampleRate()
``128 = 2B sample * 2 channels * 128 buffer size * buffer count (default 2) = 1024B``
And more ```1024B`` for output buffer in total of ``2kB`` used.
txDataWidth
^^^^^^^^^^^
This function always assumes dual-channel, keeping the same size even for MONO modes.
Get the TX data width (8, 16 or 32 bits).
This function will return ``true`` on success or ``fail`` in case of failure.
.. code-block:: arduino
When failed, an error message will be printed.
i2s_data_bit_width_t txDataWidth()
getBufferSize
^^^^^^^^^^^^^
txSlotMode
^^^^^^^^^^
Get current buffer sizes in sample words (see description for ``setBufferSize``).
Get the TX slot mode (stereo or mono).
.. code-block:: arduino
int getBufferSize()
i2s_slot_mode_t txSlotMode()
Duplex vs Simplex
*****************
rxChan
^^^^^^
Original Arduino I2S library supports only *simplex* mode (only transmit or only receive at a time). For compatibility, we kept this behavior, but ESP natively supports *duplex* mode (receive and transmit simultaneously on separate pins).
By default this library is initialized in simplex mode as it would in Arduino, switching input and output on ``sdPin`` (constant ``PIN_I2S_SD`` default pin 26).
Get the RX channel handler pointer.
setDuplex
^^^^^^^^^
.. code-block:: arduino
Switch to duplex mode and use separate pins:
i2s_chan_handle_t rxChan()
.. code-block:: arduino
rxSampleRate
^^^^^^^^^^^^
int setDuplex()
Get the RX sample rate.
input: inSdPin (constant PIN_I2S_SD_IN, default 35)
output: outSdPin (constant PIN_I2S_SD, default 26)
.. code-block:: arduino
setSimplex
^^^^^^^^^^
uint32_t rxSampleRate()
(Default mode)
rxDataWidth
^^^^^^^^^^^
Switch to simplex mode using shared data pin sdPin (constant PIN_I2S_SD, default 26).
Get the RX data width (8, 16 or 32 bits).
.. code-block:: arduino
int setSimplex()
i2s_data_bit_width_t rxDataWidth()
isDuplex
^^^^^^^^
rxSlotMode
^^^^^^^^^^
Returns 1 if current mode is duplex, 0 if current mode is simplex (default).
Get the RX slot mode (stereo or mono).
.. code-block:: arduino
int isDuplex()
i2s_slot_mode_t rxSlotMode()
Data stream
***********
I/O Operations
**************
available
readBytes
^^^^^^^^^
Returns number of **bytes** ready to read.
Read a certain amount of data bytes from the I2S interface.
.. code-block:: arduino
int available()
size_t readBytes(char *buffer, size_t size)
Parameters:
* [in] ``buffer`` is the buffer to store the read data. The buffer must be at least ``size`` bytes long.
* [in] ``size`` is the number of bytes to read.
This function will return the number of bytes read.
read
^^^^
Read ``size`` bytes from internal buffer if possible.
Read the next available byte from the I2S interface.
.. code-block:: arduino
int read(void* buffer, size_t size)
int read()
This function is non-blocking, i.e. if the requested number of bytes is not available, it will return as much as possible without waiting.
This function will return the next available byte or ``-1`` if no data is available
or an error occurred.
Hint: use ``available()`` before calling this function.
write
Parameters:
There are two versions of the write function:
[out] ``void* buffer`` buffer into which will be copied data read from internal buffer. WARNING: this buffer must be allocated before use!
The first version writes a certain amount of data bytes to the I2S interface.
[in] ``size_t size`` number of bytes required to be read.
.. code-block:: arduino
Returns number of successfully bytes read. Returns ``false``` in case of reading error.
size_t write(uint8_t *buffer, size_t size)
Read one sample.
Parameters:
.. code-block:: arduino
* [in] ``buffer`` is the buffer containing the data to be written.
int read()
* [in] ``size`` is the number of bytes to write from the buffer.
peek
^^^^
This function will return the number of bytes written.
Read one sample from the internal buffer and returns it.
The second version writes a single byte to the I2S interface.
.. code-block:: arduino
int peek()
size_t write(uint8_t d)
Parameters:
* [in] ``d`` is the byte to be written.
Repeated peeks will be returned in the same sample until ``read`` is called.
This function will return ``1`` if the byte was written or ``0`` if an error occurred.
flush
^^^^^
available
^^^^^^^^^
Force write internal buffer to driver.
Get if there is data available to be read.
.. code-block:: arduino
void flush()
int available()
write
^^^^^
This function will return ``I2S_READ_CHUNK_SIZE`` if there is data available to be read or ``-1`` if not.
peek
^^^^
Write a single byte.
Get the next available byte from the I2S interface without removing it from the buffer. Currently not implemented.
.. code-block:: arduino
size_t write(uint8_t)
int peek()
Single-sample writes are blocking - waiting until there is free space in the internal buffer to be written into.
This function will currently always return ``-1``.
Returns number of successfully written bytes, in this case, 1. Returns 0 on error.
lastError
^^^^^^^^^
Write single sample.
Get the last error code for an I/O operation on the I2S interface.
.. code-block:: arduino
size_t write(int32_t)
Single-sample writes are blocking - waiting until there is free space in the internal buffer to be written into.
int lastError()
Returns number of successfully written bytes. Returns 0 on error.
Expected return number is ``bitsPerSample/8``.
recordWAV
^^^^^^^^^
Write buffer of supplied size;
Record a short PCM WAV to memory with the current RX settings.
Returns a buffer that must be freed by the user.
.. code-block:: arduino
size_t write(const void *buffer, size_t size)
uint8_t * recordWAV(size_t rec_seconds, size_t * out_size)
Parameters:
[in] ``const void *buffer`` buffer to be written
[in] ``size_t size`` size of buffer in bytes
* [in] ``rec_seconds`` is the number of seconds to record.
Returns number of successfully written bytes. Returns 0 in case of error.
The expected return number is equal to ``size``.
* [out] ``out_size`` is the size of the returned buffer in bytes.
write
^^^^^
This function will return a pointer to the buffer containing the recorded WAV data or ``NULL`` if an error occurred.
This is a wrapper of the previous function performing typecast from `uint8_t*`` to ``void*``.
playWAV
^^^^^^^
.. code-block:: arduino
Play a PCM WAV from memory with the current TX settings.
size_t write(const uint8_t *buffer, size_t size)
.. code-block:: arduino
availableForWrite
^^^^^^^^^^^^^^^^^
void playWAV(uint8_t * data, size_t len)
Returns number of bytes available for write.
Parameters:
.. code-block:: arduino
* [in] ``data`` is the buffer containing the WAV data.
int availableForWrite()
* [in] ``len`` is the size of the buffer in bytes.
write_blocking
^^^^^^^^^^^^^^
playMP3
^^^^^^^
Core function implementing blocking write, i.e. waits until all requested data are written.
Play a MP3 from memory with the current TX settings.
.. code-block:: arduino
size_t write_blocking(const void *buffer, size_t size)
bool playMP3(uint8_t *src, size_t src_len)
WARNING: If too many bytes are requested, this can cause WatchDog Trigger Reset!
Returns number of successfully written bytes. Returns 0 on error.
write_nonblocking
^^^^^^^^^^^^^^^^^
Parameters:
Core function implementing non-blocking write, i.e. writes as much as possible and exits.
* [in] ``src`` is the buffer containing the MP3 data.
.. code-block:: arduino
* [in] ``src_len`` is the size of the buffer in bytes.
size_t write_nonblocking(const void *buffer, size_t size)
This function will return ``true`` on success or ``false`` in case of failure.
Returns number of successfully written bytes. Returns 0 on error.
When failed, an error message will be printed if the correct log level is set.
Sample code
-----------
.. code-block:: c
.. code-block:: arduino
#include <ESP_I2S.h>
#include <I2S.h>
const int buff_size = 128;
int available, read;
uint8_t buffer[buff_size];
I2S.begin(I2S_PHILIPS_MODE, 16000, 16);
I2S.read(); // Switch the driver in simplex mode to receive
available = I2S.available();
if(available < buff_size){
read = I2S.read(buffer, available);
}else{
read = I2S.read(buffer, buff_size);
I2SClass I2S;
void setup() {
I2S.setPins(5, 25, 26, 35, 0); //SCK, WS, SDOUT, SDIN, MCLK
I2S.begin(I2S_MODE_STD, 16000, I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO);
I2S.read();
available = I2S.available();
if(available < buff_size) {
read = I2S.read(buffer, available);
} else {
read = I2S.read(buffer, buff_size);
}
I2S.write(buffer, read);
I2S.end();
}
I2S.write(buffer, read);
I2S.end();
void loop() {}
/*
This is a very basic driver for the ES8388 based on the driver written by
me for NuttX. It is not complete and is missing master mode, mono mode, many
features and configuration options. You can use readReg and writeReg to
access the registers directly and configure missing features. Feel free to
contribute by adding missing features and improving the driver.
It is intended to be used only with arduino-esp32.
The default configuration can be found in the ES8388.h file.
This was only tested with the ESP32-LyraT board using 44100Hz 16-bit stereo
audio. It may not work with other configurations.
Created for arduino-esp32 on 20 Dec, 2023
by Lucas Saavedra Vaz (lucasssvaz)
*/
#include <cmath>
#include "ESP_I2S.h"
#include "Wire.h"
#include "ES8388.h"
/****************************************************************************
* Private Methods
****************************************************************************/
/*
Name: start
Description:
Unmute and start the ES8388 codec data transmission.
*/
void ES8388::start()
{
uint8_t prev_regval = 0;
uint8_t regval = 0;
log_v("Starting ES8388 transmission...");
_running = true;
prev_regval = readReg(ES8388_DACCONTROL21);
if (_audio_mode == ES_MODULE_LINE)
{
writeReg(ES8388_DACCONTROL16,
ES8388_RMIXSEL_RIN2 |
ES8388_LMIXSEL_LIN2);
writeReg(ES8388_DACCONTROL17,
ES8388_LI2LOVOL(ES8388_MIXER_GAIN_0DB) |
ES8388_LI2LO_ENABLE |
ES8388_LD2LO_DISABLE);
writeReg(ES8388_DACCONTROL20,
ES8388_RI2ROVOL(ES8388_MIXER_GAIN_0DB) |
ES8388_RI2RO_ENABLE |
ES8388_RD2RO_DISABLE);
writeReg(ES8388_DACCONTROL21,
ES8388_DAC_DLL_PWD_NORMAL |
ES8388_ADC_DLL_PWD_NORMAL |
ES8388_MCLK_DIS_NORMAL |
ES8388_OFFSET_DIS_DISABLE |
ES8388_LRCK_SEL_ADC |
ES8388_SLRCK_SAME);
}
else
{
writeReg(ES8388_DACCONTROL21,
ES8388_DAC_DLL_PWD_NORMAL |
ES8388_ADC_DLL_PWD_NORMAL |
ES8388_MCLK_DIS_NORMAL |
ES8388_OFFSET_DIS_DISABLE |
ES8388_LRCK_SEL_DAC |
ES8388_SLRCK_SAME);
}
regval = readReg(ES8388_DACCONTROL21);
if (regval != prev_regval)
{
writeReg(ES8388_CHIPPOWER,
ES8388_DACVREF_PDN_PWRUP |
ES8388_ADCVREF_PDN_PWRUP |
ES8388_DACDLL_PDN_NORMAL |
ES8388_ADCDLL_PDN_NORMAL |
ES8388_DAC_STM_RST_RESET |
ES8388_ADC_STM_RST_RESET |
ES8388_DAC_DIGPDN_RESET |
ES8388_ADC_DIGPDN_RESET);
writeReg(ES8388_CHIPPOWER,
ES8388_DACVREF_PDN_PWRUP |
ES8388_ADCVREF_PDN_PWRUP |
ES8388_DACDLL_PDN_NORMAL |
ES8388_ADCDLL_PDN_NORMAL |
ES8388_DAC_STM_RST_NORMAL |
ES8388_ADC_STM_RST_NORMAL |
ES8388_DAC_DIGPDN_NORMAL |
ES8388_ADC_DIGPDN_NORMAL);
}
if (_audio_mode == ES_MODULE_LINE || _audio_mode == ES_MODULE_ADC_DAC || _audio_mode == ES_MODULE_ADC)
{
writeReg(ES8388_ADCPOWER,
ES8388_INT1LP_NORMAL |
ES8388_FLASHLP_NORMAL |
ES8388_PDNADCBIASGEN_NORMAL |
ES8388_PDNMICB_PWRON |
ES8388_PDNADCR_PWRUP |
ES8388_PDNADCL_PWRUP |
ES8388_PDNAINR_NORMAL |
ES8388_PDNAINL_NORMAL);
}
if (_audio_mode == ES_MODULE_LINE || _audio_mode == ES_MODULE_ADC_DAC || _audio_mode == ES_MODULE_DAC)
{
writeReg(ES8388_DACPOWER,
ES8388_ROUT2_ENABLE |
ES8388_LOUT2_ENABLE |
ES8388_ROUT1_ENABLE |
ES8388_LOUT1_ENABLE |
ES8388_PDNDACR_PWRUP |
ES8388_PDNDACL_PWRUP);
}
setmute(_audio_mode, false);
log_v("ES8388 transmission started.");
}
/*
Name: reset
Description:
Reset the ES8388 codec to a known state depending on the audio mode.
*/
void ES8388::reset()
{
uint8_t regconfig;
log_v("Resetting ES8388...");
log_d("Current configuration: _bpsamp=%d, _samprate=%d, _nchannels=%d, _audio_mode=%d, _dac_output=%d, _adc_input=%d, _mic_gain=%d",
_bpsamp, _samprate, _nchannels, _audio_mode, _dac_output, _adc_input, _mic_gain);
writeReg(ES8388_DACCONTROL3,
ES8388_DACMUTE_MUTED |
ES8388_DACLER_NORMAL |
ES8388_DACSOFTRAMP_DISABLE |
ES8388_DACRAMPRATE_4LRCK);
writeReg(ES8388_CONTROL2,
ES8388_PDNVREFBUF_NORMAL |
ES8388_VREFLO_NORMAL |
ES8388_PDNIBIASGEN_NORMAL |
ES8388_PDNANA_NORMAL |
ES8388_LPVREFBUF_LP |
ES8388_LPVCMMOD_NORMAL |
(1 << 6)); /* Default value of undocumented bit */
writeReg(ES8388_CHIPPOWER,
ES8388_DACVREF_PDN_PWRUP |
ES8388_ADCVREF_PDN_PWRUP |
ES8388_DACDLL_PDN_NORMAL |
ES8388_ADCDLL_PDN_NORMAL |
ES8388_DAC_STM_RST_NORMAL |
ES8388_ADC_STM_RST_NORMAL |
ES8388_DAC_DIGPDN_NORMAL |
ES8388_ADC_DIGPDN_NORMAL);
/* Disable the internal DLL to improve 8K sample rate */
writeReg(0x35, 0xa0);
writeReg(0x37, 0xd0);
writeReg(0x39, 0xd0);
writeReg(ES8388_MASTERMODE,
ES8388_BCLKDIV(ES_MCLK_DIV_AUTO) |
ES8388_BCLK_INV_NORMAL |
ES8388_MCLKDIV2_NODIV |
ES8388_MSC_SLAVE);
writeReg(ES8388_DACPOWER,
ES8388_ROUT2_DISABLE |
ES8388_LOUT2_DISABLE |
ES8388_ROUT1_DISABLE |
ES8388_LOUT1_DISABLE |
ES8388_PDNDACR_PWRDN |
ES8388_PDNDACL_PWRDN);
writeReg(ES8388_CONTROL1,
ES8388_VMIDSEL_500K |
ES8388_ENREF_DISABLE |
ES8388_SEQEN_DISABLE |
ES8388_SAMEFS_SAME |
ES8388_DACMCLK_ADCMCLK |
ES8388_LRCM_ISOLATED |
ES8388_SCPRESET_NORMAL);
setBitsPerSample(_bpsamp);
setSampleRate(_samprate);
writeReg(ES8388_DACCONTROL16,
ES8388_RMIXSEL_RIN1 | ES8388_LMIXSEL_LIN1);
writeReg(ES8388_DACCONTROL17,
ES8388_LI2LOVOL(ES8388_MIXER_GAIN_0DB) |
ES8388_LI2LO_DISABLE |
ES8388_LD2LO_ENABLE);
writeReg(ES8388_DACCONTROL20,
ES8388_RI2ROVOL(ES8388_MIXER_GAIN_0DB) |
ES8388_RI2RO_DISABLE |
ES8388_RD2RO_ENABLE);
writeReg(ES8388_DACCONTROL21,
ES8388_DAC_DLL_PWD_NORMAL |
ES8388_ADC_DLL_PWD_NORMAL |
ES8388_MCLK_DIS_NORMAL |
ES8388_OFFSET_DIS_DISABLE |
ES8388_LRCK_SEL_DAC |
ES8388_SLRCK_SAME);
writeReg(ES8388_DACCONTROL23, ES8388_VROI_1_5K);
writeReg(ES8388_DACCONTROL24,
ES8388_LOUT1VOL(ES8388_DAC_CHVOL_DB(0)));
writeReg(ES8388_DACCONTROL25,
ES8388_ROUT1VOL(ES8388_DAC_CHVOL_DB(0)));
writeReg(ES8388_DACCONTROL26,
ES8388_LOUT2VOL(ES8388_DAC_CHVOL_DB(0)));
writeReg(ES8388_DACCONTROL27,
ES8388_ROUT2VOL(ES8388_DAC_CHVOL_DB(0)));
setmute(ES_MODULE_DAC, ES8388_DEFAULT_MUTE);
setvolume(ES_MODULE_DAC, ES8388_DEFAULT_VOL_OUT, ES8388_DEFAULT_BALANCE);
if (_dac_output == ES8388_DAC_OUTPUT_LINE2)
{
regconfig = ES_DAC_CHANNEL_LOUT1 | ES_DAC_CHANNEL_ROUT1;
}
else if (_dac_output == ES8388_DAC_OUTPUT_LINE1)
{
regconfig = ES_DAC_CHANNEL_LOUT2 | ES_DAC_CHANNEL_ROUT2;
}
else
{
regconfig = ES_DAC_CHANNEL_LOUT1 | ES_DAC_CHANNEL_ROUT1 |
ES_DAC_CHANNEL_LOUT2 | ES_DAC_CHANNEL_ROUT2;
}
writeReg(ES8388_DACPOWER, regconfig);
writeReg(ES8388_ADCPOWER,
ES8388_INT1LP_LP |
ES8388_FLASHLP_LP |
ES8388_PDNADCBIASGEN_LP |
ES8388_PDNMICB_PWRDN |
ES8388_PDNADCR_PWRDN |
ES8388_PDNADCL_PWRDN |
ES8388_PDNAINR_PWRDN |
ES8388_PDNAINL_PWRDN);
setMicGain(24); /* +24 dB */
if (_adc_input == ES8388_ADC_INPUT_LINE1)
{
regconfig = ES_ADC_CHANNEL_LINPUT1_RINPUT1;
}
else if (_adc_input == ES8388_ADC_INPUT_LINE2)
{
regconfig = ES_ADC_CHANNEL_LINPUT2_RINPUT2;
}
else
{
regconfig = ES_ADC_CHANNEL_DIFFERENCE;
}
writeReg(ES8388_ADCCONTROL2, regconfig);
writeReg(ES8388_ADCCONTROL3,
(1 << 1) | /* Default value of undocumented bit */
ES8388_TRI_NORMAL |
ES8388_MONOMIX_STEREO |
ES8388_DS_LINPUT1_RINPUT1);
setBitsPerSample(_bpsamp);
setSampleRate(_samprate);
setmute(ES_MODULE_ADC, ES8388_DEFAULT_MUTE);
setvolume(ES_MODULE_ADC, ES8388_DEFAULT_VOL_IN, ES8388_DEFAULT_BALANCE);
writeReg(ES8388_ADCPOWER,
ES8388_INT1LP_LP |
ES8388_FLASHLP_NORMAL |
ES8388_PDNADCBIASGEN_NORMAL |
ES8388_PDNMICB_PWRDN |
ES8388_PDNADCR_PWRUP |
ES8388_PDNADCL_PWRUP |
ES8388_PDNAINR_NORMAL |
ES8388_PDNAINL_NORMAL);
/* Stop sequence to avoid noise at boot */
stop();
log_v("ES8388 reset.");
}
/*
Name: stop
Description:
Mute and stop the ES8388 codec data transmission.
*/
void ES8388::stop()
{
log_v("Stopping ES8388 transmission...");
_running = false;
if (_audio_mode == ES_MODULE_LINE)
{
writeReg(ES8388_DACCONTROL21,
ES8388_DAC_DLL_PWD_NORMAL |
ES8388_ADC_DLL_PWD_NORMAL |
ES8388_MCLK_DIS_NORMAL |
ES8388_OFFSET_DIS_DISABLE |
ES8388_LRCK_SEL_DAC |
ES8388_SLRCK_SAME);
writeReg(ES8388_DACCONTROL16,
ES8388_RMIXSEL_RIN1 |
ES8388_LMIXSEL_LIN1);
writeReg(ES8388_DACCONTROL17,
ES8388_LI2LOVOL(ES8388_MIXER_GAIN_0DB) |
ES8388_LI2LO_DISABLE |
ES8388_LD2LO_ENABLE);
writeReg(ES8388_DACCONTROL20,
ES8388_RI2ROVOL(ES8388_MIXER_GAIN_0DB) |
ES8388_RI2RO_DISABLE |
ES8388_RD2RO_ENABLE);
goto stop_msg;
}
if (_audio_mode == ES_MODULE_DAC || _audio_mode == ES_MODULE_ADC_DAC)
{
writeReg(ES8388_DACPOWER,
ES8388_ROUT2_DISABLE |
ES8388_LOUT2_DISABLE |
ES8388_ROUT1_DISABLE |
ES8388_LOUT1_DISABLE |
ES8388_PDNDACR_PWRUP |
ES8388_PDNDACL_PWRUP);
}
if (_audio_mode == ES_MODULE_ADC || _audio_mode == ES_MODULE_ADC_DAC)
{
writeReg(ES8388_ADCPOWER,
ES8388_INT1LP_LP |
ES8388_FLASHLP_LP |
ES8388_PDNADCBIASGEN_LP |
ES8388_PDNMICB_PWRDN |
ES8388_PDNADCR_PWRDN |
ES8388_PDNADCL_PWRDN |
ES8388_PDNAINR_PWRDN |
ES8388_PDNAINL_PWRDN);
}
if (_audio_mode == ES_MODULE_ADC_DAC)
{
writeReg(ES8388_DACCONTROL21,
ES8388_DAC_DLL_PWD_PWRDN |
ES8388_ADC_DLL_PWD_PWRDN |
ES8388_MCLK_DIS_DISABLE |
ES8388_OFFSET_DIS_DISABLE |
ES8388_LRCK_SEL_DAC |
ES8388_SLRCK_SAME);
}
stop_msg:
setmute(_audio_mode, true);
log_v("ES8388 transmission stopped.");
}
/*
Name: setvolume
Description:
Set the volume of the ES8388 codec.
Input Parameters:
module - Module to set the volume for.
volume - Volume level {0..1000}.
balance - Balance level {0..1000}.
*/
void ES8388::setvolume(es_module_e module, uint16_t volume, uint16_t balance)
{
uint16_t leftlvl;
int16_t dbleftlvl;
uint16_t rightlvl;
int16_t dbrightlvl;
log_d("Volume = %u, Balance = %u", volume, balance);
if (volume > 1000)
{
log_w("Warning: Volume greater than 1000, setting to 1000.");
volume = 1000;
}
if (balance > 1000)
{
log_w("Warning: Balance greater than 1000, setting to 1000.");
balance = 1000;
}
_balance = balance;
/* Calculate the left channel volume level {0..1000} */
if (_balance <= 500)
{
leftlvl = volume;
}
else if (_balance == 1000)
{
leftlvl = 0;
}
else
{
leftlvl = ((((1000 - _balance) * 100) / 500) * volume) / 100;
}
/* Calculate the right channel volume level {0..1000} */
if (_balance >= 500)
{
rightlvl = volume;
}
else if (_balance == 0)
{
rightlvl = 0;
}
else
{
rightlvl = (((_balance * 100) / 500) * volume) / 100;
}
/* Convert from (0..1000) to (-96..0) */
dbleftlvl = (int16_t) (leftlvl ? (20 * log10f((float)rightlvl / 1000)) : -96);
dbrightlvl = (int16_t) (rightlvl ? (20 * log10f((float)rightlvl / 1000)) : -96);
log_v("Volume: dbleftlvl = %d, dbrightlvl = %d", dbleftlvl, dbrightlvl);
/* Convert and truncate to 1 byte */
dbleftlvl = ((-dbleftlvl) << 1) & 0xff;
dbrightlvl = ((-dbrightlvl) << 1) & 0xff;
/* Set the volume */
if (module == ES_MODULE_DAC || module == ES_MODULE_ADC_DAC)
{
writeReg(ES8388_DACCONTROL4, ES8388_LDACVOL(dbleftlvl));
writeReg(ES8388_DACCONTROL5, ES8388_RDACVOL(dbrightlvl));
_volume_out = volume;
}
if (module == ES_MODULE_ADC || module == ES_MODULE_ADC_DAC)
{
writeReg(ES8388_ADCCONTROL8, ES8388_LADCVOL(dbleftlvl));
writeReg(ES8388_ADCCONTROL9, ES8388_RADCVOL(dbrightlvl));
_volume_in = volume;
}
}
/*
Name: setmute
Description:
Mute or unmute the selected ES8388 codec module.
Input Parameters:
module - Module to mute or unmute.
enable - Mute or unmute.
*/
void ES8388::setmute(es_module_e module, bool enable)
{
uint8_t reg = 0;
log_d("module=%d, mute=%d", module, (int)enable);
_mute = enable;
if (module == ES_MODULE_DAC || module == ES_MODULE_ADC_DAC)
{
reg = readReg(ES8388_DACCONTROL3) & (~ES8388_DACMUTE_BITMASK);
writeReg(ES8388_DACCONTROL3, reg | ES8388_DACMUTE(enable));
}
if (module == ES_MODULE_ADC || module == ES_MODULE_ADC_DAC)
{
reg = readReg(ES8388_ADCCONTROL7) & (~ES8388_ADCMUTE_BITMASK);
writeReg(ES8388_ADCCONTROL7, reg | ES8388_ADCMUTE(enable));
}
}
/****************************************************************************
* Public Methods
****************************************************************************/
ES8388::~ES8388()
{
end();
}
/*
Name: begin
Description:
Initialize the ES8388 codec. Requires the I2S and I2C buses to be initialized
before calling this function.
Input Parameters:
i2s - I2S bus instance.
i2c - I2C bus instance. Defaults to Wire.
addr - I2C address of the ES8388 codec. Defaults to 0x10.
Return:
true - Success.
false - Failure.
*/
bool ES8388::begin(I2SClass& i2s, TwoWire& i2c, uint8_t addr)
{
log_v("Initializing ES8388...");
_i2c = &i2c;
_i2s = &i2s;
_addr = addr;
_fmt = ES8388_DEFAULT_FMT;
_mode = ES8388_DEFAULT_MODE;
_samprate = ES8388_DEFAULT_SAMPRATE;
_nchannels = ES8388_DEFAULT_NCHANNELS;
_bpsamp = ES8388_DEFAULT_BPSAMP;
_audio_mode = ES8388_DEFAULT_AUDIO_MODE;
_dac_output = ES8388_DEFAULT_DAC_OUTPUT;
_adc_input = ES8388_DEFAULT_ADC_INPUT;
_mic_gain = ES8388_DEFAULT_MIC_GAIN;
_running = false;
_lclk_div = ES_LCLK_DIV_256;
_word_length = ES_WORD_LENGTH_16BITS;
_i2c->beginTransmission(_addr);
if (_i2c->endTransmission() != 0)
{
log_e("Device not found at address 0x%02x. Check if the I2C and I2S buses are initialized.", _addr);
return false;
}
reset();
log_v("ES8388 initialized.");
return true;
}
/*
Name: end
Description:
Stop the ES8388 codec and reset it to a known state.
*/
void ES8388::end()
{
log_v("Ending ES8388...");
stop();
setmute(ES_MODULE_ADC_DAC, true);
_audio_mode = ES_MODULE_ADC_DAC;
reset();
log_v("ES8388 ended.");
}
/*
Name: readReg
Description:
Read a register from the ES8388 codec.
Input Parameters:
reg - Register address.
Return:
Register value.
*/
uint8_t ES8388::readReg(uint8_t reg)
{
int data;
_i2c->beginTransmission(_addr);
if (_i2c->write(reg) == 0)
{
log_e("Error writing register address 0x%02x.", reg);
return 0;
}
if (_i2c->endTransmission(false) != 0)
{
log_e("Error ending transmission.");
return 0;
}
if (!_i2c->requestFrom(_addr, (uint8_t)1))
{
log_e("Error requesting data.");
return 0;
}
if ((data = _i2c->read()) < 0)
{
log_e("Error reading data.");
return 0;
}
return (uint8_t)data;
}
/*
Name: writeReg
Description:
Write a register to the ES8388 codec.
Input Parameters:
reg - Register address.
data - Data to write.
*/
void ES8388::writeReg(uint8_t reg, uint8_t data)
{
_i2c->beginTransmission(_addr);
if (_i2c->write(reg) == 0)
{
log_e("Error writing register address 0x%02x.", reg);
return;
}
if (_i2c->write(data) == 0)
{
log_e("Error writing data 0x%02x.", data);
return;
}
if (_i2c->endTransmission(true) != 0)
{
log_e("Error ending transmission.");
return;
}
}
/*
Name: setMicGain
Description:
Set the microphone gain.
Input Parameters:
gain - Gain level in dB {0..24}.
*/
void ES8388::setMicGain(uint8_t gain)
{
static const es_mic_gain_e gain_map[] =
{
ES_MIC_GAIN_0DB,
ES_MIC_GAIN_3DB,
ES_MIC_GAIN_6DB,
ES_MIC_GAIN_9DB,
ES_MIC_GAIN_12DB,
ES_MIC_GAIN_15DB,
ES_MIC_GAIN_18DB,
ES_MIC_GAIN_21DB,
ES_MIC_GAIN_24DB,
};
log_d("gain=%d", gain);
_mic_gain = gain_map[min(gain, (uint8_t) 24) / 3];
writeReg(ES8388_ADCCONTROL1,
ES8388_MICAMPR(_mic_gain) |
ES8388_MICAMPL(_mic_gain));
log_v("Mic gain set to %d", _mic_gain);
}
/*
Name: setBitsPerSample
Description:
Set the number of bits per sample. This also configures the I2S bus.
Input Parameters:
bpsamp - Bits per sample {16, 24, 32}.
*/
void ES8388::setBitsPerSample(uint8_t bpsamp)
{
/* ES8388 also supports 18 and 20 bits per sample, but the I2S bus does not */
switch (bpsamp)
{
case 16:
_word_length = ES_WORD_LENGTH_16BITS;
break;
case 24:
_word_length = ES_WORD_LENGTH_24BITS;
break;
case 32:
_word_length = ES_WORD_LENGTH_32BITS;
break;
default:
log_e("Data length not supported.");
return;
}
_bpsamp = bpsamp;
_i2s->configureTX(_samprate, (i2s_data_bit_width_t)_bpsamp, I2S_SLOT_MODE_STEREO);
_i2s->configureRX(_samprate, (i2s_data_bit_width_t)_bpsamp, I2S_SLOT_MODE_STEREO);
if (_audio_mode == ES_MODULE_ADC || _audio_mode == ES_MODULE_ADC_DAC)
{
writeReg(ES8388_ADCCONTROL4,
ES8388_ADCFORMAT(ES_I2S_NORMAL) |
ES8388_ADCWL(_word_length) |
ES8388_ADCLRP_NORM_2ND |
ES8388_DATSEL_LL);
}
if (_audio_mode == ES_MODULE_DAC || _audio_mode == ES_MODULE_ADC_DAC)
{
writeReg(ES8388_DACCONTROL1,
ES8388_DACFORMAT(ES_I2S_NORMAL) |
ES8388_DACWL(_word_length) |
ES8388_DACLRP_NORM_2ND |
ES8388_DACLRSWAP_NORMAL);
}
log_v("Datawidth set to %u", _bpsamp);
}
/*
Name: setSampleRate
Description:
Set the sample rate. This also configures the I2S bus.
The divider depends on the sample rate and the MCLK frequency.
This needs to be re-implemented to properly support all cases.
ES8388 should also support 88100Hz and 96000Hz sample rates in
double speed mode but setting it makes the audio sound distorted.
Input Parameters:
rate - Sample rate {8000, 11025, 12000, 16000, 22050, 24000, 32000,
44100, 48000}.
*/
void ES8388::setSampleRate(uint32_t rate)
{
/*
According to the datasheet, this should only matter for the master mode
but it seems to affect the slave mode as well.
*/
switch (rate)
{
case 8000:
_lclk_div = ES_LCLK_DIV_1536;
break;
case 11025:
case 12000:
_lclk_div = ES_LCLK_DIV_1024;
break;
case 16000:
_lclk_div = ES_LCLK_DIV_768;
break;
case 22050:
case 24000:
_lclk_div = ES_LCLK_DIV_512;
break;
case 32000:
_lclk_div = ES_LCLK_DIV_384;
break;
case 44100:
case 48000:
_lclk_div = ES_LCLK_DIV_256;
break;
default:
log_e("Sample rate not supported.");
return;
}
_samprate = rate;
_i2s->configureTX(_samprate, (i2s_data_bit_width_t)_bpsamp, I2S_SLOT_MODE_STEREO);
_i2s->configureRX(_samprate, (i2s_data_bit_width_t)_bpsamp, I2S_SLOT_MODE_STEREO);
if (_audio_mode == ES_MODULE_ADC || _audio_mode == ES_MODULE_ADC_DAC)
{
writeReg(ES8388_ADCCONTROL5, ES8388_ADCFSRATIO(_lclk_div));
}
if (_audio_mode == ES_MODULE_DAC || _audio_mode == ES_MODULE_ADC_DAC)
{
writeReg(ES8388_DACCONTROL2, ES8388_DACFSRATIO(_lclk_div));
}
log_v("Sample rate set to %d in single speed mode", _samprate);
}
/*
Name: playWAV
Description:
Wrapper for the I2SClass::playWAV() method. This method starts the ES8388
codec before playing the WAV file and stops it after the WAV file has been
played.
Input Parameters:
data - Pointer to the WAV file data.
len - Length of the WAV file data.
*/
void ES8388::playWAV(uint8_t* data, size_t len)
{
_audio_mode = ES_MODULE_DAC;
reset();
log_v("Playing WAV file...");
start();
_i2s->playWAV(data, len);
stop();
log_v("WAV file played.");
}
/*
Name: recordWAV
Description:
Wrapper for the I2SClass::recordWAV() method. This method starts the ES8388
codec before recording the WAV file and stops it after the WAV file has been
recorded.
Input Parameters:
rec_seconds - Length of the WAV file to record in seconds.
out_size - Pointer to the variable that will hold the size of the WAV file.
Return:
Pointer to the WAV file data.
*/
uint8_t* ES8388::recordWAV(size_t rec_seconds, size_t* out_size)
{
uint8_t* data;
size_t size;
_audio_mode = ES_MODULE_ADC;
reset();
log_v("Recording WAV file...");
start();
data = _i2s->recordWAV(rec_seconds, &size);
stop();
log_v("WAV file recorded.");
*out_size = size;
return data;
}
void ES8388::setOutputVolume(uint16_t volume, uint16_t balance)
{
setvolume(ES_MODULE_DAC, volume, balance);
}
void ES8388::setInputVolume(uint16_t volume, uint16_t balance)
{
setvolume(ES_MODULE_ADC, volume, balance);
}
void ES8388::setOutputMute(bool enable)
{
setmute(ES_MODULE_DAC, enable);
}
void ES8388::setInputMute(bool enable)
{
setmute(ES_MODULE_ADC, enable);
}
/*
This is a very basic driver for the ES8388 based on the driver written by
me for NuttX. It is not complete and is missing master mode, mono mode,many
features and configuration options. You can use readReg and writeReg to
access the registers directly and configure missing features. Feel free to
contribute by adding missing features and improving the driver.
It is intended to be used only with arduino-esp32.
The default configuration can be found in the ES8388.h file.
This was only tested with the ESP32-LyraT board using 44100Hz 16-bit stereo
audio. It may not work with other configurations.
Created for arduino-esp32 on 20 Dec, 2023
by Lucas Saavedra Vaz (lucasssvaz)
*/
#pragma once
#include "ESP_I2S.h"
#include "Wire.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define ES8388_DAC_CHVOL_DB(v) (2*v/3 + 30)
/* Registers Addresses ******************************************************/
#define ES8388_CONTROL1 0x00
#define ES8388_CONTROL2 0x01
#define ES8388_CHIPPOWER 0x02
#define ES8388_ADCPOWER 0x03
#define ES8388_DACPOWER 0x04
#define ES8388_CHIPLOPOW1 0x05
#define ES8388_CHIPLOPOW2 0x06
#define ES8388_ANAVOLMANAG 0x07
#define ES8388_MASTERMODE 0x08
#define ES8388_ADCCONTROL1 0x09
#define ES8388_ADCCONTROL2 0x0a
#define ES8388_ADCCONTROL3 0x0b
#define ES8388_ADCCONTROL4 0x0c
#define ES8388_ADCCONTROL5 0x0d
#define ES8388_ADCCONTROL6 0x0e
#define ES8388_ADCCONTROL7 0x0f
#define ES8388_ADCCONTROL8 0x10
#define ES8388_ADCCONTROL9 0x11
#define ES8388_ADCCONTROL10 0x12
#define ES8388_ADCCONTROL11 0x13
#define ES8388_ADCCONTROL12 0x14
#define ES8388_ADCCONTROL13 0x15
#define ES8388_ADCCONTROL14 0x16
#define ES8388_DACCONTROL1 0x17
#define ES8388_DACCONTROL2 0x18
#define ES8388_DACCONTROL3 0x19
#define ES8388_DACCONTROL4 0x1a
#define ES8388_DACCONTROL5 0x1b
#define ES8388_DACCONTROL6 0x1c
#define ES8388_DACCONTROL7 0x1d
#define ES8388_DACCONTROL8 0x1e
#define ES8388_DACCONTROL9 0x1f
#define ES8388_DACCONTROL10 0x20
#define ES8388_DACCONTROL11 0x21
#define ES8388_DACCONTROL12 0x22
#define ES8388_DACCONTROL13 0x23
#define ES8388_DACCONTROL14 0x24
#define ES8388_DACCONTROL15 0x25
#define ES8388_DACCONTROL16 0x26
#define ES8388_DACCONTROL17 0x27
#define ES8388_DACCONTROL18 0x28
#define ES8388_DACCONTROL19 0x29
#define ES8388_DACCONTROL20 0x2a
#define ES8388_DACCONTROL21 0x2b
#define ES8388_DACCONTROL22 0x2c
#define ES8388_DACCONTROL23 0x2d
#define ES8388_DACCONTROL24 0x2e
#define ES8388_DACCONTROL25 0x2f
#define ES8388_DACCONTROL26 0x30
#define ES8388_DACCONTROL27 0x31
#define ES8388_DACCONTROL28 0x32
#define ES8388_DACCONTROL29 0x33
#define ES8388_DACCONTROL30 0x34
/* Register Power-up Default Values *****************************************/
#define ES8388_CONTROL1_DEFAULT 0x06
#define ES8388_CONTROL2_DEFAULT 0x5c
#define ES8388_CHIPPOWER_DEFAULT 0xc3
#define ES8388_ADCPOWER_DEFAULT 0xfc
#define ES8388_DACPOWER_DEFAULT 0xc0
#define ES8388_CHIPLOPOW1_DEFAULT 0x00
#define ES8388_CHIPLOPOW2_DEFAULT 0x00
#define ES8388_ANAVOLMANAG_DEFAULT 0x7c
#define ES8388_MASTERMODE_DEFAULT 0x80
#define ES8388_ADCCONTROL1_DEFAULT 0x00
#define ES8388_ADCCONTROL2_DEFAULT 0x00
#define ES8388_ADCCONTROL3_DEFAULT 0x02
#define ES8388_ADCCONTROL4_DEFAULT 0x00
#define ES8388_ADCCONTROL5_DEFAULT 0x06
#define ES8388_ADCCONTROL6_DEFAULT 0x30
#define ES8388_ADCCONTROL7_DEFAULT 0x20
#define ES8388_ADCCONTROL8_DEFAULT 0xc0
#define ES8388_ADCCONTROL9_DEFAULT 0xc0
#define ES8388_ADCCONTROL10_DEFAULT 0x38
#define ES8388_ADCCONTROL11_DEFAULT 0xb0
#define ES8388_ADCCONTROL12_DEFAULT 0x32
#define ES8388_ADCCONTROL13_DEFAULT 0x06
#define ES8388_ADCCONTROL14_DEFAULT 0x00
#define ES8388_DACCONTROL1_DEFAULT 0x00
#define ES8388_DACCONTROL2_DEFAULT 0x06
#define ES8388_DACCONTROL3_DEFAULT 0x22
#define ES8388_DACCONTROL4_DEFAULT 0xc0
#define ES8388_DACCONTROL5_DEFAULT 0xc0
#define ES8388_DACCONTROL6_DEFAULT 0x08
#define ES8388_DACCONTROL7_DEFAULT 0x00
#define ES8388_DACCONTROL8_DEFAULT 0x1f
#define ES8388_DACCONTROL9_DEFAULT 0xf7
#define ES8388_DACCONTROL10_DEFAULT 0xfd
#define ES8388_DACCONTROL11_DEFAULT 0xff
#define ES8388_DACCONTROL12_DEFAULT 0x1f
#define ES8388_DACCONTROL13_DEFAULT 0xf7
#define ES8388_DACCONTROL14_DEFAULT 0xfd
#define ES8388_DACCONTROL15_DEFAULT 0xff
#define ES8388_DACCONTROL16_DEFAULT 0x00
#define ES8388_DACCONTROL17_DEFAULT 0x38
#define ES8388_DACCONTROL18_DEFAULT 0x28
#define ES8388_DACCONTROL19_DEFAULT 0x28
#define ES8388_DACCONTROL20_DEFAULT 0x38
#define ES8388_DACCONTROL21_DEFAULT 0x00
#define ES8388_DACCONTROL22_DEFAULT 0x00
#define ES8388_DACCONTROL23_DEFAULT 0x00
#define ES8388_DACCONTROL24_DEFAULT 0x00
#define ES8388_DACCONTROL25_DEFAULT 0x00
#define ES8388_DACCONTROL26_DEFAULT 0x00
#define ES8388_DACCONTROL27_DEFAULT 0x00
#define ES8388_DACCONTROL28_DEFAULT 0x00
#define ES8388_DACCONTROL29_DEFAULT 0xaa
#define ES8388_DACCONTROL30_DEFAULT 0xaa
/* Register Bit Definitions *************************************************/
/* 0x00 Chip Control 1 */
#define ES8388_VMIDSEL_SHIFT (0)
#define ES8388_VMIDSEL_BITMASK (0x03 << ES8388_VMIDSEL_SHIFT)
#define ES8388_VMIDSEL_DISABLE (0 << ES8388_VMIDSEL_SHIFT)
#define ES8388_VMIDSEL_50K (1 << ES8388_VMIDSEL_SHIFT)
#define ES8388_VMIDSEL_500K (2 << ES8388_VMIDSEL_SHIFT)
#define ES8388_VMIDSEL_5K (3 << ES8388_VMIDSEL_SHIFT)
#define ES8388_ENREF_SHIFT (2)
#define ES8388_ENREF_BITMASK (0x01 << ES8388_ENREF_SHIFT)
#define ES8388_ENREF_DISABLE (0 << ES8388_ENREF_SHIFT)
#define ES8388_ENREF_ENABLE (1 << ES8388_ENREF_SHIFT)
#define ES8388_SEQEN_SHIFT (3)
#define ES8388_SEQEN_BITMASK (0x01 << ES8388_SEQEN_SHIFT)
#define ES8388_SEQEN_DISABLE (0 << ES8388_SEQEN_SHIFT)
#define ES8388_SEQEN_ENABLE (1 << ES8388_SEQEN_SHIFT)
#define ES8388_SAMEFS_SHIFT (4)
#define ES8388_SAMEFS_BITMASK (0x01 << ES8388_SAMEFS_SHIFT)
#define ES8388_SAMEFS_DIFFER (0 << ES8388_SAMEFS_SHIFT)
#define ES8388_SAMEFS_SAME (1 << ES8388_SAMEFS_SHIFT)
#define ES8388_DACMCLK_SHIFT (5)
#define ES8388_DACMCLK_BITMASK (0x01 << ES8388_DACMCLK_SHIFT)
#define ES8388_DACMCLK_ADCMCLK (0 << ES8388_DACMCLK_SHIFT)
#define ES8388_DACMCLK_DACMCLK (1 << ES8388_DACMCLK_SHIFT)
#define ES8388_LRCM_SHIFT (6)
#define ES8388_LRCM_BITMASK (0x01 << ES8388_LRCM_SHIFT)
#define ES8388_LRCM_ISOLATED (0 << ES8388_LRCM_SHIFT)
#define ES8388_LRCM_ALL (1 << ES8388_LRCM_SHIFT)
#define ES8388_SCPRESET_SHIFT (7)
#define ES8388_SCPRESET_BITMASK (0x01 << ES8388_SCPRESET_SHIFT)
#define ES8388_SCPRESET_NORMAL (0 << ES8388_SCPRESET_SHIFT)
#define ES8388_SCPRESET_RESET (1 << ES8388_SCPRESET_SHIFT)
/* 0x01 Chip Control 2 */
#define ES8388_PDNVREFBUF_SHIFT (0)
#define ES8388_PDNVREFBUF_BITMASK (0x01 << ES8388_PDNVREFBUF_SHIFT)
#define ES8388_PDNVREFBUF_NORMAL (0 << ES8388_PDNVREFBUF_SHIFT)
#define ES8388_PDNVREFBUF_PWRDN (1 << ES8388_PDNVREFBUF_SHIFT)
#define ES8388_VREFLO_SHIFT (1)
#define ES8388_VREFLO_BITMASK (0x01 << ES8388_VREFLO_SHIFT)
#define ES8388_VREFLO_NORMAL (0 << ES8388_VREFLO_SHIFT)
#define ES8388_VREFLO_LP (1 << ES8388_VREFLO_SHIFT)
#define ES8388_PDNIBIASGEN_SHIFT (2)
#define ES8388_PDNIBIASGEN_BITMASK (0x01 << ES8388_PDNIBIASGEN_SHIFT)
#define ES8388_PDNIBIASGEN_NORMAL (0 << ES8388_PDNIBIASGEN_SHIFT)
#define ES8388_PDNIBIASGEN_PWRDN (1 << ES8388_PDNIBIASGEN_SHIFT)
#define ES8388_PDNANA_SHIFT (3)
#define ES8388_PDNANA_BITMASK (0x01 << ES8388_PDNANA_SHIFT)
#define ES8388_PDNANA_NORMAL (0 << ES8388_PDNANA_SHIFT)
#define ES8388_PDNANA_PWRDN (1 << ES8388_PDNANA_SHIFT)
#define ES8388_LPVREFBUF_SHIFT (4)
#define ES8388_LPVREFBUF_BITMASK (0x01 << ES8388_LPVREFBUF_SHIFT)
#define ES8388_LPVREFBUF_NORMAL (0 << ES8388_LPVREFBUF_SHIFT)
#define ES8388_LPVREFBUF_LP (1 << ES8388_LPVREFBUF_SHIFT)
#define ES8388_LPVCMMOD_SHIFT (5)
#define ES8388_LPVCMMOD_BITMASK (0x01 << ES8388_LPVCMMOD_SHIFT)
#define ES8388_LPVCMMOD_NORMAL (0 << ES8388_LPVCMMOD_SHIFT)
#define ES8388_LPVCMMOD_LP (1 << ES8388_LPVCMMOD_SHIFT)
/* 0x02 Chip Power Management */
#define ES8388_DACVREF_PDN_SHIFT (0)
#define ES8388_DACVREF_PDN_BITMASK (0x01 << ES8388_DACVREF_PDN_SHIFT)
#define ES8388_DACVREF_PDN_PWRUP (0 << ES8388_DACVREF_PDN_SHIFT)
#define ES8388_DACVREF_PDN_PWRDN (1 << ES8388_DACVREF_PDN_SHIFT)
#define ES8388_ADCVREF_PDN_SHIFT (1)
#define ES8388_ADCVREF_PDN_BITMASK (0x01 << ES8388_ADCVREF_PDN_SHIFT)
#define ES8388_ADCVREF_PDN_PWRUP (0 << ES8388_ADCVREF_PDN_SHIFT)
#define ES8388_ADCVREF_PDN_PWRDN (1 << ES8388_ADCVREF_PDN_SHIFT)
#define ES8388_DACDLL_PDN_SHIFT (2)
#define ES8388_DACDLL_PDN_BITMASK (0x01 << ES8388_DACDLL_PDN_SHIFT)
#define ES8388_DACDLL_PDN_NORMAL (0 << ES8388_DACDLL_PDN_SHIFT)
#define ES8388_DACDLL_PDN_PWRDN (1 << ES8388_DACDLL_PDN_SHIFT)
#define ES8388_ADCDLL_PDN_SHIFT (3)
#define ES8388_ADCDLL_PDN_BITMASK (0x01 << ES8388_ADCDLL_PDN_SHIFT)
#define ES8388_ADCDLL_PDN_NORMAL (0 << ES8388_ADCDLL_PDN_SHIFT)
#define ES8388_ADCDLL_PDN_PWRDN (1 << ES8388_ADCDLL_PDN_SHIFT)
#define ES8388_DAC_STM_RST_SHIFT (4)
#define ES8388_DAC_STM_RST_BITMASK (0x01 << ES8388_DAC_STM_RST_SHIFT)
#define ES8388_DAC_STM_RST_NORMAL (0 << ES8388_DAC_STM_RST_SHIFT)
#define ES8388_DAC_STM_RST_RESET (1 << ES8388_DAC_STM_RST_SHIFT)
#define ES8388_ADC_STM_RST_SHIFT (5)
#define ES8388_ADC_STM_RST_BITMASK (0x01 << ES8388_ADC_STM_RST_SHIFT)
#define ES8388_ADC_STM_RST_NORMAL (0 << ES8388_ADC_STM_RST_SHIFT)
#define ES8388_ADC_STM_RST_RESET (1 << ES8388_ADC_STM_RST_SHIFT)
#define ES8388_DAC_DIGPDN_SHIFT (6)
#define ES8388_DAC_DIGPDN_BITMASK (0x01 << ES8388_DAC_DIGPDN_SHIFT)
#define ES8388_DAC_DIGPDN_NORMAL (0 << ES8388_DAC_DIGPDN_SHIFT)
#define ES8388_DAC_DIGPDN_RESET (1 << ES8388_DAC_DIGPDN_SHIFT)
#define ES8388_ADC_DIGPDN_SHIFT (7)
#define ES8388_ADC_DIGPDN_BITMASK (0x01 << ES8388_ADC_DIGPDN_SHIFT)
#define ES8388_ADC_DIGPDN_NORMAL (0 << ES8388_ADC_DIGPDN_SHIFT)
#define ES8388_ADC_DIGPDN_RESET (1 << ES8388_ADC_DIGPDN_SHIFT)
/* 0x03 ADC Power Management */
#define ES8388_INT1LP_SHIFT (0)
#define ES8388_INT1LP_BITMASK (0x01 << ES8388_INT1LP_SHIFT)
#define ES8388_INT1LP_NORMAL (0 << ES8388_INT1LP_SHIFT)
#define ES8388_INT1LP_LP (1 << ES8388_INT1LP_SHIFT)
#define ES8388_FLASHLP_SHIFT (1)
#define ES8388_FLASHLP_BITMASK (0x01 << ES8388_FLASHLP_SHIFT)
#define ES8388_FLASHLP_NORMAL (0 << ES8388_FLASHLP_SHIFT)
#define ES8388_FLASHLP_LP (1 << ES8388_FLASHLP_SHIFT)
#define ES8388_PDNADCBIASGEN_SHIFT (2)
#define ES8388_PDNADCBIASGEN_BITMASK (0x01 << ES8388_PDNADCBIASGEN_SHIFT)
#define ES8388_PDNADCBIASGEN_NORMAL (0 << ES8388_PDNADCBIASGEN_SHIFT)
#define ES8388_PDNADCBIASGEN_LP (1 << ES8388_PDNADCBIASGEN_SHIFT)
#define ES8388_PDNMICB_SHIFT (3)
#define ES8388_PDNMICB_BITMASK (0x01 << ES8388_PDNMICB_SHIFT)
#define ES8388_PDNMICB_PWRON (0 << ES8388_PDNMICB_SHIFT)
#define ES8388_PDNMICB_PWRDN (1 << ES8388_PDNMICB_SHIFT)
#define ES8388_PDNADCR_SHIFT (4)
#define ES8388_PDNADCR_BITMASK (0x01 << ES8388_PDNADCR_SHIFT)
#define ES8388_PDNADCR_PWRUP (0 << ES8388_PDNADCR_SHIFT)
#define ES8388_PDNADCR_PWRDN (1 << ES8388_PDNADCR_SHIFT)
#define ES8388_PDNADCL_SHIFT (5)
#define ES8388_PDNADCL_BITMASK (0x01 << ES8388_PDNADCL_SHIFT)
#define ES8388_PDNADCL_PWRUP (0 << ES8388_PDNADCL_SHIFT)
#define ES8388_PDNADCL_PWRDN (1 << ES8388_PDNADCL_SHIFT)
#define ES8388_PDNAINR_SHIFT (6)
#define ES8388_PDNAINR_BITMASK (0x01 << ES8388_PDNAINR_SHIFT)
#define ES8388_PDNAINR_NORMAL (0 << ES8388_PDNAINR_SHIFT)
#define ES8388_PDNAINR_PWRDN (1 << ES8388_PDNAINR_SHIFT)
#define ES8388_PDNAINL_SHIFT (7)
#define ES8388_PDNAINL_BITMASK (0x01 << ES8388_PDNAINL_SHIFT)
#define ES8388_PDNAINL_NORMAL (0 << ES8388_PDNAINL_SHIFT)
#define ES8388_PDNAINL_PWRDN (1 << ES8388_PDNAINL_SHIFT)
/* 0x04 DAC Power Management */
#define ES8388_ROUT2_SHIFT (2)
#define ES8388_ROUT2_BITMASK (0x01 << ES8388_ROUT2_SHIFT)
#define ES8388_ROUT2_DISABLE (0 << ES8388_ROUT2_SHIFT)
#define ES8388_ROUT2_ENABLE (1 << ES8388_ROUT2_SHIFT)
#define ES8388_LOUT2_SHIFT (3)
#define ES8388_LOUT2_BITMASK (0x01 << ES8388_LOUT2_SHIFT)
#define ES8388_LOUT2_DISABLE (0 << ES8388_LOUT2_SHIFT)
#define ES8388_LOUT2_ENABLE (1 << ES8388_LOUT2_SHIFT)
#define ES8388_ROUT1_SHIFT (4)
#define ES8388_ROUT1_BITMASK (0x01 << ES8388_ROUT1_SHIFT)
#define ES8388_ROUT1_DISABLE (0 << ES8388_ROUT1_SHIFT)
#define ES8388_ROUT1_ENABLE (1 << ES8388_ROUT1_SHIFT)
#define ES8388_LOUT1_SHIFT (5)
#define ES8388_LOUT1_BITMASK (0x01 << ES8388_LOUT1_SHIFT)
#define ES8388_LOUT1_DISABLE (0 << ES8388_LOUT1_SHIFT)
#define ES8388_LOUT1_ENABLE (1 << ES8388_LOUT1_SHIFT)
#define ES8388_PDNDACR_SHIFT (6)
#define ES8388_PDNDACR_BITMASK (0x01 << ES8388_PDNDACR_SHIFT)
#define ES8388_PDNDACR_PWRUP (0 << ES8388_PDNDACR_SHIFT)
#define ES8388_PDNDACR_PWRDN (1 << ES8388_PDNDACR_SHIFT)
#define ES8388_PDNDACL_SHIFT (7)
#define ES8388_PDNDACL_BITMASK (0x01 << ES8388_PDNDACL_SHIFT)
#define ES8388_PDNDACL_PWRUP (0 << ES8388_PDNDACL_SHIFT)
#define ES8388_PDNDACL_PWRDN (1 << ES8388_PDNDACL_SHIFT)
/* 0x05 Chip Low Power 1 */
#define ES8388_LPLOUT2_SHIFT (3)
#define ES8388_LPLOUT2_BITMASK (0x01 << ES8388_LPLOUT2_SHIFT)
#define ES8388_LPLOUT2_NORMAL (0 << ES8388_LPLOUT2_SHIFT)
#define ES8388_LPLOUT2_LP (1 << ES8388_LPLOUT2_SHIFT)
#define ES8388_LPLOUT1_SHIFT (5)
#define ES8388_LPLOUT1_BITMASK (0x01 << ES8388_LPLOUT1_SHIFT)
#define ES8388_LPLOUT1_NORMAL (0 << ES8388_LPLOUT1_SHIFT)
#define ES8388_LPLOUT1_LP (1 << ES8388_LPLOUT1_SHIFT)
#define ES8388_LPDACR_SHIFT (6)
#define ES8388_LPDACR_BITMASK (0x01 << ES8388_LPDACR_SHIFT)
#define ES8388_LPDACR_NORMAL (0 << ES8388_LPDACR_SHIFT)
#define ES8388_LPDACR_LP (1 << ES8388_LPDACR_SHIFT)
#define ES8388_LPDACL_SHIFT (7)
#define ES8388_LPDACL_BITMASK (0x01 << ES8388_LPDACL_SHIFT)
#define ES8388_LPDACL_NORMAL (0 << ES8388_LPDACL_SHIFT)
#define ES8388_LPDACL_LP (1 << ES8388_LPDACL_SHIFT)
/* 0x06 Chip Low Power 2 */
#define ES8388_LPDACVRP_SHIFT (0)
#define ES8388_LPDACVRP_BITMASK (0x01 << ES8388_LPDACVRP_SHIFT)
#define ES8388_LPDACVRP_NORMAL (0 << ES8388_LPDACVRP_SHIFT)
#define ES8388_LPDACVRP_LP (1 << ES8388_LPDACVRP_SHIFT)
#define ES8388_LPADCVRP_SHIFT (1)
#define ES8388_LPADCVRP_BITMASK (0x01 << ES8388_LPDACVRP_SHIFT)
#define ES8388_LPADCVRP_NORMAL (0 << ES8388_LPDACVRP_SHIFT)
#define ES8388_LPADCVRP_LP (1 << ES8388_LPDACVRP_SHIFT)
#define ES8388_LPLMIX_SHIFT (6)
#define ES8388_LPLMIX_BITMASK (0x01 << ES8388_LPLMIX_SHIFT)
#define ES8388_LPLMIX_NORMAL (0 << ES8388_LPLMIX_SHIFT)
#define ES8388_LPLMIX_LP (1 << ES8388_LPLMIX_SHIFT)
#define ES8388_LPPGA_SHIFT (7)
#define ES8388_LPPGA_BITMASK (0x01 << ES8388_LPPGA_SHIFT)
#define ES8388_LPPGA_NORMAL (0 << ES8388_LPPGA_SHIFT)
#define ES8388_LPPGA_LP (1 << ES8388_LPPGA_SHIFT)
/* 0x08 Master Mode Control */
#define ES8388_BCLKDIV_SHIFT (0)
#define ES8388_BCLKDIV_BITMASK (0x1f << ES8388_BCLKDIV_SHIFT)
#define ES8388_BCLKDIV(a) (a << ES8388_BCLKDIV_SHIFT)
#define ES8388_BCLK_INV_SHIFT (5)
#define ES8388_BCLK_INV_BITMASL (0x01 << ES8388_BCLK_INV_SHIFT)
#define ES8388_BCLK_INV_NORMAL (0 << ES8388_BCLK_INV_SHIFT)
#define ES8388_BCLK_INV_INVERTED (1 << ES8388_BCLK_INV_SHIFT)
#define ES8388_MCLKDIV2_SHIFT (6)
#define ES8388_MCLKDIV2_BITMASK (0x01 << ES8388_MCLKDIV2_SHIFT)
#define ES8388_MCLKDIV2_NODIV (0 << ES8388_MCLKDIV2_SHIFT)
#define ES8388_MCLKDIV2_DIV2 (1 << ES8388_MCLKDIV2_SHIFT)
#define ES8388_MSC_SHIFT (7)
#define ES8388_MSC_BITMASK (0x01 << ES8388_MSC_SHIFT)
#define ES8388_MSC_SLAVE (0 << ES8388_MSC_SHIFT)
#define ES8388_MSC_MASTER (1 << ES8388_MSC_SHIFT)
/* 0x09 ADC Control 1 */
#define ES8388_MICAMPR_SHIFT (0)
#define ES8388_MICAMPR_BITMASK (0x0f << ES8388_MICAMPR_SHIFT)
#define ES8388_MICAMPR(a) (a << ES8388_MICAMPR_SHIFT)
#define ES8388_MICAMPL_SHIFT (4)
#define ES8388_MICAMPL_BITMASK (0x0f << ES8388_MICAMPL_SHIFT)
#define ES8388_MICAMPL(a) (a << ES8388_MICAMPL_SHIFT)
/* 0x0a ADC Control 2 */
#define ES8388_DSR_SHIFT (2)
#define ES8388_DSR_BITMASK (0x01 << ES8388_DSR_SHIFT)
#define ES8388_DSR_LINPUT1_RINPUT1 (0 << ES8388_DSR_SHIFT)
#define ES8388_DSR_LINPUT2_RINPUT2 (1 << ES8388_DSR_SHIFT)
#define ES8388_DSSEL_SHIFT (3)
#define ES8388_DSSEL_BITMASK (0x01 << ES8388_DSSEL_SHIFT)
#define ES8388_DSSEL_ONE_REG (0 << ES8388_DSSEL_SHIFT)
#define ES8388_DSSEL_MULT_REG (1 << ES8388_DSSEL_SHIFT)
#define ES8388_RINSEL_SHIFT (4)
#define ES8388_RINSEL_BITMASK (0x03 << ES8388_RINSEL_SHIFT)
#define ES8388_RINSEL_RINPUT1 (0 << ES8388_RINSEL_SHIFT)
#define ES8388_RINSEL_RINPUT2 (1 << ES8388_RINSEL_SHIFT)
#define ES8388_RINSEL_DIFF (3 << ES8388_RINSEL_SHIFT)
#define ES8388_LINSEL_SHIFT (6)
#define ES8388_LINSEL_BITMASK (0x03 << ES8388_LINSEL_SHIFT)
#define ES8388_LINSEL_LINPUT1 (0 << ES8388_LINSEL_SHIFT)
#define ES8388_LINSEL_LINPUT2 (1 << ES8388_LINSEL_SHIFT)
#define ES8388_LINSEL_DIFF (3 << ES8388_LINSEL_SHIFT)
/* 0x0b ADC Control 3 */
#define ES8388_TRI_SHIFT (2)
#define ES8388_TRI_BITMASK (0x01 << ES8388_TRI_SHIFT)
#define ES8388_TRI_NORMAL (0 << ES8388_TRI_SHIFT)
#define ES8388_TRI_TRISTATED (1 << ES8388_TRI_SHIFT)
#define ES8388_MONOMIX_SHIFT (3)
#define ES8388_MONOMIX_BITMASK (0x03 << ES8388_MONOMIX_SHIFT)
#define ES8388_MONOMIX_STEREO (0 << ES8388_MONOMIX_SHIFT)
#define ES8388_MONOMIX_LADC (1 << ES8388_MONOMIX_SHIFT)
#define ES8388_MONOMIX_RADC (2 << ES8388_MONOMIX_SHIFT)
#define ES8388_DS_SHIFT (7)
#define ES8388_DS_BITMASK (0x01 << ES8388_DS_SHIFT)
#define ES8388_DS_LINPUT1_RINPUT1 (0 << ES8388_DS_SHIFT)
#define ES8388_DS_LINPUT2_RINPUT2 (1 << ES8388_DS_SHIFT)
/* 0x0c ADC Control 4 */
#define ES8388_ADCFORMAT_SHIFT (0)
#define ES8388_ADCFORMAT_BITMASK (0x03 << ES8388_ADCFORMAT_SHIFT)
#define ES8388_ADCFORMAT(a) (a << ES8388_ADCFORMAT_SHIFT)
#define ES8388_ADCWL_SHIFT (2)
#define ES8388_ADCWL_BITMASK (0x07 << ES8388_ADCWL_SHIFT)
#define ES8388_ADCWL(a) (a << ES8388_ADCWL_SHIFT)
#define ES8388_ADCLRP_SHIFT (5)
#define ES8388_ADCLRP_BITMASK (0x01 << ES8388_ADCLRP_SHIFT)
#define ES8388_ADCLRP_NORM_2ND (0 << ES8388_ADCLRP_SHIFT)
#define ES8388_ADCLRP_INV_1ST (1 << ES8388_ADCLRP_SHIFT)
#define ES8388_DATSEL_SHIFT (6)
#define ES8388_DATSEL_BITMASK (0x03 << ES8388_DATSEL_SHIFT)
#define ES8388_DATSEL_LL (0 << ES8388_DATSEL_SHIFT)
#define ES8388_DATSEL_LR (1 << ES8388_DATSEL_SHIFT)
#define ES8388_DATSEL_RR (2 << ES8388_DATSEL_SHIFT)
#define ES8388_DATSEL_RL (3 << ES8388_DATSEL_SHIFT)
/* 0x0d ADC Control 5 */
#define ES8388_ADCFSRATIO_SHIFT (0)
#define ES8388_ADCFSRATIO_BITMASK (0x1f << ES8388_ADCFSRATIO_SHIFT)
#define ES8388_ADCFSRATIO(a) (a << ES8388_ADCFSRATIO_SHIFT)
#define ES8388_ADCFSMODE_SHIFT (5)
#define ES8388_ADCFSMODE_BITMASK (0x01 << ES8388_ADCFSMODE_SHIFT)
#define ES8388_ADCFSMODE_SINGLE (0 << ES8388_ADCFSMODE_SHIFT)
#define ES8388_ADCFSMODE_DOUBLE (1 << ES8388_ADCFSMODE_SHIFT)
/* 0x0e ADC Control 6 */
#define ES8388_ADC_HPF_R_SHIFT (4)
#define ES8388_ADC_HPF_R_BITMASK (0x01 << ES8388_ADC_HPF_R_SHIFT)
#define ES8388_ADC_HPF_R_DISABLE (0 << ES8388_ADC_HPF_R_SHIFT)
#define ES8388_ADC_HPF_R_ENABLE (1 << ES8388_ADC_HPF_R_SHIFT)
#define ES8388_ADC_HPF_L_SHIFT (5)
#define ES8388_ADC_HPF_L_BITMASK (0x01 << ES8388_ADC_HPF_L_SHIFT)
#define ES8388_ADC_HPF_L_DISABLE (0 << ES8388_ADC_HPF_L_SHIFT)
#define ES8388_ADC_HPF_L_ENABLE (1 << ES8388_ADC_HPF_L_SHIFT)
#define ES8388_ADC_INVR_SHIFT (6)
#define ES8388_ADC_INVR_BITMASK (0x01 << ES8388_ADC_INVR_SHIFT)
#define ES8388_ADC_INVR_NORMAL (0 << ES8388_ADC_INVR_SHIFT)
#define ES8388_ADC_INVR_INVERTED (1 << ES8388_ADC_INVR_SHIFT)
#define ES8388_ADC_INVL_SHIFT (7)
#define ES8388_ADC_INVL_BITMASK (0x01 << ES8388_ADC_INVL_SHIFT)
#define ES8388_ADC_INVL_NORMAL (0 << ES8388_ADC_INVL_SHIFT)
#define ES8388_ADC_INVL_INVERTED (1 << ES8388_ADC_INVL_SHIFT)
/* 0x0f ADC Control 7 */
#define ES8388_ADCMUTE_SHIFT (2)
#define ES8388_ADCMUTE_BITMASK (0x01 << ES8388_ADCMUTE_SHIFT)
#define ES8388_ADCMUTE(a) (((int)a) << ES8388_ADCMUTE_SHIFT)
#define ES8388_ADCMUTE_NORMAL (0 << ES8388_ADCMUTE_SHIFT)
#define ES8388_ADCMUTE_MUTED (1 << ES8388_ADCMUTE_SHIFT)
#define ES8388_ADCLER_SHIFT (3)
#define ES8388_ADCLER_BITMASK (0x01 << ES8388_ADCLER_SHIFT)
#define ES8388_ADCLER_NORMAL (0 << ES8388_ADCLER_SHIFT)
#define ES8388_ADCLER_ADCLEFT (1 << ES8388_ADCLER_SHIFT)
#define ES8388_ADCSOFTRAMP_SHIFT (5)
#define ES8388_ADCSOFTRAMP_BITMASK (0x01 << ES8388_ADCSOFTRAMP_SHIFT)
#define ES8388_ADCSOFTRAMP_DISABLE (0 << ES8388_ADCSOFTRAMP_SHIFT)
#define ES8388_ADCSOFTRAMP_ENABLE (1 << ES8388_ADCSOFTRAMP_SHIFT)
#define ES8388_ADCRAMPRATE_SHIFT (6)
#define ES8388_ADCRAMPRATE_BITMASK (0x03 << ES8388_ADCRAMPRATE_SHIFT)
#define ES8388_ADCRAMPRATE_4LRCK (0 << ES8388_ADCRAMPRATE_SHIFT)
#define ES8388_ADCRAMPRATE_8LRCK (1 << ES8388_ADCRAMPRATE_SHIFT)
#define ES8388_ADCRAMPRATE_16LRCK (2 << ES8388_ADCRAMPRATE_SHIFT)
#define ES8388_ADCRAMPRATE_32LRCK (3 << ES8388_ADCRAMPRATE_SHIFT)
/* 0x10 ADC Control 8 */
#define ES8388_LADCVOL_SHIFT (0)
#define ES8388_LADCVOL_BITMASK (0xff << ES8388_LADCVOL_SHIFT)
#define ES8388_LADCVOL(a) (a << ES8388_LADCVOL_SHIFT)
/* 0x11 ADC Control 9 */
#define ES8388_RADCVOL_SHIFT (0)
#define ES8388_RADCVOL_BITMASK (0xff << ES8388_RADCVOL_SHIFT)
#define ES8388_RADCVOL(a) (a << ES8388_RADCVOL_SHIFT)
/* 0x12 ADC Control 10 */
#define ES8388_MINGAIN_SHIFT (0)
#define ES8388_MINGAIN_BITMASK (0x07 << ES8388_MINGAIN_SHIFT)
#define ES8388_MINGAIN(a) (a << ES8388_MINGAIN_SHIFT)
#define ES8388_MAXGAIN_SHIFT (3)
#define ES8388_MAXGAIN_BITMASK (0x07 << ES8388_MAXGAIN_SHIFT)
#define ES8388_MAXGAIN(a) (a << ES8388_MAXGAIN_SHIFT)
#define ES8388_ADCSEL_SHIFT (6)
#define ES8388_ADCSEL_BITMASK (0x03 << ES8388_ADCSEL_SHIFT)
#define ES8388_ADCSEL_OFF (0 << ES8388_ADCSEL_SHIFT)
#define ES8388_ADCSEL_RIGHT (1 << ES8388_ADCSEL_SHIFT)
#define ES8388_ADCSEL_LEFT (2 << ES8388_ADCSEL_SHIFT)
#define ES8388_ADCSEL_STEREO (3 << ES8388_ADCSEL_SHIFT)
/* 0x13 ADC Control 11 */
#define ES8388_ALCHLD_SHIFT (0)
#define ES8388_ALCHLD_BITMASK (0x0f << ES8388_ALCHLD_SHIFT)
#define ES8388_ALCHLD(a) (a << ES8388_ALCHLD_SHIFT)
#define ES8388_ALCLVL_SHIFT (4)
#define ES8388_ALCLVL_BITMASK (0x0f << ES8388_ALCLVL_SHIFT)
#define ES8388_ALCLVL(a) (a << ES8388_ALCLVL_SHIFT)
/* 0x14 ADC Control 12 */
#define ES8388_ALCATK_SHIFT (0)
#define ES8388_ALCATK_BITMASK (0x0f << ES8388_ALCATK_SHIFT)
#define ES8388_ALCATK(a) (a << ES8388_ALCATK_SHIFT)
#define ES8388_ALCDCY_SHIFT (4)
#define ES8388_ALCDCY_BITMASK (0x0f << ES8388_ALCDCY_SHIFT)
#define ES8388_ALCDCY(a) (a << ES8388_ALCDCY_SHIFT)
/* 0x15 ADC Control 13 */
#define ES8388_WIN_SIZE_SHIFT (0)
#define ES8388_WIN_SIZE_BITMASK (0x1f << ES8388_WIN_SIZE_SHIFT)
#define ES8388_WIN_SIZE(a) (a << ES8388_WIN_SIZE_SHIFT)
#define ES8388_TIME_OUT_SHIFT (5)
#define ES8388_TIME_OUT_BITMASK (0x01 << ES8388_TIME_OUT_SHIFT)
#define ES8388_TIME_OUT_DISABLE (0 << ES8388_TIME_OUT_SHIFT)
#define ES8388_TIME_OUT_ENABLE (1 << ES8388_TIME_OUT_SHIFT)
#define ES8388_ALCZC_SHIFT (6)
#define ES8388_ALCZC_BITMASK (0x01 << ES8388_ALCZC_SHIFT)
#define ES8388_ALCZC_DISABLE (0 << ES8388_ALCZC_SHIFT)
#define ES8388_ALCZC_ENABLE (1 << ES8388_ALCZC_SHIFT)
#define ES8388_ALCMODE_SHIFT (7)
#define ES8388_ALCMODE_BITMASK (0x01 << ES8388_ALCMODE_SHIFT)
#define ES8388_ALCMODE_NORMAL (0 << ES8388_ALCMODE_SHIFT)
#define ES8388_ALCMODE_LIMITER (1 << ES8388_ALCMODE_SHIFT)
/* 0x16 ADC Control 14 */
#define ES8388_NGAT_SHIFT (0)
#define ES8388_NGAT_BITMASK (0x01 << ES8388_NGAT_SHIFT)
#define ES8388_NGAT_DISABLE (0 << ES8388_NGAT_SHIFT)
#define ES8388_NGAT_ENABLE (1 << ES8388_NGAT_SHIFT)
#define ES8388_NGG_SHIFT (1)
#define ES8388_NGG_BITMASK (0x01 << ES8388_NGG_SHIFT)
#define ES8388_NGG_CONST (0 << ES8388_NGG_SHIFT)
#define ES8388_NGG_MUTE (1 << ES8388_NGG_SHIFT)
#define ES8388_NGTH_SHIFT (3)
#define ES8388_NGTH_BITMASK (0x1f << ES8388_NGTH_SHIFT)
#define ES8388_NGTH(a) (a << ES8388_NGTH_SHIFT)
/* 0x17 DAC Control 1 */
#define ES8388_DACFORMAT_SHIFT (1)
#define ES8388_DACFORMAT_BITMASK (0x03 << ES8388_DACFORMAT_SHIFT)
#define ES8388_DACFORMAT(a) (a << ES8388_DACFORMAT_SHIFT)
#define ES8388_DACWL_SHIFT (3)
#define ES8388_DACWL_BITMASK (0x07 << ES8388_DACWL_SHIFT)
#define ES8388_DACWL(a) (a << ES8388_DACWL_SHIFT)
#define ES8388_DACLRP_SHIFT (6)
#define ES8388_DACLRP_BITMASK (0x01 << ES8388_DACLRP_SHIFT)
#define ES8388_DACLRP_NORM_2ND (0 << ES8388_DACLRP_SHIFT)
#define ES8388_DACLRP_INV_1ST (1 << ES8388_DACLRP_SHIFT)
#define ES8388_DACLRSWAP_SHIFT (7)
#define ES8388_DACLRSWAP_BITMASK (0x01 << ES8388_DACLRSWAP_SHIFT)
#define ES8388_DACLRSWAP_NORMAL (0 << ES8388_DACLRSWAP_SHIFT)
#define ES8388_DACLRSWAP_SWAP (1 << ES8388_DACLRSWAP_SHIFT)
/* 0x18 DAC Control 2 */
#define ES8388_DACFSRATIO_SHIFT (0)
#define ES8388_DACFSRATIO_BITMASK (0x1f << ES8388_DACFSRATIO_SHIFT)
#define ES8388_DACFSRATIO(a) (a << ES8388_DACFSRATIO_SHIFT)
#define ES8388_DACFSMODE_SHIFT (5)
#define ES8388_DACFSMODE_BITMASK (0x01 << ES8388_DACFSMODE_SHIFT)
#define ES8388_DACFSMODE_SINGLE (0 << ES8388_DACFSMODE_SHIFT)
#define ES8388_DACFSMODE_DOUBLE (1 << ES8388_DACFSMODE_SHIFT)
/* 0x19 DAC Control 3 */
#define ES8388_DACMUTE_SHIFT (2)
#define ES8388_DACMUTE_BITMASK (0x01 << ES8388_DACMUTE_SHIFT)
#define ES8388_DACMUTE(a) (((int)a) << ES8388_DACMUTE_SHIFT)
#define ES8388_DACMUTE_NORMAL (0 << ES8388_DACMUTE_SHIFT)
#define ES8388_DACMUTE_MUTED (1 << ES8388_DACMUTE_SHIFT)
#define ES8388_DACLER_SHIFT (3)
#define ES8388_DACLER_BITMASK (0x01 << ES8388_DACLER_SHIFT)
#define ES8388_DACLER_NORMAL (0 << ES8388_DACLER_SHIFT)
#define ES8388_DACLER_ADCLEFT (1 << ES8388_DACLER_SHIFT)
#define ES8388_DACSOFTRAMP_SHIFT (5)
#define ES8388_DACSOFTRAMP_BITMASK (0x01 << ES8388_DACSOFTRAMP_SHIFT)
#define ES8388_DACSOFTRAMP_DISABLE (0 << ES8388_DACSOFTRAMP_SHIFT)
#define ES8388_DACSOFTRAMP_ENABLE (1 << ES8388_DACSOFTRAMP_SHIFT)
#define ES8388_DACRAMPRATE_SHIFT (6)
#define ES8388_DACRAMPRATE_BITMASK (0x03 << ES8388_DACRAMPRATE_SHIFT)
#define ES8388_DACRAMPRATE_4LRCK (0 << ES8388_DACRAMPRATE_SHIFT)
#define ES8388_DACRAMPRATE_32LRCK (1 << ES8388_DACRAMPRATE_SHIFT)
#define ES8388_DACRAMPRATE_64LRCK (2 << ES8388_DACRAMPRATE_SHIFT)
#define ES8388_DACRAMPRATE_128LRCK (3 << ES8388_DACRAMPRATE_SHIFT)
/* 0x1a DAC Control 4 */
#define ES8388_LDACVOL_SHIFT (0)
#define ES8388_LDACVOL_BITMASK (0xff << ES8388_LDACVOL_SHIFT)
#define ES8388_LDACVOL(a) (a << ES8388_LDACVOL_SHIFT)
/* 0x1b DAC Control 5 */
#define ES8388_RDACVOL_SHIFT (0)
#define ES8388_RDACVOL_BITMASK (0xff << ES8388_RDACVOL_SHIFT)
#define ES8388_RDACVOL(a) (a << ES8388_RDACVOL_SHIFT)
/* 0x1c DAC Control 6 */
#define ES8388_CLICKFREE_SHIFT (3)
#define ES8388_CLICKFREE_BITMASK (0x01 << ES8388_CLICKFREE_SHIFT)
#define ES8388_CLICKFREE_DISABLE (0 << ES8388_CLICKFREE_SHIFT)
#define ES8388_CLICKFREE_ENABLE (1 << ES8388_CLICKFREE_SHIFT)
#define ES8388_DAC_INVR_SHIFT (4)
#define ES8388_DAC_INVR_BITMASK (0x01 << ES8388_DAC_INVR_SHIFT)
#define ES8388_DAC_INVR_NOINV (0 << ES8388_DAC_INVR_SHIFT)
#define ES8388_DAC_INVR_180INV (1 << ES8388_DAC_INVR_SHIFT)
#define ES8388_DAC_INVL_SHIFT (5)
#define ES8388_DAC_INVL_BITMASK (0x01 << ES8388_DAC_INVL_SHIFT)
#define ES8388_DAC_INVL_NOINV (0 << ES8388_DAC_INVL_SHIFT)
#define ES8388_DAC_INVL_180INV (1 << ES8388_DAC_INVL_SHIFT)
#define ES8388_DEEMP_SHIFT (6)
#define ES8388_DEEMP_BITMASK (0x03 << ES8388_DEEMP_SHIFT)
#define ES8388_DEEMP_DISABLE (0 << ES8388_DEEMP_SHIFT)
#define ES8388_DEEMP_32KHZ (1 << ES8388_DEEMP_SHIFT)
#define ES8388_DEEMP_44KHZ (2 << ES8388_DEEMP_SHIFT)
#define ES8388_DEEMP_48KHZ (3 << ES8388_DEEMP_SHIFT)
/* 0x1d DAC Control 7 */
#define ES8388_VPP_SCALE_SHIFT (0)
#define ES8388_VPP_SCALE_BITMASK (0x03 << ES8388_VPP_SCALE_SHIFT)
#define ES8388_VPP_SCALE_3_5V (0 << ES8388_VPP_SCALE_SHIFT)
#define ES8388_VPP_SCALE_4_0V (1 << ES8388_VPP_SCALE_SHIFT)
#define ES8388_VPP_SCALE_3_0V (2 << ES8388_VPP_SCALE_SHIFT)
#define ES8388_VPP_SCALE_2_5V (3 << ES8388_VPP_SCALE_SHIFT)
#define ES8388_SE_SHIFT (2)
#define ES8388_SE_BITMASK (0x07 << ES8388_SE_SHIFT)
#define ES8388_SE(a) (a << ES8388_SE_SHIFT)
#define ES8388_MONO_SHIFT (5)
#define ES8388_MONO_BITMASK (0x01 << ES8388_MONO_SHIFT)
#define ES8388_MONO_STEREO (0 << ES8388_MONO_SHIFT)
#define ES8388_MONO_MONO (1 << ES8388_MONO_SHIFT)
#define ES8388_ZEROR_SHIFT (6)
#define ES8388_ZEROR_BITMASK (0x01 << ES8388_ZEROR_SHIFT)
#define ES8388_ZEROR_NORMAL (0 << ES8388_ZEROR_SHIFT)
#define ES8388_ZEROR_ZERO (1 << ES8388_ZEROR_SHIFT)
#define ES8388_ZEROL_SHIFT (7)
#define ES8388_ZEROL_BITMASK (0x01 << ES8388_ZEROL_SHIFT)
#define ES8388_ZEROL_NORMAL (0 << ES8388_ZEROL_SHIFT)
#define ES8388_ZEROL_ZERO (1 << ES8388_ZEROL_SHIFT)
/* 0x1e DAC Control 8
* 0x1f DAC Control 9
* 0x20 DAC Control 10
* 0x21 DAC Control 11
* 0x22 DAC Control 12
* 0x23 DAC Control 13
* 0x24 DAC Control 14
* 0x25 DAC Control 15
*/
#define ES8388_SHELVING_COEF_SHIFT (0)
#define ES8388_SHELVING_COEF_BITMASK (0xff << ES8388_SHELVING_COEF_SHIFT)
#define ES8388_SHELVING_COEF(a) (a << ES8388_SHELVING_COEF_SHIFT)
/* 0x26 DAC Control 16 */
#define ES8388_RMIXSEL_SHIFT (0)
#define ES8388_RMIXSEL_BITMASK (0x07 << ES8388_RMIXSEL_SHIFT)
#define ES8388_RMIXSEL_RIN1 (0 << ES8388_RMIXSEL_SHIFT)
#define ES8388_RMIXSEL_RIN2 (1 << ES8388_RMIXSEL_SHIFT)
#define ES8388_RMIXSEL_PIN (3 << ES8388_RMIXSEL_SHIFT)
#define ES8388_RMIXSEL_NIN (4 << ES8388_RMIXSEL_SHIFT)
#define ES8388_LMIXSEL_SHIFT (3)
#define ES8388_LMIXSEL_BITMASK (0x07 << ES8388_LMIXSEL_SHIFT)
#define ES8388_LMIXSEL_LIN1 (0 << ES8388_LMIXSEL_SHIFT)
#define ES8388_LMIXSEL_LIN2 (1 << ES8388_LMIXSEL_SHIFT)
#define ES8388_LMIXSEL_PIN (3 << ES8388_LMIXSEL_SHIFT)
#define ES8388_LMIXSEL_NIN (4 << ES8388_LMIXSEL_SHIFT)
/* 0x27 DAC Control 17 */
#define ES8388_LI2LOVOL_SHIFT (3)
#define ES8388_LI2LOVOL_BITMASK (0x07 << ES8388_LI2LOVOL_SHIFT)
#define ES8388_LI2LOVOL(a) (a << ES8388_LI2LOVOL_SHIFT)
#define ES8388_LI2LO_SHIFT (6)
#define ES8388_LI2LO_BITMASK (0x01 << ES8388_LI2LO_SHIFT)
#define ES8388_LI2LO_DISABLE (0 << ES8388_LI2LO_SHIFT)
#define ES8388_LI2LO_ENABLE (1 << ES8388_LI2LO_SHIFT)
#define ES8388_LD2LO_SHIFT (7)
#define ES8388_LD2LO_BITMASK (0x01 << ES8388_LD2LO_SHIFT)
#define ES8388_LD2LO_DISABLE (0 << ES8388_LD2LO_SHIFT)
#define ES8388_LD2LO_ENABLE (1 << ES8388_LD2LO_SHIFT)
/* 0x2a DAC Control 20 */
#define ES8388_RI2ROVOL_SHIFT (3)
#define ES8388_RI2ROVOL_BITMASK (0x07 << ES8388_RI2ROVOL_SHIFT)
#define ES8388_RI2ROVOL(a) (a << ES8388_RI2ROVOL_SHIFT)
#define ES8388_RI2RO_SHIFT (6)
#define ES8388_RI2RO_BITMASK (0x01 << ES8388_RI2RO_SHIFT)
#define ES8388_RI2RO_DISABLE (0 << ES8388_RI2RO_SHIFT)
#define ES8388_RI2RO_ENABLE (1 << ES8388_RI2RO_SHIFT)
#define ES8388_RD2RO_SHIFT (7)
#define ES8388_RD2RO_BITMASK (0x01 << ES8388_RD2RO_SHIFT)
#define ES8388_RD2RO_DISABLE (0 << ES8388_RD2RO_SHIFT)
#define ES8388_RD2RO_ENABLE (1 << ES8388_RD2RO_SHIFT)
/* 0x2b DAC Control 21 */
#define ES8388_DAC_DLL_PWD_SHIFT (2)
#define ES8388_DAC_DLL_PWD_BITMASK (0x01 << ES8388_DAC_DLL_PWD_SHIFT)
#define ES8388_DAC_DLL_PWD_NORMAL (0 << ES8388_DAC_DLL_PWD_SHIFT)
#define ES8388_DAC_DLL_PWD_PWRDN (1 << ES8388_DAC_DLL_PWD_SHIFT)
#define ES8388_ADC_DLL_PWD_SHIFT (3)
#define ES8388_ADC_DLL_PWD_BITMASK (0x01 << ES8388_ADC_DLL_PWD_SHIFT)
#define ES8388_ADC_DLL_PWD_NORMAL (0 << ES8388_ADC_DLL_PWD_SHIFT)
#define ES8388_ADC_DLL_PWD_PWRDN (1 << ES8388_ADC_DLL_PWD_SHIFT)
#define ES8388_MCLK_DIS_SHIFT (4)
#define ES8388_MCLK_DIS_BITMASK (0x01 << ES8388_MCLK_DIS_SHIFT)
#define ES8388_MCLK_DIS_NORMAL (0 << ES8388_MCLK_DIS_SHIFT)
#define ES8388_MCLK_DIS_DISABLE (1 << ES8388_MCLK_DIS_SHIFT)
#define ES8388_OFFSET_DIS_SHIFT (5)
#define ES8388_OFFSET_DIS_BITMASK (0x01 << ES8388_OFFSET_DIS_SHIFT)
#define ES8388_OFFSET_DIS_DISABLE (0 << ES8388_OFFSET_DIS_SHIFT)
#define ES8388_OFFSET_DIS_ENABLE (1 << ES8388_OFFSET_DIS_SHIFT)
#define ES8388_LRCK_SEL_SHIFT (6)
#define ES8388_LRCK_SEL_BITMASK (0x01 << ES8388_LRCK_SEL_SHIFT)
#define ES8388_LRCK_SEL_DAC (0 << ES8388_LRCK_SEL_SHIFT)
#define ES8388_LRCK_SEL_ADC (1 << ES8388_LRCK_SEL_SHIFT)
#define ES8388_SLRCK_SHIFT (7)
#define ES8388_SLRCK_BITMASK (0x01 << ES8388_SLRCK_SHIFT)
#define ES8388_SLRCK_SEPARATE (0 << ES8388_SLRCK_SHIFT)
#define ES8388_SLRCK_SAME (1 << ES8388_SLRCK_SHIFT)
/* 0x2c DAC Control 22 */
#define ES8388_OFFSET_SHIFT (0)
#define ES8388_OFFSET_BITMASK (0xff << ES8388_OFFSET_SHIFT)
#define ES8388_OFFSET(a) (a << ES8388_OFFSET_SHIFT)
/* 0x2d DAC Control 23 */
#define ES8388_VROI_SHIFT (4)
#define ES8388_VROI_BITMASK (0x01 << ES8388_VROI_SHIFT)
#define ES8388_VROI_1_5K (0 << ES8388_VROI_SHIFT)
#define ES8388_VROI_40K (1 << ES8388_VROI_SHIFT)
/* 0x2e DAC Control 24 */
#define ES8388_LOUT1VOL_SHIFT (0)
#define ES8388_LOUT1VOL_BITMASK (0x3f << ES8388_LOUT1VOL_SHIFT)
#define ES8388_LOUT1VOL(a) (a << ES8388_LOUT1VOL_SHIFT)
/* 0x2f DAC Control 25 */
#define ES8388_ROUT1VOL_SHIFT (0)
#define ES8388_ROUT1VOL_BITMASK (0x3f << ES8388_ROUT1VOL_SHIFT)
#define ES8388_ROUT1VOL(a) (a << ES8388_ROUT1VOL_SHIFT)
/* 0x30 DAC Control 26 */
#define ES8388_LOUT2VOL_SHIFT (0)
#define ES8388_LOUT2VOL_BITMASK (0x3f << ES8388_LOUT2VOL_SHIFT)
#define ES8388_LOUT2VOL(a) (a << ES8388_LOUT2VOL_SHIFT)
/* 0x31 DAC Control 27 */
#define ES8388_ROUT2VOL_SHIFT (0)
#define ES8388_ROUT2VOL_BITMASK (0x3f << ES8388_ROUT2VOL_SHIFT)
#define ES8388_ROUT2VOL(a) (a << ES8388_ROUT2VOL_SHIFT)
/* Codec Default Parameters *************************************************/
#define ES8388_DEFAULT_SAMPRATE 44100
#define ES8388_DEFAULT_NCHANNELS 2
#define ES8388_DEFAULT_BPSAMP 16
#define ES8388_DEFAULT_VOL_OUT 250
#define ES8388_DEFAULT_VOL_IN 1000
#define ES8388_DEFAULT_BALANCE 500
#define ES8388_DEFAULT_MUTE true
#define ES8388_DEFAULT_AUDIO_MODE ES_MODULE_ADC_DAC
#define ES8388_DEFAULT_DAC_OUTPUT ES8388_DAC_OUTPUT_ALL
#define ES8388_DEFAULT_ADC_INPUT ES8388_ADC_INPUT_LINE1
#define ES8388_DEFAULT_MIC_GAIN ES_MIC_GAIN_24DB
#define ES8388_DEFAULT_MODE ES_MODE_SLAVE
#define ES8388_DEFAULT_FMT ES_I2S_NORMAL
/****************************************************************************
* Public Types
****************************************************************************/
typedef enum
{
ES8388_DAC_OUTPUT_LINE1,
ES8388_DAC_OUTPUT_LINE2,
ES8388_DAC_OUTPUT_ALL,
} es8388_dac_output_e;
typedef enum
{
ES8388_ADC_INPUT_LINE1,
ES8388_ADC_INPUT_LINE2,
ES8388_ADC_INPUT_ALL,
ES8388_ADC_INPUT_DIFFERENCE,
} es8388_adc_input_e;
typedef enum
{
ES8388_MIXER_GAIN_6DB,
ES8388_MIXER_GAIN_3DB,
ES8388_MIXER_GAIN_0DB,
ES8388_MIXER_GAIN_N3DB,
ES8388_MIXER_GAIN_N6DB,
ES8388_MIXER_GAIN_N9DB,
ES8388_MIXER_GAIN_N12DB,
ES8388_MIXER_GAIN_N15DB,
} es8388_mixer_gain_e;
typedef enum
{
ES_WORD_LENGTH_16BITS = 0x03,
ES_WORD_LENGTH_18BITS = 0x02,
ES_WORD_LENGTH_20BITS = 0x01,
ES_WORD_LENGTH_24BITS = 0x00,
ES_WORD_LENGTH_32BITS = 0x04
} es_word_length_e;
typedef enum
{
ES_MCLK_DIV_AUTO,
ES_MCLK_DIV_1,
ES_MCLK_DIV_2,
ES_MCLK_DIV_3,
ES_MCLK_DIV_4,
ES_MCLK_DIV_6,
ES_MCLK_DIV_8,
ES_MCLK_DIV_9,
ES_MCLK_DIV_11,
ES_MCLK_DIV_12,
ES_MCLK_DIV_16,
ES_MCLK_DIV_18,
ES_MCLK_DIV_22,
ES_MCLK_DIV_24,
ES_MCLK_DIV_33,
ES_MCLK_DIV_36,
ES_MCLK_DIV_44,
ES_MCLK_DIV_48,
ES_MCLK_DIV_66,
ES_MCLK_DIV_72,
ES_MCLK_DIV_5,
ES_MCLK_DIV_10,
ES_MCLK_DIV_15,
ES_MCLK_DIV_17,
ES_MCLK_DIV_20,
ES_MCLK_DIV_25,
ES_MCLK_DIV_30,
ES_MCLK_DIV_32,
ES_MCLK_DIV_34,
ES_MCLK_DIV_7,
ES_MCLK_DIV_13,
ES_MCLK_DIV_14
} es_sclk_div_e;
typedef enum
{
ES_LCLK_DIV_128 = 0,
ES_LCLK_DIV_192 = 1,
ES_LCLK_DIV_256 = 2,
ES_LCLK_DIV_384 = 3,
ES_LCLK_DIV_512 = 4,
ES_LCLK_DIV_576 = 5,
ES_LCLK_DIV_768 = 6,
ES_LCLK_DIV_1024 = 7,
ES_LCLK_DIV_1152 = 8,
ES_LCLK_DIV_1408 = 9,
ES_LCLK_DIV_1536 = 10,
ES_LCLK_DIV_2112 = 11,
ES_LCLK_DIV_2304 = 12,
ES_LCLK_DIV_125 = 16,
ES_LCLK_DIV_136 = 17,
ES_LCLK_DIV_250 = 18,
ES_LCLK_DIV_272 = 19,
ES_LCLK_DIV_375 = 20,
ES_LCLK_DIV_500 = 21,
ES_LCLK_DIV_544 = 22,
ES_LCLK_DIV_750 = 23,
ES_LCLK_DIV_1000 = 24,
ES_LCLK_DIV_1088 = 25,
ES_LCLK_DIV_1496 = 26,
ES_LCLK_DIV_1500 = 27
} es_lclk_div_e;
typedef enum
{
ES_D2SE_PGA_GAIN_DIS,
ES_D2SE_PGA_GAIN_EN
} es_d2se_pga_e;
typedef enum
{
ES_ADC_CHANNEL_LINPUT1_RINPUT1 = 0x00,
ES_ADC_CHANNEL_MIC1 = 0x05,
ES_ADC_CHANNEL_MIC2 = 0x06,
ES_ADC_CHANNEL_LINPUT2_RINPUT2 = 0x50,
ES_ADC_CHANNEL_DIFFERENCE = 0xf0
} es_adc_channel_e;
typedef enum
{
ES_DAC_CHANNEL_LOUT1 = 0x04,
ES_DAC_CHANNEL_LOUT2 = 0x08,
ES_DAC_CHANNEL_SPK = 0x09,
ES_DAC_CHANNEL_ROUT1 = 0x10,
ES_DAC_CHANNEL_ROUT2 = 0x20,
ES_DAC_CHANNEL_ALL = 0x3c
} es_dac_channel_e;
typedef enum
{
ES_MIC_GAIN_0DB,
ES_MIC_GAIN_3DB,
ES_MIC_GAIN_6DB,
ES_MIC_GAIN_9DB,
ES_MIC_GAIN_12DB,
ES_MIC_GAIN_15DB,
ES_MIC_GAIN_18DB,
ES_MIC_GAIN_21DB,
ES_MIC_GAIN_24DB
} es_mic_gain_e;
typedef enum
{
ES_MODULE_ADC = 1,
ES_MODULE_DAC,
ES_MODULE_ADC_DAC,
ES_MODULE_LINE
} es_module_e;
typedef enum
{
ES_MODE_SLAVE,
ES_MODE_MASTER
} es_mode_e;
typedef enum
{
ES_I2S_NORMAL,
ES_I2S_LEFT,
ES_I2S_RIGHT,
ES_I2S_DSP
} es_i2s_fmt_e;
/****************************************************************************
* Class Definitions
****************************************************************************/
class ES8388
{
private:
TwoWire* _i2c; /* The I2C bus */
I2SClass* _i2s; /* The I2S bus */
uint8_t _addr; /* The I2C address */
es_i2s_fmt_e _fmt; /* The current I2S format */
es_mode_e _mode; /* The current codec mode */
uint32_t _samprate; /* Configured samprate (samples/sec) */
uint16_t _balance; /* Current balance level {0..1000} */
uint16_t _volume_out; /* Current output volume level {0..1000} */
uint16_t _volume_in; /* Current input volume level {0..1000} */
uint8_t _nchannels; /* Number of channels (1 or 2) */
uint8_t _bpsamp; /* Bits per sample */
bool _mute; /* True: Output is muted */
es_module_e _audio_mode; /* The current audio mode of the ES8388 chip */
es8388_dac_output_e _dac_output; /* The current output of the ES8388 DAC */
es8388_adc_input_e _adc_input; /* The current input of the ES8388 ADC */
es_mic_gain_e _mic_gain; /* The current microphone gain */
bool _running; /* True: The ES8388 is running */
es_lclk_div_e _lclk_div; /* The current LCLK divider */
es_word_length_e _word_length; /* The current word length (enum of _bpsamp) */
void reset();
void start();
void stop();
void setvolume(es_module_e module, uint16_t volume, uint16_t balance);
void setmute(es_module_e module, bool enable);
public:
~ES8388();
bool begin(I2SClass& i2s, TwoWire& i2c = Wire, uint8_t addr = 0x10);
void end();
void playWAV(uint8_t* data, size_t len);
uint8_t* recordWAV(size_t rec_seconds, size_t* out_size);
uint8_t readReg(uint8_t reg);
void writeReg(uint8_t reg, uint8_t data);
void setOutputVolume(uint16_t volume, uint16_t balance);
void setInputVolume(uint16_t volume, uint16_t balance);
void setOutputMute(bool enable);
void setInputMute(bool enable);
void setBitsPerSample(uint8_t bpsamp);
void setSampleRate(uint32_t rate);
void setMicGain(uint8_t gain);
};
/*
ESP32-LyraT I2S ES8388 loopback example
This simple example demonstrates using the I2S library in combination
with the ES8388 codec on the ESP32-LyraT board to record and play back
audio data.
Don't forget to enable the PSRAM in the Tools menu!
Created for arduino-esp32 on 20 Dec, 2023
by Lucas Saavedra Vaz (lucasssvaz)
*/
#include "ESP_I2S.h"
#include "Wire.h"
#include "ES8388.h"
/* Pin definitions */
/* I2C */
const uint8_t I2C_SCL = 23;
const uint8_t I2C_SDA = 18;
const uint32_t I2C_FREQ = 400000;
/* I2S */
const uint8_t I2S_MCLK = 0; /* Master clock */
const uint8_t I2S_SCK = 5; /* Audio data bit clock */
const uint8_t I2S_WS = 25; /* Audio data left and right clock */
const uint8_t I2S_SDOUT = 26; /* ESP32 audio data output (to speakers) */
const uint8_t I2S_SDIN = 35; /* ESP32 audio data input (from microphone) */
/* PA */
const uint8_t PA_ENABLE = 21; /* Power amplifier enable */
void setup() {
I2SClass i2s;
ES8388 codec;
uint8_t *wav_buffer;
size_t wav_size;
// Initialize the serial port
Serial.begin(115200);
while (!Serial) { delay(10); }
pinMode(PA_ENABLE, OUTPUT);
digitalWrite(PA_ENABLE, HIGH);
Serial.println("Initializing I2C bus...");
// Initialize the I2C bus
Wire.begin(I2C_SDA, I2C_SCL, I2C_FREQ);
Serial.println("Initializing I2S bus...");
// Set up the pins used for audio input
i2s.setPins(I2S_SCK, I2S_WS, I2S_SDOUT, I2S_SDIN, I2S_MCLK);
// Initialize the I2S bus in standard mode
if (!i2s.begin(I2S_MODE_STD, 44100, I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO, I2S_STD_SLOT_BOTH)) {
Serial.println("Failed to initialize I2S bus!");
return;
}
Serial.println("Initializing ES8388...");
if (!codec.begin(i2s)) {
Serial.println("Failed to initialize ES8388!");
return;
}
Serial.println("Recording 10 seconds of audio data...");
// Record 10 seconds of audio data
wav_buffer = codec.recordWAV(10, &wav_size);
Serial.println("Recording complete. Playing audio data in 3 seconds.");
delay(3000);
// Play the audio data
Serial.println("Playing audio data...");
codec.playWAV(wav_buffer, wav_size);
Serial.println("Application complete.");
}
void loop() {}
/*
ESP32-S2-EYE I2S record to WAV example
This simple example demonstrates using the I2S library to record
5 seconds of audio data and write it to a WAV file on the SD card.
Don't forget to select the OPI PSRAM, 8MB flash size and Enable USB CDC
on boot in the Tools menu!
Created for arduino-esp32 on 18 Dec, 2023
by Lucas Saavedra Vaz (lucasssvaz)
*/
#include "ESP_I2S.h"
#include "FS.h"
#include "SD_MMC.h"
const uint8_t I2S_SCK = 41;
const uint8_t I2S_WS = 42;
const uint8_t I2S_DIN = 2;
const uint8_t SD_CMD = 38;
const uint8_t SD_CLK = 39;
const uint8_t SD_DATA0 = 40;
void setup() {
// Create an instance of the I2SClass
I2SClass i2s;
// Create variables to store the audio data
uint8_t *wav_buffer;
size_t wav_size;
// Initialize the serial port
Serial.begin(115200);
while (!Serial) { delay(10); }
Serial.println("Initializing I2S bus...");
// Set up the pins used for audio input
i2s.setPins(I2S_SCK, I2S_WS, -1, I2S_DIN);
// Initialize the I2S bus in standard mode
if (!i2s.begin(I2S_MODE_STD, 16000, I2S_DATA_BIT_WIDTH_32BIT, I2S_SLOT_MODE_MONO, I2S_STD_SLOT_LEFT)) {
Serial.println("Failed to initialize I2S bus!");
return;
}
Serial.println("I2S bus initialized.");
Serial.println("Initializing SD card...");
// Set up the pins used for SD card access
if (!SD_MMC.setPins(SD_CLK, SD_CMD, SD_DATA0)) {
Serial.println("Failed to set SD pins!");
return;
}
// Mount the SD card
if(!SD_MMC.begin("/sdcard", true)){
Serial.println("Failed to initialize SD card!");
return;
}
Serial.println("SD card initialized.");
Serial.println("Recording 5 seconds of audio data...");
// Record 5 seconds of audio data
wav_buffer = i2s.recordWAV(5, &wav_size);
// Create a file on the SD card
File file = SD_MMC.open("/test.wav", FILE_WRITE);
if (!file) {
Serial.println("Failed to open file for writing!");
return;
}
Serial.println("Writing audio data to file...");
// Write the audio data to the file
if (file.write(wav_buffer, wav_size) != wav_size) {
Serial.println("Failed to write audio data to file!");
return;
}
// Close the file
file.close();
Serial.println("Application complete.");
}
void loop() {}
/*
This example generates a square wave based tone at a specified frequency
and sample rate. Then outputs the data using the I2S interface to a
MAX08357 I2S Amp Breakout board.
I2S Circuit:
* Arduino/Genuino Zero, MKR family and Nano 33 IoT
* MAX08357:
* GND connected GND
* VIN connected 5V
* LRC connected to pin 0 (Zero) or 3 (MKR), A2 (Nano) or 25 (ESP32)
* BCLK connected to pin 1 (Zero) or 2 (MKR), A3 (Nano) or 5 (ESP32)
* DIN connected to pin 9 (Zero) or A6 (MKR), 4 (Nano) or 26 (ESP32)
DAC Circuit:
* ESP32 or ESP32-S2
* Audio amplifier
- Note:
- ESP32 has DAC on GPIO pins 25 and 26.
- ESP32-S2 has DAC on GPIO pins 17 and 18.
- Connect speaker(s) or headphones.
created 17 November 2016
by Sandeep Mistry
For ESP extended
Tomas Pilny
2nd September 2021
Lucas Saavedra Vaz (lucasssvaz)
22nd December 2023
*/
#include <ESP_I2S.h>
const int frequency = 440; // frequency of square wave in Hz
const int amplitude = 500; // amplitude of square wave
const int sampleRate = 8000; // sample rate in Hz
i2s_data_bit_width_t bps = I2S_DATA_BIT_WIDTH_16BIT;
i2s_mode_t mode = I2S_MODE_STD;
i2s_slot_mode_t slot = I2S_SLOT_MODE_STEREO;
const int halfWavelength = (sampleRate / frequency); // half wavelength of square wave
int32_t sample = amplitude; // current sample value
int count = 0;
I2SClass i2s;
void setup() {
Serial.begin(115200);
Serial.println("I2S simple tone");
// start I2S at the sample rate with 16-bits per sample
if (!i2s.begin(mode, sampleRate, bps, slot)) {
Serial.println("Failed to initialize I2S!");
while (1); // do nothing
}
}
void loop() {
if (count % halfWavelength == 0 ) {
// invert the sample every half wavelength count multiple to generate square wave
sample = -1 * sample;
}
i2s.write(sample); // Right channel
i2s.write(sample); // Left channel
// increment the counter for the next sample
count++;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment