doc/i2s: update i2s programming guide on s3 & c3

This commit is contained in:
laokaiyao
2021-06-17 18:49:44 +08:00
parent f7f8c9c11f
commit d51b85989b
20 changed files with 722 additions and 854 deletions

View File

@@ -1,24 +1,14 @@
I2S
===
.. only:: esp32c3
.. warning::
This document is not updated for ESP32-C3 yet.
{IDF_TARGET_I2S_NUM:default="two", esp32s2="one", esp32c3="one"}
Overview
--------
I2S (Inter-IC Sound) is a serial, synchronous communication protocol that is usually used for transmitting audio data between two digital audio devices.
.. only:: esp32
{IDF_TARGET_NAME} contains two I2S peripherals. These peripherals can be configured to input and output sample data via the I2S driver.
.. only:: esp32s2
{IDF_TARGET_NAME} contains one I2S peripheral. These peripherals can be configured to input and output sample data via the I2S driver.
{IDF_TARGET_NAME} contains {IDF_TARGET_I2S_NUM} I2S peripheral(s). These peripherals can be configured to input and output sample data via the I2S driver.
An I2S bus consists of the following lines:
@@ -30,20 +20,22 @@ Each I2S controller has the following features that can be configured using the
- Operation as system master or slave
- Capable of acting as transmitter or receiver
- Dedicated DMA controller that allows for streaming sample data without requiring the CPU to copy each data sample
- DMA controller that allows for streaming sample data without requiring the CPU to copy each data sample
Each controller can operate in half-duplex communication mode. Thus, the two controllers can be combined to establish full-duplex communication.
I2S0 output can be routed directly to the digital-to-analog converter's (DAC) output channels (GPIO 25 & GPIO 26) to produce direct analog output without involving any external I2S codecs. I2S0 can also be used for transmitting PDM (Pulse-density modulation) signals.
The I2S peripherals also support LCD mode for communicating data over a parallel bus, as used by some LCD displays and camera modules. LCD mode has the following operational modes:
- LCD master transmitting mode
- Camera slave receiving mode
- ADC/DAC mode
.. only:: esp32
I2S0 output can be routed directly to the digital-to-analog converter's (DAC) output channels (GPIO 25 & GPIO 26) to produce direct analog output without involving any external I2S codecs. I2S0 can also be used for transmitting PDM (Pulse-density modulation) signals.
.. only:: esp32 or esp32s2
The I2S peripherals also support LCD mode for communicating data over a parallel bus, as used by some LCD displays and camera modules. LCD mode has the following operational modes:
- LCD master transmitting mode
- Camera slave receiving mode
- ADC/DAC mode
For more information, see *{IDF_TARGET_NAME} Technical Reference Manual* > *I2S Controller (I2S)* > LCD Mode [`PDF <{IDF_TARGET_TRM_EN_URL}#camlcdctrl>`__].
.. note::
@@ -68,26 +60,50 @@ Install the I2S driver by calling the function :cpp:func`i2s_driver_install` and
- The structure :cpp:type:`i2s_config_t` with defined communication parameters
- Event queue size and handle
I2S will start automatically once :cpp:func`i2s_driver_install` returns ``ESP_OK``.
Configuration example:
.. code-block:: c
.. only:: not SOC_I2S_SUPPORTS_TDM
static const int i2s_num = 0; // i2s port number
.. code-block:: c
static const i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = 44100,
.bits_per_sample = 16,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = 0, // default interrupt priority
.dma_buf_count = 8,
.dma_buf_len = 64,
.use_apll = false
};
static const int i2s_num = 0; // i2s port number
i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL);
i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = 44100,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S
.tx_desc_auto_clear = false,
.dma_buf_count = 8,
.dma_buf_len = 64,
.use_apll = false,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 // Interrupt level 1, default 0
};
i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL);
.. only:: SOC_I2S_SUPPORTS_TDM
.. code-block:: c
static const int i2s_num = 0; // i2s port number
i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = 44100,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.tx_desc_auto_clear = false,
.dma_buf_count = 8,
.dma_buf_len = 64,
.bits_per_chan = I2S_BITS_PER_SAMPLE_16BIT
};
i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL);
Setting Communication Pins
^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -100,15 +116,14 @@ Once the driver is installed, configure physical GPIO pins to which signals will
.. code-block:: c
static const i2s_pin_config_t pin_config = {
.bck_io_num = 26,
.ws_io_num = 25,
.data_out_num = 22,
.bck_io_num = 4,
.ws_io_num = 5,
.data_out_num = 18,
.data_in_num = I2S_PIN_NO_CHANGE
};
i2s_set_pin(i2s_num, &pin_config);
Running I2S Communication
^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -117,14 +132,17 @@ To perform a transmission:
- Prepare the data for sending
- Call the function :cpp:func:`i2s_write` and pass the data buffer address and data length to it
The function will write the data to the I2S DMA Tx buffer, and then the data will be transmitted automatically.
The function will write the data to the DMA Tx buffer, and then the data will be transmitted automatically.
.. code-block:: c
i2s_write(I2S_NUM, samples_data, ((bits+8)/16)*SAMPLE_PER_CYCLE*4, &i2s_bytes_write, 100);
To retrieve received data, use the function :cpp:func:`i2s_read`. It will retrieve the data from the DMA Rx buffer, once the data is received by the I2S controller.
To retrieve received data, use the function :cpp:func:`i2s_read`. It will retrieve the data from the I2S DMA Rx buffer, once the data is received by the I2S controller.
.. code-block:: c
i2s_read(I2S_NUM, data_recv, ((bits+8)/16)*SAMPLE_PER_CYCLE*4, &i2s_bytes_read, 100);
You can temporarily stop the I2S driver by calling the function :cpp:func:`i2s_stop`, which will disable the I2S Tx/Rx units until the function :cpp:func:`i2s_start` is called. If the function :cpp:func`i2s_driver_install` is used, the driver will start up automatically eliminating the need to call :cpp:func:`i2s_start`.
@@ -140,87 +158,184 @@ Application Example
A code example for the I2S driver can be found in the directory :example:`peripherals/i2s`.
In addition, there are two short configuration examples for the I2S driver.
.. only:: SOC_I2S_SUPPORTS_ADC_DAC
In addition, there are two short configuration examples for the I2S driver.
.. only:: not SOC_I2S_SUPPORTS_ADC_DAC
In addition, there is a short configuration examples for the I2S driver.
I2S configuration
^^^^^^^^^^^^^^^^^
.. code-block:: c
Example for general usage.
#include "driver/i2s.h"
#include "freertos/queue.h"
.. only:: not SOC_I2S_SUPPORTS_TDM
static const int i2s_num = 0; // i2s port number
.. code-block:: c
static const i2s_config_t i2s_config = {
.param_cfg = {
#include "driver/i2s.h"
static const int i2s_num = 0; // i2s port number
i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = 44100,
.slot_bits_cfg = 16,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
},
.intr_alloc_flags = 0, // default interrupt priority
.dma_buf_count = 8,
.dma_buf_len = 64,
.use_apll = false
};
.communication_format = I2S_COMM_FORMAT_STAND_I2S
.tx_desc_auto_clear = false,
.dma_buf_count = 8,
.dma_buf_len = 64,
.use_apll = false,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 // Interrupt level 1, default 0
};
static const i2s_pin_config_t pin_config = {
.bck_io_num = 26,
.ws_io_num = 25,
.data_out_num = 22,
.data_in_num = I2S_PIN_NO_CHANGE
};
...
static const i2s_pin_config_t pin_config = {
.bck_io_num = 4,
.ws_io_num = 5,
.data_out_num = 18,
.data_in_num = I2S_PIN_NO_CHANGE
};
i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver
i2s_set_pin(i2s_num, &pin_config);
i2s_set_sample_rates(i2s_num, 22050); //set sample rates
...
/* You can reset parameters by calling 'i2s_set_clk'
*
* The low 16 bits are the valid data bits in one chan and the high 16 bits are
* the total bits in one chan. If high 16 bits is smaller than low 16 bits, it will
* be set to a same value as low 16 bits.
*/
uint32_t bits_cfg = (I2S_BITS_PER_CHAN_32BIT << 16) | I2S_BITS_PER_SAMPLE_16BIT;
i2s_set_clk(i2s_num, 22050, bits_cfg, I2S_CHANNEL_STEREO);
...
i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver
.. only:: SOC_I2S_SUPPORTS_TDM
Configuring I2S to use internal DAC for analog output
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: c
.. code-block:: c
#include "driver/i2s.h"
#include "driver/i2s.h"
#include "freertos/queue.h"
static const int i2s_num = 0; // i2s port number
static const int i2s_num = 0; // i2s port number
static const i2s_config_t i2s_config = {
.param_cfg = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN,
i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = 44100,
.slot_bits_cfg = 16, /* the DAC module will only take the 8bits from MSB */
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
},
.intr_alloc_flags = 0, // default interrupt priority
.dma_buf_count = 8,
.dma_buf_len = 64,
.use_apll = false
};
.communication_format = I2S_COMM_FORMAT_STAND_I2S
.tx_desc_auto_clear = false,
.dma_buf_count = 8,
.dma_buf_len = 64
};
...
static const i2s_pin_config_t pin_config = {
.bck_io_num = 4,
.ws_io_num = 5,
.data_out_num = 18,
.data_in_num = I2S_PIN_NO_CHANGE
};
i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver
i2s_set_pin(i2s_num, &pin_config);
i2s_set_pin(i2s_num, NULL); //for internal DAC, this will enable both of the internal channels
//You can call i2s_set_dac_mode to set built-in DAC output mode.
//i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN);
i2s_set_sample_rates(i2s_num, 22050); //set sample rates
...
/* You can reset parameters by calling 'i2s_set_clk'
*
* The low 16 bits are the valid data bits in one chan and the high 16 bits are
* the total bits in one chan. If high 16 bits is smaller than low 16 bits, it will
* be set to a same value as low 16 bits.
*/
uint32_t bits_cfg = (I2S_BITS_PER_CHAN_32BIT << 16) | I2S_BITS_PER_SAMPLE_16BIT;
i2s_set_clk(i2s_num, 22050, bits_cfg, I2S_CHANNEL_STEREO);
...
i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver
I2S on {IDF_TARGET_NAME} support TDM mode, up to 16 channels are available in TDM mode. If you want to use TDM mode, set field ``channel_format`` of :cpp:type:`i2s_config_t` to ``I2S_CHANNEL_FMT_TDM``. Then enable the channels by setting ``tdm_chan_cfg.chan_mask`` using masks in :cpp:type:`i2s_channel_t`, the number of active channels and total channels will be calculate automatically. Also you can set a particular total channel number for it, but it shouldn't be smaller than the largest channel you use.
.. code-block:: c
#include "driver/i2s.h"
static const int i2s_num = 0; // i2s port number
i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = 44100,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_TDM,
.communication_format = I2S_COMM_FORMAT_STAND_I2S
.tx_desc_auto_clear = false,
.dma_buf_count = 8,
.dma_buf_len = 64,
.chan_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH2
};
static const i2s_pin_config_t pin_config = {
.bck_io_num = 4,
.ws_io_num = 5,
.data_out_num = 18,
.data_in_num = I2S_PIN_NO_CHANGE
};
i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver
i2s_set_pin(i2s_num, &pin_config);
...
/* You can reset parameters by calling 'i2s_set_clk'
*
* The low 16 bits are the valid data bits in one chan and the high 16 bits are
* the total bits in one chan. If high 16 bits is smaller than low 16 bits, it will
* be set to a same value as low 16 bits.
*/
uint32_t bits_cfg = (I2S_BITS_PER_CHAN_32BIT << 16) | I2S_BITS_PER_SAMPLE_16BIT;
i2s_set_clk(i2s_port_t i2s_num, 22050, bits_cfg, I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1); // set clock
...
i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver
.. only:: SOC_I2S_SUPPORTS_ADC_DAC
Configuring I2S to use internal DAC for analog output
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: c
#include "driver/i2s.h"
#include "freertos/queue.h"
static const int i2s_num = 0; // i2s port number
static const i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN,
.sample_rate = 44100,
.bits_per_sample = 16, /* the DAC module will only take the 8bits from MSB */
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.intr_alloc_flags = 0, // default interrupt priority
.dma_buf_count = 8,
.dma_buf_len = 64,
.use_apll = false
};
...
i2s_driver_install(i2s_num, &i2s_config, 0, NULL); //install and start i2s driver
i2s_set_pin(i2s_num, NULL); //for internal DAC, this will enable both of the internal channels
//You can call i2s_set_dac_mode to set built-in DAC output mode.
//i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN);
i2s_set_sample_rates(i2s_num, 22050); //set sample rates
i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver
API Reference
-------------