diff --git a/components/driver/i2s.c b/components/driver/i2s.c index bffea378d9..e433510012 100644 --- a/components/driver/i2s.c +++ b/components/driver/i2s.c @@ -18,10 +18,13 @@ #include "driver/i2s.h" #include "hal/gpio_hal.h" #include "hal/i2s_hal.h" -#if SOC_I2S_SUPPORTS_ADC_DAC +#if SOC_I2S_SUPPORTS_DAC #include "driver/dac.h" +#endif // SOC_I2S_SUPPORTS_DAC + +#if SOC_I2S_SUPPORTS_ADC #include "adc1_private.h" -#endif +#endif // SOC_I2S_SUPPORTS_ADC #if SOC_GDMA_SUPPORTED #include "esp_private/gdma.h" @@ -65,8 +68,8 @@ static const char *TAG = "I2S"; typedef struct { char **buf; int buf_size; - int rw_pos; - void *curr_ptr; + volatile int rw_pos; + volatile void *curr_ptr; SemaphoreHandle_t mux; xQueueHandle queue; lldesc_t **desc; @@ -91,7 +94,6 @@ typedef struct { #else i2s_isr_handle_t i2s_isr_handle; /*!< I2S Interrupt handle*/ #endif - int intr_alloc_flags; /*!< Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info */ bool tx_desc_auto_clear; /*!< I2S auto clear tx descriptor on underflow */ bool use_apll; /*!< I2S use APLL clock */ int fixed_mclk; /*!< I2S fixed MLCK clock */ @@ -110,18 +112,90 @@ static portMUX_TYPE i2s_spinlock[SOC_I2S_NUM] = { [0 ... SOC_I2S_NUM - 1] = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED, }; -#if SOC_I2S_SUPPORTS_ADC_DAC +#if SOC_I2S_SUPPORTS_ADC static int _i2s_adc_unit = -1; static int _i2s_adc_channel = -1; #endif -/*------------------------------------------------------------- +/* + * This block is an overview of APIs in i2s.c + * Functions with [main] tag are summary functions that provide main i2s service + * Functions with [helper] tag are helper functions that served for summary functions + * Functions with [intr] tag are interrupt handling functions or interrupt callback functions + ------------------------------------------------------------- I2S GPIO operation ------------------------------------------------------------- - [helper] gpio_matrix_out_check_and_set - [helper] gpio_matrix_in_check_and_set - [helper] i2s_check_set_mclk - [main] i2s_set_pin + ------------------------------------------------------------- + I2S DMA operation + ------------------------------------------------------------- + - [intr] i2s_dma_rx_callback + - [intr] i2s_dma_tx_callback + - [intr] i2s_intr_handler_default + - [helper] i2s_dma_intr_init + - [helper] i2s_tx_reset + - [helper] i2s_rx_reset + - [helper] i2s_tx_start + - [helper] i2s_rx_start + - [helper] i2s_tx_stop + - [helper] i2s_rx_stop + ------------------------------------------------------------- + I2S buffer operation + ------------------------------------------------------------- + - [helper] i2s_get_buf_size + - [helper] i2s_delete_dma_buffer + - [helper] i2s_alloc_dma_buffer + - [main] i2s_realloc_dma_buffer + - [main] i2s_destroy_dma_object + - [main] i2s_create_dma_object + - [main] i2s_zero_dma_buffer + ------------------------------------------------------------- + I2S clock operation + ------------------------------------------------------------- + - [helper] i2s_get_source_clock + - [helper] i2s_calculate_adc_dac_clock + - [helper] i2s_calculate_pdm_tx_clock + - [helper] i2s_calculate_pdm_rx_clock + - [helper] i2s_calculate_common_clock + - [main] i2s_calculate_clock + ------------------------------------------------------------- + I2S configuration + ------------------------------------------------------------- + - [helper] i2s_get_max_channel_num + - [helper] i2s_get_active_channel_num + - [helper] i2s_set_dac_mode + - [helper] _i2s_adc_mode_recover + - [main] i2s_set_adc_mode + - [main] i2s_adc_enable + - [main] i2s_adc_disable + - [helper] i2s_set_sample_rates + - [main] i2s_pcm_config + - [helper] i2s_set_pdm_rx_down_sample + - [helper] i2s_set_pdm_tx_up_sample + - [helper] i2s_check_cfg_validity + - [helper] i2s_tx_set_clk_and_channel + - [helper] i2s_rx_set_clk_and_channel + - [main] i2s_get_clk + - [main] i2s_set_clk + ------------------------------------------------------------- + I2S driver operation + ------------------------------------------------------------- + - [main] i2s_start + - [main] i2s_stop + - [helper] i2s_driver_init + - [helper] i2s_dma_object_init + - [main] i2s_driver_install + - [main] i2s_driver_uninstall + - [main] i2s_write + - [main] i2s_write_expand + - [main] i2s_read + -------------------------------------------------------------*/ + +/*------------------------------------------------------------- + I2S GPIO operation -------------------------------------------------------------*/ /** * @brief I2S GPIO matrix set ouput @@ -209,7 +283,7 @@ esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin) { ESP_RETURN_ON_FALSE((i2s_num < I2S_NUM_MAX), ESP_ERR_INVALID_ARG, TAG, "i2s_num error"); if (pin == NULL) { -#if SOC_I2S_SUPPORTS_ADC_DAC +#if SOC_I2S_SUPPORTS_DAC return i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN); #else return ESP_ERR_INVALID_ARG; @@ -257,17 +331,6 @@ esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin) /*------------------------------------------------------------- I2S DMA operation - ------------------------------------------------------------- - - [intr] i2s_dma_rx_callback - - [intr] i2s_dma_tx_callback - - [intr] i2s_intr_handler_default - - [helper] i2s_dma_intr_init - - [helper] i2s_tx_reset - - [helper] i2s_rx_reset - - [helper] i2s_tx_start - - [helper] i2s_rx_start - - [helper] i2s_tx_stop - - [helper] i2s_rx_stop -------------------------------------------------------------*/ #if SOC_GDMA_SUPPORTED /** @@ -278,7 +341,8 @@ esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin) * @param event_data GDMA rx event data * @param user_data GDMA user data * @return - * - whether need yield + * - true need yield + * - false no need */ static bool IRAM_ATTR i2s_dma_rx_callback(gdma_channel_handle_t dma_chan, gdma_event_data_t *event_data, void *user_data) { @@ -433,19 +497,25 @@ static void IRAM_ATTR i2s_intr_handler_default(void *arg) * - ESP_ERR_INVALID_ARG Invalid arguments * - ESP_ERR_INVALID_STATE GDMA state error */ -static esp_err_t i2s_dma_intr_init(i2s_port_t i2s_num) +static esp_err_t i2s_dma_intr_init(i2s_port_t i2s_num, int intr_flag) { #if SOC_GDMA_SUPPORTED /* Set GDMA trigger module */ gdma_trigger_t trig = {.periph = GDMA_TRIG_PERIPH_I2S}; + + switch (i2s_num) { #if SOC_I2S_NUM > 1 - /* Set GDMA trigger instance */ - trig.instance_id = (i2s_num == I2S_NUM_0) ? SOC_GDMA_TRIG_PERIPH_I2S0 : SOC_GDMA_TRIG_PERIPH_I2S1; -#else - trig.instance_id = SOC_GDMA_TRIG_PERIPH_I2S0; -#endif // SOC_I2S_NUM + case I2S_NUM_1: + trig.instance_id = SOC_GDMA_TRIG_PERIPH_I2S1; + break; +#endif + default: + trig.instance_id = SOC_GDMA_TRIG_PERIPH_I2S0; + break; + } + /* Set GDMA config */ - gdma_channel_alloc_config_t dma_cfg = {.flags.reserve_sibling = 1}; + gdma_channel_alloc_config_t dma_cfg = {}; if ( p_i2s[i2s_num]->hal_cfg.mode & I2S_MODE_TX) { dma_cfg.direction = GDMA_CHANNEL_DIRECTION_TX; /* Register a new GDMA tx channel */ @@ -466,7 +536,7 @@ static esp_err_t i2s_dma_intr_init(i2s_port_t i2s_num) } #else /* Initial I2S module interrupt */ - ESP_RETURN_ON_ERROR(esp_intr_alloc(i2s_periph_signal[i2s_num].irq, p_i2s[i2s_num]->intr_alloc_flags, i2s_intr_handler_default, p_i2s[i2s_num], &p_i2s[i2s_num]->i2s_isr_handle), TAG, "Register I2S Interrupt error"); + ESP_RETURN_ON_ERROR(esp_intr_alloc(i2s_periph_signal[i2s_num].irq, intr_flag, i2s_intr_handler_default, p_i2s[i2s_num], &p_i2s[i2s_num]->i2s_isr_handle), TAG, "Register I2S Interrupt error"); #endif // SOC_GDMA_SUPPORTED return ESP_OK; } @@ -548,11 +618,11 @@ static void i2s_rx_start(i2s_port_t i2s_num) */ static void i2s_tx_stop(i2s_port_t i2s_num) { + i2s_hal_stop_tx(&(p_i2s[i2s_num]->hal)); #if SOC_GDMA_SUPPORTED gdma_stop(p_i2s[i2s_num]->tx_dma_chan); #else i2s_hal_stop_tx_link(&(p_i2s[i2s_num]->hal)); - i2s_hal_stop_tx(&(p_i2s[i2s_num]->hal)); i2s_hal_disable_tx_intr(&(p_i2s[i2s_num]->hal)); i2s_hal_disable_tx_dma(&(p_i2s[i2s_num]->hal)); #endif @@ -565,11 +635,11 @@ static void i2s_tx_stop(i2s_port_t i2s_num) */ static void i2s_rx_stop(i2s_port_t i2s_num) { + i2s_hal_stop_rx(&(p_i2s[i2s_num]->hal)); #if SOC_GDMA_SUPPORTED gdma_stop(p_i2s[i2s_num]->rx_dma_chan); #else i2s_hal_stop_rx_link(&(p_i2s[i2s_num]->hal)); - i2s_hal_stop_rx(&(p_i2s[i2s_num]->hal)); i2s_hal_disable_rx_intr(&(p_i2s[i2s_num]->hal)); i2s_hal_disable_rx_dma(&(p_i2s[i2s_num]->hal)); #endif @@ -577,14 +647,6 @@ static void i2s_rx_stop(i2s_port_t i2s_num) /*------------------------------------------------------------- I2S buffer operation - ------------------------------------------------------------- - - [helper] i2s_get_buf_size - - [helper] i2s_delete_dma_buffer - - [helper] i2s_alloc_dma_buffer - - [main] i2s_realloc_dma_buffer - - [main] i2s_destroy_dma_object - - [main] i2s_create_dma_object - - [main] i2s_zero_dma_buffer -------------------------------------------------------------*/ /** * @brief I2S get DMA buffer size @@ -647,14 +709,14 @@ static esp_err_t i2s_alloc_dma_buffer(i2s_port_t i2s_num, i2s_dma_t *dma_obj) uint32_t buf_cnt = p_i2s[i2s_num]->dma_buf_count; for (int cnt = 0; cnt < buf_cnt; cnt++) { /* Allocate DMA buffer */ - dma_obj->buf[cnt] = (char *) heap_caps_calloc(1, dma_obj->buf_size, MALLOC_CAP_DMA); + dma_obj->buf[cnt] = (char *) heap_caps_calloc(dma_obj->buf_size, sizeof(char), MALLOC_CAP_DMA); ESP_GOTO_ON_FALSE(dma_obj->buf[cnt], ESP_ERR_NO_MEM, err, TAG, "Error malloc dma buffer"); /* Initialize DMA buffer to 0 */ memset(dma_obj->buf[cnt], 0, dma_obj->buf_size); ESP_LOGD(TAG, "Addr[%d] = %d", cnt, (int)dma_obj->buf[cnt]); /* Allocate DMA descpriptor */ - dma_obj->desc[cnt] = (lldesc_t *) heap_caps_malloc(sizeof(lldesc_t), MALLOC_CAP_DMA); + dma_obj->desc[cnt] = (lldesc_t *) heap_caps_calloc(1, sizeof(lldesc_t), MALLOC_CAP_DMA); ESP_GOTO_ON_FALSE(dma_obj->desc[cnt], ESP_ERR_NO_MEM, err, TAG, "Error malloc dma description entry"); } /* DMA descriptor must be initialize after all descriptor has been created, otherwise they can't be linked together as a chain */ @@ -759,22 +821,26 @@ static esp_err_t i2s_create_dma_object(i2s_port_t i2s_num, i2s_dma_t **dma) uint32_t buf_cnt = p_i2s[i2s_num]->dma_buf_count; /* Allocate new DMA structure */ *dma = (i2s_dma_t *) malloc(sizeof(i2s_dma_t)); - ESP_RETURN_ON_FALSE(dma, ESP_ERR_NO_MEM, TAG, "DMA object secondary pointer is NULL"); + ESP_RETURN_ON_FALSE(*dma, ESP_ERR_NO_MEM, TAG, "DMA object allocate failed"); /* Allocate DMA buffer poiter */ - (*dma)->buf = (char **)malloc(sizeof(char *) * buf_cnt); + (*dma)->buf = (char **)heap_caps_calloc(buf_cnt, sizeof(char *), MALLOC_CAP_DMA); if (!(*dma)->buf) { goto err; } - memset((*dma)->buf, 0, sizeof(char *) * buf_cnt); - /* Allocate DMA descriptor poiter */ - (*dma)->desc = (lldesc_t **) malloc(sizeof(lldesc_t *) * buf_cnt); + /* Allocate secondary pointer of DMA descriptor chain */ + (*dma)->desc = (lldesc_t **)heap_caps_calloc(buf_cnt, sizeof(lldesc_t *), MALLOC_CAP_DMA); if (!(*dma)->desc) { goto err; } - memset((*dma)->desc, 0, sizeof(lldesc_t *) * buf_cnt); /* Create queue and mutex */ (*dma)->queue = xQueueCreate(buf_cnt - 1, sizeof(char *)); + if (!(*dma)->queue) { + goto err; + } (*dma)->mux = xSemaphoreCreateMutex(); + if (!(*dma)->mux) { + goto err; + } return ESP_OK; err: @@ -821,13 +887,6 @@ esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num) /*------------------------------------------------------------- I2S clock operation - ------------------------------------------------------------- - - [helper] i2s_get_source_clock - - [helper] i2s_calculate_adc_dac_clock - - [helper] i2s_calculate_pdm_tx_clock - - [helper] i2s_calculate_pdm_rx_clock - - [helper] i2s_calculate_common_clock - - [main] i2s_calculate_clock -------------------------------------------------------------*/ #if SOC_I2S_SUPPORTS_APLL /** @@ -863,7 +922,7 @@ esp_err_t i2s_zero_dma_buffer(i2s_port_t i2s_num) * * @return ESP_ERR_INVALID_ARG or ESP_OK */ -float i2s_apll_get_fi2s(int bits_per_sample, int sdm0, int sdm1, int sdm2, int odir) +static float i2s_apll_get_division_coefficient(int bits_per_sample, int sdm0, int sdm1, int sdm2, int odir) { int f_xtal = (int)rtc_clk_xtal_freq_get() * 1000000; @@ -898,8 +957,8 @@ static void i2s_apll_calculate_fi2s(int rate, int bits_per_sample, int *sdm0, in min_diff = SOC_I2S_APLL_MAX_FREQ; for (_sdm2 = 4; _sdm2 < 9; _sdm2 ++) { - max_rate = i2s_apll_get_fi2s(bits_per_sample, 255, 255, _sdm2, 0); - min_rate = i2s_apll_get_fi2s(bits_per_sample, 0, 0, _sdm2, 31); + max_rate = i2s_apll_get_division_coefficient(bits_per_sample, 255, 255, _sdm2, 0); + min_rate = i2s_apll_get_division_coefficient(bits_per_sample, 0, 0, _sdm2, 31); avg = (max_rate + min_rate) / 2; if (abs(avg - rate) < min_diff) { min_diff = abs(avg - rate); @@ -908,8 +967,8 @@ static void i2s_apll_calculate_fi2s(int rate, int bits_per_sample, int *sdm0, in } min_diff = SOC_I2S_APLL_MAX_FREQ; for (_odir = 0; _odir < 32; _odir ++) { - max_rate = i2s_apll_get_fi2s(bits_per_sample, 255, 255, *sdm2, _odir); - min_rate = i2s_apll_get_fi2s(bits_per_sample, 0, 0, *sdm2, _odir); + max_rate = i2s_apll_get_division_coefficient(bits_per_sample, 255, 255, *sdm2, _odir); + min_rate = i2s_apll_get_division_coefficient(bits_per_sample, 0, 0, *sdm2, _odir); avg = (max_rate + min_rate) / 2; if (abs(avg - rate) < min_diff) { min_diff = abs(avg - rate); @@ -918,8 +977,8 @@ static void i2s_apll_calculate_fi2s(int rate, int bits_per_sample, int *sdm0, in } min_diff = SOC_I2S_APLL_MAX_FREQ; for (_sdm2 = 4; _sdm2 < 9; _sdm2 ++) { - max_rate = i2s_apll_get_fi2s(bits_per_sample, 255, 255, _sdm2, *odir); - min_rate = i2s_apll_get_fi2s(bits_per_sample, 0, 0, _sdm2, *odir); + max_rate = i2s_apll_get_division_coefficient(bits_per_sample, 255, 255, _sdm2, *odir); + min_rate = i2s_apll_get_division_coefficient(bits_per_sample, 0, 0, _sdm2, *odir); avg = (max_rate + min_rate) / 2; if (abs(avg - rate) < min_diff) { min_diff = abs(avg - rate); @@ -929,8 +988,8 @@ static void i2s_apll_calculate_fi2s(int rate, int bits_per_sample, int *sdm0, in min_diff = SOC_I2S_APLL_MAX_FREQ; for (_sdm1 = 0; _sdm1 < 256; _sdm1 ++) { - max_rate = i2s_apll_get_fi2s(bits_per_sample, 255, _sdm1, *sdm2, *odir); - min_rate = i2s_apll_get_fi2s(bits_per_sample, 0, _sdm1, *sdm2, *odir); + max_rate = i2s_apll_get_division_coefficient(bits_per_sample, 255, _sdm1, *sdm2, *odir); + min_rate = i2s_apll_get_division_coefficient(bits_per_sample, 0, _sdm1, *sdm2, *odir); avg = (max_rate + min_rate) / 2; if (abs(avg - rate) < min_diff) { min_diff = abs(avg - rate); @@ -940,7 +999,7 @@ static void i2s_apll_calculate_fi2s(int rate, int bits_per_sample, int *sdm0, in min_diff = SOC_I2S_APLL_MAX_FREQ; for (_sdm0 = 0; _sdm0 < 256; _sdm0 ++) { - avg = i2s_apll_get_fi2s(bits_per_sample, _sdm0, *sdm1, *sdm2, *odir); + avg = i2s_apll_get_division_coefficient(bits_per_sample, _sdm0, *sdm1, *sdm2, *odir); if (abs(avg - rate) < min_diff) { min_diff = abs(avg - rate); *sdm0 = _sdm0; @@ -966,7 +1025,10 @@ static uint32_t i2s_get_source_clock(i2s_port_t i2s_num, bool use_apll, uint32_t int sdm1 = 0; int sdm2 = 0; int odir = 0; - if ((fixed_mclk / p_i2s[i2s_num]->hal_cfg.chan_bits / 16) < SOC_I2S_APLL_MIN_RATE) { + if (fixed_mclk == 0) { + ESP_LOGI(TAG, "fixed_mclk is not set, set to 128 MHz as default"); + fixed_mclk = 128000000; + }else if ((fixed_mclk / p_i2s[i2s_num]->hal_cfg.chan_bits / 16) < SOC_I2S_APLL_MIN_RATE) { ESP_LOGW(TAG, "fixed_mclk is too small, use I2S_CLK_D2CLK as default clock source"); goto err; } @@ -990,7 +1052,7 @@ err: #endif } -#if SOC_I2S_SUPPORTS_ADC_DAC +#if SOC_I2S_SUPPORTS_ADC || SOC_I2S_SUPPORTS_DAC /** * @brief I2S calculate clock for built-in ADC/DAC mode * @@ -1022,7 +1084,7 @@ static esp_err_t i2s_calculate_adc_dac_clock(int i2s_num, i2s_hal_clock_cfg_t *c return ESP_OK; } -#endif // SOC_I2S_SUPPORTS_ADC_DAC +#endif // SOC_I2S_SUPPORTS_ADC || SOC_I2S_SUPPORTS_DAC #if SOC_I2S_SUPPORTS_PDM_TX /** @@ -1037,7 +1099,7 @@ static esp_err_t i2s_calculate_adc_dac_clock(int i2s_num, i2s_hal_clock_cfg_t *c static esp_err_t i2s_calculate_pdm_tx_clock(int i2s_num, i2s_hal_clock_cfg_t *clk_cfg) { ESP_RETURN_ON_FALSE(clk_cfg, ESP_ERR_INVALID_ARG, TAG, "input clk_cfg is NULL"); - ESP_RETURN_ON_FALSE(p_i2s[i2s_num]->hal_cfg.mode == I2S_MODE_PDM, ESP_ERR_INVALID_ARG, TAG, "current mode is not PDM"); + ESP_RETURN_ON_FALSE(p_i2s[i2s_num]->hal_cfg.mode & I2S_MODE_PDM, ESP_ERR_INVALID_ARG, TAG, "current mode is not PDM"); /* Set I2S module clock */ clk_cfg->sclk = i2s_get_source_clock(i2s_num, p_i2s[i2s_num]->use_apll, p_i2s[i2s_num]->fixed_mclk); @@ -1074,7 +1136,7 @@ static esp_err_t i2s_calculate_pdm_tx_clock(int i2s_num, i2s_hal_clock_cfg_t *cl static esp_err_t i2s_calculate_pdm_rx_clock(int i2s_num, i2s_hal_clock_cfg_t *clk_cfg) { ESP_RETURN_ON_FALSE(clk_cfg, ESP_ERR_INVALID_ARG, TAG, "input clk_cfg is NULL"); - ESP_RETURN_ON_FALSE(p_i2s[i2s_num]->hal_cfg.mode == I2S_MODE_PDM, ESP_ERR_INVALID_ARG, TAG, "current mode is not PDM"); + ESP_RETURN_ON_FALSE(p_i2s[i2s_num]->hal_cfg.mode & I2S_MODE_PDM, ESP_ERR_INVALID_ARG, TAG, "current mode is not PDM"); /* Set I2S module clock */ clk_cfg->sclk = i2s_get_source_clock(i2s_num, p_i2s[i2s_num]->use_apll, p_i2s[i2s_num]->fixed_mclk); @@ -1111,19 +1173,37 @@ static esp_err_t i2s_calculate_common_clock(int i2s_num, i2s_hal_clock_cfg_t *cl { ESP_RETURN_ON_FALSE(clk_cfg, ESP_ERR_INVALID_ARG, TAG, "input clk_cfg is NULL"); - /* Temp value for simplification */ uint32_t rate = p_i2s[i2s_num]->hal_cfg.sample_rate; - uint32_t chan_num = p_i2s[i2s_num]->hal_cfg.total_chan; + uint32_t chan_num = p_i2s[i2s_num]->hal_cfg.total_chan < 2 ? 2 : p_i2s[i2s_num]->hal_cfg.total_chan; uint32_t chan_bit = p_i2s[i2s_num]->hal_cfg.chan_bits; - i2s_mclk_multiple_t multi = p_i2s[i2s_num]->mclk_multiple ? p_i2s[i2s_num]->mclk_multiple : I2S_MCLK_MULTIPLE_256; - + uint32_t multi; /* Set I2S module clock */ clk_cfg->sclk = i2s_get_source_clock(i2s_num, p_i2s[i2s_num]->use_apll, p_i2s[i2s_num]->fixed_mclk); + /* Calculate multiple */ + if (p_i2s[i2s_num]->hal_cfg.mode & I2S_MODE_MASTER) { + multi = p_i2s[i2s_num]->mclk_multiple ? p_i2s[i2s_num]->mclk_multiple : I2S_MCLK_MULTIPLE_256; + } else { + /* Only need to set the multiple of mclk to sample rate for MASTER mode, + * because BCK and WS clock are provided by the external codec in SLAVE mode. + * The multiple should be big enough to get a high module clock which could detect the edges of externel clock more accurately, + * otherwise the data we receive or send would get a large latency and go wrong due to the slow module clock. + * But on ESP32 and ESP32S2, due to the different clock work mode in hardware, + * their multiple should be set to an appropriate range according to the sample bits, + * and this particular multiple finally aims at guaranteeing the bclk_div not smaller than 8, + * if not, the I2S may can't send data or send wrong data. + * Here use 'SOC_I2S_SUPPORTS_TDM' to differentialize other chips with ESP32 and ESP32S2. + */ +#if SOC_I2S_SUPPORTS_TDM + multi = clk_cfg->sclk / rate; +#else + multi = 64 * chan_bit; +#endif + } /* Set I2S bit clock */ clk_cfg->bclk = rate * chan_num * chan_bit; /* Set I2S bit clock division according to the sample rate and multiple of mclk */ clk_cfg->bclk_div = rate * multi / clk_cfg->bclk; - /* Get I2S master clock, mclk = bclk * bclk_div */ + /* Get I2S master clock, mclk = bclk * bclk_div = rate * multiple */ clk_cfg->mclk = clk_cfg->bclk * clk_cfg->bclk_div; /* Get I2S master clock rough division, later will calculate the fine division parameters in HAL */ clk_cfg->mclk_div = clk_cfg->sclk / clk_cfg->mclk; @@ -1146,47 +1226,45 @@ static esp_err_t i2s_calculate_common_clock(int i2s_num, i2s_hal_clock_cfg_t *cl */ static esp_err_t i2s_calculate_clock(i2s_port_t i2s_num, i2s_hal_clock_cfg_t *clk_cfg) { -#if SOC_I2S_SUPPORTS_ADC_DAC - if (p_i2s[i2s_num]->hal_cfg.mode & (I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN)) { - ESP_RETURN_ON_ERROR(i2s_calculate_adc_dac_clock(i2s_num, clk_cfg), TAG, "ADC/DAC clock calculate failed"); + /* Calculate clock for ADC mode */ +#if SOC_I2S_SUPPORTS_ADC + if (p_i2s[i2s_num]->hal_cfg.mode & I2S_MODE_ADC_BUILT_IN) { + ESP_RETURN_ON_ERROR(i2s_calculate_adc_dac_clock(i2s_num, clk_cfg), TAG, "ADC clock calculate failed"); return ESP_OK; } -#endif +#endif // SOC_I2S_SUPPORTS_ADC + /* Calculate clock for DAC mode */ +#if SOC_I2S_SUPPORTS_DAC + if (p_i2s[i2s_num]->hal_cfg.mode & I2S_MODE_DAC_BUILT_IN) { + ESP_RETURN_ON_ERROR(i2s_calculate_adc_dac_clock(i2s_num, clk_cfg), TAG, "DAC clock calculate failed"); + return ESP_OK; + } +#endif // SOC_I2S_SUPPORTS_DAC + + /* Calculate clock for PDM mode */ +#if SOC_I2S_SUPPORTS_PDM_TX || SOC_I2S_SUPPORTS_PDM_RX + if (p_i2s[i2s_num]->hal_cfg.mode & I2S_MODE_PDM) { #if SOC_I2S_SUPPORTS_PDM_TX - if (p_i2s[i2s_num]->hal_cfg.mode & I2S_MODE_PDM && p_i2s[i2s_num]->hal_cfg.mode & I2S_MODE_TX) { - ESP_RETURN_ON_ERROR(i2s_calculate_pdm_tx_clock(i2s_num, clk_cfg), TAG, "PDM TX clock calculate failed"); - return ESP_OK; - } -#endif + if (p_i2s[i2s_num]->hal_cfg.mode & I2S_MODE_TX) { + ESP_RETURN_ON_ERROR(i2s_calculate_pdm_tx_clock(i2s_num, clk_cfg), TAG, "PDM TX clock calculate failed"); + } +#endif // SOC_I2S_SUPPORTS_PDM_TX #if SOC_I2S_SUPPORTS_PDM_RX - if (p_i2s[i2s_num]->hal_cfg.mode & I2S_MODE_PDM && p_i2s[i2s_num]->hal_cfg.mode & I2S_MODE_RX) { - ESP_RETURN_ON_ERROR(i2s_calculate_pdm_rx_clock(i2s_num, clk_cfg), TAG, "PDM RX clock calculate failed"); + if (p_i2s[i2s_num]->hal_cfg.mode & I2S_MODE_RX) { + ESP_RETURN_ON_ERROR(i2s_calculate_pdm_rx_clock(i2s_num, clk_cfg), TAG, "PDM RX clock calculate failed"); + } +#endif // SOC_I2S_SUPPORTS_PDM_RX return ESP_OK; } -#endif +#endif // SOC_I2S_SUPPORTS_PDM_TX || SOC_I2S_SUPPORTS_PDM_RX + + /* Calculate clock for common mode */ ESP_RETURN_ON_ERROR(i2s_calculate_common_clock(i2s_num, clk_cfg), TAG, "Common clock calculate failed"); return ESP_OK; } /*------------------------------------------------------------- I2S configuration - ------------------------------------------------------------- - - [helper] i2s_get_max_channel_num - - [helper] i2s_get_active_channel_num - - [helper] i2s_set_dac_mode - - [helper] _i2s_adc_mode_recover - - [main] i2s_set_adc_mode - - [main] i2s_adc_enable - - [main] i2s_adc_disable - - [helper] i2s_set_sample_rates - - [main] i2s_pcm_config - - [helper] i2s_set_pdm_rx_down_sample - - [helper] i2s_set_pdm_tx_up_sample - - [helper] i2s_check_cfg_validity - - [helper] i2s_tx_set_clk_and_channel - - [helper] i2s_rx_set_clk_and_channel - - [main] i2s_get_clk - - [main] i2s_set_clk -------------------------------------------------------------*/ #if SOC_I2S_SUPPORTS_TDM /** @@ -1194,7 +1272,7 @@ static esp_err_t i2s_calculate_clock(i2s_port_t i2s_num, i2s_hal_clock_cfg_t *cl * * @param chan_mask I2S channel mask that indicates which channels are actived * @return - * - max actived channel number + * - Max actived channel number */ static uint32_t i2s_get_max_channel_num(i2s_channel_t chan_mask) { @@ -1205,7 +1283,8 @@ static uint32_t i2s_get_max_channel_num(i2s_channel_t chan_mask) max_chan = i + 1; } } - return max_chan; + /* Can't be smaller than 2 */ + return max_chan < 2 ? 2 : max_chan; } #endif @@ -1216,7 +1295,7 @@ static uint32_t i2s_get_max_channel_num(i2s_channel_t chan_mask) * * @param hal_cfg [input/output] I2S hal configuration structer * @return - * - active channel number + * - Active channel number */ static uint32_t i2s_get_active_channel_num(const i2s_hal_config_t *hal_cfg) { @@ -1245,7 +1324,7 @@ static uint32_t i2s_get_active_channel_num(const i2s_hal_config_t *hal_cfg) } } -#if SOC_I2S_SUPPORTS_ADC_DAC +#if SOC_I2S_SUPPORTS_DAC /** * @brief I2S set built-in DAC mode * @@ -1275,7 +1354,9 @@ esp_err_t i2s_set_dac_mode(i2s_dac_mode_t dac_mode) } return ESP_OK; } +#endif // SOC_I2S_SUPPORTS_DAC +#if SOC_I2S_SUPPORTS_ADC /** * @brief ADC mode recover * @@ -1372,7 +1453,7 @@ esp_err_t i2s_set_sample_rates(i2s_port_t i2s_num, uint32_t rate) /** * @brief Configure I2S a/u-law decompress or compress * @note This function should be called after i2s driver installed - * Only take effecttive when the i2s 'communication_format' is set to 'I2S_COMM_FORMAT_STAND_PCM_SHORT' or 'I2S_COMM_FORMAT_STAND_PCM_LONG' + * Only take effect when the i2s 'communication_format' is set to 'I2S_COMM_FORMAT_STAND_PCM_SHORT' or 'I2S_COMM_FORMAT_STAND_PCM_LONG' * * @param i2s_num I2S_NUM_0 * @param pcm_cfg Including mode selection and a/u-law decompress or compress configuration paramater @@ -1477,7 +1558,7 @@ static esp_err_t i2s_check_cfg_validity(i2s_port_t i2s_num, i2s_hal_config_t *cf ESP_RETURN_ON_FALSE(!(cfg->mode & I2S_MODE_PDM), ESP_ERR_INVALID_ARG, TAG, "I2S PDM mode not supported on current chip"); #endif // SOC_I2S_SUPPORTS_PDM_TX || SOC_I2S_SUPPORTS_PDM_RX -#if SOC_I2S_SUPPORTS_ADC_DAC +#if SOC_I2S_SUPPORTS_ADC || SOC_I2S_SUPPORTS_DAC /* Check built-in ADC/DAC mode */ if (cfg->mode & (I2S_MODE_ADC_BUILT_IN | I2S_MODE_DAC_BUILT_IN)) { ESP_RETURN_ON_FALSE(i2s_num == I2S_NUM_0, ESP_ERR_INVALID_ARG, TAG, "I2S built-in ADC/DAC only support on I2S0"); @@ -1487,7 +1568,7 @@ static esp_err_t i2s_check_cfg_validity(i2s_port_t i2s_num, i2s_hal_config_t *cf ESP_RETURN_ON_FALSE((cfg->mode & I2S_MODE_TX) || (cfg->mode & I2S_MODE_RX), ESP_ERR_INVALID_ARG, TAG, "I2S no TX/RX mode selected"); /* Check communication format */ ESP_RETURN_ON_FALSE(cfg->comm_fmt && (cfg->comm_fmt < I2S_COMM_FORMAT_STAND_MAX), ESP_ERR_INVALID_ARG, TAG, "invalid communication formats"); -#endif // SOC_I2S_SUPPORTS_ADC_DAC +#endif // SOC_I2S_SUPPORTS_ADC || SOC_I2S_SUPPORTS_DAC return ESP_OK; } @@ -1553,20 +1634,30 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_ if (p_i2s[i2s_num]->last_buf_size) { cfg->sample_rate = rate; cfg->sample_bits = bits_cfg & 0xFFFF; - cfg->chan_bits = (bits_cfg >> 16) ? (bits_cfg >> 16) : cfg->sample_bits; + cfg->chan_bits = (bits_cfg >> 16) > cfg->sample_bits ? (bits_cfg >> 16) : cfg->sample_bits; #if SOC_I2S_SUPPORTS_TDM cfg->chan_mask = ch; + cfg->chan_fmt = ch == I2S_CHANNEL_MONO ? I2S_CHANNEL_FMT_ONLY_RIGHT : cfg->chan_fmt; cfg->active_chan = i2s_get_active_channel_num(cfg); uint32_t max_channel = i2s_get_max_channel_num(cfg->chan_mask); /* If total channel is smaller than max actived channel number then set it to the max active channel number */ cfg->total_chan = p_i2s[i2s_num]->hal_cfg.total_chan < max_channel ? max_channel : p_i2s[i2s_num]->hal_cfg.total_chan; -#endif -#if !SOC_I2S_SUPPORTS_TDM - cfg->active_chan = i2s_get_active_channel_num(cfg); - cfg->total_chan = ch == I2S_CHANNEL_MONO ? 2 : cfg->active_chan; +#else /* Default */ - cfg->chan_fmt = cfg->chan_fmt < I2S_CHANNEL_FMT_ONLY_RIGHT ? I2S_CHANNEL_FMT_ONLY_RIGHT : cfg->chan_fmt; + cfg->chan_fmt = ch == I2S_CHANNEL_MONO ? I2S_CHANNEL_FMT_ONLY_RIGHT : cfg->chan_fmt; + cfg->active_chan = i2s_get_active_channel_num(cfg); + cfg->total_chan = 2; #endif + if (cfg->mode & I2S_MODE_TX) { + xSemaphoreTake(p_i2s[i2s_num]->tx->mux, (portTickType)portMAX_DELAY); + i2s_hal_tx_set_channel_style(&(p_i2s[i2s_num]->hal), cfg); + xSemaphoreGive(p_i2s[i2s_num]->tx->mux); + } + if (cfg->mode & I2S_MODE_RX) { + xSemaphoreTake(p_i2s[i2s_num]->rx->mux, (portTickType)portMAX_DELAY); + i2s_hal_rx_set_channel_style(&(p_i2s[i2s_num]->hal), cfg); + xSemaphoreGive(p_i2s[i2s_num]->rx->mux); + } } uint32_t data_bits = cfg->sample_bits; @@ -1578,42 +1669,27 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_ i2s_stop(i2s_num); i2s_hal_clock_cfg_t clk_cfg; - i2s_hal_clock_cfg_t *p_clk_cfg = NULL; - - /* If uising chips like ESP32 and ESP32S2 - * Only need to calculate clock for MASTER mode - * Because BCK and WS clock are provided by the external codec in SLAVE mode - * In SLAVE mode, the mclk_div and bck_div will be set to 1 - * So that we can get a high module clock which could detect the edges of externel clock more accurately - * Otherwise the data we receive or send would get a large latency and go wrong due to the slow module clock - * But ESP32 and ESP32S2 have to calculate and set the clock to guarantee the function in slave mode - * Here use 'SOC_I2S_SUPPORTS_TDM' to differentialize ESP32 and ESP32S2 with other chips - */ -#if SOC_I2S_SUPPORTS_TDM - if (cfg->mode & I2S_MODE_MASTER) { -#endif - p_clk_cfg = &clk_cfg; - /* To get sclk, mclk, mclk_div bclk and bclk_div */ - i2s_calculate_clock(i2s_num, p_clk_cfg); -#if SOC_I2S_SUPPORTS_TDM - } -#endif + /* To get sclk, mclk, mclk_div bclk and bclk_div */ + i2s_calculate_clock(i2s_num, &clk_cfg); uint32_t buf_size = i2s_get_buf_size(i2s_num); bool need_realloc = p_i2s[i2s_num]->last_buf_size != buf_size; - p_i2s[i2s_num]->last_buf_size = buf_size; /* TX mode clock reset */ if (cfg->mode & I2S_MODE_TX) { ESP_RETURN_ON_FALSE(p_i2s[i2s_num]->tx, ESP_ERR_INVALID_ARG, TAG, "I2S TX DMA object has not initialized yet"); /* Waiting for transmit finish */ xSemaphoreTake(p_i2s[i2s_num]->tx->mux, (portTickType)portMAX_DELAY); - i2s_tx_set_clk_and_channel(i2s_num, p_clk_cfg); + i2s_tx_set_clk_and_channel(i2s_num, &clk_cfg); /* If buffer size changed, the DMA buffer need realloc */ if (need_realloc) { p_i2s[i2s_num]->tx->buf_size = buf_size; ret = i2s_realloc_dma_buffer(i2s_num, p_i2s[i2s_num]->tx); } + /* If not the first time, update I2S tx channel style */ + if (p_i2s[i2s_num]->last_buf_size) { + i2s_hal_tx_set_channel_style(&(p_i2s[i2s_num]->hal), &(p_i2s[i2s_num]->hal_cfg)); + } /* Reset the queue to avoid receive invalid data */ xQueueReset(p_i2s[i2s_num]->tx->queue); xSemaphoreGive(p_i2s[i2s_num]->tx->mux); @@ -1624,7 +1700,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_ ESP_RETURN_ON_FALSE(p_i2s[i2s_num]->rx, ESP_ERR_INVALID_ARG, TAG, "I2S TX DMA object has not initialized yet"); /* Waiting for receive finish */ xSemaphoreTake(p_i2s[i2s_num]->rx->mux, (portTickType)portMAX_DELAY); - i2s_rx_set_clk_and_channel(i2s_num, p_clk_cfg); + i2s_rx_set_clk_and_channel(i2s_num, &clk_cfg); /* If buffer size changed, the DMA buffer need realloc */ if (need_realloc) { p_i2s[i2s_num]->rx->buf_size = buf_size; @@ -1632,11 +1708,17 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_ /* Reset the end-of-frame number */ i2s_hal_set_rx_eof_num(&(p_i2s[i2s_num]->hal), buf_size); } + /* If not the first time, update I2S rx channel style */ + if (p_i2s[i2s_num]->last_buf_size) { + i2s_hal_rx_set_channel_style(&(p_i2s[i2s_num]->hal), &(p_i2s[i2s_num]->hal_cfg)); + } /* Reset the queue to avoid receiving invalid data */ xQueueReset(p_i2s[i2s_num]->rx->queue); xSemaphoreGive(p_i2s[i2s_num]->rx->mux); ESP_RETURN_ON_ERROR(ret, TAG, "I2S%d rx DMA buffer malloc failed", i2s_num); } + /* Update last buffer size */ + p_i2s[i2s_num]->last_buf_size = buf_size; /* I2S start */ i2s_start(i2s_num); @@ -1646,16 +1728,6 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_ /*------------------------------------------------------------- I2S driver operation - ------------------------------------------------------------- - - [main] i2s_start - - [main] i2s_stop - - [helper] i2s_driver_init - - [helper] i2s_dma_object_init - - [main] i2s_driver_install - - [main] i2s_driver_uninstall - - [main] i2s_write - - [main] i2s_write_expand - - [main] i2s_read -------------------------------------------------------------*/ /** * @brief Start I2S driver @@ -1736,7 +1808,6 @@ static esp_err_t i2s_driver_init(i2s_port_t i2s_num, const i2s_config_t *i2s_con p_i2s[i2s_num]->dma_buf_count = i2s_config->dma_buf_count; p_i2s[i2s_num]->dma_buf_len = i2s_config->dma_buf_len; p_i2s[i2s_num]->last_buf_size = 0; - p_i2s[i2s_num]->intr_alloc_flags = i2s_config->intr_alloc_flags; p_i2s[i2s_num]->use_apll = i2s_config->use_apll; p_i2s[i2s_num]->fixed_mclk = i2s_config->fixed_mclk; p_i2s[i2s_num]->mclk_multiple = i2s_config->mclk_multiple; @@ -1791,7 +1862,7 @@ static esp_err_t i2s_driver_init(i2s_port_t i2s_num, const i2s_config_t *i2s_con /* Calculate actived channel number in channel mask */ p_i2s[i2s_num]->hal_cfg.active_chan = i2s_get_active_channel_num(&p_i2s[i2s_num]->hal_cfg); /* Total channel number is equal to the actived channel number in non-TDM mode */ - p_i2s[i2s_num]->hal_cfg.total_chan = p_i2s[i2s_num]->hal_cfg.active_chan; + p_i2s[i2s_num]->hal_cfg.total_chan = 2; #endif return ESP_OK; } @@ -1837,7 +1908,6 @@ static esp_err_t i2s_dma_object_init(i2s_port_t i2s_num) esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, int queue_size, void *i2s_queue) { esp_err_t ret = ESP_OK; - i2s_obj_t *pre_alloc_i2s_obj = NULL; /* Step 1: Check the validity of input parameters */ /* Check the validity of i2s device number */ @@ -1848,7 +1918,7 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, ESP_RETURN_ON_FALSE((i2s_config->dma_buf_len >= 8 && i2s_config->dma_buf_len <= 1024), ESP_ERR_INVALID_ARG, TAG, "I2S buffer length at most 1024 and more than 8"); /* Step 2: Allocate driver object and register to platform */ - pre_alloc_i2s_obj = calloc(1, sizeof(i2s_obj_t)); + i2s_obj_t *pre_alloc_i2s_obj = calloc(1, sizeof(i2s_obj_t)); ESP_RETURN_ON_FALSE(pre_alloc_i2s_obj, ESP_ERR_NO_MEM, TAG, "no mem for I2S driver"); ret = i2s_priv_register_object(pre_alloc_i2s_obj, i2s_num); if (ret != ESP_OK) { @@ -1860,40 +1930,43 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config, /* Step 3: Initialize I2S object, assign configarations */ ESP_GOTO_ON_ERROR(i2s_driver_init(i2s_num, i2s_config), err, TAG, "I2S init failed"); /* Check the validity of I2S configuration */ - ESP_GOTO_ON_ERROR(i2s_check_cfg_validity(i2s_num, &(p_i2s[i2s_num]->hal_cfg)), err, TAG, "I2S configuration is invalid"); + ESP_GOTO_ON_ERROR(i2s_check_cfg_validity(i2s_num, &(pre_alloc_i2s_obj->hal_cfg)), err, TAG, "I2S configuration is invalid"); /* Get device instance */ - i2s_hal_get_instance(&(p_i2s[i2s_num]->hal), i2s_num); + i2s_hal_init(&(pre_alloc_i2s_obj->hal), i2s_num); #ifdef CONFIG_PM_ENABLE - esp_pm_lock_type_t pm_lock = ESP_PM_NO_LIGHT_SLEEP; + esp_pm_lock_type_t pm_lock = ESP_PM_APB_FREQ_MAX; #if SOC_I2S_SUPPORTS_APLL if (i2s_config->use_apll) { pm_lock = ESP_PM_NO_LIGHT_SLEEP; } #endif // SOC_I2S_SUPPORTS_APLL - ESP_GOTO_ON_ERROR(esp_pm_lock_create(pm_lock, 0, "i2s_driver", &p_i2s[i2s_num]->pm_lock), err, TAG, "I2S pm lock error"); + ESP_GOTO_ON_ERROR(esp_pm_lock_create(pm_lock, 0, "i2s_driver", &pre_alloc_i2s_obj->pm_lock), err, TAG, "I2S pm lock error"); #endif //CONFIG_PM_ENABLE /* Step 4: Initialize I2S DMA interrupt and DMA object */ - ESP_GOTO_ON_ERROR(i2s_dma_intr_init(i2s_num), err, TAG, "I2S interrupt initailze failed"); + ESP_GOTO_ON_ERROR(i2s_dma_intr_init(i2s_num, i2s_config->intr_alloc_flags), err, TAG, "I2S interrupt initailze failed"); /* Initialize I2S DMA object */ ESP_GOTO_ON_ERROR(i2s_dma_object_init(i2s_num), err, TAG, "I2S dma object create failed"); -#if SOC_I2S_SUPPORTS_ADC_DAC +#if SOC_I2S_SUPPORTS_ADC /* If using built-in ADC, we need to enable ADC power manerge*/ - if (p_i2s[i2s_num]->hal_cfg.mode & I2S_MODE_ADC_BUILT_IN) { + if (pre_alloc_i2s_obj->hal_cfg.mode & I2S_MODE_ADC_BUILT_IN) { adc_power_acquire(); } #endif + /* Enable module clock */ + i2s_hal_enable_module_clock(&p_i2s[i2s_num]->hal); /* Step 5: Initialize I2S configuration and set the configurations to register */ - i2s_hal_init(&(p_i2s[i2s_num]->hal), &p_i2s[i2s_num]->hal_cfg); + i2s_hal_config_param(&(pre_alloc_i2s_obj->hal), &pre_alloc_i2s_obj->hal_cfg); /* Step 6: Initialise i2s event queue if user needs */ if (i2s_queue) { pre_alloc_i2s_obj->i2s_queue = xQueueCreate(queue_size, sizeof(i2s_event_t)); - ESP_GOTO_ON_ERROR((pre_alloc_i2s_obj->i2s_queue != NULL), err, TAG, "I2S queue create failed"); + printf("queue handle %p\n", pre_alloc_i2s_obj->i2s_queue); + ESP_GOTO_ON_FALSE(pre_alloc_i2s_obj->i2s_queue, ESP_ERR_NO_MEM, err, TAG, "I2S queue create failed"); *((QueueHandle_t *) i2s_queue) = pre_alloc_i2s_obj->i2s_queue; ESP_LOGI(TAG, "queue free spaces: %d", uxQueueSpacesAvailable(pre_alloc_i2s_obj->i2s_queue)); } else { @@ -1924,7 +1997,7 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num) ESP_RETURN_ON_FALSE(p_i2s[i2s_num], ESP_ERR_INVALID_STATE, TAG, "I2S port %d has not installed", i2s_num); i2s_obj_t *obj = p_i2s[i2s_num]; i2s_stop(i2s_num); -#if SOC_I2S_SUPPORTS_ADC_DAC +#if SOC_I2S_SUPPORTS_DAC i2s_set_dac_mode(I2S_DAC_CHANNEL_DISABLE); #endif #if SOC_GDMA_SUPPORTED @@ -1964,6 +2037,8 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num) p_i2s[i2s_num]->pm_lock = NULL; } #endif + /* Disable module clock */ + i2s_hal_disable_module_clock(&p_i2s[i2s_num]->hal); i2s_priv_deregister_object(i2s_num); free(obj); return ESP_OK; diff --git a/components/driver/include/driver/i2s.h b/components/driver/include/driver/i2s.h index 53dd2799a7..6fffd9311e 100644 --- a/components/driver/include/driver/i2s.h +++ b/components/driver/include/driver/i2s.h @@ -17,7 +17,7 @@ #include "driver/periph_ctrl.h" #include "esp_intr_alloc.h" -#if SOC_I2S_SUPPORTS_ADC_DAC +#if SOC_I2S_SUPPORTS_ADC #include "driver/adc.h" #endif @@ -430,7 +430,7 @@ esp_err_t i2s_set_clk(i2s_port_t i2s_num, uint32_t rate, uint32_t bits_cfg, i2s_ */ float i2s_get_clk(i2s_port_t i2s_num); -#if SOC_I2S_SUPPORTS_ADC_DAC +#if SOC_I2S_SUPPORTS_ADC /** * @brief Set built-in ADC mode for I2S DMA, this function will initialize ADC pad, * and set ADC parameters. @@ -466,7 +466,9 @@ esp_err_t i2s_adc_enable(i2s_port_t i2s_num); * - ESP_ERR_INVALID_STATE Driver state error */ esp_err_t i2s_adc_disable(i2s_port_t i2s_num); +#endif // SOC_I2S_SUPPORTS_ADC +#if SOC_I2S_SUPPORTS_DAC /** * @brief Set I2S dac mode, I2S built-in DAC is disabled by default * @@ -481,7 +483,7 @@ esp_err_t i2s_adc_disable(i2s_port_t i2s_num); * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t i2s_set_dac_mode(i2s_dac_mode_t dac_mode); -#endif //SOC_I2S_SUPPORTS_ADC_DAC +#endif //SOC_I2S_SUPPORTS_DAC #ifdef __cplusplus diff --git a/components/driver/test/test_i2s.c b/components/driver/test/test_i2s.c index 2e303b6e3d..5a0e79755d 100644 --- a/components/driver/test/test_i2s.c +++ b/components/driver/test/test_i2s.c @@ -380,11 +380,12 @@ TEST_CASE("I2S write and read test(master rx and slave tx)", "[i2s]") i2s_write(I2S_NUM_1, data_wr, sizeof(uint8_t) * 400, &i2s_bytes_write, 1000 / portTICK_PERIOD_MS); printf("write data size: %d\n", i2s_bytes_write); int flag = 0; // break loop flag - int end_position = 0; + volatile int end_position = 0; // write data to slave while (!flag) { TEST_ESP_OK(i2s_read(I2S_NUM_0, i2s_read_buff + length, 10000 - length, &bytes_read, 1000 / portTICK_PERIOD_MS)); if (bytes_read > 0) { + printf("read data size: %d\n", bytes_read); for (int i = length; i < length + bytes_read; i++) { if (i2s_read_buff[i] == 100) { flag = 1; @@ -494,7 +495,7 @@ TEST_CASE("I2S APLL clock variation test", "[i2s]") TEST_ASSERT(initial_size == esp_get_free_heap_size()); } -#if SOC_I2S_SUPPORTS_ADC_DAC +#if SOC_I2S_SUPPORTS_ADC /* Only ESP32 need I2S adc/dac test */ TEST_CASE("I2S adc test", "[i2s]") { @@ -560,7 +561,9 @@ TEST_CASE("I2S adc test", "[i2s]") free(i2sReadBuffer); i2s_driver_uninstall(I2S_NUM_0); } +#endif +#if SOC_I2S_SUPPORTS_DAC TEST_CASE("I2S dac test", "[i2s]") { // dac, adc i2s diff --git a/components/esp_lcd/src/esp_lcd_panel_io_i2s.c b/components/esp_lcd/src/esp_lcd_panel_io_i2s.c index f132b3bd29..653a50a016 100644 --- a/components/esp_lcd/src/esp_lcd_panel_io_i2s.c +++ b/components/esp_lcd/src/esp_lcd_panel_io_i2s.c @@ -536,7 +536,7 @@ static unsigned long i2s_lcd_select_periph_clock(i2s_hal_context_t *hal) #error "invalid LCD peripheral clock source" #endif i2s_ll_tx_clk_set_src(hal->dev, clock_source); - i2s_ll_clk_cal_t clk_cal_config = { + i2s_ll_mclk_div_t clk_cal_config = { .mclk_div = LCD_PERIPH_CLOCK_PRE_SCALE, .a = 1, .b = 0, diff --git a/components/hal/esp32/include/hal/i2s_ll.h b/components/hal/esp32/include/hal/i2s_ll.h index 159446b41d..fd20c406cb 100644 --- a/components/hal/esp32/include/hal/i2s_ll.h +++ b/components/hal/esp32/include/hal/i2s_ll.h @@ -50,7 +50,7 @@ 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 -} i2s_ll_clk_cal_t; +} i2s_ll_mclk_div_t; /** * @brief Enable DMA descriptor owner check @@ -98,6 +98,18 @@ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) } } +/** + * @brief I2S module disable clock. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_disable_clock(i2s_dev_t *hw) +{ + if (hw->clkm_conf.clk_en == 1) { + hw->clkm_conf.clk_en = 0; + } +} + /** * @brief I2S tx msb right enable * @@ -272,7 +284,7 @@ static inline void i2s_ll_tx_set_bck_div_num(i2s_dev_t *hw, uint32_t val) * @param hw Peripheral I2S hardware instance address. * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_tx_set_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) +static inline void i2s_ll_tx_set_clk(i2s_dev_t *hw, i2s_ll_mclk_div_t *set) { HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clkm_conf, clkm_div_num, set->mclk_div); hw->clkm_conf.clkm_div_b = set->b; @@ -296,7 +308,7 @@ static inline void i2s_ll_rx_set_bck_div_num(i2s_dev_t *hw, uint32_t val) * @param hw Peripheral I2S hardware instance address. * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_rx_set_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) +static inline void i2s_ll_rx_set_clk(i2s_dev_t *hw, i2s_ll_mclk_div_t *set) { HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clkm_conf, clkm_div_num, set->mclk_div); hw->clkm_conf.clkm_div_b = set->b; @@ -713,9 +725,9 @@ static inline void i2s_ll_rx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena) * @brief Enable I2S loopback mode * * @param hw Peripheral I2S hardware instance address. - * @param loopback_en Set true to enable loopback mode. + * @param loopback_en Set true to share BCK and WS signal for tx module and rx module. */ -static inline void i2s_ll_enable_loop_back(i2s_dev_t *hw, bool loopback_en) +static inline void i2s_ll_share_bck_ws(i2s_dev_t *hw, bool loopback_en) { hw->conf.sig_loopback = loopback_en; } diff --git a/components/hal/esp32c3/include/hal/i2s_ll.h b/components/hal/esp32c3/include/hal/i2s_ll.h index 44f9142c1a..670db91616 100644 --- a/components/hal/esp32c3/include/hal/i2s_ll.h +++ b/components/hal/esp32c3/include/hal/i2s_ll.h @@ -44,7 +44,7 @@ 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 -} i2s_ll_clk_cal_t; +} i2s_ll_mclk_div_t; /** * @brief I2S module general init, enable I2S clock. @@ -56,6 +56,16 @@ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) hw->tx_clkm_conf.clk_en = 1; } +/** + * @brief I2S module disable I2S clock. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_disable_clock(i2s_dev_t *hw) +{ + hw->tx_clkm_conf.clk_en = 0; +} + /** * @brief Enable I2S tx module clock * @@ -201,7 +211,7 @@ static inline void i2s_ll_tx_set_bck_div_num(i2s_dev_t *hw, uint32_t val) * @param hw Peripheral I2S hardware instance address. * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_tx_set_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) +static inline void i2s_ll_tx_set_clk(i2s_dev_t *hw, i2s_ll_mclk_div_t *set) { if (set->a == 0 || set->b == 0) { hw->tx_clkm_div_conf.tx_clkm_div_x = 0; @@ -240,7 +250,7 @@ static inline void i2s_ll_rx_set_bck_div_num(i2s_dev_t *hw, uint32_t val) * @param hw Peripheral I2S hardware instance address. * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_rx_set_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) +static inline void i2s_ll_rx_set_clk(i2s_dev_t *hw, i2s_ll_mclk_div_t *set) { if (set->a == 0 || set->b == 0) { hw->rx_clkm_div_conf.rx_clkm_div_x = 0; @@ -783,6 +793,10 @@ static inline void i2s_ll_set_single_data(i2s_dev_t *hw, uint32_t data) /** * @brief Enable TX mono mode + * @note MONO in hardware means only one channel got data, but another doesn't + * MONO in software means two channel share same data + * This function aims to use MONO in software meaning + * so 'tx_mono' and 'tx_chan_equal' should be enabled at the same time * * @param hw Peripheral I2S hardware instance address. * @param mono_ena Set true to enable mono mde. @@ -809,9 +823,9 @@ static inline void i2s_ll_rx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena) * @brief Enable loopback mode * * @param hw Peripheral I2S hardware instance address. - * @param ena Set true to enable loopback mode. + * @param ena Set true to share BCK and WS signal for tx module and rx module. */ -static inline void i2s_ll_enable_loop_back(i2s_dev_t *hw, bool ena) +static inline void i2s_ll_share_bck_ws(i2s_dev_t *hw, bool ena) { hw->tx_conf.sig_loopback = ena; } diff --git a/components/hal/esp32h2/include/hal/i2s_ll.h b/components/hal/esp32h2/include/hal/i2s_ll.h index d9c70cd130..e241ac2185 100644 --- a/components/hal/esp32h2/include/hal/i2s_ll.h +++ b/components/hal/esp32h2/include/hal/i2s_ll.h @@ -45,7 +45,7 @@ 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 -} i2s_ll_clk_cal_t; +} i2s_ll_mclk_div_t; /** * @brief I2S module general init, enable I2S clock. @@ -57,6 +57,16 @@ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) hw->tx_clkm_conf.clk_en = 1; } +/** + * @brief I2S module disable I2S clock. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_disable_clock(i2s_dev_t *hw) +{ + hw->tx_clkm_conf.clk_en = 0; +} + /** * @brief Enable I2S tx module clock * @@ -202,7 +212,7 @@ static inline void i2s_ll_tx_set_bck_div_num(i2s_dev_t *hw, uint32_t val) * @param hw Peripheral I2S hardware instance address. * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_tx_set_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) +static inline void i2s_ll_tx_set_clk(i2s_dev_t *hw, i2s_ll_mclk_div_t *set) { if (set->a == 0 || set->b == 0) { hw->tx_clkm_div_conf.tx_clkm_div_x = 0; @@ -241,7 +251,7 @@ static inline void i2s_ll_rx_set_bck_div_num(i2s_dev_t *hw, uint32_t val) * @param hw Peripheral I2S hardware instance address. * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_rx_set_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) +static inline void i2s_ll_rx_set_clk(i2s_dev_t *hw, i2s_ll_mclk_div_t *set) { if (set->a == 0 || set->b == 0) { hw->rx_clkm_div_conf.rx_clkm_div_x = 0; @@ -785,9 +795,9 @@ static inline void i2s_ll_set_single_data(i2s_dev_t *hw, uint32_t data) * @brief Enable loopback mode * * @param hw Peripheral I2S hardware instance address. - * @param ena Set true to enable loopback mode. + * @param ena Set true to share BCK and WS signal for tx module and rx module. */ -static inline void i2s_ll_enable_loop_back(i2s_dev_t *hw, bool ena) +static inline void i2s_ll_share_bck_ws(i2s_dev_t *hw, bool ena) { hw->tx_conf.sig_loopback = ena; } @@ -806,13 +816,18 @@ static inline void i2s_ll_set_pdm2pcm_conv_en(i2s_dev_t *hw, bool val) /** * @brief Enable TX mono mode + * @note MONO in hardware means only one channel got data, but another doesn't + * MONO in software means two channel share same data + * This function aims to use MONO in software meaning + * so 'tx_mono' and 'tx_chan_equal' should be enabled at the same time * * @param hw Peripheral I2S hardware instance address. * @param mono_ena Set true to enable mono mde. */ static inline void i2s_ll_tx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena) { - abort(); + hw->tx_conf.tx_mono = mono_ena; + hw->tx_conf.tx_chan_equal = mono_ena; } /** @@ -823,7 +838,8 @@ static inline void i2s_ll_tx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena) */ static inline void i2s_ll_rx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena) { - abort(); + hw->rx_conf.rx_mono = mono_ena; + hw->rx_conf.rx_mono_fst_vld = mono_ena; } #ifdef __cplusplus diff --git a/components/hal/esp32s2/include/hal/i2s_ll.h b/components/hal/esp32s2/include/hal/i2s_ll.h index 725d4343b2..6f453221ee 100644 --- a/components/hal/esp32s2/include/hal/i2s_ll.h +++ b/components/hal/esp32s2/include/hal/i2s_ll.h @@ -45,7 +45,7 @@ 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 -} i2s_ll_clk_cal_t; +} i2s_ll_mclk_div_t; #define I2S_LL_EVENT_TX_EOF (1 << 12) #define I2S_LL_BCK_MAX_PRESCALE (64) @@ -97,6 +97,18 @@ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) } } +/** + * @brief I2S module disable clock. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_disable_clock(i2s_dev_t *hw) +{ + if (hw->clkm_conf.clk_en == 1) { + hw->clkm_conf.clk_en = 0; + } +} + /** * @brief I2S tx msb right enable * @@ -268,7 +280,7 @@ static inline void i2s_ll_tx_set_bck_div_num(i2s_dev_t *hw, uint32_t val) * @param hw Peripheral I2S hardware instance address. * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_tx_set_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) +static inline void i2s_ll_tx_set_clk(i2s_dev_t *hw, i2s_ll_mclk_div_t *set) { HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clkm_conf, clkm_div_num, set->mclk_div); hw->clkm_conf.clkm_div_b = set->b; @@ -292,7 +304,7 @@ static inline void i2s_ll_rx_set_bck_div_num(i2s_dev_t *hw, uint32_t val) * @param hw Peripheral I2S hardware instance address. * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_rx_set_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) +static inline void i2s_ll_rx_set_clk(i2s_dev_t *hw, i2s_ll_mclk_div_t *set) { HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clkm_conf, clkm_div_num, set->mclk_div); hw->clkm_conf.clkm_div_b = set->b; @@ -813,9 +825,9 @@ static inline void i2s_ll_rx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena) * @brief Enable I2S loopback mode * * @param hw Peripheral I2S hardware instance address. - * @param loopback_en Set true to enable loopback mode. + * @param loopback_en Set true to share BCK and WS signal for tx module and rx module. */ -static inline void i2s_ll_enable_loop_back(i2s_dev_t *hw, bool loopback_en) +static inline void i2s_ll_share_bck_ws(i2s_dev_t *hw, bool loopback_en) { hw->conf.sig_loopback = loopback_en; } diff --git a/components/hal/esp32s3/include/hal/i2s_ll.h b/components/hal/esp32s3/include/hal/i2s_ll.h index 8f5de0f56d..5e27b9352e 100644 --- a/components/hal/esp32s3/include/hal/i2s_ll.h +++ b/components/hal/esp32s3/include/hal/i2s_ll.h @@ -45,7 +45,7 @@ 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 -} i2s_ll_clk_cal_t; +} i2s_ll_mclk_div_t; /** * @brief I2S module general init, enable I2S clock. @@ -57,6 +57,16 @@ static inline void i2s_ll_enable_clock(i2s_dev_t *hw) hw->tx_clkm_conf.clk_en = 1; } +/** + * @brief I2S module disable I2S clock. + * + * @param hw Peripheral I2S hardware instance address. + */ +static inline void i2s_ll_disable_clock(i2s_dev_t *hw) +{ + hw->tx_clkm_conf.clk_en = 0; +} + /** * @brief Enable I2S tx module clock * @@ -204,7 +214,7 @@ static inline void i2s_ll_tx_set_bck_div_num(i2s_dev_t *hw, uint32_t val) * @param hw Peripheral I2S hardware instance address. * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_tx_set_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) +static inline void i2s_ll_tx_set_clk(i2s_dev_t *hw, i2s_ll_mclk_div_t *set) { if (set->a == 0 || set->b == 0) { hw->tx_clkm_div_conf.tx_clkm_div_x = 0; @@ -243,7 +253,7 @@ static inline void i2s_ll_rx_set_bck_div_num(i2s_dev_t *hw, uint32_t val) * @param hw Peripheral I2S hardware instance address. * @param set Pointer to I2S clock devider configuration paramater */ -static inline void i2s_ll_rx_set_clk(i2s_dev_t *hw, i2s_ll_clk_cal_t *set) +static inline void i2s_ll_rx_set_clk(i2s_dev_t *hw, i2s_ll_mclk_div_t *set) { if (set->a == 0 || set->b == 0) { hw->rx_clkm_div_conf.rx_clkm_div_x = 0; @@ -808,6 +818,10 @@ static inline void i2s_ll_set_single_data(i2s_dev_t *hw, uint32_t data) /** * @brief Enable TX mono mode + * @note MONO in hardware means only one channel got data, but another doesn't + * MONO in software means two channel share same data + * This function aims to use MONO in software meaning + * so 'tx_mono' and 'tx_chan_equal' should be enabled at the same time * * @param hw Peripheral I2S hardware instance address. * @param mono_ena Set true to enable mono mde. @@ -834,9 +848,9 @@ static inline void i2s_ll_rx_enable_mono_mode(i2s_dev_t *hw, bool mono_ena) * @brief Enable loopback mode * * @param hw Peripheral I2S hardware instance address. - * @param ena Set true to enable loopback mode. + * @param ena Set true to share BCK and WS signal for tx module and rx module. */ -static inline void i2s_ll_enable_loop_back(i2s_dev_t *hw, bool ena) +static inline void i2s_ll_share_bck_ws(i2s_dev_t *hw, bool ena) { hw->tx_conf.sig_loopback = ena; } diff --git a/components/hal/i2s_hal.c b/components/hal/i2s_hal.c index 431a887484..1f49ac1c65 100644 --- a/components/hal/i2s_hal.c +++ b/components/hal/i2s_hal.c @@ -25,15 +25,18 @@ * Fmclk = bck_div*fbck = fsclk/(mclk_div+b/a) * * @param clk_cfg I2S clock configuration(input) - * @param cal Point to `i2s_ll_clk_cal_t` structure(output). + * @param cal Point to `i2s_ll_mclk_div_t` structure(output). */ -static void i2s_hal_mclk_div_decimal_cal(i2s_hal_clock_cfg_t *clk_cfg, i2s_ll_clk_cal_t *cal) +static void i2s_hal_mclk_div_decimal_cal(i2s_hal_clock_cfg_t *clk_cfg, i2s_ll_mclk_div_t *cal) { int ma = 0; int mb = 0; cal->mclk_div = clk_cfg->mclk_div; cal->a = 1; cal->b = 0; + if (!clk_cfg->sclk) { + return; + } uint32_t freq_diff = clk_cfg->sclk - clk_cfg->mclk * cal->mclk_div; uint32_t min = ~0; for (int a = 2; a <= I2S_LL_MCLK_DIVIDER_MAX; a++) { @@ -62,7 +65,7 @@ void i2s_hal_set_clock_src(i2s_hal_context_t *hal, i2s_clock_src_t sel) void i2s_hal_tx_clock_config(i2s_hal_context_t *hal, i2s_hal_clock_cfg_t *clk_cfg) { - i2s_ll_clk_cal_t mclk_set; + i2s_ll_mclk_div_t mclk_set; i2s_hal_mclk_div_decimal_cal(clk_cfg, &mclk_set); i2s_ll_tx_set_clk(hal->dev, &mclk_set); i2s_ll_tx_set_bck_div_num(hal->dev, clk_cfg->bclk_div); @@ -70,7 +73,7 @@ void i2s_hal_tx_clock_config(i2s_hal_context_t *hal, i2s_hal_clock_cfg_t *clk_cf void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, i2s_hal_clock_cfg_t *clk_cfg) { - i2s_ll_clk_cal_t mclk_set; + i2s_ll_mclk_div_t mclk_set; i2s_hal_mclk_div_decimal_cal(clk_cfg, &mclk_set); i2s_ll_rx_set_clk(hal->dev, &mclk_set); i2s_ll_rx_set_bck_div_num(hal->dev, clk_cfg->bclk_div); @@ -88,36 +91,12 @@ void i2s_hal_enable_slave_fd_mode(i2s_hal_context_t *hal) i2s_ll_rx_set_slave_mod(hal->dev, true); //RX Slave } -void i2s_hal_get_instance(i2s_hal_context_t *hal, int i2s_num) +void i2s_hal_init(i2s_hal_context_t *hal, int i2s_num) { /* Get hardware instance */ hal->dev = I2S_LL_GET_HW(i2s_num); - /* Enable I2S module clock */ - i2s_ll_enable_clock(hal->dev); } -#if SOC_I2S_SUPPORTS_ADC_DAC -void i2s_hal_enable_adc_dac_mode(i2s_hal_context_t *hal, i2s_mode_t mode) -{ - if (mode & I2S_MODE_DAC_BUILT_IN) { - i2s_ll_enable_builtin_dac(hal->dev, true); - } - /* In ADC built-in mode, we need to call i2s_set_adc_mode to initialize the specific ADC channel. - * In the current stage, we only support ADC1 and single channel mode. - * In default data mode, the ADC data is in 12-bit resolution mode. - */ - if (mode & I2S_MODE_ADC_BUILT_IN) { - i2s_ll_enable_builtin_adc(hal->dev, true); - } -} - -void i2s_hal_disable_adc_dac_mode(i2s_hal_context_t *hal) -{ - i2s_ll_enable_builtin_dac(hal->dev, false); - i2s_ll_enable_builtin_adc(hal->dev, false); -} -#endif - #if SOC_I2S_SUPPORTS_PDM_TX void i2s_hal_tx_set_pdm_mode_default(i2s_hal_context_t *hal, uint32_t sample_rate) { @@ -271,18 +250,26 @@ void i2s_hal_rx_set_channel_style(i2s_hal_context_t *hal, const i2s_hal_config_t #endif } -void i2s_hal_init(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg) +void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg) { -#if SOC_I2S_SUPPORTS_ADC_DAC - if (hal_cfg->mode & (I2S_MODE_DAC_BUILT_IN | I2S_MODE_ADC_BUILT_IN)) { - i2s_hal_enable_adc_dac_mode(hal, hal_cfg->mode); - /* Return directly if using ADC/DAC mode, no need to set othet configurations */ +#if SOC_I2S_SUPPORTS_ADC + if (hal_cfg->mode & I2S_MODE_ADC_BUILT_IN) { + /* In ADC built-in mode, we need to call i2s_set_adc_mode to initialize the specific ADC channel. + * In the current stage, we only support ADC1 and single channel mode. + * In default data mode, the ADC data is in 12-bit resolution mode. + */ + i2s_ll_enable_builtin_adc(hal->dev, true); return; } - /* If not using built-in ADC/DAC, disable them */ - i2s_hal_disable_adc_dac_mode(hal); + i2s_ll_enable_builtin_adc(hal->dev, false); +#endif +#if SOC_I2S_SUPPORTS_DAC + if (hal_cfg->mode & I2S_MODE_DAC_BUILT_IN) { + i2s_ll_enable_builtin_dac(hal->dev, true); + return; + } + i2s_ll_enable_builtin_dac(hal->dev, false); #endif - /* Set configurations for TX mode */ if (hal_cfg->mode & I2S_MODE_TX) { i2s_ll_tx_stop(hal->dev); @@ -320,8 +307,8 @@ void i2s_hal_init(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg) } /* Set configurations for full-duplex mode */ - if ((hal_cfg->mode & I2S_MODE_RX) && (hal_cfg->mode & I2S_MODE_TX)) { - i2s_ll_enable_loop_back(hal->dev, true); + if ((hal_cfg->mode & I2S_MODE_RX) && (hal_cfg->mode & I2S_MODE_TX)) { + i2s_ll_share_bck_ws(hal->dev, true); if (hal_cfg->mode & I2S_MODE_MASTER) { i2s_hal_enable_master_fd_mode(hal); } else { diff --git a/components/hal/include/hal/i2s_hal.h b/components/hal/include/hal/i2s_hal.h index 3c436db179..a08813db80 100644 --- a/components/hal/include/hal/i2s_hal.h +++ b/components/hal/include/hal/i2s_hal.h @@ -74,6 +74,20 @@ typedef struct { uint32_t version; } i2s_hal_context_t; +/** + * @brief Enable I2S module clock + * + * @param hal Context of the HAL layer + */ +#define i2s_hal_enable_module_clock(hal) i2s_ll_enable_clock((hal)->dev); + +/** + * @brief Disable I2S module clock + * + * @param hal Context of the HAL layer + */ +#define i2s_hal_disable_module_clock(hal) i2s_ll_disable_clock((hal)->dev); + /** * @brief Reset I2S TX channel * @@ -109,7 +123,7 @@ typedef struct { * @param hal Context of the HAL layer * @param i2s_num The uart port number, the max port number is (I2S_NUM_MAX -1) */ -void i2s_hal_get_instance(i2s_hal_context_t *hal, int i2s_num); +void i2s_hal_init(i2s_hal_context_t *hal, int i2s_num); /** * @brief Configure I2S source clock @@ -141,7 +155,7 @@ void i2s_hal_rx_set_channel_style(i2s_hal_context_t *hal, const i2s_hal_config_t * @param hal Context of the HAL layer * @param hal_cfg I2S hal configuration structer, refer to `i2s_hal_config_t` */ -void i2s_hal_init(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg); +void i2s_hal_config_param(i2s_hal_context_t *hal, const i2s_hal_config_t *hal_cfg); /** * @brief Enable I2S master full-duplex mode @@ -264,7 +278,7 @@ void i2s_hal_rx_clock_config(i2s_hal_context_t *hal, i2s_hal_clock_cfg_t *clk_cf * * @param hal Context of the HAL layer */ -#define i2s_hal_enable_sig_loopback(hal) i2s_ll_enable_loop_back((hal)->dev, true) +#define i2s_hal_enable_sig_loopback(hal) i2s_ll_share_bck_ws((hal)->dev, true) /** * @brief Set I2S configuration for common TX mode @@ -501,7 +515,7 @@ void i2s_hal_rx_set_pdm_mode_default(i2s_hal_context_t *hal); #define i2s_hal_get_in_eof_des_addr(hal, addr) i2s_ll_rx_get_eof_des_addr((hal)->dev, addr) #endif -#if SOC_I2S_SUPPORTS_ADC_DAC +#if SOC_I2S_SUPPORTS_ADC /** * @brief Enable Builtin DAC * @@ -516,13 +530,6 @@ void i2s_hal_rx_set_pdm_mode_default(i2s_hal_context_t *hal); */ #define i2s_hal_enable_builtin_adc(hal) i2s_ll_enable_builtin_adc((hal)->dev, true); -/** - * @brief Disable Builtin DAC - * - * @param hal Context of the HAL layer - */ -#define i2s_hal_disable_builtin_dac(hal) i2s_ll_enable_builtin_dac((hal)->dev, false); - /** * @brief Disable Builtin ADC * @@ -531,6 +538,15 @@ void i2s_hal_rx_set_pdm_mode_default(i2s_hal_context_t *hal); #define i2s_hal_disable_builtin_adc(hal) i2s_ll_enable_builtin_adc((hal)->dev, false); #endif +#if SOC_I2S_SUPPORTS_DAC +/** + * @brief Disable Builtin DAC + * + * @param hal Context of the HAL layer + */ +#define i2s_hal_disable_builtin_dac(hal) i2s_ll_enable_builtin_dac((hal)->dev, false); +#endif + #ifdef __cplusplus } #endif diff --git a/components/hal/include/hal/i2s_types.h b/components/hal/include/hal/i2s_types.h index d22dfc5c0e..48d745eb2f 100644 --- a/components/hal/include/hal/i2s_types.h +++ b/components/hal/include/hal/i2s_types.h @@ -92,12 +92,12 @@ typedef enum { I2S_COMM_FORMAT_STAND_MAX, /*!< standard max*/ //old definition will be removed in the future. - // I2S_COMM_FORMAT_I2S __attribute__((deprecated)) = 0x01, /*!< I2S communication format I2S, correspond to `I2S_COMM_FORMAT_STAND_I2S`*/ - // I2S_COMM_FORMAT_I2S_MSB __attribute__((deprecated)) = 0x01, /*!< I2S format MSB, (I2S_COMM_FORMAT_I2S |I2S_COMM_FORMAT_I2S_MSB) correspond to `I2S_COMM_FORMAT_STAND_I2S`*/ - // I2S_COMM_FORMAT_I2S_LSB __attribute__((deprecated)) = 0x02, /*!< I2S format LSB, (I2S_COMM_FORMAT_I2S |I2S_COMM_FORMAT_I2S_LSB) correspond to `I2S_COMM_FORMAT_STAND_MSB`*/ - // I2S_COMM_FORMAT_PCM __attribute__((deprecated)) = 0x04, /*!< I2S communication format PCM, correspond to `I2S_COMM_FORMAT_STAND_PCM_SHORT`*/ - // I2S_COMM_FORMAT_PCM_SHORT __attribute__((deprecated)) = 0x04, /*!< PCM Short, (I2S_COMM_FORMAT_PCM | I2S_COMM_FORMAT_PCM_SHORT) correspond to `I2S_COMM_FORMAT_STAND_PCM_SHORT`*/ - // I2S_COMM_FORMAT_PCM_LONG __attribute__((deprecated)) = 0x08, /*!< PCM Long, (I2S_COMM_FORMAT_PCM | I2S_COMM_FORMAT_PCM_LONG) correspond to `I2S_COMM_FORMAT_STAND_PCM_LONG`*/ + I2S_COMM_FORMAT_I2S __attribute__((deprecated)) = 0x01, /*!< I2S communication format I2S, correspond to `I2S_COMM_FORMAT_STAND_I2S`*/ + I2S_COMM_FORMAT_I2S_MSB __attribute__((deprecated)) = 0x01, /*!< I2S format MSB, (I2S_COMM_FORMAT_I2S |I2S_COMM_FORMAT_I2S_MSB) correspond to `I2S_COMM_FORMAT_STAND_I2S`*/ + I2S_COMM_FORMAT_I2S_LSB __attribute__((deprecated)) = 0x02, /*!< I2S format LSB, (I2S_COMM_FORMAT_I2S |I2S_COMM_FORMAT_I2S_LSB) correspond to `I2S_COMM_FORMAT_STAND_MSB`*/ + I2S_COMM_FORMAT_PCM __attribute__((deprecated)) = 0x04, /*!< I2S communication format PCM, correspond to `I2S_COMM_FORMAT_STAND_PCM_SHORT`*/ + I2S_COMM_FORMAT_PCM_SHORT __attribute__((deprecated)) = 0x04, /*!< PCM Short, (I2S_COMM_FORMAT_PCM | I2S_COMM_FORMAT_PCM_SHORT) correspond to `I2S_COMM_FORMAT_STAND_PCM_SHORT`*/ + I2S_COMM_FORMAT_PCM_LONG __attribute__((deprecated)) = 0x08, /*!< PCM Long, (I2S_COMM_FORMAT_PCM | I2S_COMM_FORMAT_PCM_LONG) correspond to `I2S_COMM_FORMAT_STAND_PCM_LONG`*/ } i2s_comm_format_t; /** @@ -123,11 +123,13 @@ typedef enum { I2S_MODE_SLAVE = (0x1 << 1), /*!< Slave mode*/ I2S_MODE_TX = (0x1 << 2), /*!< TX mode*/ I2S_MODE_RX = (0x1 << 3), /*!< RX mode*/ -#if SOC_I2S_SUPPORTS_ADC_DAC +#if SOC_I2S_SUPPORTS_DAC //built-in DAC functions are only supported on I2S0 for ESP32 chip. 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*/ +#endif // SOC_I2S_SUPPORTS_DAC +#if SOC_I2S_SUPPORTS_ADC I2S_MODE_ADC_BUILT_IN = (0x1 << 5), /*!< Input I2S data from built-in ADC, each data can be 12-bit width at most*/ -#endif +#endif // SOC_I2S_SUPPORTS_ADC // PDM functions are only supported on I2S0 (all chips). I2S_MODE_PDM = (0x1 << 6), /*!< I2S PDM mode*/ } i2s_mode_t; @@ -152,7 +154,7 @@ typedef enum { I2S_MCLK_MULTIPLE_384 = 384, /*!< mclk = sample_rate * 384 */ } i2s_mclk_multiple_t; -#if SOC_I2S_SUPPORTS_ADC_DAC +#if SOC_I2S_SUPPORTS_DAC /** * @brief I2S DAC mode for i2s_set_dac_mode. * @@ -165,7 +167,7 @@ typedef enum { I2S_DAC_CHANNEL_BOTH_EN = 0x3, /*!< Enable both of the I2S built-in DAC channels.*/ I2S_DAC_CHANNEL_MAX = 0x4, /*!< I2S built-in DAC mode max index*/ } i2s_dac_mode_t; -#endif //SOC_I2S_SUPPORTS_ADC_DAC +#endif //SOC_I2S_SUPPORTS_DAC #if SOC_I2S_SUPPORTS_PCM /** diff --git a/components/soc/esp32/include/soc/soc_caps.h b/components/soc/esp32/include/soc/soc_caps.h index e2bd1842b4..54dd6b674a 100644 --- a/components/soc/esp32/include/soc/soc_caps.h +++ b/components/soc/esp32/include/soc/soc_caps.h @@ -137,7 +137,8 @@ #define SOC_I2S_NUM (2) #define SOC_I2S_SUPPORTS_PDM_TX (1) #define SOC_I2S_SUPPORTS_PDM_RX (1) -#define SOC_I2S_SUPPORTS_ADC_DAC (1) // ESP32 support ADC and DAC +#define SOC_I2S_SUPPORTS_ADC (1) // ESP32 support ADC and DAC +#define SOC_I2S_SUPPORTS_DAC (1) #define SOC_I2S_SUPPORTS_APLL (1)// ESP32 support APLL #define SOC_I2S_APLL_MIN_FREQ (250000000) diff --git a/docs/en/api-reference/peripherals/i2s.rst b/docs/en/api-reference/peripherals/i2s.rst index 6fd3bd2415..99e4924105 100644 --- a/docs/en/api-reference/peripherals/i2s.rst +++ b/docs/en/api-reference/peripherals/i2s.rst @@ -166,11 +166,11 @@ Application Example A code example for the I2S driver can be found in the directory :example:`peripherals/i2s`. -.. only:: SOC_I2S_SUPPORTS_ADC_DAC +.. only:: SOC_I2S_SUPPORTS_ADC or SOC_I2S_SUPPORTS_DAC In addition, there are two short configuration examples for the I2S driver. -.. only:: not SOC_I2S_SUPPORTS_ADC_DAC +.. only:: not SOC_I2S_SUPPORTS_ADC or SOC_I2S_SUPPORTS_DAC In addition, there is a short configuration examples for the I2S driver. @@ -310,7 +310,7 @@ Example for general usage. i2s_driver_uninstall(i2s_num); //stop & destroy i2s driver -.. only:: SOC_I2S_SUPPORTS_ADC_DAC +.. only:: SOC_I2S_SUPPORTS_ADC or SOC_I2S_SUPPORTS_DAC Configuring I2S to use internal DAC for analog output ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^