From d51b85989b4b5d7611341535d44b435363453f99 Mon Sep 17 00:00:00 2001 From: laokaiyao Date: Thu, 17 Jun 2021 18:49:44 +0800 Subject: [PATCH] doc/i2s: update i2s programming guide on s3 & c3 --- components/driver/i2s.c | 95 +- components/driver/include/driver/i2s.h | 60 +- components/driver/test/test_i2s.c | 4 +- components/hal/CMakeLists.txt | 2 +- components/hal/esp32/include/hal/i2s_ll.h | 8 +- components/hal/esp32c3/include/hal/i2s_ll.h | 41 +- components/hal/esp32h2/include/hal/i2s_ll.h | 885 +++++++----------- components/hal/esp32s2/include/hal/i2s_ll.h | 8 +- components/hal/esp32s3/include/hal/i2s_ll.h | 40 +- components/hal/i2s_hal.c | 44 +- components/hal/include/hal/i2s_hal.h | 54 +- components/hal/include/hal/i2s_types.h | 27 +- components/soc/esp32/include/soc/soc_caps.h | 1 - components/soc/esp32c3/i2s_periph.c | 1 + components/soc/esp32c3/include/soc/soc_caps.h | 1 - components/soc/esp32h2/include/soc/soc_caps.h | 5 +- .../soc/esp32h2/ld/esp32h2.peripherals.ld | 2 +- components/soc/esp32s3/i2s_periph.c | 2 + components/soc/esp32s3/include/soc/soc_caps.h | 1 - docs/en/api-reference/peripherals/i2s.rst | 295 ++++-- 20 files changed, 722 insertions(+), 854 deletions(-) diff --git a/components/driver/i2s.c b/components/driver/i2s.c index 645b4c253f..5857e67bd6 100644 --- a/components/driver/i2s.c +++ b/components/driver/i2s.c @@ -14,12 +14,13 @@ #include "freertos/semphr.h" #include "soc/lldesc.h" +#include "driver/periph_ctrl.h" #include "driver/gpio.h" #include "driver/i2s.h" #include "hal/gpio_hal.h" +#include "hal/i2s_hal.h" #if SOC_I2S_SUPPORTS_ADC_DAC #include "driver/dac.h" -#include "hal/i2s_hal.h" #include "adc1_private.h" #endif @@ -138,22 +139,6 @@ static void gpio_matrix_in_check_and_set(int gpio, uint32_t signal_idx, bool inv } } -#if SOC_I2S_SUPPORTS_PCM -esp_err_t i2s_pcm_config(i2s_port_t i2s_num, i2s_mode_t mode, i2s_pcm_mode_t pcm_cfg) -{ - ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); - - if (mode & I2S_MODE_TX) { - i2s_hal_tx_pcm_cfg(&(p_i2s[i2s_num]->hal), pcm_cfg); - } else if (mode & I2S_MODE_RX) { - i2s_hal_rx_pcm_cfg(&(p_i2s[i2s_num]->hal), pcm_cfg); - } else { - return ESP_ERR_INVALID_ARG; - } - return ESP_OK; -} -#endif - float i2s_get_clk(i2s_port_t i2s_num) { ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); @@ -428,7 +413,6 @@ static esp_err_t i2s_fbclk_cal(int i2s_num, uint32_t rate, int channel, int chan } #endif // SOC_I2S_SUPPORTS_ADC_DAC -#if SOC_I2S_SUPPORTS_PDM if ( p_i2s[i2s_num]->mode & I2S_MODE_PDM) { #if SOC_I2S_SUPPORTS_PDM_TX if ( p_i2s[i2s_num]->mode & I2S_MODE_TX) { @@ -447,7 +431,6 @@ static esp_err_t i2s_fbclk_cal(int i2s_num, uint32_t rate, int channel, int chan #endif // SOC_I2S_SUPPORTS_PDM_RX _bck_div = 8; } -#endif // SOC_I2S_SUPPORTS_PDM #if SOC_I2S_SUPPORTS_APLL int sdm0 = 0; @@ -487,7 +470,7 @@ static uint32_t i2s_get_active_chan_num(i2s_hal_config_t *hal_cfg) case I2S_CHANNEL_FMT_TDM: { uint32_t num = 0; uint32_t max_chan = 0; - uint32_t chan_mask = hal_cfg->chan_cfg.chan_mask; + uint32_t chan_mask = hal_cfg->chan_mask; for (int i = 0; chan_mask && i < 16; i++, chan_mask >>= 1) { if ((chan_mask & 0x01) == 1) { @@ -495,10 +478,9 @@ static uint32_t i2s_get_active_chan_num(i2s_hal_config_t *hal_cfg) max_chan = i + 1; } } - if (max_chan > hal_cfg->chan_cfg.total_chan) { - hal_cfg->chan_cfg.total_chan = max_chan; + if (max_chan > hal_cfg->total_chan) { + hal_cfg->total_chan = max_chan; } - hal_cfg->chan_cfg.active_chan = num; return num; } #endif @@ -514,9 +496,9 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_ i2s_hal_config_t *cfg = &p_i2s[i2s_num]->hal_cfg; int data_bits = 0; - int slot_bits = 0; - int active_slot_num = 0; - int slot_num = 0; + int chan_bits = 0; + int active_chan_num = 0; + int chan_num = 0; cfg->ch = ch; cfg->sample_rate = rate; @@ -524,16 +506,16 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_ cfg->bits_cfg.chan_bits = cfg->bits_cfg.chan_bits < cfg->bits_cfg.sample_bits ? cfg->bits_cfg.sample_bits : cfg->bits_cfg.chan_bits; - slot_bits = cfg->bits_cfg.chan_bits; + chan_bits = cfg->bits_cfg.chan_bits; data_bits = cfg->bits_cfg.sample_bits; #if SOC_I2S_SUPPORTS_TDM - cfg->chan_cfg.chan_mask = ch & 0xFFFF; - active_slot_num = i2s_get_active_chan_num(cfg); - slot_num = cfg->chan_cfg.total_chan; + cfg->chan_mask = ch & 0xFFFF; + active_chan_num = i2s_get_active_chan_num(cfg); + chan_num = cfg->total_chan; #else - active_slot_num = i2s_get_active_chan_num(cfg); - slot_num = ch == I2S_CHANNEL_MONO ? 2 : active_slot_num; + active_chan_num = i2s_get_active_chan_num(cfg); + chan_num = ch == I2S_CHANNEL_MONO ? 2 : active_chan_num; #endif ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); @@ -551,7 +533,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_ xSemaphoreTake(p_i2s[i2s_num]->rx->mux, (portTickType)portMAX_DELAY); } //malloc DMA buffer - if (i2s_alloc_dma_buffer(i2s_num, data_bits, active_slot_num) != ESP_OK ) { + if (i2s_alloc_dma_buffer(i2s_num, data_bits, active_chan_num) != ESP_OK ) { return ESP_ERR_NO_MEM; } @@ -559,13 +541,13 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_ uint32_t i2s_bck = 0; // I2S back clock uint32_t bck_div = 0; // I2S bck div //calculate bck_div, f_bck and select source clock - if (i2s_fbclk_cal(i2s_num, rate, slot_num, slot_bits, &i2s_clk, &i2s_bck, &bck_div) != ESP_OK) { + if (i2s_fbclk_cal(i2s_num, rate, chan_num, chan_bits, &i2s_clk, &i2s_bck, &bck_div) != ESP_OK) { return ESP_FAIL; } //configure i2s clock if (p_i2s[i2s_num]->mode & I2S_MODE_TX) { i2s_hal_tx_clock_config(&(p_i2s[i2s_num]->hal), i2s_clk, i2s_bck, bck_div); - i2s_hal_set_tx_sample_bit(&(p_i2s[i2s_num]->hal), slot_bits, data_bits); + i2s_hal_set_tx_sample_bit(&(p_i2s[i2s_num]->hal), chan_bits, data_bits); // wait all writing on-going finish if (p_i2s[i2s_num]->tx) { xSemaphoreGive(p_i2s[i2s_num]->tx->mux); @@ -573,7 +555,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_ } if (p_i2s[i2s_num]->mode & I2S_MODE_RX) { i2s_hal_rx_clock_config(&(p_i2s[i2s_num]->hal), i2s_clk, i2s_bck, bck_div); - i2s_hal_set_rx_sample_bit(&(p_i2s[i2s_num]->hal), slot_bits, data_bits); + i2s_hal_set_rx_sample_bit(&(p_i2s[i2s_num]->hal), chan_bits, data_bits); // wait all writing on-going finish if (p_i2s[i2s_num]->rx) { xSemaphoreGive(p_i2s[i2s_num]->rx->mux); @@ -1002,11 +984,9 @@ static esp_err_t i2s_check_cfg_static(i2s_port_t i2s_num) ESP_RETURN_ON_FALSE(!((cfg->mode & I2S_MODE_DAC_BUILT_IN) && (i2s_num != I2S_NUM_0)), ESP_ERR_INVALID_ARG, TAG, "I2S DAC built-in only support on I2S0"); return ESP_OK; #endif -#if SOC_I2S_SUPPORTS_PDM //We only check if the I2S number is invalid when set to PDM mode. ESP_RETURN_ON_FALSE(!((cfg->mode & I2S_MODE_PDM) && (i2s_num != I2S_NUM_0)), ESP_ERR_INVALID_ARG, TAG, "I2S DAC PDM only support on I2S0"); return ESP_OK; -#endif ESP_RETURN_ON_FALSE(cfg->comm_fmt && (cfg->comm_fmt < I2S_COMM_FORMAT_STAND_MAX), ESP_ERR_INVALID_ARG, TAG, "invalid communication formats"); ESP_RETURN_ON_FALSE(!((cfg->comm_fmt & I2S_COMM_FORMAT_STAND_MSB) && (cfg->comm_fmt & I2S_COMM_FORMAT_STAND_PCM_LONG)), ESP_ERR_INVALID_ARG, TAG, "multiple communication formats specified"); @@ -1096,29 +1076,30 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, p_i2s[i2s_num]->hal_cfg.comm_fmt = i2s_config->communication_format; p_i2s[i2s_num]->hal_cfg.chan_fmt = i2s_config->channel_format; p_i2s[i2s_num]->hal_cfg.bits_cfg.sample_bits = i2s_config->bits_per_sample; - p_i2s[i2s_num]->hal_cfg.bits_cfg.chan_bits = i2s_config->bits_per_slot; + p_i2s[i2s_num]->hal_cfg.bits_cfg.chan_bits = i2s_config->bits_per_chan; #if SOC_I2S_SUPPORTS_TDM + int active_chan = 0; switch (i2s_config->channel_format) { case I2S_CHANNEL_FMT_RIGHT_LEFT: case I2S_CHANNEL_FMT_ALL_RIGHT: case I2S_CHANNEL_FMT_ALL_LEFT: - p_i2s[i2s_num]->hal_cfg.chan_cfg.chan_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1; - p_i2s[i2s_num]->hal_cfg.chan_cfg.active_chan = 2; - p_i2s[i2s_num]->hal_cfg.chan_cfg.total_chan = 2; + p_i2s[i2s_num]->hal_cfg.chan_mask = I2S_TDM_ACTIVE_CH0 | I2S_TDM_ACTIVE_CH1; + p_i2s[i2s_num]->hal_cfg.total_chan = 2; + active_chan = 2; break; case I2S_CHANNEL_FMT_ONLY_RIGHT: - p_i2s[i2s_num]->hal_cfg.chan_cfg.chan_mask = i2s_config->tdm_flags.left_align_en ? I2S_TDM_ACTIVE_CH1 : I2S_TDM_ACTIVE_CH0; - p_i2s[i2s_num]->hal_cfg.chan_cfg.active_chan = 1; - p_i2s[i2s_num]->hal_cfg.chan_cfg.total_chan = 1; + p_i2s[i2s_num]->hal_cfg.chan_mask = i2s_config->tdm_flags.left_align_en ? I2S_TDM_ACTIVE_CH1 : I2S_TDM_ACTIVE_CH0; + p_i2s[i2s_num]->hal_cfg.total_chan = 1; + active_chan = 1; break; case I2S_CHANNEL_FMT_ONLY_LEFT: - p_i2s[i2s_num]->hal_cfg.chan_cfg.chan_mask = i2s_config->tdm_flags.left_align_en ? I2S_TDM_ACTIVE_CH0 : I2S_TDM_ACTIVE_CH1; - p_i2s[i2s_num]->hal_cfg.chan_cfg.active_chan = 1; - p_i2s[i2s_num]->hal_cfg.chan_cfg.total_chan = 1; + p_i2s[i2s_num]->hal_cfg.chan_mask = i2s_config->tdm_flags.left_align_en ? I2S_TDM_ACTIVE_CH0 : I2S_TDM_ACTIVE_CH1; + p_i2s[i2s_num]->hal_cfg.total_chan = 1; + active_chan = 1; break; case I2S_CHANNEL_FMT_TDM: - ESP_RETURN_ON_FALSE((i2s_config->tdm_chan_cfg.chan_mask != 0), ESP_ERR_INVALID_ARG, TAG, "i2s all channel are disabled"); - p_i2s[i2s_num]->hal_cfg.chan_cfg.chan_mask = i2s_config->tdm_chan_cfg.chan_mask; + ESP_RETURN_ON_FALSE((i2s_config->chan_mask != 0), ESP_ERR_INVALID_ARG, TAG, "i2s all channel are disabled"); + p_i2s[i2s_num]->hal_cfg.chan_mask = i2s_config->chan_mask; i2s_get_active_chan_num(&p_i2s[i2s_num]->hal_cfg); break; default: @@ -1138,6 +1119,18 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, p_i2s[i2s_num]->dma_buf_count = i2s_config->dma_buf_count; p_i2s[i2s_num]->dma_buf_len = i2s_config->dma_buf_len; +#if SOC_I2S_SUPPORTS_PCM + // Set PCM compress type for PCM communication mode + if (p_i2s[i2s_num]->communication_format & I2S_COMM_FORMAT_STAND_PCM_SHORT) { + if (p_i2s[i2s_num]->mode & I2S_MODE_TX) { + i2s_hal_tx_pcm_cfg(&(p_i2s[i2s_num]->hal), i2s_config->pcm_compress_type); + } + if (p_i2s[i2s_num]->mode & I2S_MODE_RX) { + i2s_hal_rx_pcm_cfg(&(p_i2s[i2s_num]->hal), i2s_config->pcm_compress_type); + } + } +#endif // SOC_I2S_SUPPORTS_PCM + #ifdef CONFIG_PM_ENABLE if (i2s_config->use_apll) { ret = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "i2s_driver", &p_i2s[i2s_num]->pm_lock); @@ -1198,7 +1191,7 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, #if SOC_I2S_SUPPORTS_TDM ret = i2s_set_clk(i2s_num, i2s_config->sample_rate, p_i2s[i2s_num]->hal_cfg.bits_cfg.val, - (i2s_channel_t)p_i2s[i2s_num]->hal_cfg.chan_cfg.active_chan); + (i2s_channel_t)active_chan); #else ret = i2s_set_clk(i2s_num, i2s_config->sample_rate, p_i2s[i2s_num]->hal_cfg.bits_cfg.val, diff --git a/components/driver/include/driver/i2s.h b/components/driver/include/driver/i2s.h index 04b0ed30d7..5ec6f2841a 100644 --- a/components/driver/include/driver/i2s.h +++ b/components/driver/include/driver/i2s.h @@ -13,9 +13,7 @@ #include "soc/i2s_periph.h" #include "soc/rtc_periph.h" #include "soc/soc_caps.h" -#include "hal/i2s_hal.h" #include "hal/i2s_types.h" -#include "driver/periph_ctrl.h" #include "esp_intr_alloc.h" #if SOC_I2S_SUPPORTS_ADC_DAC @@ -50,9 +48,15 @@ typedef struct { int data_in_num; /*!< DATA in pin*/ } i2s_pin_config_t; -#if SOC_I2S_SUPPORTS_TDM -typedef i2s_hal_chan_cfg_t tdm_chan_cfg_t; -typedef i2s_hal_tdm_flags_t tdm_flags_t; +#if SOC_I2S_SUPPORTS_PCM +/** + * @brief I2S PCM configuration + * + */ +typedef struct { + i2s_pcm_compress_t pcm_mode; /*!< I2S PCM a/u-law decompress or compress mode */ +} i2s_pcm_cfg_t; + #endif /** @@ -72,15 +76,30 @@ typedef struct { bool use_apll; /*!< I2S using APLL as main I2S clock, enable it to get accurate clock */ bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor if there is underflow condition (helps in avoiding noise in case of data unavailability) */ int fixed_mclk; /*!< I2S using fixed MCLK output. If use_apll = true and fixed_mclk > 0, then the clock output for i2s is fixed and equal to the fixed_mclk value.*/ - i2s_bits_per_slot_t bits_per_slot; /*!< I2S total bits in one channel, Should not be smaller than 'bits_per_sample', default '0' means equal to 'bits_per_sample' */ + i2s_bits_per_chan_t bits_per_chan; /*!< I2S total bits in one channel, Should not be smaller than 'bits_per_sample', default '0' means equal to 'bits_per_sample' */ + +#if SOC_I2S_SUPPORTS_PCM + i2s_pcm_compress_t pcm_compress_type; /*!< I2S PCM a/u-law decompress or compress mode. Set this field if `communication_format` is set to `I2S_COMM_FORMAT_STAND_PCM_SHORT` or `I2S_COMM_FORMAT_STAND_PCM_LONG` */ +#endif // SOC_I2S_SUPPORTS_PCM + #if SOC_I2S_SUPPORTS_TDM - tdm_chan_cfg_t tdm_chan_cfg; /*!< I2S TDM channel configurations*/ - tdm_flags_t tdm_flags; /*!< I2S TDM flags*/ -#endif + i2s_channel_t chan_mask; /*!< I2S active channel bit mask, set value in `i2s_channel_t` to enable specific channel, the bit map of active channel can not exceed (0x1< 1 /* ESP32S2 and ESP32C3 has only single I2S port and hence following test cases are not applicable */ TEST_CASE("I2S write and read test(master tx and slave rx)", "[i2s]") { @@ -492,7 +492,7 @@ TEST_CASE("I2S APLL clock variation test", "[i2s]") TEST_ASSERT(initial_size == esp_get_free_heap_size()); } -#if DISABLED_FOR_TARGETS(ESP32) +#if SOC_I2S_SUPPORTS_ADC_DAC /* Only ESP32 need I2S adc/dac test */ TEST_CASE("I2S adc test", "[i2s]") { diff --git a/components/hal/CMakeLists.txt b/components/hal/CMakeLists.txt index b298d44ae8..04802d9f30 100644 --- a/components/hal/CMakeLists.txt +++ b/components/hal/CMakeLists.txt @@ -14,13 +14,13 @@ if(NOT BOOTLOADER_BUILD) "spi_hal_iram.c" "spi_slave_hal.c" "spi_slave_hal_iram.c" - "i2s_hal.c" "sigmadelta_hal.c" "timer_hal.c" "ledc_hal.c" "ledc_hal_iram.c" "i2c_hal.c" "i2c_hal_iram.c" + "i2s_hal.c" "gpio_hal.c" "uart_hal.c" "uart_hal_iram.c" diff --git a/components/hal/esp32/include/hal/i2s_ll.h b/components/hal/esp32/include/hal/i2s_ll.h index 79fa062f1c..eaa74bec20 100644 --- a/components/hal/esp32/include/hal/i2s_ll.h +++ b/components/hal/esp32/include/hal/i2s_ll.h @@ -453,10 +453,10 @@ static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, int eof_num) } /** - * @brief Congfigure TX slot bit and audio data bit, on ESP32, sample_bit should equals to data_bit + * @brief Congfigure TX chan bit and audio data bit, on ESP32, sample_bit should equals to data_bit * * @param hw Peripheral I2S hardware instance address. - * @param sample_bit The slot bit width + * @param sample_bit The chan bit width * @param data_bit The audio data bit width */ static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) @@ -466,10 +466,10 @@ static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i } /** - * @brief Congfigure RX slot bit and audio data bit, on ESP32, sample_bit should equals to data_bit + * @brief Congfigure RX chan bit and audio data bit, on ESP32, sample_bit should equals to data_bit * * @param hw Peripheral I2S hardware instance address. - * @param sample_bit The slot bit width + * @param sample_bit The chan bit width * @param data_bit The audio data bit width */ static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) diff --git a/components/hal/esp32c3/include/hal/i2s_ll.h b/components/hal/esp32c3/include/hal/i2s_ll.h index dc568148af..94eb7d9077 100644 --- a/components/hal/esp32c3/include/hal/i2s_ll.h +++ b/components/hal/esp32c3/include/hal/i2s_ll.h @@ -28,7 +28,6 @@ extern "C" { #endif - #define I2S_LL_GET_HW(num) (&I2S0) #define I2S_LL_TDM_CH_MASK (0xffff) @@ -320,10 +319,10 @@ static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, int eof_num) } /** - * @brief Congfigure TX slot bit and audio data bit + * @brief Congfigure TX chan bit and audio data bit * * @param hw Peripheral I2S hardware instance address. - * @param sample_bit The slot bit width + * @param sample_bit The chan bit width * @param data_bit The audio data bit width */ static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) @@ -333,10 +332,10 @@ static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i } /** - * @brief Congfigure RX slot bit and audio data bit + * @brief Congfigure RX chan bit and audio data bit * * @param hw Peripheral I2S hardware instance address. - * @param sample_bit The slot bit width + * @param sample_bit The chan bit width * @param data_bit The audio data bit width */ static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) @@ -390,52 +389,52 @@ static inline void i2s_ll_rx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enab } /** - * @brief Configure TX total slot number + * @brief Configure TX total chan number * * @param hw Peripheral I2S hardware instance address. - * @param total_num Total slot number + * @param total_num Total chan number */ -static inline void i2s_ll_set_tx_slot_num(i2s_dev_t *hw, int total_num) +static inline void i2s_ll_set_tx_chan_num(i2s_dev_t *hw, int total_num) { hw->tx_tdm_ctrl.tx_tdm_tot_chan_num = total_num - 1; } /** - * @brief Configure RX total slot number + * @brief Configure RX total chan number * * @param hw Peripheral I2S hardware instance address. - * @param total_num Total slot number + * @param total_num Total chan number */ -static inline void i2s_ll_set_rx_slot_num(i2s_dev_t *hw, int total_num) +static inline void i2s_ll_set_rx_chan_num(i2s_dev_t *hw, int total_num) { hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = total_num - 1; } /** - * @brief Set the bimap of the active TX slot, only the active slot can launch audio data. + * @brief Set the bimap of the active TX chan, only the active chan can launch audio data. * * @param hw Peripheral I2S hardware instance address. - * @param slot_mask mask of tx active slot + * @param chan_mask mask of tx active chan */ -static inline void i2s_ll_set_tx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_mask) +static inline void i2s_ll_set_tx_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask) { typeof(hw->tx_tdm_ctrl) tdm_ctrl_reg = hw->tx_tdm_ctrl; tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK; - tdm_ctrl_reg.val |= slot_mask & I2S_LL_TDM_CH_MASK; + tdm_ctrl_reg.val |= chan_mask & I2S_LL_TDM_CH_MASK; hw->tx_tdm_ctrl.val = tdm_ctrl_reg.val; } /** - * @brief Set the bimap of the active RX slot, only the active slot can receive audio data. + * @brief Set the bimap of the active RX chan, only the active chan can receive audio data. * * @param hw Peripheral I2S hardware instance address. - * @param slot_mask mask of rx active slot + * @param chan_mask mask of rx active chan */ -static inline void i2s_ll_set_rx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_mask) +static inline void i2s_ll_set_rx_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask) { typeof(hw->rx_tdm_ctrl) tdm_ctrl_reg = hw->rx_tdm_ctrl; tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK; - tdm_ctrl_reg.val |= slot_mask & I2S_LL_TDM_CH_MASK; + tdm_ctrl_reg.val |= chan_mask & I2S_LL_TDM_CH_MASK; hw->rx_tdm_ctrl.val = tdm_ctrl_reg.val; } @@ -556,7 +555,7 @@ static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool pdm_enable) * @param hw Peripheral I2S hardware instance address. * @param pcm_cfg PCM configuration paramater */ -static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_mode_t pcm_cfg) +static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) { if (pcm_cfg == I2S_PCM_DISABLE) { hw->tx_conf.tx_pcm_bypass = 1; @@ -572,7 +571,7 @@ static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_mode_t pcm_cfg) * @param hw Peripheral I2S hardware instance address. * @param pcm_cfg PCM configuration paramater */ -static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_mode_t pcm_cfg) +static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) { if (pcm_cfg == I2S_PCM_DISABLE) { hw->rx_conf.rx_pcm_bypass = 1; diff --git a/components/hal/esp32h2/include/hal/i2s_ll.h b/components/hal/esp32h2/include/hal/i2s_ll.h index c54d7de83a..056cb5ce55 100644 --- a/components/hal/esp32h2/include/hal/i2s_ll.h +++ b/components/hal/esp32h2/include/hal/i2s_ll.h @@ -21,9 +21,7 @@ // The LL layer for ESP32-S3 I2S register operations #pragma once - #include -#include #include "soc/i2s_periph.h" #include "hal/i2s_types.h" @@ -31,676 +29,657 @@ extern "C" { #endif -// Get I2S hardware instance with giving i2s num -#define I2S_LL_GET_HW(num) (((num) == 0) ? (&I2S0) : NULL) +#define I2S_LL_GET_HW(num) (&I2S0) -#define I2S_INTR_IN_SUC_EOF BIT(9) -#define I2S_INTR_OUT_EOF BIT(12) -#define I2S_INTR_IN_DSCR_ERR BIT(13) -#define I2S_INTR_OUT_DSCR_ERR BIT(14) -#define I2S_INTR_MAX (0xFFFFFFFF) +#define I2S_LL_TDM_CH_MASK (0xffff) +#define I2S_LL_PDM_BCK_FACTOR (64) +#define I2S_LL_BASE_CLK (2*APB_CLK_FREQ) + +#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (9) +#define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1) + +/* I2S clock configuration structure */ +typedef struct { + uint16_t mclk_div; // I2S module clock devider, Fmclk = Fsclk /(mclk_div+b/a) + uint16_t a; + uint16_t b; // The decimal part of module clock devider, the decimal is: b/a + uint16_t bck_div; // The BCK devider, Fbck = Fmclk / bck_div +} i2s_ll_clk_cal_t; /** - * @brief Reset rx fifo + * @brief I2S module general init, enable I2S clock. * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) +static inline void i2s_ll_enable_clock(i2s_dev_t *hw) { - abort(); // TODO ESP32-H2 IDF-2098 - - + hw->tx_clkm_conf.clk_en = 1; } /** - * @brief Reset tx fifo + * @brief Enable I2S tx module clock * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_reset_tx_fifo(i2s_dev_t *hw) +static inline void i2s_ll_enable_tx_clock(i2s_dev_t *hw) { - abort(); // TODO ESP32-H2 IDF-2098 - - + hw->tx_clkm_conf.tx_clk_active = 1; } /** - * @brief Enable rx interrupt + * @brief Enable I2S rx module clock * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_enable_rx_intr(i2s_dev_t *hw) +static inline void i2s_ll_enable_rx_clock(i2s_dev_t *hw) { - abort(); // TODO ESP32-H2 IDF-2098 - - + hw->rx_clkm_conf.rx_clk_active = 1; } /** - * @brief Disable rx interrupt + * @brief I2S mclk use tx module clock * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_disable_rx_intr(i2s_dev_t *hw) +static inline void i2s_ll_mclk_use_tx_clk(i2s_dev_t *hw) { - abort(); // TODO ESP32-H2 IDF-2098 - - + hw->rx_clkm_conf.mclk_sel = 0; } /** - * @brief Disable tx interrupt + * @brief I2S mclk use rx module clock * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_disable_tx_intr(i2s_dev_t *hw) +static inline void i2s_ll_mclk_use_rx_clk(i2s_dev_t *hw) { - abort(); // TODO ESP32-H2 IDF-2098 - - + hw->rx_clkm_conf.mclk_sel = 1; } /** - * @brief Enable tx interrupt + * @brief Enable I2S TX slave mode * * @param hw Peripheral I2S hardware instance address. + * @param slave_en Set true to enable slave mode */ -static inline void i2s_ll_enable_tx_intr(i2s_dev_t *hw) +static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, bool slave_en) { - abort(); // TODO ESP32-H2 IDF-2098 - - + hw->tx_conf.tx_slave_mod = slave_en; } /** - * @brief Reset dma in + * @brief Enable I2S RX slave mode * * @param hw Peripheral I2S hardware instance address. + * @param slave_en Set true to enable slave mode */ -static inline void i2s_ll_reset_dma_in(i2s_dev_t *hw) +static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, bool slave_en) { - abort(); // TODO ESP32-H2 IDF-2098 - - + hw->rx_conf.rx_slave_mod = slave_en; } /** - * @brief Reset dma out - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_reset_dma_out(i2s_dev_t *hw) -{ - abort(); // TODO ESP32-H2 IDF-2098 - - -} - -/** - * @brief Reset tx + * @brief Reset I2S TX module * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_reset_tx(i2s_dev_t *hw) { - abort(); // TODO ESP32-H2 IDF-2098 - - + hw->tx_conf.tx_reset = 1; + hw->tx_conf.tx_reset = 0; } /** - * @brief Reset rx + * @brief Reset I2S RX module * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_reset_rx(i2s_dev_t *hw) { - abort(); // TODO ESP32-H2 IDF-2098 - - + hw->rx_conf.rx_reset = 1; + hw->rx_conf.rx_reset = 0; } /** - * @brief Start out link + * @brief Reset I2S TX FIFO * * @param hw Peripheral I2S hardware instance address. */ -static inline void i2s_ll_start_out_link(i2s_dev_t *hw) +static inline void i2s_ll_reset_tx_fifo(i2s_dev_t *hw) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->tx_conf.tx_fifo_reset = 1; + hw->tx_conf.tx_fifo_reset = 0; } /** - * @brief Start tx + * @brief Reset I2S RX FIFO + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_reset_rx_fifo(i2s_dev_t *hw) +{ + hw->rx_conf.rx_fifo_reset = 1; + hw->rx_conf.rx_fifo_reset = 0; +} + +/** + * @brief Set TX source clock + * + * @param hw Peripheral I2S hardware instance address. + * @param src I2S source clock. + */ +static inline void i2s_ll_set_tx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) +{ + hw->tx_clkm_conf.tx_clk_sel = 2; +} + +/** + * @brief Set RX source clock + * + * @param hw Peripheral I2S hardware instance address. + * @param src I2S source clock, ESP32-S3 only support `I2S_CLK_D2CLK` + */ +static inline void i2s_ll_set_rx_clk_src(i2s_dev_t *hw, i2s_clock_src_t src) +{ + hw->rx_clkm_conf.rx_clk_sel = 2; +} + +/** + * @brief Configure I2S TX clock devider + * + * @param hw Peripheral I2S hardware instance address. + * @param set Pointer to I2S clock devider configuration paramater + */ +static inline void i2s_ll_set_tx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) +{ + if (set->a == 0 || set->b == 0) { + hw->tx_clkm_div_conf.tx_clkm_div_x = 0; + hw->tx_clkm_div_conf.tx_clkm_div_y = 0; + hw->tx_clkm_div_conf.tx_clkm_div_z = 0; + } else { + if (set->b > set->a / 2) { + hw->tx_clkm_div_conf.tx_clkm_div_x = set->a / (set->a - set->b) - 1; + hw->tx_clkm_div_conf.tx_clkm_div_y = set->a % (set->a - set->b); + hw->tx_clkm_div_conf.tx_clkm_div_z = set->a - set->b; + hw->tx_clkm_div_conf.tx_clkm_div_yn1 = 1; + } else { + hw->tx_clkm_div_conf.tx_clkm_div_x = set->a / set->b - 1; + hw->tx_clkm_div_conf.tx_clkm_div_y = set->a % set->b + 1; + hw->tx_clkm_div_conf.tx_clkm_div_z = set->b; + hw->tx_clkm_div_conf.tx_clkm_div_yn1 = 0; + } + } + hw->tx_clkm_conf.tx_clkm_div_num = set->mclk_div; + hw->tx_conf1.tx_bck_div_num = set->bck_div - 1; +} + +/** + * @brief Configure I2S RX clock devider + * + * @param hw Peripheral I2S hardware instance address. + * @param set Pointer to I2S clock devider configuration paramater + */ +static inline void i2s_ll_set_rx_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) +{ + if (set->a == 0 || set->b == 0) { + hw->rx_clkm_div_conf.rx_clkm_div_x = 0; + hw->rx_clkm_div_conf.rx_clkm_div_y = 0; + hw->rx_clkm_div_conf.rx_clkm_div_z = 0; + } else { + if (set->b > set->a / 2) { + hw->rx_clkm_div_conf.rx_clkm_div_x = set->a / (set->a - set->b) - 1; + hw->rx_clkm_div_conf.rx_clkm_div_y = set->a % (set->a - set->b); + hw->rx_clkm_div_conf.rx_clkm_div_z = set->a - set->b; + hw->rx_clkm_div_conf.rx_clkm_div_yn1 = 1; + } else { + hw->rx_clkm_div_conf.rx_clkm_div_x = set->a / set->b - 1; + hw->rx_clkm_div_conf.rx_clkm_div_y = set->a % set->b + 1; + hw->rx_clkm_div_conf.rx_clkm_div_z = set->b; + hw->rx_clkm_div_conf.rx_clkm_div_yn1 = 0; + } + } + hw->rx_clkm_conf.rx_clkm_div_num = set->mclk_div; + hw->rx_conf1.rx_bck_div_num = set->bck_div - 1; +} + +/** + * @brief Start I2S TX * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_start_tx(i2s_dev_t *hw) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->tx_conf.tx_update = 0; + hw->tx_conf.tx_update = 1; + hw->tx_conf.tx_start = 1; } /** - * @brief Start in link - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_start_in_link(i2s_dev_t *hw) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Start rx + * @brief Start I2S RX * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_start_rx(i2s_dev_t *hw) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->rx_conf.rx_update = 0; + hw->rx_conf.rx_update = 1; + hw->rx_conf.rx_start = 1; } /** - * @brief Stop out link - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_stop_out_link(i2s_dev_t *hw) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Stop tx + * @brief Stop I2S TX * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_stop_tx(i2s_dev_t *hw) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->tx_conf.tx_start = 0; } /** - * @brief Stop in link - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_stop_in_link(i2s_dev_t *hw) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Stop rx + * @brief Stop I2S RX * * @param hw Peripheral I2S hardware instance address. */ static inline void i2s_ll_stop_rx(i2s_dev_t *hw) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->rx_conf.rx_start = 0; } /** - * @brief Enable dma + * @brief Configure TX WS signal width * * @param hw Peripheral I2S hardware instance address. + * @param width WS width in BCK cycle */ -static inline void i2s_ll_enable_dma(i2s_dev_t *hw) +static inline void i2s_ll_set_tx_tdm_ws_width(i2s_dev_t *hw, int width) { - abort(); // TODO ESP32-H2 IDF-2098 - // //Enable and configure DMA - // typeof(hw->lc_conf) lc_conf; - // lc_conf.val = 0; - // lc_conf.out_eof_mode = 1; - + hw->tx_conf1.tx_tdm_ws_width = width - 1; } /** - * @brief Get I2S interrupt status + * @brief Configure RX WS signal width * * @param hw Peripheral I2S hardware instance address. - * @param val value to get interrupt status + * @param width WS width in BCK cycle */ -static inline void i2s_ll_get_intr_status(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_rx_tdm_ws_width(i2s_dev_t *hw, int width) { - abort(); // TODO ESP32-H2 IDF-2098 - // *val = hw->int_st.val; + hw->rx_conf1.rx_tdm_ws_width = width - 1; } /** - * @brief Clear I2S interrupt status + * @brief Configure the received length to trigger in_suc_eof interrupt * * @param hw Peripheral I2S hardware instance address. - * @param val value to clear interrupt status + * @param eof_num the byte length to trigger in_suc_eof interrupt */ -static inline void i2s_ll_clear_intr_status(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, int eof_num) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->rx_eof_num.rx_eof_num = eof_num; } /** - * @brief Get I2S out eof des address + * @brief Congfigure TX chan bit and audio data bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to get out eof des address + * @param sample_bit The chan bit width + * @param data_bit The audio data bit width */ -static inline void i2s_ll_get_out_eof_des_addr(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) { - abort(); // TODO ESP32-H2 IDF-2098 - // *val = hw->out_eof_des_addr; + hw->tx_conf1.tx_bits_mod = data_bit - 1; + hw->tx_conf1.tx_tdm_chan_bits = sample_bit - 1; } /** - * @brief Get I2S in eof des address + * @brief Congfigure RX chan bit and audio data bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to get in eof des address + * @param sample_bit The chan bit width + * @param data_bit The audio data bit width */ -static inline void i2s_ll_get_in_eof_des_addr(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) { - abort(); // TODO ESP32-H2 IDF-2098 - // *val = hw->in_eof_des_addr; + hw->rx_conf1.rx_bits_mod = data_bit - 1; + hw->rx_conf1.rx_tdm_chan_bits = sample_bit - 1; } /** - * @brief Get I2S tx fifo mode + * @brief Configure RX half_sample_bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx fifo mode + * @param half_sample_bits half sample bit width */ -static inline void i2s_ll_get_tx_fifo_mod(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_tx_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) { - abort(); // TODO ESP32-H2 IDF-2098 - // *val = hw->fifo_conf.tx_fifo_mod; + hw->tx_conf1.tx_half_sample_bits = half_sample_bits - 1; } /** - * @brief Set I2S tx fifo mode + * @brief Configure RX half_sample_bit * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx fifo mode + * @param half_sample_bits half sample bit width */ -static inline void i2s_ll_set_tx_fifo_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_half_sample_bit(i2s_dev_t *hw, int half_sample_bits) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->rx_conf1.rx_half_sample_bits = half_sample_bits - 1; } /** - * @brief Get I2S rx fifo mode + * @brief Enable TX MSB shift, the data will be launch at the first BCK clock * * @param hw Peripheral I2S hardware instance address. - * @param val value to get rx fifo mode + * @param msb_shift_enable Set true to enable MSB shift */ -static inline void i2s_ll_get_rx_fifo_mod(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_tx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enable) { - abort(); // TODO ESP32-H2 IDF-2098 - // *val = hw->fifo_conf.rx_fifo_mod; + hw->tx_conf1.tx_msb_shift = msb_shift_enable; } /** - * @brief Set I2S rx fifo mode + * @brief Enable RX MSB shift, the data will be launch at the first BCK clock * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx fifo mode + * @param msb_shift_enable Set true to enable MSB shift */ -static inline void i2s_ll_set_rx_fifo_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_rx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enable) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->rx_conf1.rx_msb_shift = msb_shift_enable; } /** - * @brief Set I2S tx chan mode + * @brief Configure TX total chan number * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx chan mode + * @param total_num Total chan number */ -static inline void i2s_ll_set_tx_chan_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_tx_chan_num(i2s_dev_t *hw, int total_num) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->tx_tdm_ctrl.tx_tdm_tot_chan_num = total_num - 1; } /** - * @brief Set I2S rx chan mode + * @brief Configure RX total chan number * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx chan mode + * @param total_num Total chan number */ -static inline void i2s_ll_set_rx_chan_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_chan_num(i2s_dev_t *hw, int total_num) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = total_num - 1; } /** - * @brief Set I2S out link address + * @brief Set the bimap of the active TX chan, only the active chan can launch audio data. * * @param hw Peripheral I2S hardware instance address. - * @param val value to set out link address + * @param chan_mask mask of tx active chan */ -static inline void i2s_ll_set_out_link_addr(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_tx_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask) { - abort(); // TODO ESP32-H2 IDF-2098 - + typeof(hw->tx_tdm_ctrl) tdm_ctrl_reg = hw->tx_tdm_ctrl; + tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK; + tdm_ctrl_reg.val |= chan_mask & I2S_LL_TDM_CH_MASK; + hw->tx_tdm_ctrl.val = tdm_ctrl_reg.val; } /** - * @brief Set I2S in link address + * @brief Set the bimap of the active RX chan, only the active chan can receive audio data. * * @param hw Peripheral I2S hardware instance address. - * @param val value to set in link address + * @param chan_mask mask of rx active chan */ -static inline void i2s_ll_set_in_link_addr(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask) { - abort(); // TODO ESP32-H2 IDF-2098 - + typeof(hw->rx_tdm_ctrl) tdm_ctrl_reg = hw->rx_tdm_ctrl; + tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK; + tdm_ctrl_reg.val |= chan_mask & I2S_LL_TDM_CH_MASK; + hw->rx_tdm_ctrl.val = tdm_ctrl_reg.val; } /** - * @brief Set I2S rx eof num + * @brief Set TX WS signal pol level * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx eof num + * @param ws_pol_level pin level of WS(output) when receiving left channel data */ -static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, uint32_t val) +static inline void i2s_set_tx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->tx_conf.tx_ws_idle_pol = ws_pol_level; } /** - * @brief Get I2S tx pdm fp + * @brief Set RX WS signal pol level * * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx pdm fp + * @param ws_pol_level pin level of WS(input) when receiving left channel data */ -static inline void i2s_ll_get_tx_pdm_fp(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_set_rx_ws_idle_pol(i2s_dev_t *hw, int ws_pol_level) { - abort(); // TODO ESP32-H2 IDF-2098 - // *val = hw->pdm_freq_conf.tx_pdm_fp; + hw->rx_conf.rx_ws_idle_pol = ws_pol_level; } /** - * @brief Get I2S tx pdm fs + * @brief Enable TX PDM mode. * * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx pdm fs + * @param pdm_enable Set true to TX enable PDM mode */ -static inline void i2s_ll_get_tx_pdm_fs(i2s_dev_t *hw, uint32_t *val) +static inline void i2s_ll_set_tx_pdm_en(i2s_dev_t *hw, bool pdm_enable) { - abort(); // TODO ESP32-H2 IDF-2098 - // *val = hw->pdm_freq_conf.tx_pdm_fs; + if (pdm_enable) { + hw->tx_conf.tx_tdm_en = 0; + hw->tx_conf.tx_pdm_en = 1; + } else { + hw->tx_conf.tx_pdm_en = 0; + hw->tx_conf.tx_tdm_en = 1; + } } /** - * @brief Set I2S tx pdm fp + * @brief Configure I2S TX pdm * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx pdm fp + * @param sample_rate The sample rate to be set. */ -static inline void i2s_ll_set_tx_pdm_fp(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_tx_pdm_cfg(i2s_dev_t *hw, uint32_t sample_rate) { - abort(); // TODO ESP32-H2 IDF-2098 - + uint32_t fp = 960; + uint32_t fs = sample_rate / 100; + typeof(hw->tx_pcm2pdm_conf) pdm_conf_reg = hw->tx_pcm2pdm_conf; + typeof(hw->tx_pcm2pdm_conf1) pdm_conf1_reg = hw->tx_pcm2pdm_conf1; + pdm_conf_reg.pcm2pdm_conv_en = 1; + pdm_conf_reg.tx_pdm_prescale = 0; + pdm_conf_reg.tx_pdm_hp_in_shift = 1; + pdm_conf_reg.tx_pdm_lp_in_shift = 1; + pdm_conf_reg.tx_pdm_sinc_in_shift = 1; + pdm_conf_reg.tx_pdm_sigmadelta_in_shift = 1; + pdm_conf_reg.tx_pdm_sinc_osr2 = fp / fs; + pdm_conf_reg.tx_pdm_dac_mode_en = 1; + pdm_conf_reg.tx_pdm_sigmadelta_dither = 0; + pdm_conf_reg.tx_pdm_sigmadelta_dither2 = 0; + pdm_conf_reg.tx_pdm_dac_2out_en = 1; + pdm_conf1_reg.tx_pdm_fp = fp; + pdm_conf1_reg.tx_pdm_fs = fs; + pdm_conf1_reg.tx_iir_hp_mult12_5 = 7; + pdm_conf1_reg.tx_iir_hp_mult12_0 = 6; + pdm_conf_reg.tx_pdm_hp_bypass = 0; + hw->tx_pcm2pdm_conf = pdm_conf_reg; + hw->tx_pcm2pdm_conf1 = pdm_conf1_reg; } /** - * @brief Set I2S tx pdm fs + * @brief Configure I2S TX PDM sample rate + * Fpdm = 64*Fpcm*fp/fs * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx pdm fs + * @param fp The fp value of TX PDM filter module group0. + * @param fs The fs value of TX PDM filter module group0. */ -static inline void i2s_ll_set_tx_pdm_fs(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t fp, uint32_t fs) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->tx_pcm2pdm_conf1.tx_pdm_fp = fp; + hw->tx_pcm2pdm_conf1.tx_pdm_fs = fs; + hw->tx_pcm2pdm_conf.tx_pdm_sinc_osr2 = fp / fs; } /** - * @brief Get I2S rx sinc dsr 16 en + * @brief Get I2S TX PDM configuration * * @param hw Peripheral I2S hardware instance address. - * @param val value to get rx sinc dsr 16 en + * @param fp Pointer to accept TX PDM fp configuration paramater + * @param fs Pointer to accept TX PDM fs configuration paramater */ -static inline void i2s_ll_get_rx_sinc_dsr_16_en(i2s_dev_t *hw, bool *val) +static inline void i2s_ll_get_tx_pdm_fpfs(i2s_dev_t *hw, uint32_t *fp, uint32_t *fs) { - abort(); // TODO ESP32-H2 IDF-2098 - // *val = hw->pdm_conf.rx_sinc_dsr_16_en; + *fp = hw->tx_pcm2pdm_conf1.tx_pdm_fp; + *fs = hw->tx_pcm2pdm_conf1.tx_pdm_fs; } /** - * @brief Set I2S clkm div num + * @brief Enable RX PDM mode. * * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div num + * @param pdm_enable Set true to RX enable PDM mode */ -static inline void i2s_ll_set_clkm_div_num(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool pdm_enable) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->rx_conf.rx_pdm_en = pdm_enable; + hw->rx_conf.rx_tdm_en = !pdm_enable; } /** - * @brief Set I2S clkm div b + * @brief Configura TX a/u-law decompress or compress * * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div b + * @param pcm_cfg PCM configuration paramater */ -static inline void i2s_ll_set_clkm_div_b(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) { - abort(); // TODO ESP32-H2 IDF-2098 - + if (pcm_cfg == I2S_PCM_DISABLE) { + hw->tx_conf.tx_pcm_bypass = 1; + } else { + hw->tx_conf.tx_pcm_conf = pcm_cfg; + hw->tx_conf.tx_pcm_bypass = 0; + } } /** - * @brief Set I2S clkm div a + * @brief Configure RX a/u-law decompress or compress * * @param hw Peripheral I2S hardware instance address. - * @param val value to set clkm div a + * @param pcm_cfg PCM configuration paramater */ -static inline void i2s_ll_set_clkm_div_a(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) { - abort(); // TODO ESP32-H2 IDF-2098 - + if (pcm_cfg == I2S_PCM_DISABLE) { + hw->rx_conf.rx_pcm_bypass = 1; + } else { + hw->rx_conf.rx_pcm_conf = pcm_cfg; + hw->rx_conf.rx_pcm_bypass = 0; + } } /** - * @brief Set I2S tx bck div num + * @brief Enable TX audio data left alignment * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx bck div num + * @param ena Set true to enable left alignment */ -static inline void i2s_ll_set_tx_bck_div_num(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_tx_left_align_enable(i2s_dev_t *hw, bool ena) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->tx_conf.tx_left_align = ena; } /** - * @brief Set I2S rx bck div num + * @brief Enable RX audio data left alignment * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx bck div num + * @param ena Set true to enable left alignment */ -static inline void i2s_ll_set_rx_bck_div_num(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_rx_left_align_enable(i2s_dev_t *hw, bool ena) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->rx_conf.rx_left_align = ena; } /** - * @brief Set I2S clk sel + * @brief Enable TX big endian mode * * @param hw Peripheral I2S hardware instance address. - * @param val value to set clk sel + * @param ena Set true to enable big endian mode */ -static inline void i2s_ll_set_clk_sel(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_rx_big_endian_enable(i2s_dev_t *hw, bool ena) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->rx_conf.rx_big_endian = ena; } /** - * @brief Set I2S tx bits mod + * @brief Enable RX big endian mode * * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx bits mod + * @param ena Set true to enable big endian mode */ -static inline void i2s_ll_set_tx_bits_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_tx_big_endian_enable(i2s_dev_t *hw, bool ena) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->tx_conf.tx_big_endian = ena; } /** - * @brief Set I2S rx bits mod + * @brief Configure TX bit order * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx bits mod + * @param lsb_order_ena Set true to enable LSB bit order */ -static inline void i2s_ll_set_rx_bits_mod(i2s_dev_t *hw, uint32_t val) +static inline void i2s_ll_tx_set_bit_order(i2s_dev_t *hw, bool lsb_order_ena) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->tx_conf.tx_bit_order = lsb_order_ena; } /** - * @brief Set I2S rx sinc dsr 16 en + * @brief Configure RX bit order * * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx sinc dsr 16 en + * @param lsb_order_ena Set true to enable LSB bit order */ -static inline void i2s_ll_set_rx_sinc_dsr_16_en(i2s_dev_t *hw, bool val) +static inline void i2s_ll_rx_set_bit_order(i2s_dev_t *hw, bool lsb_order_ena) { - abort(); // TODO ESP32-H2 IDF-2098 - + hw->rx_conf.rx_bit_order = lsb_order_ena; } /** - * @brief Set I2S dscr en + * @brief Configure TX skip mask enable * * @param hw Peripheral I2S hardware instance address. - * @param val value to set dscr en + * @param skip_mask_ena Set true to skip inactive channels. */ -static inline void i2s_ll_set_dscr_en(i2s_dev_t *hw, bool val) +static inline void i2s_ll_tx_set_skip_mask(i2s_dev_t *hw, bool skip_mask_ena) { - abort(); // TODO ESP32-H2 IDF-2098 + hw->tx_tdm_ctrl.tx_tdm_skip_msk_en = skip_mask_ena; +} + +/** + * @brief Configure single data + * + * @param hw Peripheral I2S hardware instance address. + * @param data Single data to be set + */ +static inline void i2s_ll_single_data_config(i2s_dev_t *hw, uint32_t data) +{ + hw->conf_single_data = data; } /** - * @brief Set I2S lcd en + * @brief Enable loopback mode * * @param hw Peripheral I2S hardware instance address. - * @param val value to set lcd en + * @param ena Set true to enable loopback mode. */ -static inline void i2s_ll_set_lcd_en(i2s_dev_t *hw, bool val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S camera en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set camera en - */ -static inline void i2s_ll_set_camera_en(i2s_dev_t *hw, bool val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S pcm2pdm conv en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set pcm2pdm conv en - */ -static inline void i2s_ll_set_pcm2pdm_conv_en(i2s_dev_t *hw, bool val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S TX to MSB Alignment Standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_tx_format_msb_align(i2s_dev_t *hw) -{ -} - - -static inline void i2s_ll_set_rx_format_msb_align(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S TX to PCM long standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_tx_pcm_long(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S RX to PCM long standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_rx_pcm_long(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S RX to PCM short standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_rx_pcm_short(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S RX to philip standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_rx_format_philip(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S TX to PCM short standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_tx_pcm_short(i2s_dev_t *hw) -{ -} - -/** - * @brief Set I2S TX to philip standard - * - * @param hw Peripheral I2S hardware instance address. - */ -static inline void i2s_ll_set_tx_format_philip(i2s_dev_t *hw) +static inline void i2s_ll_loop_back_ena(i2s_dev_t *hw, bool ena) { + hw->tx_conf.sig_loopback = ena; } /** @@ -715,198 +694,6 @@ static inline void i2s_ll_set_pdm2pcm_conv_en(i2s_dev_t *hw, bool val) } -/** - * @brief Set I2S rx pdm en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx pdm en - */ -static inline void i2s_ll_set_rx_pdm_en(i2s_dev_t *hw, bool val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S tx pdm en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx pdm en - */ -static inline void i2s_ll_set_tx_pdm_en(i2s_dev_t *hw, bool val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S tx fifo mod force en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx fifo mod force en - */ -static inline void i2s_ll_set_tx_fifo_mod_force_en(i2s_dev_t *hw, bool val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S rx fifo mod force en - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx fifo mod force en - */ -static inline void i2s_ll_set_rx_fifo_mod_force_en(i2s_dev_t *hw, bool val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S tx right first - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx right first - */ -static inline void i2s_ll_set_tx_right_first(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S rx right first - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx right first - */ -static inline void i2s_ll_set_rx_right_first(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S tx slave mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx slave mod - */ -static inline void i2s_ll_set_tx_slave_mod(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S rx slave mod - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx slave mod - */ -static inline void i2s_ll_set_rx_slave_mod(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Get I2S tx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get tx msb right - */ -static inline void i2s_ll_get_tx_msb_right(i2s_dev_t *hw, uint32_t *val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - // *val = hw->conf.tx_msb_right; -} - -/** - * @brief Get I2S rx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to get rx msb right - */ -static inline void i2s_ll_get_rx_msb_right(i2s_dev_t *hw, uint32_t *val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - // *val = hw->conf.rx_msb_right; -} - -/** - * @brief Set I2S tx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx msb right - */ -static inline void i2s_ll_set_tx_msb_right(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S rx msb right - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx msb right - */ -static inline void i2s_ll_set_rx_msb_right(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S tx mono - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx mono - */ -static inline void i2s_ll_set_tx_mono(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S rx mono - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set rx mono - */ -static inline void i2s_ll_set_rx_mono(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S tx sinc osr2 - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set tx sinc osr2 - */ -static inline void i2s_ll_set_tx_sinc_osr2(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - -/** - * @brief Set I2S sig loopback - * - * @param hw Peripheral I2S hardware instance address. - * @param val value to set sig loopback - */ -static inline void i2s_ll_set_sig_loopback(i2s_dev_t *hw, uint32_t val) -{ - abort(); // TODO ESP32-H2 IDF-2098 - -} - #ifdef __cplusplus } #endif diff --git a/components/hal/esp32s2/include/hal/i2s_ll.h b/components/hal/esp32s2/include/hal/i2s_ll.h index e1f677cf32..5ca3262018 100644 --- a/components/hal/esp32s2/include/hal/i2s_ll.h +++ b/components/hal/esp32s2/include/hal/i2s_ll.h @@ -448,10 +448,10 @@ static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, uint32_t eof_num) } /** - * @brief Congfigure TX slot bit and audio data bit, on ESP32-S2, sample_bit should equals to data_bit + * @brief Congfigure TX chan bit and audio data bit, on ESP32-S2, sample_bit should equals to data_bit * * @param hw Peripheral I2S hardware instance address. - * @param sample_bit The slot bit width + * @param sample_bit The chan bit width * @param data_bit The audio data bit width */ static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) @@ -461,10 +461,10 @@ static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i } /** - * @brief Congfigure RX slot bit and audio data bit, on ESP32-S2, sample_bit should equals to data_bit + * @brief Congfigure RX chan bit and audio data bit, on ESP32-S2, sample_bit should equals to data_bit * * @param hw Peripheral I2S hardware instance address. - * @param sample_bit The slot bit width + * @param sample_bit The chan bit width * @param data_bit The audio data bit width */ static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) diff --git a/components/hal/esp32s3/include/hal/i2s_ll.h b/components/hal/esp32s3/include/hal/i2s_ll.h index 85b91dc077..3b2766fe5c 100644 --- a/components/hal/esp32s3/include/hal/i2s_ll.h +++ b/components/hal/esp32s3/include/hal/i2s_ll.h @@ -322,10 +322,10 @@ static inline void i2s_ll_set_rx_eof_num(i2s_dev_t *hw, int eof_num) } /** - * @brief Congfigure TX slot bit and audio data bit + * @brief Congfigure TX chan bit and audio data bit * * @param hw Peripheral I2S hardware instance address. - * @param sample_bit The slot bit width + * @param sample_bit The chan bit width * @param data_bit The audio data bit width */ static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) @@ -335,10 +335,10 @@ static inline void i2s_ll_set_tx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, i } /** - * @brief Congfigure RX slot bit and audio data bit + * @brief Congfigure RX chan bit and audio data bit * * @param hw Peripheral I2S hardware instance address. - * @param sample_bit The slot bit width + * @param sample_bit The chan bit width * @param data_bit The audio data bit width */ static inline void i2s_ll_set_rx_sample_bit(i2s_dev_t *hw, uint8_t sample_bit, int data_bit) @@ -392,52 +392,52 @@ static inline void i2s_ll_rx_msb_shift_enable(i2s_dev_t *hw, bool msb_shift_enab } /** - * @brief Configure TX total slot number + * @brief Configure TX total chan number * * @param hw Peripheral I2S hardware instance address. - * @param total_num Total slot number + * @param total_num Total chan number */ -static inline void i2s_ll_set_tx_slot_num(i2s_dev_t *hw, int total_num) +static inline void i2s_ll_set_tx_chan_num(i2s_dev_t *hw, int total_num) { hw->tx_tdm_ctrl.tx_tdm_tot_chan_num = total_num - 1; } /** - * @brief Configure RX total slot number + * @brief Configure RX total chan number * * @param hw Peripheral I2S hardware instance address. - * @param total_num Total slot number + * @param total_num Total chan number */ -static inline void i2s_ll_set_rx_slot_num(i2s_dev_t *hw, int total_num) +static inline void i2s_ll_set_rx_chan_num(i2s_dev_t *hw, int total_num) { hw->rx_tdm_ctrl.rx_tdm_tot_chan_num = total_num - 1; } /** - * @brief Set the bimap of the active TX slot, only the active slot can launch audio data. + * @brief Set the bimap of the active TX chan, only the active chan can launch audio data. * * @param hw Peripheral I2S hardware instance address. - * @param slot_mask mask of tx active slot + * @param chan_mask mask of tx active chan */ -static inline void i2s_ll_set_tx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_mask) +static inline void i2s_ll_set_tx_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask) { typeof(hw->tx_tdm_ctrl) tdm_ctrl_reg = hw->tx_tdm_ctrl; tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK; - tdm_ctrl_reg.val |= slot_mask & I2S_LL_TDM_CH_MASK; + tdm_ctrl_reg.val |= chan_mask & I2S_LL_TDM_CH_MASK; hw->tx_tdm_ctrl.val = tdm_ctrl_reg.val; } /** - * @brief Set the bimap of the active RX slot, only the active slot can receive audio data. + * @brief Set the bimap of the active RX chan, only the active chan can receive audio data. * * @param hw Peripheral I2S hardware instance address. - * @param slot_mask mask of rx active slot + * @param chan_mask mask of rx active chan */ -static inline void i2s_ll_set_rx_active_slot_mask(i2s_dev_t *hw, uint32_t slot_mask) +static inline void i2s_ll_set_rx_active_chan_mask(i2s_dev_t *hw, uint32_t chan_mask) { typeof(hw->rx_tdm_ctrl) tdm_ctrl_reg = hw->rx_tdm_ctrl; tdm_ctrl_reg.val &= ~I2S_LL_TDM_CH_MASK; - tdm_ctrl_reg.val |= slot_mask & I2S_LL_TDM_CH_MASK; + tdm_ctrl_reg.val |= chan_mask & I2S_LL_TDM_CH_MASK; hw->rx_tdm_ctrl.val = tdm_ctrl_reg.val; } @@ -588,7 +588,7 @@ static inline void i2s_ll_get_pdm_rx_dsr(i2s_dev_t *hw, i2s_pdm_dsr_t *dsr) * @param hw Peripheral I2S hardware instance address. * @param pcm_cfg PCM configuration paramater */ -static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_mode_t pcm_cfg) +static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) { if (pcm_cfg == I2S_PCM_DISABLE) { hw->tx_conf.tx_pcm_bypass = 1; @@ -604,7 +604,7 @@ static inline void i2s_ll_tx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_mode_t pcm_cfg) * @param hw Peripheral I2S hardware instance address. * @param pcm_cfg PCM configuration paramater */ -static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_mode_t pcm_cfg) +static inline void i2s_ll_rx_pcm_cfg(i2s_dev_t *hw, i2s_pcm_compress_t pcm_cfg) { if (pcm_cfg == I2S_PCM_DISABLE) { hw->rx_conf.rx_pcm_bypass = 1; diff --git a/components/hal/i2s_hal.c b/components/hal/i2s_hal.c index 49726d8204..bbabba6ba7 100644 --- a/components/hal/i2s_hal.c +++ b/components/hal/i2s_hal.c @@ -148,14 +148,14 @@ static void i2s_hal_format_config(i2s_hal_context_t *hal, const i2s_hal_config_t } } #else - int slot_bits = hal_cfg->bits_cfg.chan_bits; - int slot_num = hal_cfg->chan_cfg.total_chan; + int chan_bits = hal_cfg->bits_cfg.chan_bits; + int chan_num = hal_cfg->total_chan; bool msb_shift_en = false; int tdm_ws_width = 0; switch (hal_cfg->comm_fmt) { case I2S_COMM_FORMAT_STAND_MSB: msb_shift_en = false; - tdm_ws_width = slot_num * slot_bits / 2; + tdm_ws_width = chan_num * chan_bits / 2; break; case I2S_COMM_FORMAT_STAND_PCM_SHORT: msb_shift_en = false; @@ -163,22 +163,22 @@ static void i2s_hal_format_config(i2s_hal_context_t *hal, const i2s_hal_config_t break; case I2S_COMM_FORMAT_STAND_PCM_LONG: msb_shift_en = false; - tdm_ws_width = slot_bits; + tdm_ws_width = chan_bits; break; default: //I2S_COMM_FORMAT_STAND_I2S msb_shift_en = true; - tdm_ws_width = slot_num * slot_bits / 2; + tdm_ws_width = chan_num * chan_bits / 2; break; } if (hal_cfg->mode & I2S_MODE_TX) { i2s_ll_tx_msb_shift_enable(hal->dev, msb_shift_en); i2s_ll_set_tx_tdm_ws_width(hal->dev, tdm_ws_width); - i2s_ll_set_tx_half_sample_bit(hal->dev, slot_num * slot_bits / 2); + i2s_ll_set_tx_half_sample_bit(hal->dev, chan_num * chan_bits / 2); } if (hal_cfg->mode & I2S_MODE_RX) { i2s_ll_rx_msb_shift_enable(hal->dev, msb_shift_en); i2s_ll_set_rx_tdm_ws_width(hal->dev, tdm_ws_width); - i2s_ll_set_rx_half_sample_bit(hal->dev, slot_num * slot_bits / 2); + i2s_ll_set_rx_half_sample_bit(hal->dev, chan_num * chan_bits / 2); } #endif } @@ -186,23 +186,23 @@ static void i2s_hal_format_config(i2s_hal_context_t *hal, const i2s_hal_config_t void i2s_hal_samples_config(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg) { int data_bits = hal_cfg->bits_cfg.sample_bits; - int slot_bits = hal_cfg->bits_cfg.chan_bits; + int chan_bits = hal_cfg->bits_cfg.chan_bits; #if SOC_I2S_SUPPORTS_TDM - int slot_num = hal_cfg->chan_cfg.total_chan; + int chan_num = hal_cfg->total_chan; if (hal_cfg->mode & I2S_MODE_TX) { - i2s_ll_set_tx_slot_num(hal->dev, slot_num); - i2s_ll_set_tx_sample_bit(hal->dev, slot_bits, data_bits); + i2s_ll_set_tx_chan_num(hal->dev, chan_num); + i2s_ll_set_tx_sample_bit(hal->dev, chan_bits, data_bits); } if (hal_cfg->mode & I2S_MODE_RX) { - i2s_ll_set_rx_slot_num(hal->dev, slot_num); - i2s_ll_set_rx_sample_bit(hal->dev, slot_bits, data_bits); + i2s_ll_set_rx_chan_num(hal->dev, chan_num); + i2s_ll_set_rx_sample_bit(hal->dev, chan_bits, data_bits); } #else if (hal_cfg->mode & I2S_MODE_TX) { - i2s_ll_set_tx_sample_bit(hal->dev, slot_bits, data_bits); + i2s_ll_set_tx_sample_bit(hal->dev, chan_bits, data_bits); } if (hal_cfg->mode & I2S_MODE_RX) { - i2s_ll_set_rx_sample_bit(hal->dev, slot_bits, data_bits); + i2s_ll_set_rx_sample_bit(hal->dev, chan_bits, data_bits); } #endif //I2S standards config: Philip, MSB or PCM, Only I2S mode should do this configuration. @@ -224,7 +224,7 @@ void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cf i2s_ll_set_tx_clk_src(hal->dev, I2S_CLK_D2CLK); // Set I2S_CLK_D2CLK as default i2s_ll_mclk_use_tx_clk(hal->dev); - i2s_ll_set_tx_active_slot_mask(hal->dev, hal_cfg->chan_cfg.chan_mask); + i2s_ll_set_tx_active_chan_mask(hal->dev, hal_cfg->chan_mask); i2s_ll_tx_left_align_enable(hal->dev, hal_cfg->flags.left_align_en); i2s_ll_tx_big_endian_enable(hal->dev, hal_cfg->flags.big_edin_en); i2s_ll_tx_set_bit_order(hal->dev, hal_cfg->flags.bit_order_msb_en); @@ -247,7 +247,7 @@ void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cf i2s_ll_set_rx_clk_src(hal->dev, I2S_CLK_D2CLK); // Set I2S_CLK_D2CLK as default i2s_ll_mclk_use_rx_clk(hal->dev); - i2s_ll_set_rx_active_slot_mask(hal->dev, hal_cfg->chan_cfg.chan_mask); + i2s_ll_set_rx_active_chan_mask(hal->dev, hal_cfg->chan_mask); i2s_ll_rx_left_align_enable(hal->dev, hal_cfg->flags.left_align_en); i2s_ll_rx_big_endian_enable(hal->dev, hal_cfg->flags.big_edin_en); i2s_ll_rx_set_bit_order(hal->dev, hal_cfg->flags.bit_order_msb_en); @@ -271,11 +271,9 @@ void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cf } #endif -#if SOC_I2S_SUPPORTS_PDM - bool is_pdm = ((hal_cfg->mode & I2S_MODE_PDM) > 0); #if SOC_I2S_SUPPORTS_PDM_TX if (hal_cfg->mode & I2S_MODE_TX) { - if (is_pdm) { + if (hal_cfg->mode & I2S_MODE_PDM) { i2s_ll_tx_pdm_cfg(hal->dev, hal_cfg->sample_rate); } else { i2s_ll_set_tx_pdm_en(hal->dev, false); @@ -284,15 +282,13 @@ void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cf #endif // SOC_I2S_SUPPORTS_PDM_TX #if SOC_I2S_SUPPORTS_PDM_RX if (hal_cfg->mode & I2S_MODE_RX) { - if (is_pdm) { + if (hal_cfg->mode & I2S_MODE_PDM) { i2s_ll_rx_pdm_cfg(hal->dev); } else { i2s_ll_set_rx_pdm_en(hal->dev, false); } } #endif // SOC_I2S_SUPPORTS_PDM_RX -#endif // SOC_I2S_SUPPORTS_PDM - //Configure I2S slot number,sample bit. + //Configure I2S chan number,sample bit. i2s_hal_samples_config(hal, hal_cfg); - } diff --git a/components/hal/include/hal/i2s_hal.h b/components/hal/include/hal/i2s_hal.h index d26697f976..be07a92e41 100644 --- a/components/hal/include/hal/i2s_hal.h +++ b/components/hal/include/hal/i2s_hal.h @@ -44,35 +44,6 @@ typedef union { uint32_t val; /*!< I2S cannel bits configiration value */ } i2s_hal_bits_cfg_t; -#if SOC_I2S_SUPPORTS_TDM -/** - * @brief I2S channel configurations - * - */ -typedef union { - struct { - uint32_t total_chan : 8; /*!< Total number of I2S channels */ - uint32_t active_chan : 8; /*!< Active channel number, it will be set automatically if chan_mask is set */ - uint32_t chan_mask : 16; /*!< Active channel bit mask, set value in `i2s_channel_t` to enable specific channel, the bit map of active channel can not exceed (0x1<dev, slot_bit, data_bit) +#define i2s_hal_set_tx_sample_bit(hal, chan_bit, data_bit) i2s_ll_set_tx_sample_bit((hal)->dev, chan_bit, data_bit) /** * @brief Set I2S RX sample bit * * @param hal Context of the HAL layer - * @param slot_bit I2S RX slot bit + * @param chan_bit I2S RX chan bit * @param data_bit The sample data bit length. */ -#define i2s_hal_set_rx_sample_bit(hal, slot_bit, data_bit) i2s_ll_set_rx_sample_bit((hal)->dev, slot_bit, data_bit) +#define i2s_hal_set_rx_sample_bit(hal, chan_bit, data_bit) i2s_ll_set_rx_sample_bit((hal)->dev, chan_bit, data_bit) /** * @brief Configure I2S TX module clock devider @@ -250,7 +230,7 @@ void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbc * @brief Configure I2S TX PCM encoder or decoder. * * @param hal Context of the HAL layer - * @param cfg PCM configure paramater, refer to `i2s_pcm_mode_t` + * @param cfg PCM configure paramater, refer to `i2s_pcm_compress_t` */ #define i2s_hal_tx_pcm_cfg(hal, cfg) i2s_ll_tx_pcm_cfg((hal)->dev, cfg) @@ -258,7 +238,7 @@ void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, uint32_t sclk, uint32_t fbc * @brief Configure I2S RX PCM encoder or decoder. * * @param hal Context of the HAL layer - * @param cfg PCM configure paramater, refer to `i2s_pcm_mode_t` + * @param cfg PCM configure paramater, refer to `i2s_pcm_compress_t` */ #define i2s_hal_rx_pcm_cfg(hal, cfg) i2s_ll_rx_pcm_cfg((hal)->dev, cfg) #endif diff --git a/components/hal/include/hal/i2s_types.h b/components/hal/include/hal/i2s_types.h index 5c6ee96ad3..6b12b4812d 100644 --- a/components/hal/include/hal/i2s_types.h +++ b/components/hal/include/hal/i2s_types.h @@ -36,16 +36,16 @@ typedef enum { } i2s_bits_per_sample_t; /** - * @brief I2S bit width per slot. + * @brief I2S bit width per chan. * */ typedef enum { - I2S_BITS_PER_SLOT_8BIT = (8), /*!< slot bit 8*/ - I2S_BITS_PER_SLOT_16BIT = (16), /*!< slot bit 16*/ - I2S_BITS_PER_SLOT_24BIT = (24), /*!< slot bit 24*/ - I2S_BITS_PER_SLOT_32BIT = (32), /*!< slot bit 32*/ - I2S_BITS_PER_SLOT_EQU_SAMPLE = (0), /*!< slot bit equals to data bit*/ -} i2s_bits_per_slot_t; + I2S_BITS_PER_CHAN_DEFAULT = (0), /*!< chan bit equals to data bit*/ + I2S_BITS_PER_CHAN_8BIT = (8), /*!< chan bit 8*/ + I2S_BITS_PER_CHAN_16BIT = (16), /*!< chan bit 16*/ + I2S_BITS_PER_CHAN_24BIT = (24), /*!< chan bit 24*/ + I2S_BITS_PER_CHAN_32BIT = (32), /*!< chan bit 32*/ +} i2s_bits_per_chan_t; /** * @brief I2S channel. @@ -84,9 +84,6 @@ typedef enum { #endif } i2s_channel_t; - - - /** * @brief I2S communication standard format * @@ -134,10 +131,8 @@ typedef enum { I2S_MODE_DAC_BUILT_IN = (0x1 << 4), /*!< Output I2S data to built-in DAC, no matter the data format is 16bit or 32 bit, the DAC module will only take the 8bits from MSB*/ I2S_MODE_ADC_BUILT_IN = (0x1 << 5), /*!< Input I2S data from built-in ADC, each data can be 12-bit width at most*/ #endif -#if SOC_I2S_SUPPORTS_PDM // PDM functions are only supported on I2S0 (all chips). I2S_MODE_PDM = (0x1 << 6), /*!< I2S PDM mode*/ -#endif } i2s_mode_t; /** @@ -169,12 +164,12 @@ typedef enum { * */ typedef enum { - I2S_PCM_A_DECOMPRESS=0, /*!< A-law decompress*/ + I2S_PCM_DISABLE = 0, /*!< Disable A/U law decopress or compress*/ + I2S_PCM_A_DECOMPRESS, /*!< A-law decompress*/ I2S_PCM_A_COMPRESS, /*!< A-law compress*/ I2S_PCM_U_DECOMPRESS, /*!< U-law decompress*/ I2S_PCM_U_COMPRESS, /*!< U-law compress*/ - I2S_PCM_DISABLE, /*!< Disable A/U law decopress or compress*/ -} i2s_pcm_mode_t; +} i2s_pcm_compress_t; #endif #if SOC_I2S_SUPPORTS_PDM_RX @@ -188,7 +183,6 @@ typedef enum { } i2s_pdm_dsr_t; #endif -#if SOC_I2S_SUPPORTS_PDM /** * @brief PDM PCM convter enable/disable. * @@ -197,7 +191,6 @@ typedef enum { PDM_PCM_CONV_ENABLE, /*!< Enable PDM PCM convert*/ PDM_PCM_CONV_DISABLE, /*!< Disable PDM PCM convert*/ } pdm_pcm_conv_t; -#endif #ifdef __cplusplus diff --git a/components/soc/esp32/include/soc/soc_caps.h b/components/soc/esp32/include/soc/soc_caps.h index a4c2a5c07e..544209a925 100644 --- a/components/soc/esp32/include/soc/soc_caps.h +++ b/components/soc/esp32/include/soc/soc_caps.h @@ -138,7 +138,6 @@ #define SOC_I2S_NUM (2) #define SOC_I2S_SUPPORTS_PDM_TX (1) #define SOC_I2S_SUPPORTS_PDM_RX (1) -#define SOC_I2S_SUPPORTS_PDM (1) // (SOC_I2S_SUPPORTS_PDM_RX | SOC_I2S_SUPPORTS_PDM_TX) #define SOC_I2S_SUPPORTS_ADC_DAC (1) // ESP32 support ADC and DAC #define SOC_I2S_SUPPORTS_APLL (1)// ESP32 support APLL diff --git a/components/soc/esp32c3/i2s_periph.c b/components/soc/esp32c3/i2s_periph.c index 5e6e82a7ab..b4b35836c3 100644 --- a/components/soc/esp32c3/i2s_periph.c +++ b/components/soc/esp32c3/i2s_periph.c @@ -26,6 +26,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .rx_ws_sig = I2SI_WS_IN_IDX, .data_out_sig = I2SO_SD_OUT_IDX, .data_in_sig = I2SI_SD_IN_IDX, + .irq = -1, .module = PERIPH_I2S1_MODULE, } }; diff --git a/components/soc/esp32c3/include/soc/soc_caps.h b/components/soc/esp32c3/include/soc/soc_caps.h index d781839b6f..1557305eef 100644 --- a/components/soc/esp32c3/include/soc/soc_caps.h +++ b/components/soc/esp32c3/include/soc/soc_caps.h @@ -112,7 +112,6 @@ #define SOC_I2S_SUPPORTS_PCM (1) #define SOC_I2S_SUPPORTS_PDM_TX (1) #define SOC_I2S_SUPPORTS_PDM_RX (0) -#define SOC_I2S_SUPPORTS_PDM (1) //(SOC_I2S_SUPPORTS_PDM_RX | SOC_I2S_SUPPORTS_PDM_TX) #define SOC_I2S_SUPPORTS_TDM (1) #define SOC_I2S_APLL_MIN_FREQ (250000000) #define SOC_I2S_APLL_MAX_FREQ (500000000) diff --git a/components/soc/esp32h2/include/soc/soc_caps.h b/components/soc/esp32h2/include/soc/soc_caps.h index 64fa8dd3b9..40a4ecb249 100644 --- a/components/soc/esp32h2/include/soc/soc_caps.h +++ b/components/soc/esp32h2/include/soc/soc_caps.h @@ -106,7 +106,10 @@ /*-------------------------- I2S CAPS ----------------------------------------*/ #define SOC_I2S_NUM (1) - +#define SOC_I2S_SUPPORTS_PCM (1) +#define SOC_I2S_SUPPORTS_PDM_TX (1) +#define SOC_I2S_SUPPORTS_PDM_RX (0) +#define SOC_I2S_SUPPORTS_TDM (1) #define SOC_I2S_APLL_MIN_FREQ (250000000) #define SOC_I2S_APLL_MAX_FREQ (500000000) #define SOC_I2S_APLL_MIN_RATE (10675) //in Hz, I2S Clock rate limited by hardware diff --git a/components/soc/esp32h2/ld/esp32h2.peripherals.ld b/components/soc/esp32h2/ld/esp32h2.peripherals.ld index 38e6b58258..ee3154ad43 100644 --- a/components/soc/esp32h2/ld/esp32h2.peripherals.ld +++ b/components/soc/esp32h2/ld/esp32h2.peripherals.ld @@ -7,7 +7,7 @@ PROVIDE ( SIGMADELTA = 0x60004f00 ); PROVIDE ( RTCCNTL = 0x60008000 ); PROVIDE ( RTCIO = 0x60008400 ); PROVIDE ( HINF = 0x6000B000 ); -PROVIDE ( I2S1 = 0x6002d000 ); +PROVIDE ( I2S0 = 0x6002d000 ); PROVIDE ( I2C0 = 0x60013000 ); PROVIDE ( UHCI0 = 0x60014000 ); PROVIDE ( UHCI1 = 0x6000c000 ); diff --git a/components/soc/esp32s3/i2s_periph.c b/components/soc/esp32s3/i2s_periph.c index f1b3b494d2..13960bd5f2 100644 --- a/components/soc/esp32s3/i2s_periph.c +++ b/components/soc/esp32s3/i2s_periph.c @@ -26,6 +26,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .rx_ws_sig = I2S0I_WS_IN_IDX, .data_out_sig = I2S0O_SD_OUT_IDX, .data_in_sig = I2S0I_SD_IN_IDX, + .irq = -1, .module = PERIPH_I2S0_MODULE, }, { @@ -35,6 +36,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = { .rx_ws_sig = I2S1I_WS_IN_IDX, .data_out_sig = I2S1O_SD_OUT_IDX, .data_in_sig = I2S1I_SD_IN_IDX, + .irq = -1, .module = PERIPH_I2S1_MODULE, } }; diff --git a/components/soc/esp32s3/include/soc/soc_caps.h b/components/soc/esp32s3/include/soc/soc_caps.h index 5edff45ab4..f2fda6ab00 100644 --- a/components/soc/esp32s3/include/soc/soc_caps.h +++ b/components/soc/esp32s3/include/soc/soc_caps.h @@ -67,7 +67,6 @@ #define SOC_I2S_SUPPORTS_PCM (1) #define SOC_I2S_SUPPORTS_PDM_TX (1) #define SOC_I2S_SUPPORTS_PDM_RX (1) -#define SOC_I2S_SUPPORTS_PDM (1) //(SOC_I2S_SUPPORTS_PDM_RX | SOC_I2S_SUPPORTS_PDM_TX) #define SOC_I2S_SUPPORTS_TDM (1) /*-------------------------- LEDC CAPS ---------------------------------------*/ diff --git a/docs/en/api-reference/peripherals/i2s.rst b/docs/en/api-reference/peripherals/i2s.rst index 06c6d44fd5..55b9c883b3 100644 --- a/docs/en/api-reference/peripherals/i2s.rst +++ b/docs/en/api-reference/peripherals/i2s.rst @@ -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 -------------