Merge branch 'feature/support_4_line_pdm_rx_on_esp32s3' into 'master'

i2s: support 4 line pdm rx on esp32s3

Closes IDF-6120

See merge request espressif/esp-idf!20753
pull/10165/head
Kevin (Lao Kaiyao) 2022-11-04 18:44:52 +08:00
commit 48b23b7c46
28 zmienionych plików z 203 dodań i 73 usunięć

Wyświetl plik

@ -118,9 +118,9 @@ static esp_err_t i2s_pdm_tx_set_gpio(i2s_chan_handle_t handle, const i2s_pdm_tx_
i2s_pdm_tx_config_t *pdm_tx_cfg = (i2s_pdm_tx_config_t *)handle->mode_info;
/* Set data output GPIO */
i2s_gpio_check_and_set(gpio_cfg->dout, i2s_periph_signal[id].data_out_sig, false, false);
#if SOC_I2S_HW_VERSION_2
#if SOC_I2S_PDM_MAX_TX_LINES > 1
if (pdm_tx_cfg->slot_cfg.line_mode == I2S_PDM_TX_TWO_LINE_DAC) {
i2s_gpio_check_and_set(gpio_cfg->dout2, i2s_periph_signal[id].data_out1_sig, false, false);
i2s_gpio_check_and_set(gpio_cfg->dout2, i2s_periph_signal[id].data_out_sigs[1], false, false);
}
#endif
@ -393,8 +393,17 @@ static esp_err_t i2s_pdm_rx_set_gpio(i2s_chan_handle_t handle, const i2s_pdm_rx_
ESP_ERR_INVALID_ARG, TAG, "clk gpio is invalid");
ESP_RETURN_ON_FALSE((gpio_cfg->din == -1 || GPIO_IS_VALID_GPIO(gpio_cfg->din)),
ESP_ERR_INVALID_ARG, TAG, "dout gpio is invalid");
i2s_pdm_rx_config_t *pdm_rx_cfg = (i2s_pdm_rx_config_t *)handle->mode_info;
/* Set data input GPIO */
#if SOC_I2S_PDM_MAX_RX_LINES > 1
for (int i = 0; i < SOC_I2S_PDM_MAX_RX_LINES; i++) {
if (pdm_rx_cfg->slot_cfg.slot_mask & (0x03 << (i * 2))) {
i2s_gpio_check_and_set(gpio_cfg->dins[i], i2s_periph_signal[id].data_in_sigs[i], true, false);
}
}
#else
i2s_gpio_check_and_set(gpio_cfg->din, i2s_periph_signal[id].data_in_sig, true, false);
#endif
if (handle->role == I2S_ROLE_SLAVE) {
/* For "tx + rx + slave" or "rx + slave" mode, select RX signal index for ws and bck */
@ -410,7 +419,6 @@ static esp_err_t i2s_pdm_rx_set_gpio(i2s_chan_handle_t handle, const i2s_pdm_rx_
i2s_ll_mclk_bind_to_rx_clk(handle->controller->hal.dev);
#endif
/* Update the mode info: gpio configuration */
i2s_pdm_rx_config_t *pdm_rx_cfg = (i2s_pdm_rx_config_t *)handle->mode_info;
memcpy(&(pdm_rx_cfg->gpio_cfg), gpio_cfg, sizeof(i2s_pdm_rx_gpio_config_t));
return ESP_OK;
@ -433,9 +441,9 @@ esp_err_t i2s_channel_init_pdm_rx_mode(i2s_chan_handle_t handle, const i2s_pdm_r
}
handle->mode_info = calloc(1, sizeof(i2s_pdm_rx_config_t));
ESP_GOTO_ON_FALSE(handle->mode_info, ESP_ERR_NO_MEM, err, TAG, "no memory for storing the configurations");
ESP_GOTO_ON_ERROR(i2s_pdm_rx_set_gpio(handle, &pdm_rx_cfg->gpio_cfg), err, TAG, "initialize channel failed while setting gpio pins");
/* i2s_set_pdm_rx_slot should be called before i2s_set_pdm_rx_clock while initializing, because clock is relay on the slot */
/* i2s_set_pdm_rx_slot should be called before i2s_set_pdm_rx_clock and i2s_pdm_rx_set_gpio while initializing, because clock is relay on the slot */
ESP_GOTO_ON_ERROR(i2s_pdm_rx_set_slot(handle, &pdm_rx_cfg->slot_cfg), err, TAG, "initialize channel failed while setting slot");
ESP_GOTO_ON_ERROR(i2s_pdm_rx_set_gpio(handle, &pdm_rx_cfg->gpio_cfg), err, TAG, "initialize channel failed while setting gpio pins");
#if SOC_I2S_SUPPORTS_APLL
/* Enable APLL and acquire its lock when the clock source is APLL */
if (pdm_rx_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) {

Wyświetl plik

@ -75,8 +75,11 @@ typedef struct {
* @brief I2S PDM tx mode GPIO pins configuration
*/
typedef struct {
gpio_num_t clk; /*!< PDM clk pin, output */
gpio_num_t din; /*!< DATA pin, input */
gpio_num_t clk; /*!< PDM clk pin, output */
union {
gpio_num_t din; /*!< DATA pin 0, input */
gpio_num_t dins[SOC_I2S_PDM_MAX_RX_LINES]; /*!< DATA pins, input, only take effect when corresponding I2S_PDM_RX_LINEx_SLOT_xxx is enabled in i2s_pdm_rx_slot_config_t::slot_mask */
};
struct {
uint32_t clk_inv: 1; /*!< Set 1 to invert the clk output */
} invert_flags; /*!< GPIO pin invert flags */
@ -280,7 +283,7 @@ typedef struct {
typedef struct {
gpio_num_t clk; /*!< PDM clk pin, output */
gpio_num_t dout; /*!< DATA pin, output */
#if SOC_I2S_HW_VERSION_2
#if SOC_I2S_PDM_MAX_TX_LINES > 1
gpio_num_t dout2; /*!< The second data pin for the DAC dual-line mode,
* only take effect when the line mode is `I2S_PDM_TX_TWO_LINE_DAC`
*/

Wyświetl plik

@ -145,7 +145,7 @@ void i2s_hal_pdm_set_tx_slot(i2s_hal_context_t *hal, bool is_slave, const i2s_ha
i2s_ll_tx_force_enable_fifo_mod(hal->dev, true);
i2s_ll_tx_set_sample_bit(hal->dev, slot_bit_width, slot_cfg->data_bit_width);
i2s_ll_tx_enable_mono_mode(hal->dev, is_mono);
i2s_ll_tx_select_pdm_slot(hal->dev, slot_cfg->pdm_tx.slot_mask, is_mono);
i2s_ll_tx_select_pdm_slot(hal->dev, slot_cfg->pdm_tx.slot_mask & I2S_STD_SLOT_BOTH, is_mono);
i2s_ll_tx_enable_msb_right(hal->dev, false);
i2s_ll_tx_enable_right_first(hal->dev, false);
#elif SOC_I2S_HW_VERSION_2
@ -202,10 +202,15 @@ void i2s_hal_pdm_set_rx_slot(i2s_hal_context_t *hal, bool is_slave, const i2s_ha
#elif SOC_I2S_HW_VERSION_2
i2s_ll_tx_set_half_sample_bit(hal->dev, 16);
i2s_ll_rx_enable_mono_mode(hal->dev, false);
#if SOC_I2S_PDM_MAX_RX_LINES > 1
uint32_t slot_mask = (slot_cfg->slot_mode == I2S_SLOT_MODE_STEREO && slot_cfg->pdm_rx.slot_mask <= I2S_PDM_SLOT_BOTH) ?
I2S_PDM_SLOT_BOTH : slot_cfg->pdm_rx.slot_mask;
#else
/* Set the channel mask to enable corresponding slots, always enable two slots for stereo mode */
i2s_ll_rx_set_active_chan_mask(hal->dev, slot_cfg->slot_mode == I2S_SLOT_MODE_STEREO ?
I2S_PDM_SLOT_BOTH : slot_cfg->pdm_rx.slot_mask);
#endif
uint32_t slot_mask = slot_cfg->slot_mode == I2S_SLOT_MODE_STEREO ? I2S_PDM_SLOT_BOTH : slot_cfg->pdm_rx.slot_mask;
#endif // SOC_I2S_SUPPORTS_PDM_RX > 1
i2s_ll_rx_set_active_chan_mask(hal->dev, slot_mask);
#endif // SOC_I2S_SUPPORTS_PDM_RX
}
void i2s_hal_pdm_enable_rx_channel(i2s_hal_context_t *hal)

Wyświetl plik

@ -141,6 +141,18 @@ typedef enum {
I2S_PDM_SLOT_RIGHT = BIT(0), /*!< I2S PDM only transmits or receives the PDM device whose 'select' pin is pulled up */
I2S_PDM_SLOT_LEFT = BIT(1), /*!< I2S PDM only transmits or receives the PDM device whose 'select' pin is pulled down */
I2S_PDM_SLOT_BOTH = BIT(0) | BIT(1), /*!< I2S PDM transmits or receives both two slots */
#if SOC_I2S_PDM_MAX_RX_LINES > 1
/* The following enumerators are only used in multi-line PDM RX mode */
I2S_PDM_RX_LINE0_SLOT_RIGHT = I2S_PDM_SLOT_RIGHT, /*!< I2S PDM receives the right slot on line 0 */
I2S_PDM_RX_LINE0_SLOT_LEFT = I2S_PDM_SLOT_LEFT, /*!< I2S PDM receives the left slot on line 0 */
I2S_PDM_RX_LINE1_SLOT_RIGHT = BIT(2), /*!< I2S PDM receives the right slot on line 1 */
I2S_PDM_RX_LINE1_SLOT_LEFT = BIT(3), /*!< I2S PDM receives the left slot on line 1 */
I2S_PDM_RX_LINE2_SLOT_RIGHT = BIT(4), /*!< I2S PDM receives the right slot on line 2 */
I2S_PDM_RX_LINE2_SLOT_LEFT = BIT(5), /*!< I2S PDM receives the left slot on line 2 */
I2S_PDM_RX_LINE3_SLOT_RIGHT = BIT(6), /*!< I2S PDM receives the right slot on line 3 */
I2S_PDM_RX_LINE3_SLOT_LEFT = BIT(7), /*!< I2S PDM receives the left slot on line 3 */
I2S_PDM_LINE_SLOT_ALL = 0x00ff, /*!< I2S PDM receives all slots */
#endif
} i2s_pdm_slot_mask_t;
#if SOC_I2S_SUPPORTS_TDM

Wyświetl plik

@ -25,7 +25,6 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
.s_rx_ws_sig = I2S0I_WS_IN_IDX,
.data_out_sig = I2S0O_DATA_OUT23_IDX,
.data_out1_sig = -1,
.data_in_sig = I2S0I_DATA_IN15_IDX,
.irq = ETS_I2S0_INTR_SOURCE,
@ -45,7 +44,6 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
.s_rx_ws_sig = I2S1I_WS_IN_IDX,
.data_out_sig = I2S1O_DATA_OUT23_IDX,
.data_out1_sig = -1,
.data_in_sig = I2S1I_DATA_IN15_IDX,
.irq = ETS_I2S1_INTR_SOURCE,

Wyświetl plik

@ -307,10 +307,18 @@ config SOC_I2S_SUPPORTS_PDM_TX
bool
default y
config SOC_I2S_PDM_MAX_TX_LINES
int
default 1
config SOC_I2S_SUPPORTS_PDM_RX
bool
default y
config SOC_I2S_PDM_MAX_RX_LINES
int
default 1
config SOC_I2S_SUPPORTS_ADC_DAC
bool
default y

Wyświetl plik

@ -187,7 +187,9 @@
#define SOC_I2S_SUPPORTS_APLL (1)
#define SOC_I2S_SUPPORTS_PDM (1)
#define SOC_I2S_SUPPORTS_PDM_TX (1)
#define SOC_I2S_PDM_MAX_TX_LINES (1U)
#define SOC_I2S_SUPPORTS_PDM_RX (1)
#define SOC_I2S_PDM_MAX_RX_LINES (1U)
#define SOC_I2S_SUPPORTS_ADC_DAC (1)
#define SOC_I2S_SUPPORTS_ADC (1)
#define SOC_I2S_SUPPORTS_DAC (1)

Wyświetl plik

@ -24,8 +24,8 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
.s_tx_ws_sig = I2SO_WS_IN_IDX,
.s_rx_ws_sig = I2SI_WS_IN_IDX,
.data_out_sig = I2SO_SD_OUT_IDX,
.data_out1_sig = I2SO_SD1_OUT_IDX,
.data_out_sigs[0] = I2SO_SD_OUT_IDX,
.data_out_sigs[1] = I2SO_SD1_OUT_IDX,
.data_in_sig = I2SI_SD_IN_IDX,
.irq = -1,

Wyświetl plik

@ -383,9 +383,9 @@ config SOC_I2S_SUPPORTS_PDM_TX
bool
default y
config SOC_I2S_SUPPORTS_PDM_CODEC
bool
default y
config SOC_I2S_PDM_MAX_TX_LINES
int
default 2
config SOC_I2S_SUPPORTS_TDM
bool

Wyświetl plik

@ -92,7 +92,7 @@
#define GPIO_SD1_OUT_IDX 56
#define GPIO_SD2_OUT_IDX 57
#define GPIO_SD3_OUT_IDX 58
#define I2SO_SD1_OUT_IDX 59
#define I2SO_SD1_OUT_IDX 59 // Only used in I2S PDM TX mode
#define FSPICLK_IN_IDX 63
#define FSPICLK_OUT_IDX 63
#define FSPIQ_IN_IDX 64

Wyświetl plik

@ -186,7 +186,7 @@
#define SOC_I2S_SUPPORTS_PCM (1)
#define SOC_I2S_SUPPORTS_PDM (1)
#define SOC_I2S_SUPPORTS_PDM_TX (1)
#define SOC_I2S_SUPPORTS_PDM_CODEC (1)
#define SOC_I2S_PDM_MAX_TX_LINES (2)
#define SOC_I2S_SUPPORTS_TDM (1)
/*-------------------------- LEDC CAPS ---------------------------------------*/

Wyświetl plik

@ -24,7 +24,8 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
.s_tx_ws_sig = I2SO_WS_IN_IDX,
.s_rx_ws_sig = I2SI_WS_IN_IDX,
.data_out_sig = I2SO_SD_OUT_IDX,
.data_out_sigs[0] = I2SO_SD_OUT_IDX,
.data_out_sigs[1] = I2SO_SD1_OUT_IDX,
.data_in_sig = I2SI_SD_IN_IDX,
.irq = -1,

Wyświetl plik

@ -315,9 +315,9 @@ config SOC_I2S_SUPPORTS_PDM_TX
bool
default y
config SOC_I2S_SUPPORTS_PDM_CODEC
bool
default y
config SOC_I2S_PDM_MAX_TX_LINES
int
default 2
config SOC_I2S_SUPPORTS_TDM
bool

Wyświetl plik

@ -194,7 +194,7 @@
#define SOC_I2S_SUPPORTS_PCM (1)
#define SOC_I2S_SUPPORTS_PDM (1)
#define SOC_I2S_SUPPORTS_PDM_TX (1)
#define SOC_I2S_SUPPORTS_PDM_CODEC (1)
#define SOC_I2S_PDM_MAX_TX_LINES (2)
#define SOC_I2S_SUPPORTS_TDM (1)
// TODO: IDF-5328 (Copy from esp32c3, need check)

Wyświetl plik

@ -24,8 +24,8 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
.s_tx_ws_sig = I2SO_WS_IN_IDX,
.s_rx_ws_sig = I2SI_WS_IN_IDX,
.data_out_sig = I2SO_SD_OUT_IDX,
.data_out1_sig = I2SO_SD1_OUT_IDX,
.data_out_sigs[0] = I2SO_SD_OUT_IDX,
.data_out_sigs[1] = I2SO_SD1_OUT_IDX,
.data_in_sig = I2SI_SD_IN_IDX,
.irq = ETS_I2S1_INTR_SOURCE,

Wyświetl plik

@ -359,9 +359,9 @@ config SOC_I2S_SUPPORTS_PDM_TX
bool
default y
config SOC_I2S_SUPPORTS_PDM_CODEC
bool
default y
config SOC_I2S_PDM_MAX_TX_LINES
int
default 2
config SOC_I2S_SUPPORTS_TDM
bool

Wyświetl plik

@ -192,7 +192,7 @@
#define SOC_I2S_SUPPORTS_PCM (1)
#define SOC_I2S_SUPPORTS_PDM (1)
#define SOC_I2S_SUPPORTS_PDM_TX (1)
#define SOC_I2S_SUPPORTS_PDM_CODEC (1)
#define SOC_I2S_PDM_MAX_TX_LINES (2)
#define SOC_I2S_SUPPORTS_TDM (1)
/*-------------------------- LEDC CAPS ---------------------------------------*/

Wyświetl plik

@ -25,7 +25,6 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
.s_rx_ws_sig = I2S0I_WS_IN_IDX,
.data_out_sig = I2S0O_DATA_OUT23_IDX,
.data_out1_sig = -1,
.data_in_sig = I2S0I_DATA_IN15_IDX,
.irq = ETS_I2S0_INTR_SOURCE,

Wyświetl plik

@ -24,9 +24,12 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
.s_tx_ws_sig = I2S0O_WS_IN_IDX,
.s_rx_ws_sig = I2S0I_WS_IN_IDX,
.data_out_sig = I2S0O_SD_OUT_IDX,
.data_out1_sig = I2S0O_SD1_OUT_IDX,
.data_in_sig = I2S0I_SD_IN_IDX,
.data_out_sigs[0] = I2S0O_SD_OUT_IDX,
.data_out_sigs[1] = I2S0O_SD1_OUT_IDX,
.data_in_sigs[0] = I2S0I_SD_IN_IDX,
.data_in_sigs[1] = I2S0I_SD1_IN_IDX,
.data_in_sigs[2] = I2S0I_SD2_IN_IDX,
.data_in_sigs[3] = I2S0I_SD3_IN_IDX,
.irq = -1,
.module = PERIPH_I2S0_MODULE,
@ -44,9 +47,12 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
.s_tx_ws_sig = I2S1O_WS_IN_IDX,
.s_rx_ws_sig = I2S1I_WS_IN_IDX,
.data_out_sig = I2S1O_SD_OUT_IDX,
.data_out1_sig = -1,
.data_in_sig = I2S1I_SD_IN_IDX,
.data_out_sigs[0] = I2S1O_SD_OUT_IDX,
.data_out_sigs[1] = -1,
.data_in_sigs[0] = I2S1I_SD_IN_IDX,
.data_in_sigs[1] = -1,
.data_in_sigs[2] = -1,
.data_in_sigs[3] = -1,
.irq = -1,
.module = PERIPH_I2S1_MODULE,

Wyświetl plik

@ -447,13 +447,17 @@ config SOC_I2S_SUPPORTS_PDM_TX
bool
default y
config SOC_I2S_PDM_MAX_TX_LINES
int
default 2
config SOC_I2S_SUPPORTS_PDM_RX
bool
default y
config SOC_I2S_SUPPORTS_PDM_CODEC
bool
default y
config SOC_I2S_PDM_MAX_RX_LINES
int
default 4
config SOC_I2S_SUPPORTS_TDM
bool

Wyświetl plik

@ -1,16 +1,8 @@
// Copyright 2017-2021 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* SPDX-FileCopyrightText: 2017-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _SOC_GPIO_SIG_MAP_H_
#define _SOC_GPIO_SIG_MAP_H_
@ -113,11 +105,11 @@
#define BB_DIAG14_IDX 49
#define GPIO_BT_PRIORITY_IDX 50
#define BB_DIAG15_IDX 50
#define I2S0I_SD1_IN_IDX 51
#define I2S0I_SD1_IN_IDX 51 // Only used in I2S PDM RX mode
#define BB_DIAG16_IDX 51
#define I2S0I_SD2_IN_IDX 52
#define I2S0I_SD2_IN_IDX 52 // Only used in I2S PDM RX mode
#define BB_DIAG17_IDX 52
#define I2S0I_SD3_IN_IDX 53
#define I2S0I_SD3_IN_IDX 53 // Only used in I2S PDM RX mode
#define BB_DIAG18_IDX 53
#define CORE1_GPIO_IN7_IDX 54
#define CORE1_GPIO_OUT7_IDX 54
@ -232,7 +224,7 @@
#define SUBSPICS1_OUT_IDX 125
#define FSPIDQS_OUT_IDX 126
#define SPI3_CS2_OUT_IDX 127
#define I2S0O_SD1_OUT_IDX 128
#define I2S0O_SD1_OUT_IDX 128 // Only used in I2S PDM TX mode
#define CORE1_GPIO_IN0_IDX 129
#define CORE1_GPIO_OUT0_IDX 129
#define CORE1_GPIO_IN1_IDX 130

Wyświetl plik

@ -187,8 +187,9 @@
#define SOC_I2S_SUPPORTS_PCM (1)
#define SOC_I2S_SUPPORTS_PDM (1)
#define SOC_I2S_SUPPORTS_PDM_TX (1)
#define SOC_I2S_PDM_MAX_TX_LINES (2)
#define SOC_I2S_SUPPORTS_PDM_RX (1)
#define SOC_I2S_SUPPORTS_PDM_CODEC (1)
#define SOC_I2S_PDM_MAX_RX_LINES (4)
#define SOC_I2S_SUPPORTS_TDM (1)
/*-------------------------- LEDC CAPS ---------------------------------------*/

Wyświetl plik

@ -31,9 +31,19 @@ typedef struct {
const uint8_t s_tx_ws_sig;
const uint8_t s_rx_ws_sig;
const uint8_t data_out_sig;
const uint8_t data_out1_sig; // Only valid in version 2
const uint8_t data_in_sig;
union {
const uint8_t data_out_sig;
#if SOC_I2S_PDM_MAX_TX_LINES
const uint8_t data_out_sigs[SOC_I2S_PDM_MAX_TX_LINES]; // Only valid in version 2
#endif
};
union {
const uint8_t data_in_sig;
#if SOC_I2S_PDM_MAX_RX_LINES
const uint8_t data_in_sigs[SOC_I2S_PDM_MAX_RX_LINES];
#endif
};
const uint8_t irq;
const periph_module_t module;

Wyświetl plik

@ -135,7 +135,7 @@ Standard mode always has left and right two sound channels which are called 'slo
PDM Mode (TX)
^^^^^^^^^^^^^
PDM(Pulse-density Modulation) mode for tx channel can convert PCM data into PDM format which always has left and right slots. PDM TX can only support 16 bits width sample data. PDM TX only needs CLK pin for clock signal and DOUT pin for data signal (i.e. WS and SD signal in the following figure, the BCK signal is an internal bit sampling clock, not needed between PDM devices). This mode allows user to configure the up-sampling parameters :cpp:member:`i2s_pdm_tx_clk_config_t::up_sample_fp` :cpp:member:`i2s_pdm_tx_clk_config_t::up_sample_fs`. The up-sampling rate can be calculated by ``up_sample_rate = fp / fs``, there are up-sampling modes in PDM TX:
PDM(Pulse-density Modulation) mode for tx channel can convert PCM data into PDM format which always has left and right slots. PDM TX can only support 16 bits width sample data. PDM TX is only supported on I2S0, it needs at least a CLK pin for clock signal and a DOUT pin for data signal (i.e. WS and SD signal in the following figure, the BCK signal is an internal bit sampling clock, not needed between PDM devices). This mode allows user to configure the up-sampling parameters :cpp:member:`i2s_pdm_tx_clk_config_t::up_sample_fp` :cpp:member:`i2s_pdm_tx_clk_config_t::up_sample_fs`. The up-sampling rate can be calculated by ``up_sample_rate = fp / fs``, there are up-sampling modes in PDM TX:
- **Fixed Clock Frequency**: In this mode the up-sampling rate will change according to the sample rate. Setting ``fp = 960`` and ``fs = sample_rate / 100``, then the clock frequency(Fpdm) on CLK pin will be fixed to 128 * 48 KHz = 6.144 MHz, note that this frequency is not equal to the sample rate(Fpcm).
- **Fixed Up-sampling Rate**: In this mode the up-sampling rate is fixed to 2. Setting ``fp = 960`` and ``fs = 480``, then the clock frequency(Fpdm) on CLK pin will be ``128 * sample_rate``
@ -148,7 +148,7 @@ Standard mode always has left and right two sound channels which are called 'slo
PDM Mode (RX)
^^^^^^^^^^^^^
PDM(Pulse-density Modulation) mode for rx channel can receive PDM format data and convert the data into PCM format. PDM RX can only support 16 bits width sample data. PDM RX only need WS pin for clock signal and DIN pin for data signal. This mode allows user to configure the down-sampling parameter :cpp:member:`i2s_pdm_rx_clk_config_t::dn_sample_mode`, there are two down-sampling modes in 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, it can only support 16 bits width sample data. PDM RX needs at least a CLK pin for clock signal and a DIN pin for data signal. This mode allows user to configure the down-sampling parameter :cpp:member:`i2s_pdm_rx_clk_config_t::dn_sample_mode`, there are two down-sampling modes in PDM RX:
- :cpp:enumerator:`i2s_pdm_dsr_t::I2S_PDM_DSR_8S`: In this mode, the clock frequency(Fpdm) on WS pin will be sample_rate(Fpcm) * 64.
- :cpp:enumerator:`i2s_pdm_dsr_t::I2S_PDM_DSR_16S`: In this mode, the clock frequency(Fpdm) on WS pin will be sample_rate(Fpcm) * 128.
@ -343,7 +343,7 @@ Here is the table of the real data on the line with different :cpp:member:`i2s_s
Similar for 8-bit and 32-bit data width, the type of the buffer is better to be ``uint8_t`` and ``uint32_t`` type. But specially, when the data width is 24-bit, the data buffer should aligned with 3-byte(i.e. every 3 bytes stands for a 24-bit data in one slot), additionally, :cpp:member:`i2s_chan_config_t::dma_frame_num`, :cpp:member:`i2s_std_clk_config_t::mclk_multiple` and the writting buffer size should be the multiple of ``3``, otherwise the data on the line or the sample rate will be incorrect.
.. only:: esp32c3 or esp32s3 or esp32h2
.. only:: not (esp32 or esp32s2)
+----------------+-----------+-----------+----------+----------+----------+----------+----------+----------+----------+----------+
| data bit width | slot mode | slot mask | ws low | ws high | ws low | ws high | ws low | ws high | ws low | ws high |
@ -464,7 +464,7 @@ Here is the table of the data that received in the buffer with different :cpp:me
``8-bit``, ``24-bit`` and ``32-bit`` are similar as ``16-bit``, the data bit-width in the receiving buffer are equal to the data bit-width on the line. Additionally, when using ``24-bit`` data width, :cpp:member:`i2s_chan_config_t::dma_frame_num`, :cpp:member:`i2s_std_clk_config_t::mclk_multiple` and the receiving buffer size should be the multiple of ``3``, otherwise the data on the line or the sample rate will be incorrect.
.. only:: esp32c3 or esp32s3 or esp32h2
.. only:: not (esp32 or esp32s2)
+----------------+-----------+-----------+----------+----------+----------+----------+----------+----------+----------+----------+
| data bit width | slot mode | slot mask | data 0 | data 1 | data 2 | data 3 | data 4 | data 5 | data 6 | data 7 |
@ -569,7 +569,7 @@ Here is the table of the data that received in the buffer with different :cpp:me
| | both | 0x0001 | 0x0002 | 0x0003 | 0x0004 | 0x0005 | 0x0006 | 0x0007 | 0x0008 |
+-----------+-----------+----------+----------+----------+----------+----------+----------+----------+----------+
.. only:: esp32c3 or esp32s3 or esp32h2
.. only:: not esp32
Here is the table of the real data on the line with different :cpp:member:`i2s_pdm_tx_slot_config_t::slot_mode` and :cpp:member:`i2s_pdm_tx_slot_config_t::line_mode` (The PDM format on the line is transferred to PCM format for easier comprehension).
@ -676,6 +676,8 @@ Here is the table of the data that received in the buffer with different :cpp:me
The right slot is received first in stereo mode. To switch the left and right slot in the buffer, please set the :cpp:member:`i2s_pdm_rx_gpio_config_t::invert_flags::clk_inv` to force invert the clock signal.
Specially, ESP32-S3 can support up to 4 data lines in PDM RX mode, each data line can be connected to two PDM MICs (left and right slots), which means the PDM RX on ESP32-S3 can support up to 8 PDM MICs. To enable multiple data lines, set the bits in :cpp:member:`i2s_pdm_rx_gpio_config_t::slot_mask` to enable corresponding slots first, and then set the data GPIOs in :cpp:type:`i2s_pdm_rx_gpio_config_t`.
.. code-block:: c
#include "driver/i2s_pdm.h"

Wyświetl plik

@ -80,8 +80,8 @@ examples/peripherals/i2s/i2s_codec/i2s_es8311:
reason: target esp32c6 is not supported yet
examples/peripherals/i2s/i2s_recorder:
disable:
- if: SOC_I2S_SUPPORTS_PDM_RX != 1
enable:
- if: SOC_I2S_SUPPORTS_PDM_RX > 0
examples/peripherals/lcd/i2c_oled:
disable:

Wyświetl plik

@ -18,7 +18,7 @@ This example is going to show how to use the PDM TX and RX mode.
#### PDM RX
* A PDM microphone whose `sel` pin is supposed to be pulled down, and connecting its `clk` pin to `EXAMPLE_PDM_RX_CLK_IO`, `data` pin to `EXAMPLE_PDM_RX_DIN_IO`.
* For non-ESP32-S3 SoC, a PDM microphone whose `sel` pin is supposed to be pulled down, and connecting its `clk` pin to `EXAMPLE_PDM_RX_CLK_IO`, `data` pin to `EXAMPLE_PDM_RX_DIN_IO`.
```
┌───────────────────────┐ ┌──────────────────┐
@ -36,6 +36,66 @@ This example is going to show how to use the PDM TX and RX mode.
└───────────────────────┘ └──────────────────┘
```
* For ESP32-S3 SoC, this example shows how to support 8 PDM microphones, in this case, the connection can be:
```
┌──────────────────┐ ┌─────────────────────────┐ ┌──────────────────┐
│ PDM microphone3 │ │ ESP │ │ PDM microphone1 │
│ │ PDM clock │ │ PDM clock │ │
│ CLK │◄───┬───────────────────┤ EXAMPLE_PDM_RX_CLK_IO ├───────────────────┬───►│ CLK │
│ │ │ │ │ │ │ │
│ DATA ├────┼────┐ │ EXAMPLE_PDM_RX_DIN_IO │◄─────────────┬────┼────┤ DATA │
│ │ │ │ │ │ │ │ │ │
│ SEL ├────┼────┼─────────┐ │ │ ┌─────────┼────┼────┤ SEL │
│ │ │ │ │ │ │ │ │ │ │ │
│ GND ├────┼────┼────┐ │ │ │ │ ┌────┼────┼────┤ GND │
│ │ │ │ │ │ │ │ │ │ │ │ │ │
│ VCC ├────┼────┼────┼────┤ │ │ ├────┼────┼────┼────┤ VCC │
└──────────────────┘ │ │ │ │ │ │ │ │ │ │ └──────────────────┘
│ │ │ │ │ │ │ │ │ │
┌──────────────────┐ │ │ │ │ │ │ │ │ │ │ ┌──────────────────┐
│ PDM microphone4 │ │ │ │ │ │ │ │ │ │ │ │ PDM microphone2 │
│ │ │ │ │ │ │ │ │ │ │ │ │ │
│ CLK │◄───┤ │ │ │ │ │ │ │ │ ├───►│ CLK │
│ │ │ │ │ │ │ │ │ │ │ │ │ │
│ DATA ├────┼────┴────┼────┼───►│ EXAMPLE_PDM_RX_DIN1_IO │ │ │ └────┼────┤ DATA │
│ │ │ │ │ │ │ │ │ │ │ │
│ SEL ├────┼─────────┤ │ │ │ │ ├─────────┼────┤ SEL │
│ │ │ │ │ │ │ │ │ │ │ │
│ GND ├────┼─────────┤ │ │ │ │ ├─────────┼────┤ GND │
│ │ │ │ │ │ │ │ │ │ │ │
│ VCC ├────┼─────────┼────┤ │ │ ├────┼─────────┼────┤ VCC │
└──────────────────┘ │ │ │ │ │ │ │ │ └──────────────────┘
│ │ │ │ │ │ │ │
┌──────────────────┐ │ │ │ │ │ │ │ │ ┌──────────────────┐
│ PDM microphone7 │ │ │ │ │ │ │ │ │ │ PDM microphone5 │
│ │ │ │ │ │ │ │ │ │ │ │
│ CLK │◄───┤ │ │ │ │ │ │ ├───►│ CLK │
│ │ │ │ │ │ │ │ │ │ │ │
│ DATA ├────┼────┐ │ │ │ EXAMPLE_PDM_RX_DIN2_IO │◄───┼────┼────┬────┼────┤ DATA │
│ │ │ │ │ │ │ │ │ │ │ │ │ │
│ SEL ├────┼────┼────┼────┤ │ │ ├────┼────┼────┼────┤ SEL │
│ │ │ │ │ │ │ │ │ │ │ │ │ │
│ GND ├────┼────┼────┤ │ │ │ │ ├────┼────┼────┤ GND │
│ │ │ │ │ │ │ │ │ │ │ │ │ │
│ VCC ├────┼────┼────┼────┤ │ │ ├────┼────┼────┼────┤ VCC │
└──────────────────┘ │ │ │ │ │ │ │ │ │ │ └──────────────────┘
│ │ │ │ │ │ │ │ │ │
┌──────────────────┐ │ │ │ │ │ │ │ │ │ │ ┌──────────────────┐
│ PDM microphone8 │ │ │ │ │ │ │ │ │ │ │ │ PDM microphone6 │
│ │ │ │ │ │ │ │ │ │ │ │ │ │
│ CLK │◄───┘ │ │ │ │ │ │ │ │ └───►│ CLK │
│ │ │ │ │ │ │ │ │ │ │ │
│ DATA ├─────────┴────┼────┼───►│ EXAMPLE_PDM_RX_DIN3_IO │ │ │ └─────────┤ DATA │
│ │ │ │ │ │ │ │ │ │
│ SEL ├──────────────┤ │ │ │ │ ├──────────────┤ SEL │
│ │ │ │ │ │ │ │ │ │
│ GND ├──────────────┴────┼────┤ GND ├────┼────┴──────────────┤ GND │
│ │ │ │ │ │ │ │
│ VCC ├───────────────────┴────┤ VCC ├────┴───────────────────┤ VCC │
└──────────────────┘ └─────────────────────────┘ └──────────────────┘
```
#### PDM TX
* An earphone or a speaker

Wyświetl plik

@ -15,7 +15,12 @@
#include "i2s_pdm_example.h"
#define EXAMPLE_PDM_RX_CLK_IO GPIO_NUM_0 // I2S PDM RX clock io number
#define EXAMPLE_PDM_RX_DIN_IO GPIO_NUM_2 // I2S PDM RX data in io number
#define EXAMPLE_PDM_RX_DIN_IO GPIO_NUM_4 // I2S PDM RX data in io number
#if CONFIG_IDF_TARGET_ESP32S3
#define EXAMPLE_PDM_RX_DIN1_IO GPIO_NUM_5 // I2S PDM RX data line1 in io number
#define EXAMPLE_PDM_RX_DIN2_IO GPIO_NUM_6 // I2S PDM RX data line2 in io number
#define EXAMPLE_PDM_RX_DIN3_IO GPIO_NUM_7 // I2S PDM RX data line3 in io number
#endif
#define EXAMPLE_PDM_RX_FREQ_HZ 16000 // I2S PDM RX frequency
@ -39,12 +44,27 @@ static i2s_chan_handle_t i2s_example_init_pdm_rx(void)
.slot_cfg = I2S_PDM_RX_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO),
.gpio_cfg = {
.clk = EXAMPLE_PDM_RX_CLK_IO,
#if CONFIG_IDF_TARGET_ESP32S3
// Only ESP32-S3 can support 4-line PDM RX
.dins = {
EXAMPLE_PDM_RX_DIN_IO,
EXAMPLE_PDM_RX_DIN1_IO,
EXAMPLE_PDM_RX_DIN2_IO,
EXAMPLE_PDM_RX_DIN3_IO,
},
#else
.din = EXAMPLE_PDM_RX_DIN_IO,
#endif
.invert_flags = {
.clk_inv = false,
},
},
};
#if CONFIG_IDF_TARGET_ESP32S3
// Enable all slots for example
pdm_rx_cfg.slot_cfg.slot_mode = I2S_SLOT_MODE_STEREO;
pdm_rx_cfg.slot_cfg.slot_mask = I2S_PDM_LINE_SLOT_ALL;
#endif
ESP_ERROR_CHECK(i2s_channel_init_pdm_rx_mode(rx_chan, &pdm_rx_cfg));
/* Step 3: Enable the rx channels before reading data */

Wyświetl plik

@ -1101,7 +1101,6 @@ components/soc/esp32s3/include/soc/extmem_struct.h
components/soc/esp32s3/include/soc/fe_reg.h
components/soc/esp32s3/include/soc/gpio_pins.h
components/soc/esp32s3/include/soc/gpio_reg.h
components/soc/esp32s3/include/soc/gpio_sig_map.h
components/soc/esp32s3/include/soc/hinf_reg.h
components/soc/esp32s3/include/soc/hinf_struct.h
components/soc/esp32s3/include/soc/host_reg.h