mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
i2s: update examples and unit-tests
This commit is contained in:
parent
621d0aa942
commit
0fe3bb8ab7
@ -7,7 +7,7 @@
|
||||
/**
|
||||
* This file is for the backward compatible to the deprecated I2S APIs,
|
||||
* The deprecated APIs will no longer supported in the future
|
||||
* Please refer to "driver/i2s_controller.h" for the latest I2S driver
|
||||
* Please refer to "driver/i2s_std.h", "driver/i2s_pdm.h" and ""driver/i2s_tdm.h"" for the latest I2S driver
|
||||
* Note that only one set of I2S APIs is allowed to be used at the same time
|
||||
*/
|
||||
|
||||
|
@ -180,7 +180,7 @@ static i2s_controller_t *i2s_acquire_controller_obj(int id)
|
||||
if (!s_i2s.controller[id]) {
|
||||
/* Try to occupy this i2s controller
|
||||
if failed, this controller could be occupied by other components */
|
||||
if (i2s_platform_acquire_occupation(id, "i2s_controller") == ESP_OK) {
|
||||
if (i2s_platform_acquire_occupation(id, "i2s_driver") == ESP_OK) {
|
||||
i2s_obj = pre_alloc;
|
||||
portENTER_CRITICAL(&s_i2s.spinlock);
|
||||
s_i2s.controller[id] = i2s_obj;
|
||||
@ -556,7 +556,7 @@ esp_err_t i2s_check_set_mclk(i2s_port_t id, gpio_num_t gpio_num)
|
||||
}
|
||||
#else
|
||||
ESP_RETURN_ON_FALSE(GPIO_IS_VALID_GPIO(gpio_num), ESP_ERR_INVALID_ARG, TAG, "mck_io_num invalid");
|
||||
gpio_matrix_out_check_and_set(gpio_num, i2s_periph_signal[id].mck_out_sig, 0, 0);
|
||||
i2s_gpio_check_and_set(gpio_num, i2s_periph_signal[id].mck_out_sig, false);
|
||||
#endif
|
||||
ESP_LOGI(TAG, "MCLK is pinned to GPIO%d on I2S%d", id, gpio_num);
|
||||
return ESP_OK;
|
||||
@ -572,7 +572,7 @@ esp_err_t i2s_new_channel(const i2s_chan_config_t *chan_cfg, i2s_chan_handle_t *
|
||||
/* Parameter validity check */
|
||||
I2S_NULL_POINTER_CHECK(TAG, chan_cfg);
|
||||
I2S_NULL_POINTER_CHECK(TAG, tx_handle || rx_handle);
|
||||
ESP_RETURN_ON_FALSE(chan_cfg->id < SOC_I2S_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid I2S port id");
|
||||
ESP_RETURN_ON_FALSE(chan_cfg->id < SOC_I2S_NUM || chan_cfg->id == I2S_NUM_AUTO, ESP_ERR_INVALID_ARG, TAG, "invalid I2S port id");
|
||||
ESP_RETURN_ON_FALSE(chan_cfg->dma_desc_num >= 2, ESP_ERR_INVALID_ARG, TAG, "there should be at least 2 DMA buffers");
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
@ -676,9 +676,9 @@ esp_err_t i2s_del_channel(i2s_chan_handle_t handle)
|
||||
* because the clock of some registers are bound to APLL,
|
||||
* otherwise, once APLL is disabled, the registers can't be updated anymore */
|
||||
if (handle->dir == I2S_DIR_TX) {
|
||||
i2s_ll_tx_clk_set_src(handle->parent->hal.dev, I2S_CLK_160M_PLL);
|
||||
i2s_ll_tx_clk_set_src(handle->parent->hal.dev, I2S_CLK_PLL_160M);
|
||||
} else {
|
||||
i2s_ll_rx_clk_set_src(handle->parent->hal.dev, I2S_CLK_160M_PLL);
|
||||
i2s_ll_rx_clk_set_src(handle->parent->hal.dev, I2S_CLK_PLL_160M);
|
||||
}
|
||||
periph_rtc_apll_release();
|
||||
}
|
||||
@ -898,7 +898,7 @@ err:
|
||||
esp_err_t i2s_clear_dma_buffer(i2s_chan_handle_t handle)
|
||||
{
|
||||
I2S_NULL_POINTER_CHECK(TAG, handle);
|
||||
ESP_RETURN_ON_FALSE(handle->state > I2S_CHAN_STATE_INIT, ESP_ERR_INVALID_STATE, TAG, "this channel has not initialized yet");
|
||||
ESP_RETURN_ON_FALSE(handle->state >= I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, TAG, "this channel has not initialized yet");
|
||||
/* Clear all the DMA buffer */
|
||||
for (int desc_num = handle->dma.desc_num; desc_num > 0; desc_num--) {
|
||||
memset(handle->dma.bufs[desc_num-1], 0, handle->dma.buf_size);
|
||||
|
@ -636,7 +636,7 @@ static uint32_t i2s_config_source_clock(i2s_port_t i2s_num, bool use_apll, uint3
|
||||
return I2S_LL_BASE_CLK;
|
||||
#else
|
||||
if (use_apll) {
|
||||
ESP_LOGW(TAG, "APLL not supported on current chip, use I2S_CLK_160M_PLL as default clock source");
|
||||
ESP_LOGW(TAG, "APLL not supported on current chip, use I2S_CLK_PLL_160M as default clock source");
|
||||
}
|
||||
return I2S_LL_BASE_CLK;
|
||||
#endif
|
||||
@ -793,20 +793,6 @@ static esp_err_t i2s_calculate_clock(i2s_port_t i2s_num, i2s_hal_clock_info_t *c
|
||||
/*-------------------------------------------------------------
|
||||
I2S configuration
|
||||
-------------------------------------------------------------*/
|
||||
#if SOC_I2S_SUPPORTS_TDM
|
||||
|
||||
static uint32_t i2s_get_active_channel_num(uint32_t chan_mask)
|
||||
{
|
||||
uint32_t num = 0;
|
||||
for (int i = 0; chan_mask; i++, chan_mask >>= 1) {
|
||||
if (chan_mask & 0x01) {
|
||||
num++;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if SOC_I2S_SUPPORTS_ADC_DAC
|
||||
static void i2s_dac_set_slot_legacy(void)
|
||||
{
|
||||
@ -1111,7 +1097,7 @@ esp_err_t i2s_set_sample_rates(i2s_port_t i2s_num, uint32_t rate)
|
||||
uint32_t mask = 0;
|
||||
#if SOC_I2S_SUPPORTS_TDM
|
||||
if (p_i2s[i2s_num]->mode == I2S_COMM_MODE_TDM) {
|
||||
mask = ((i2s_tdm_slot_config_t *)slot_cfg)->slot_mask;;
|
||||
mask = slot_cfg->tdm.slot_mask;
|
||||
}
|
||||
#endif
|
||||
return i2s_set_clk(i2s_num, rate, slot_cfg->data_bit_width, slot_cfg->slot_mode | (mask << 16));
|
||||
@ -1241,7 +1227,6 @@ static esp_err_t i2s_config_transfer(i2s_port_t i2s_num, const i2s_config_t *i2s
|
||||
#define SLOT_CFG(m) p_i2s[i2s_num]->slot_cfg.m
|
||||
#define CLK_CFG() p_i2s[i2s_num]->clk_cfg
|
||||
/* Convert legacy configuration into general part of slot and clock configuration */
|
||||
p_i2s[i2s_num]->slot_cfg.mode = p_i2s[i2s_num]->mode;
|
||||
p_i2s[i2s_num]->slot_cfg.data_bit_width = i2s_config->bits_per_sample;
|
||||
p_i2s[i2s_num]->slot_cfg.slot_bit_width = (int)i2s_config->bits_per_chan < (int)i2s_config->bits_per_sample ?
|
||||
i2s_config->bits_per_sample : i2s_config->bits_per_chan;
|
||||
@ -1250,11 +1235,11 @@ static esp_err_t i2s_config_transfer(i2s_port_t i2s_num, const i2s_config_t *i2s
|
||||
I2S_SLOT_MODE_STEREO : I2S_SLOT_MODE_MONO;
|
||||
CLK_CFG().sample_rate_hz = i2s_config->sample_rate;
|
||||
CLK_CFG().mclk_multiple = i2s_config->mclk_multiple == 0 ? I2S_MCLK_MULTIPLE_256 : i2s_config->mclk_multiple;
|
||||
CLK_CFG().clk_src = I2S_CLK_160M_PLL;
|
||||
CLK_CFG().clk_src = I2S_CLK_PLL_160M;
|
||||
p_i2s[i2s_num]->fixed_mclk = i2s_config->fixed_mclk;
|
||||
p_i2s[i2s_num]->use_apll = false;
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
CLK_CFG().clk_src = i2s_config->use_apll ? I2S_CLK_APLL : I2S_CLK_160M_PLL;
|
||||
CLK_CFG().clk_src = i2s_config->use_apll ? I2S_CLK_APLL : I2S_CLK_PLL_160M;
|
||||
p_i2s[i2s_num]->use_apll = i2s_config->use_apll;
|
||||
#endif // SOC_I2S_SUPPORTS_APLL
|
||||
|
||||
@ -1331,8 +1316,8 @@ static esp_err_t i2s_config_transfer(i2s_port_t i2s_num, const i2s_config_t *i2s
|
||||
/* Generate TDM slot configuration */
|
||||
SLOT_CFG(tdm).slot_mask = i2s_config->chan_mask >> 16;
|
||||
|
||||
SLOT_CFG(tdm).ws_width = I2S_TDM_AUTO_WS_WIDTH;
|
||||
tdm_slot->slot_mode = I2S_SLOT_MODE_STEREO;
|
||||
SLOT_CFG(tdm).ws_width = 0; // I2S_TDM_AUTO_WS_WIDTH
|
||||
p_i2s[i2s_num]->slot_cfg.slot_mode = I2S_SLOT_MODE_STEREO;
|
||||
SLOT_CFG(tdm).ws_pol = false;
|
||||
if (i2s_config->communication_format == I2S_COMM_FORMAT_STAND_I2S) {
|
||||
SLOT_CFG(tdm).bit_shift = true;
|
||||
@ -1344,7 +1329,7 @@ static esp_err_t i2s_config_transfer(i2s_port_t i2s_num, const i2s_config_t *i2s
|
||||
}
|
||||
else if (i2s_config->communication_format == I2S_COMM_FORMAT_STAND_PCM_LONG) {
|
||||
SLOT_CFG(tdm).bit_shift = true;
|
||||
SLOT_CFG(tdm).ws_width = SLOT_CFG(tdm).slot_bit_width;
|
||||
SLOT_CFG(tdm).ws_width = p_i2s[i2s_num]->slot_cfg.slot_bit_width;
|
||||
SLOT_CFG(tdm).ws_pol = true;
|
||||
}
|
||||
SLOT_CFG(tdm).left_align = i2s_config->left_align;
|
||||
@ -1353,10 +1338,10 @@ static esp_err_t i2s_config_transfer(i2s_port_t i2s_num, const i2s_config_t *i2s
|
||||
SLOT_CFG(tdm).skip_mask = i2s_config->skip_msk;
|
||||
|
||||
/* Generate TDM clock configuration */
|
||||
p_i2s[i2s_num]->active_slot = __builtin_popcount(tdm_slot->slot_mode);
|
||||
p_i2s[i2s_num]->active_slot = __builtin_popcount(SLOT_CFG(tdm).slot_mask);
|
||||
uint32_t mx_slot = 32 - __builtin_clz(SLOT_CFG(tdm).slot_mask);
|
||||
mx_slot = mx_slot < 2 ? 2 : mx_slot;
|
||||
p_i2s[i2s_num]->.total_slot = mx_slot < i2s_config->total_chan ? mx_slot : i2s_config->total_chan;
|
||||
p_i2s[i2s_num]->total_slot = mx_slot < i2s_config->total_chan ? mx_slot : i2s_config->total_chan;
|
||||
goto finish;
|
||||
}
|
||||
#endif // SOC_I2S_SUPPORTS_TDM
|
||||
@ -1515,10 +1500,10 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num)
|
||||
if (obj->use_apll) {
|
||||
// switch back to PLL clock source
|
||||
if (obj->dir & I2S_DIR_TX) {
|
||||
i2s_ll_tx_clk_set_src(obj->hal.dev, I2S_CLK_160M_PLL);
|
||||
i2s_ll_tx_clk_set_src(obj->hal.dev, I2S_CLK_PLL_160M);
|
||||
}
|
||||
if (obj->dir & I2S_DIR_RX) {
|
||||
i2s_ll_rx_clk_set_src(obj->hal.dev, I2S_CLK_160M_PLL);
|
||||
i2s_ll_rx_clk_set_src(obj->hal.dev, I2S_CLK_PLL_160M);
|
||||
}
|
||||
periph_rtc_apll_release();
|
||||
}
|
||||
@ -1556,6 +1541,7 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config,
|
||||
/* Step 2: Allocate driver object and register to platform */
|
||||
i2s_obj_t *i2s_obj = calloc(1, sizeof(i2s_obj_t));
|
||||
ESP_RETURN_ON_FALSE(i2s_obj, ESP_ERR_NO_MEM, TAG, "no mem for I2S driver");
|
||||
p_i2s[i2s_num] = i2s_obj;
|
||||
if (i2s_platform_acquire_occupation(i2s_num, "i2s_legacy") != ESP_OK) {
|
||||
free(i2s_obj);
|
||||
ESP_LOGE(TAG, "register I2S object to platform failed");
|
||||
|
@ -30,7 +30,7 @@ static esp_err_t i2s_pdm_tx_calculate_clock(i2s_chan_handle_t handle, const i2s_
|
||||
clk_info->bclk_div = 8;
|
||||
clk_info->mclk = clk_info->bclk * clk_info->bclk_div;
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
clk_info->sclk = clk_cfg->clk_src == I2S_CLK_160M_PLL ? I2S_LL_BASE_CLK : i2s_set_get_apll_freq(clk_info->mclk);
|
||||
clk_info->sclk = clk_cfg->clk_src == I2S_CLK_PLL_160M ? I2S_LL_BASE_CLK : i2s_set_get_apll_freq(clk_info->mclk);
|
||||
#else
|
||||
clk_info->sclk = I2S_LL_BASE_CLK;
|
||||
#endif
|
||||
@ -66,19 +66,6 @@ static esp_err_t i2s_pdm_tx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_tx
|
||||
}
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
/* Enable APLL and acquire its lock when initializing or clock source changed to APLL */
|
||||
if (clk_cfg->clk_src == I2S_CLK_APLL && (handle->state == I2S_CHAN_STATE_INIT || pdm_tx_cfg->clk_cfg.clk_src == I2S_CLK_160M_PLL)) {
|
||||
periph_rtc_apll_acquire();
|
||||
handle->apll_en = true;
|
||||
}
|
||||
/* Disable APLL and release its lock when clock source is changed to D2CLK */
|
||||
if (clk_cfg->clk_src == I2S_CLK_160M_PLL && pdm_tx_cfg->clk_cfg.clk_src == I2S_CLK_APLL) {
|
||||
periph_rtc_apll_release();
|
||||
handle->apll_en = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
i2s_hal_clock_info_t clk_info;
|
||||
/* Calculate clock parameters */
|
||||
ESP_RETURN_ON_ERROR(i2s_pdm_tx_calculate_clock(handle, clk_cfg, &clk_info), TAG, "clock calculate failed");
|
||||
@ -90,11 +77,18 @@ static esp_err_t i2s_pdm_tx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_tx
|
||||
i2s_hal_set_tx_clock(&handle->parent->hal, &clk_info, clk_cfg->clk_src);
|
||||
portEXIT_CRITICAL(&s_i2s.spinlock);
|
||||
|
||||
/* Update the mode info: clock configuration */
|
||||
memcpy(&(pdm_tx_cfg->clk_cfg), clk_cfg, sizeof(i2s_pdm_tx_clk_config_t));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t i2s_pdm_tx_set_slot(i2s_chan_handle_t handle, const i2s_pdm_tx_slot_config_t *slot_cfg)
|
||||
{
|
||||
/* Update the total slot num and active slot num */
|
||||
handle->total_slot = 2;
|
||||
handle->active_slot = slot_cfg->slot_mode == I2S_SLOT_MODE_MONO ? 1 : 2;
|
||||
|
||||
uint32_t buf_size = i2s_get_buf_size(handle, slot_cfg->data_bit_width, handle->dma.frame_num);
|
||||
/* The DMA buffer need to re-allocate if the buffer size changed */
|
||||
if (handle->dma.buf_size != buf_size) {
|
||||
@ -112,9 +106,9 @@ static esp_err_t i2s_pdm_tx_set_slot(i2s_chan_handle_t handle, const i2s_pdm_tx_
|
||||
i2s_hal_pdm_set_tx_slot(&(handle->parent->hal), is_slave, (i2s_hal_slot_config_t*)slot_cfg);
|
||||
portEXIT_CRITICAL(&s_i2s.spinlock);
|
||||
|
||||
/* Update the total slot num and active slot num */
|
||||
handle->total_slot = 2;
|
||||
handle->active_slot = slot_cfg->slot_mode == I2S_SLOT_MODE_MONO ? 1 : 2;
|
||||
/* Update the mode info: slot configuration */
|
||||
i2s_pdm_tx_config_t *pdm_tx_cfg = (i2s_pdm_tx_config_t *)handle->mode_info;
|
||||
memcpy(&(pdm_tx_cfg->slot_cfg), slot_cfg, sizeof(i2s_pdm_tx_slot_config_t));
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -145,6 +139,9 @@ static esp_err_t i2s_pdm_tx_set_gpio(i2s_chan_handle_t handle, const i2s_pdm_tx_
|
||||
#if SOC_I2S_HW_VERSION_2
|
||||
i2s_ll_mclk_bind_to_tx_clk(handle->parent->hal.dev);
|
||||
#endif
|
||||
/* Update the mode info: gpio configuration */
|
||||
i2s_pdm_tx_config_t *pdm_tx_cfg = (i2s_pdm_tx_config_t *)handle->mode_info;
|
||||
memcpy(&(pdm_tx_cfg->gpio_cfg), gpio_cfg, sizeof(i2s_pdm_tx_gpio_config_t));
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -159,16 +156,25 @@ esp_err_t i2s_init_pdm_tx_channel(i2s_chan_handle_t handle, const i2s_pdm_tx_con
|
||||
|
||||
xSemaphoreTake(handle->mutex, portMAX_DELAY);
|
||||
ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_REGISTER, ESP_ERR_INVALID_STATE, err, TAG, "the channel has initialized already");
|
||||
handle->mode = I2S_COMM_MODE_PDM;
|
||||
/* Allocate memory for storing the configurations of PDM tx mode */
|
||||
if (handle->mode_info) {
|
||||
free(handle->mode_info);
|
||||
}
|
||||
handle->mode_info = calloc(1, sizeof(i2s_pdm_tx_config_t));
|
||||
ESP_GOTO_ON_FALSE(handle->mode_info, ESP_ERR_NO_MEM, err, TAG, "no memory for storing the configurations");
|
||||
ESP_GOTO_ON_ERROR(i2s_pdm_tx_set_gpio(handle, &pdm_tx_cfg->gpio_cfg), err, TAG, "initialize channel failed while setting gpio pins");
|
||||
/* i2s_set_slot should be called before i2s_set_clock while initializing, because clock is relay on the slot */
|
||||
ESP_GOTO_ON_ERROR(i2s_pdm_tx_set_slot(handle, &pdm_tx_cfg->slot_cfg), err, TAG, "initialize channel failed while setting slot");
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
/* Enable APLL and acquire its lock when the clock source is APLL */
|
||||
if (pdm_tx_cfg->clk_cfg.clk_src == I2S_CLK_APLL) {
|
||||
periph_rtc_apll_acquire();
|
||||
handle->apll_en = true;
|
||||
}
|
||||
#endif
|
||||
ESP_GOTO_ON_ERROR(i2s_pdm_tx_set_clock(handle, &pdm_tx_cfg->clk_cfg), err, TAG, "initialize channel failed while setting clock");
|
||||
ESP_GOTO_ON_ERROR(i2s_init_dma_intr(handle, ESP_INTR_FLAG_LEVEL1), err, TAG, "initialize dma interrupt failed");
|
||||
/* Store the configurations of standard mode */
|
||||
i2s_pdm_tx_config_t *mode_info = calloc(1, sizeof(i2s_pdm_tx_config_t));
|
||||
ESP_GOTO_ON_FALSE(mode_info, ESP_ERR_NO_MEM, err, TAG, "no memory for storing the configurations");
|
||||
memcpy(mode_info, pdm_tx_cfg, sizeof(i2s_pdm_tx_config_t));
|
||||
handle->mode_info = mode_info;
|
||||
|
||||
i2s_ll_tx_enable_pdm(handle->parent->hal.dev);
|
||||
#if SOC_I2S_HW_VERSION_2
|
||||
@ -198,12 +204,22 @@ esp_err_t i2s_reconfig_pdm_tx_clock(i2s_chan_handle_t handle, const i2s_pdm_tx_c
|
||||
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_PDM, ESP_ERR_INVALID_ARG, err, TAG, "this handle is not working in standard moded");
|
||||
ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "invalid state, I2S should be stopped before reconfiguring the clock");
|
||||
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
i2s_pdm_tx_config_t *pdm_tx_cfg = (i2s_pdm_tx_config_t*)handle->mode_info;
|
||||
ESP_GOTO_ON_FALSE(pdm_tx_cfg, ESP_ERR_INVALID_STATE, err, TAG, "initialization not complete");
|
||||
/* Enable APLL and acquire its lock when the clock source is changed to APLL */
|
||||
if (clk_cfg->clk_src == I2S_CLK_APLL && pdm_tx_cfg->clk_cfg.clk_src == I2S_CLK_PLL_160M) {
|
||||
periph_rtc_apll_acquire();
|
||||
handle->apll_en = true;
|
||||
}
|
||||
/* Disable APLL and release its lock when clock source is changed to 160M_PLL */
|
||||
if (clk_cfg->clk_src == I2S_CLK_PLL_160M && pdm_tx_cfg->clk_cfg.clk_src == I2S_CLK_APLL) {
|
||||
periph_rtc_apll_release();
|
||||
handle->apll_en = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
ESP_GOTO_ON_ERROR(i2s_pdm_tx_set_clock(handle, &pdm_tx_cfg->clk_cfg), err, TAG, "update clock failed");
|
||||
/* Update the stored clock information */
|
||||
memcpy(&pdm_tx_cfg->clk_cfg, clk_cfg, sizeof(i2s_pdm_tx_clk_config_t));
|
||||
ESP_GOTO_ON_ERROR(i2s_pdm_tx_set_clock(handle, clk_cfg), err, TAG, "update clock failed");
|
||||
|
||||
xSemaphoreGive(handle->mutex);
|
||||
|
||||
@ -229,8 +245,6 @@ esp_err_t i2s_reconfig_pdm_tx_slot(i2s_chan_handle_t handle, const i2s_pdm_tx_sl
|
||||
ESP_GOTO_ON_FALSE(pdm_tx_cfg, ESP_ERR_INVALID_STATE, err, TAG, "initialization not complete");
|
||||
|
||||
ESP_GOTO_ON_ERROR(i2s_pdm_tx_set_slot(handle, slot_cfg), err, TAG, "set i2s standard slot failed");
|
||||
/* Update the stored slot information */
|
||||
memcpy(&pdm_tx_cfg->slot_cfg, slot_cfg, sizeof(i2s_pdm_tx_slot_config_t));
|
||||
|
||||
/* If the slot bit width changed, then need to update the clock */
|
||||
uint32_t slot_bits = slot_cfg->slot_bit_width == I2S_SLOT_BIT_WIDTH_AUTO ? slot_cfg->data_bit_width : slot_cfg->slot_bit_width;
|
||||
@ -258,13 +272,7 @@ esp_err_t i2s_reconfig_pdm_tx_gpio(i2s_chan_handle_t handle, const i2s_pdm_tx_gp
|
||||
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_PDM, ESP_ERR_INVALID_ARG, err, TAG, "This handle is not working in standard moded");
|
||||
ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "Invalid state, I2S should be stopped before reconfiguring the gpio");
|
||||
|
||||
i2s_pdm_tx_config_t *pdm_tx_cfg = (i2s_pdm_tx_config_t*)handle->mode_info;
|
||||
ESP_GOTO_ON_FALSE(pdm_tx_cfg, ESP_ERR_INVALID_STATE, err, TAG, "initialization not complete");
|
||||
|
||||
ESP_GOTO_ON_ERROR(i2s_pdm_tx_set_gpio(handle, gpio_cfg), err, TAG, "set i2s standard slot failed");
|
||||
|
||||
/* Update the stored slot information */
|
||||
memcpy(&pdm_tx_cfg->gpio_cfg, gpio_cfg, sizeof(i2s_pdm_tx_gpio_config_t));
|
||||
xSemaphoreGive(handle->mutex);
|
||||
|
||||
return ESP_OK;
|
||||
@ -290,7 +298,7 @@ static esp_err_t i2s_pdm_rx_calculate_clock(i2s_chan_handle_t handle, const i2s_
|
||||
clk_info->bclk_div = 8;
|
||||
clk_info->mclk = clk_info->bclk * clk_info->bclk_div;
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
clk_info->sclk = clk_cfg->clk_src == I2S_CLK_160M_PLL ? I2S_LL_BASE_CLK : i2s_set_get_apll_freq(clk_info->mclk);
|
||||
clk_info->sclk = clk_cfg->clk_src == I2S_CLK_PLL_160M ? I2S_LL_BASE_CLK : i2s_set_get_apll_freq(clk_info->mclk);
|
||||
#else
|
||||
clk_info->sclk = I2S_LL_BASE_CLK;
|
||||
#endif
|
||||
@ -325,19 +333,6 @@ static esp_err_t i2s_pdm_rx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_rx
|
||||
}
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
/* Enable APLL and acquire its lock when initializing or clock source changed to APLL */
|
||||
if (clk_cfg->clk_src == I2S_CLK_APLL && (handle->state == I2S_CHAN_STATE_INIT || pdm_rx_cfg->clk_cfg.clk_src == I2S_CLK_160M_PLL)) {
|
||||
periph_rtc_apll_acquire();
|
||||
handle->apll_en = true;
|
||||
}
|
||||
/* Disable APLL and release its lock when clock source is changed to D2CLK */
|
||||
if (clk_cfg->clk_src == I2S_CLK_160M_PLL && pdm_rx_cfg->clk_cfg.clk_src == I2S_CLK_APLL) {
|
||||
periph_rtc_apll_release();
|
||||
handle->apll_en = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
i2s_hal_clock_info_t clk_info;
|
||||
/* Calculate clock parameters */
|
||||
ESP_RETURN_ON_ERROR(i2s_pdm_rx_calculate_clock(handle, clk_cfg, &clk_info), TAG, "clock calculate failed");
|
||||
@ -349,11 +344,18 @@ static esp_err_t i2s_pdm_rx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_rx
|
||||
i2s_hal_set_rx_clock(&handle->parent->hal, &clk_info, clk_cfg->clk_src);
|
||||
portEXIT_CRITICAL(&s_i2s.spinlock);
|
||||
|
||||
/* Update the mode info: clock configuration */
|
||||
memcpy(&(pdm_rx_cfg->clk_cfg), clk_cfg, sizeof(i2s_pdm_rx_clk_config_t));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t i2s_pdm_rx_set_slot(i2s_chan_handle_t handle, const i2s_pdm_rx_slot_config_t *slot_cfg)
|
||||
{
|
||||
/* Update the total slot num and active slot num */
|
||||
handle->total_slot = 2;
|
||||
handle->active_slot = slot_cfg->slot_mode == I2S_SLOT_MODE_MONO ? 1 : 2;
|
||||
|
||||
uint32_t buf_size = i2s_get_buf_size(handle, slot_cfg->data_bit_width, handle->dma.frame_num);
|
||||
/* The DMA buffer need to re-allocate if the buffer size changed */
|
||||
if (handle->dma.buf_size != buf_size) {
|
||||
@ -371,9 +373,9 @@ static esp_err_t i2s_pdm_rx_set_slot(i2s_chan_handle_t handle, const i2s_pdm_rx_
|
||||
i2s_hal_pdm_set_rx_slot(&(handle->parent->hal), is_slave, (i2s_hal_slot_config_t*)slot_cfg);
|
||||
portEXIT_CRITICAL(&s_i2s.spinlock);
|
||||
|
||||
/* Update the total slot num and active slot num */
|
||||
handle->total_slot = 2;
|
||||
handle->active_slot = slot_cfg->slot_mode == I2S_SLOT_MODE_MONO ? 1 : 2;
|
||||
/* Update the mode info: slot configuration */
|
||||
i2s_pdm_rx_config_t *pdm_rx_cfg = (i2s_pdm_rx_config_t *)handle->mode_info;
|
||||
memcpy(&(pdm_rx_cfg->slot_cfg), slot_cfg, sizeof(i2s_pdm_rx_slot_config_t));
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -403,6 +405,9 @@ static esp_err_t i2s_pdm_rx_set_gpio(i2s_chan_handle_t handle, const i2s_pdm_rx_
|
||||
#if SOC_I2S_HW_VERSION_2
|
||||
i2s_ll_mclk_bind_to_rx_clk(handle->parent->hal.dev);
|
||||
#endif
|
||||
/* Update the mode info: gpio configuration */
|
||||
i2s_pdm_rx_config_t *pdm_rx_cfg = (i2s_pdm_rx_config_t *)handle->mode_info;
|
||||
memcpy(&(pdm_rx_cfg->gpio_cfg), gpio_cfg, sizeof(i2s_pdm_rx_gpio_config_t));
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -417,16 +422,25 @@ esp_err_t i2s_init_pdm_rx_channel(i2s_chan_handle_t handle, const i2s_pdm_rx_con
|
||||
|
||||
xSemaphoreTake(handle->mutex, portMAX_DELAY);
|
||||
ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_REGISTER, ESP_ERR_INVALID_STATE, err, TAG, "the channel has initialized already");
|
||||
handle->mode = I2S_COMM_MODE_PDM;
|
||||
/* Allocate memory for storing the configurations of PDM rx mode */
|
||||
if (handle->mode_info) {
|
||||
free(handle->mode_info);
|
||||
}
|
||||
handle->mode_info = calloc(1, sizeof(i2s_pdm_rx_config_t));
|
||||
ESP_GOTO_ON_FALSE(handle->mode_info, ESP_ERR_NO_MEM, err, TAG, "no memory for storing the configurations");
|
||||
ESP_GOTO_ON_ERROR(i2s_pdm_rx_set_gpio(handle, &pdm_rx_cfg->gpio_cfg), err, TAG, "initialize channel failed while setting gpio pins");
|
||||
/* i2s_set_slot should be called before i2s_set_clock while initializing, because clock is relay on the slot */
|
||||
ESP_GOTO_ON_ERROR(i2s_pdm_rx_set_slot(handle, &pdm_rx_cfg->slot_cfg), err, TAG, "initialize channel failed while setting slot");
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
/* Enable APLL and acquire its lock when the clock source is APLL */
|
||||
if (pdm_rx_cfg->clk_cfg.clk_src == I2S_CLK_APLL) {
|
||||
periph_rtc_apll_acquire();
|
||||
handle->apll_en = true;
|
||||
}
|
||||
#endif
|
||||
ESP_GOTO_ON_ERROR(i2s_pdm_rx_set_clock(handle, &pdm_rx_cfg->clk_cfg), err, TAG, "initialize channel failed while setting clock");
|
||||
ESP_GOTO_ON_ERROR(i2s_init_dma_intr(handle, ESP_INTR_FLAG_LEVEL1), err, TAG, "initialize dma interrupt failed");
|
||||
/* Store the configurations of standard mode */
|
||||
i2s_pdm_rx_config_t *mode_info = calloc(1, sizeof(i2s_pdm_rx_config_t));
|
||||
ESP_GOTO_ON_FALSE(mode_info, ESP_ERR_NO_MEM, err, TAG, "no memory for storing the configurations");
|
||||
memcpy(mode_info, pdm_rx_cfg, sizeof(i2s_pdm_rx_config_t));
|
||||
handle->mode_info = mode_info;
|
||||
|
||||
i2s_ll_rx_enable_pdm(handle->parent->hal.dev);
|
||||
#if SOC_I2S_HW_VERSION_2
|
||||
@ -456,12 +470,22 @@ esp_err_t i2s_reconfig_pdm_rx_clock(i2s_chan_handle_t handle, const i2s_pdm_rx_c
|
||||
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_PDM, ESP_ERR_INVALID_ARG, err, TAG, "this handle is not working in standard moded");
|
||||
ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "invalid state, I2S should be stopped before reconfiguring the clock");
|
||||
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
i2s_pdm_rx_config_t *pdm_rx_cfg = (i2s_pdm_rx_config_t*)handle->mode_info;
|
||||
ESP_GOTO_ON_FALSE(pdm_rx_cfg, ESP_ERR_INVALID_STATE, err, TAG, "initialization not complete");
|
||||
/* Enable APLL and acquire its lock when the clock source is changed to APLL */
|
||||
if (clk_cfg->clk_src == I2S_CLK_APLL && pdm_rx_cfg->clk_cfg.clk_src == I2S_CLK_PLL_160M) {
|
||||
periph_rtc_apll_acquire();
|
||||
handle->apll_en = true;
|
||||
}
|
||||
/* Disable APLL and release its lock when clock source is changed to 160M_PLL */
|
||||
if (clk_cfg->clk_src == I2S_CLK_PLL_160M && pdm_rx_cfg->clk_cfg.clk_src == I2S_CLK_APLL) {
|
||||
periph_rtc_apll_release();
|
||||
handle->apll_en = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
ESP_GOTO_ON_ERROR(i2s_pdm_rx_set_clock(handle, &pdm_rx_cfg->clk_cfg), err, TAG, "update clock failed");
|
||||
/* Update the stored clock information */
|
||||
memcpy(&pdm_rx_cfg->clk_cfg, clk_cfg, sizeof(i2s_pdm_rx_clk_config_t));
|
||||
ESP_GOTO_ON_ERROR(i2s_pdm_rx_set_clock(handle, clk_cfg), err, TAG, "update clock failed");
|
||||
|
||||
xSemaphoreGive(handle->mutex);
|
||||
|
||||
@ -487,8 +511,6 @@ esp_err_t i2s_reconfig_pdm_rx_slot(i2s_chan_handle_t handle, const i2s_pdm_rx_sl
|
||||
ESP_GOTO_ON_FALSE(pdm_rx_cfg, ESP_ERR_INVALID_STATE, err, TAG, "initialization not complete");
|
||||
|
||||
ESP_GOTO_ON_ERROR(i2s_pdm_rx_set_slot(handle, slot_cfg), err, TAG, "set i2s standard slot failed");
|
||||
/* Update the stored slot information */
|
||||
memcpy(&pdm_rx_cfg->slot_cfg, slot_cfg, sizeof(i2s_pdm_rx_slot_config_t));
|
||||
|
||||
/* If the slot bit width changed, then need to update the clock */
|
||||
uint32_t slot_bits = slot_cfg->slot_bit_width == I2S_SLOT_BIT_WIDTH_AUTO ? slot_cfg->data_bit_width : slot_cfg->slot_bit_width;
|
||||
@ -515,13 +537,7 @@ esp_err_t i2s_reconfig_pdm_rx_gpio(i2s_chan_handle_t handle, const i2s_pdm_rx_gp
|
||||
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_PDM, ESP_ERR_INVALID_ARG, err, TAG, "This handle is not working in standard moded");
|
||||
ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "Invalid state, I2S should be stopped before reconfiguring the gpio");
|
||||
|
||||
i2s_pdm_rx_config_t *pdm_rx_cfg = (i2s_pdm_rx_config_t*)handle->mode_info;
|
||||
ESP_GOTO_ON_FALSE(pdm_rx_cfg, ESP_ERR_INVALID_STATE, err, TAG, "initialization not complete");
|
||||
|
||||
ESP_GOTO_ON_ERROR(i2s_pdm_rx_set_gpio(handle, gpio_cfg), err, TAG, "set i2s standard slot failed");
|
||||
|
||||
/* Update the stored slot information */
|
||||
memcpy(&pdm_rx_cfg->gpio_cfg, gpio_cfg, sizeof(i2s_pdm_rx_gpio_config_t));
|
||||
xSemaphoreGive(handle->mutex);
|
||||
|
||||
return ESP_OK;
|
||||
|
@ -29,7 +29,6 @@ extern "C" {
|
||||
*/
|
||||
typedef enum {
|
||||
I2S_CHAN_STATE_REGISTER, /*!< i2s channel is registered (not initialized) */
|
||||
I2S_CHAN_STATE_INIT, /*!< i2s channel is initializing */
|
||||
I2S_CHAN_STATE_READY, /*!< i2s channel is stopped (initialized) */
|
||||
I2S_CHAN_STATE_IDLE, /*!< i2s channel is idling (initialized and started) */
|
||||
I2S_CHAN_STATE_WRITING, /*!< i2s channel is writing (initialized and started) */
|
||||
|
@ -37,7 +37,7 @@ static esp_err_t i2s_std_calculate_clock(i2s_chan_handle_t handle, const i2s_std
|
||||
clk_info->mclk = clk_info->bclk * clk_info->bclk_div;
|
||||
}
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
clk_info->sclk = clk_cfg->clk_src == I2S_CLK_160M_PLL ? I2S_LL_BASE_CLK : i2s_set_get_apll_freq(clk_info->mclk);
|
||||
clk_info->sclk = clk_cfg->clk_src == I2S_CLK_PLL_160M ? I2S_LL_BASE_CLK : i2s_set_get_apll_freq(clk_info->mclk);
|
||||
#else
|
||||
clk_info->sclk = I2S_LL_BASE_CLK;
|
||||
#endif
|
||||
@ -71,19 +71,6 @@ static esp_err_t i2s_std_set_clock(i2s_chan_handle_t handle, const i2s_std_clk_c
|
||||
}
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
/* Enable APLL and acquire its lock when initializing or clock source changed to APLL */
|
||||
if (clk_cfg->clk_src == I2S_CLK_APLL && (handle->state == I2S_CHAN_STATE_INIT || std_cfg->clk_cfg.clk_src == I2S_CLK_160M_PLL)) {
|
||||
periph_rtc_apll_acquire();
|
||||
handle->apll_en = true;
|
||||
}
|
||||
/* Disable APLL and release its lock when clock source is changed to D2CLK */
|
||||
if (clk_cfg->clk_src == I2S_CLK_160M_PLL && std_cfg->clk_cfg.clk_src == I2S_CLK_APLL) {
|
||||
periph_rtc_apll_release();
|
||||
handle->apll_en = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
i2s_hal_clock_info_t clk_info;
|
||||
/* Calculate clock parameters */
|
||||
ESP_RETURN_ON_ERROR(i2s_std_calculate_clock(handle, clk_cfg, &clk_info), TAG, "clock calculate failed");
|
||||
@ -99,11 +86,18 @@ static esp_err_t i2s_std_set_clock(i2s_chan_handle_t handle, const i2s_std_clk_c
|
||||
}
|
||||
portEXIT_CRITICAL(&s_i2s.spinlock);
|
||||
|
||||
/* Update the mode info: clock configuration */
|
||||
memcpy(&(std_cfg->clk_cfg), clk_cfg, sizeof(i2s_std_clk_config_t));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t i2s_std_set_slot(i2s_chan_handle_t handle, const i2s_std_slot_config_t *slot_cfg)
|
||||
{
|
||||
/* Update the total slot num and active slot num */
|
||||
handle->total_slot = 2;
|
||||
handle->active_slot = slot_cfg->slot_mode == I2S_SLOT_MODE_MONO ? 1 : 2;
|
||||
|
||||
uint32_t buf_size = i2s_get_buf_size(handle, slot_cfg->data_bit_width, handle->dma.frame_num);
|
||||
/* The DMA buffer need to re-allocate if the buffer size changed */
|
||||
if (handle->dma.buf_size != buf_size) {
|
||||
@ -134,9 +128,9 @@ static esp_err_t i2s_std_set_slot(i2s_chan_handle_t handle, const i2s_std_slot_c
|
||||
}
|
||||
portEXIT_CRITICAL(&s_i2s.spinlock);
|
||||
|
||||
/* Update the total slot num and active slot num */
|
||||
handle->total_slot = 2;
|
||||
handle->active_slot = slot_cfg->slot_mode == I2S_SLOT_MODE_MONO ? 1 : 2;
|
||||
/* Update the mode info: slot configuration */
|
||||
i2s_std_config_t *std_cfg = (i2s_std_config_t*)(handle->mode_info);
|
||||
memcpy(&(std_cfg->slot_cfg), slot_cfg, sizeof(i2s_std_slot_config_t));
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -157,6 +151,11 @@ static esp_err_t i2s_std_set_gpio(i2s_chan_handle_t handle, const i2s_std_gpio_c
|
||||
/* Set data input GPIO */
|
||||
i2s_gpio_check_and_set(gpio_cfg->din, i2s_periph_signal[id].data_in_sig, true);
|
||||
}
|
||||
/* Loopback if dout = din */
|
||||
if (gpio_cfg->dout != -1 &&
|
||||
gpio_cfg->dout == gpio_cfg->din) {
|
||||
gpio_set_direction(gpio_cfg->dout, GPIO_MODE_INPUT_OUTPUT);
|
||||
}
|
||||
|
||||
if (handle->role == I2S_ROLE_SLAVE) {
|
||||
/* For "tx + slave" mode, select TX signal index for ws and bck */
|
||||
@ -187,6 +186,9 @@ static esp_err_t i2s_std_set_gpio(i2s_chan_handle_t handle, const i2s_std_gpio_c
|
||||
i2s_gpio_check_and_set(gpio_cfg->bclk, i2s_periph_signal[id].m_tx_bck_sig, false);
|
||||
}
|
||||
}
|
||||
/* Update the mode info: gpio configuration */
|
||||
i2s_std_config_t *std_cfg = (i2s_std_config_t*)(handle->mode_info);
|
||||
memcpy(&(std_cfg->gpio_cfg), gpio_cfg, sizeof(i2s_std_gpio_config_t));
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -197,18 +199,26 @@ esp_err_t i2s_init_std_channel(i2s_chan_handle_t handle, const i2s_std_config_t
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
xSemaphoreTake(handle->mutex, portMAX_DELAY);
|
||||
handle->mode = I2S_COMM_MODE_STD;
|
||||
/* Allocate memory for storing the configurations of standard mode */
|
||||
if (handle->mode_info) {
|
||||
free(handle->mode_info);
|
||||
}
|
||||
handle->mode_info = calloc(1, sizeof(i2s_std_config_t));
|
||||
ESP_GOTO_ON_FALSE(handle->mode_info, ESP_ERR_NO_MEM, err, TAG, "no memory for storing the configurations");
|
||||
ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_REGISTER, ESP_ERR_INVALID_STATE, err, TAG, "the channel has initialized already");
|
||||
ESP_GOTO_ON_ERROR(i2s_std_set_gpio(handle, &std_cfg->gpio_cfg), err, TAG, "initialize channel failed while setting gpio pins");
|
||||
/* i2s_set_slot should be called before i2s_set_clock while initializing, because clock is relay on the slot */
|
||||
ESP_GOTO_ON_ERROR(i2s_std_set_slot(handle, &std_cfg->slot_cfg), err, TAG, "initialize channel failed while setting slot");
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
/* Enable APLL and acquire its lock when the clock source is APLL */
|
||||
if (std_cfg->clk_cfg.clk_src == I2S_CLK_APLL) {
|
||||
periph_rtc_apll_acquire();
|
||||
handle->apll_en = true;
|
||||
}
|
||||
#endif
|
||||
ESP_GOTO_ON_ERROR(i2s_std_set_clock(handle, &std_cfg->clk_cfg), err, TAG, "initialize channel failed while setting clock");
|
||||
ESP_GOTO_ON_ERROR(i2s_init_dma_intr(handle, ESP_INTR_FLAG_LEVEL1), err, TAG, "initialize dma interrupt failed");
|
||||
/* Store the configurations of standard mode */
|
||||
i2s_std_config_t *mode_info = calloc(1, sizeof(i2s_std_config_t));
|
||||
ESP_GOTO_ON_FALSE(mode_info, ESP_ERR_NO_MEM, err, TAG, "no memory for storing the configurations");
|
||||
memcpy(mode_info, std_cfg, sizeof(i2s_std_config_t));
|
||||
handle->mode_info = mode_info;
|
||||
|
||||
#if SOC_I2S_HW_VERSION_2
|
||||
/* Enable clock to start outputting mclk signal. Some codecs will reset once mclk stop */
|
||||
if (handle->dir == I2S_DIR_TX) {
|
||||
@ -241,12 +251,21 @@ esp_err_t i2s_reconfig_std_clock(i2s_chan_handle_t handle, const i2s_std_clk_con
|
||||
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_STD, ESP_ERR_INVALID_ARG, err, TAG, "this handle is not working in standard moded");
|
||||
ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "invalid state, I2S should be stopped before reconfiguring the clock");
|
||||
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
i2s_std_config_t *std_cfg = (i2s_std_config_t*)handle->mode_info;
|
||||
ESP_GOTO_ON_FALSE(std_cfg, ESP_ERR_INVALID_STATE, err, TAG, "initialization not complete");
|
||||
|
||||
ESP_GOTO_ON_ERROR(i2s_std_set_clock(handle, &std_cfg->clk_cfg), err, TAG, "update clock failed");
|
||||
/* Update the stored clock information */
|
||||
memcpy(&std_cfg->clk_cfg, clk_cfg, sizeof(i2s_std_clk_config_t));
|
||||
/* Enable APLL and acquire its lock when the clock source is changed to APLL */
|
||||
if (clk_cfg->clk_src == I2S_CLK_APLL && std_cfg->clk_cfg.clk_src == I2S_CLK_PLL_160M) {
|
||||
periph_rtc_apll_acquire();
|
||||
handle->apll_en = true;
|
||||
}
|
||||
/* Disable APLL and release its lock when clock source is changed to 160M_PLL */
|
||||
if (clk_cfg->clk_src == I2S_CLK_PLL_160M && std_cfg->clk_cfg.clk_src == I2S_CLK_APLL) {
|
||||
periph_rtc_apll_release();
|
||||
handle->apll_en = false;
|
||||
}
|
||||
#endif
|
||||
ESP_GOTO_ON_ERROR(i2s_std_set_clock(handle, clk_cfg), err, TAG, "update clock failed");
|
||||
|
||||
xSemaphoreGive(handle->mutex);
|
||||
|
||||
@ -271,8 +290,6 @@ esp_err_t i2s_reconfig_std_slot(i2s_chan_handle_t handle, const i2s_std_slot_con
|
||||
ESP_GOTO_ON_FALSE(std_cfg, ESP_ERR_INVALID_STATE, err, TAG, "initialization not complete");
|
||||
|
||||
ESP_GOTO_ON_ERROR(i2s_std_set_slot(handle, slot_cfg), err, TAG, "set i2s standard slot failed");
|
||||
/* Update the stored slot information */
|
||||
memcpy(&std_cfg->slot_cfg, slot_cfg, sizeof(i2s_std_slot_config_t));
|
||||
|
||||
/* If the slot bit width changed, then need to update the clock */
|
||||
uint32_t slot_bits = slot_cfg->slot_bit_width == I2S_SLOT_BIT_WIDTH_AUTO ? slot_cfg->data_bit_width : slot_cfg->slot_bit_width;
|
||||
@ -299,13 +316,7 @@ esp_err_t i2s_reconfig_std_gpio(i2s_chan_handle_t handle, const i2s_std_gpio_con
|
||||
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_STD, ESP_ERR_INVALID_ARG, err, TAG, "This handle is not working in standard moded");
|
||||
ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "Invalid state, I2S should be stopped before reconfiguring the gpio");
|
||||
|
||||
i2s_std_config_t *std_cfg = (i2s_std_config_t*)handle->mode_info;
|
||||
ESP_GOTO_ON_FALSE(std_cfg, ESP_ERR_INVALID_STATE, err, TAG, "initialization not complete");
|
||||
|
||||
ESP_GOTO_ON_ERROR(i2s_std_set_gpio(handle, gpio_cfg), err, TAG, "set i2s standard slot failed");
|
||||
|
||||
/* Update the stored slot information */
|
||||
memcpy(&std_cfg->gpio_cfg, gpio_cfg, sizeof(i2s_std_gpio_config_t));
|
||||
xSemaphoreGive(handle->mutex);
|
||||
|
||||
return ESP_OK;
|
||||
|
@ -38,7 +38,7 @@ static esp_err_t i2s_tdm_calculate_clock(i2s_chan_handle_t handle, const i2s_tdm
|
||||
clk_info->mclk = clk_info->bclk * clk_info->bclk_div;
|
||||
}
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
clk_info->sclk = clk_cfg->clk_src == I2S_CLK_160M_PLL ? I2S_LL_BASE_CLK : i2s_set_get_apll_freq(clk_info->mclk);
|
||||
clk_info->sclk = clk_cfg->clk_src == I2S_CLK_PLL_160M ? I2S_LL_BASE_CLK : i2s_set_get_apll_freq(clk_info->mclk);
|
||||
#else
|
||||
clk_info->sclk = I2S_LL_BASE_CLK;
|
||||
#endif
|
||||
@ -72,19 +72,6 @@ static esp_err_t i2s_tdm_set_clock(i2s_chan_handle_t handle, const i2s_tdm_clk_c
|
||||
}
|
||||
#endif //CONFIG_PM_ENABLE
|
||||
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
/* Enable APLL and acquire its lock when initializing or clock source changed to APLL */
|
||||
if (clk_cfg->clk_src == I2S_CLK_APLL && (handle->state == I2S_CHAN_STATE_INIT || tdm_cfg->clk_cfg.clk_src == I2S_CLK_160M_PLL)) {
|
||||
periph_rtc_apll_acquire();
|
||||
handle->apll_en = true;
|
||||
}
|
||||
/* Disable APLL and release its lock when clock source is changed to D2CLK */
|
||||
if (clk_cfg->clk_src == I2S_CLK_160M_PLL && tdm_cfg->clk_cfg.clk_src == I2S_CLK_APLL) {
|
||||
periph_rtc_apll_release();
|
||||
handle->apll_en = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
i2s_hal_clock_info_t clk_info;
|
||||
/* Calculate clock parameters */
|
||||
ESP_RETURN_ON_ERROR(i2s_tdm_calculate_clock(handle, clk_cfg, &clk_info), TAG, "clock calculate failed");
|
||||
@ -100,11 +87,20 @@ static esp_err_t i2s_tdm_set_clock(i2s_chan_handle_t handle, const i2s_tdm_clk_c
|
||||
}
|
||||
portEXIT_CRITICAL(&s_i2s.spinlock);
|
||||
|
||||
/* Update the mode info: clock configuration */
|
||||
memcpy(&(tdm_cfg->clk_cfg), clk_cfg, sizeof(i2s_tdm_clk_config_t));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t i2s_tdm_set_slot(i2s_chan_handle_t handle, const i2s_tdm_slot_config_t *slot_cfg)
|
||||
{
|
||||
/* Update the total slot num and active slot num */
|
||||
handle->active_slot = slot_cfg->slot_mode == I2S_SLOT_MODE_MONO ? 1 : __builtin_popcount(slot_cfg->slot_mask);
|
||||
uint32_t max_slot_num = 32 - __builtin_clz(slot_cfg->slot_mask);
|
||||
handle->total_slot = slot_cfg->total_slot < max_slot_num ? max_slot_num : slot_cfg->total_slot;
|
||||
handle->total_slot = handle->total_slot < 2 ? 2 : handle->total_slot; // At least two slots in a frame
|
||||
|
||||
uint32_t buf_size = i2s_get_buf_size(handle, slot_cfg->data_bit_width, handle->dma.frame_num);
|
||||
/* The DMA buffer need to re-allocate if the buffer size changed */
|
||||
if (handle->dma.buf_size != buf_size) {
|
||||
@ -129,17 +125,15 @@ static esp_err_t i2s_tdm_set_slot(i2s_chan_handle_t handle, const i2s_tdm_slot_c
|
||||
portENTER_CRITICAL(&s_i2s.spinlock);
|
||||
/* Configure the hardware to apply TDM format */
|
||||
if (handle->dir == I2S_DIR_TX) {
|
||||
i2s_hal_tdm_set_tx_slot(&(handle->parent->hal), is_slave, slot_cfg);
|
||||
i2s_hal_tdm_set_tx_slot(&(handle->parent->hal), is_slave, (i2s_hal_slot_config_t*)slot_cfg);
|
||||
} else {
|
||||
i2s_hal_tdm_set_rx_slot(&(handle->parent->hal), is_slave, slot_cfg);
|
||||
i2s_hal_tdm_set_rx_slot(&(handle->parent->hal), is_slave, (i2s_hal_slot_config_t*)slot_cfg);
|
||||
}
|
||||
portEXIT_CRITICAL(&s_i2s.spinlock);
|
||||
|
||||
/* Update the total slot num and active slot num */
|
||||
handle->active_slot = slot_cfg->slot_mode == I2S_SLOT_MODE_MONO ? 1 : __builtin_popcount(slot_cfg->slot_mask);
|
||||
uint32_t max_slot_num = 32 - __builtin_clz(slot_cfg->slot_mask);
|
||||
handle->total_slot = slot_cfg->total_slot < max_slot_num ? max_slot_num : slot_cfg->total_slot;
|
||||
handle->total_slot = handle->total_slot < 2 ? 2 : handle->total_slot; // At least two slots in a frame
|
||||
/* Update the mode info: slot configuration */
|
||||
i2s_tdm_config_t *tdm_cfg = (i2s_tdm_config_t*)(handle->mode_info);
|
||||
memcpy(&(tdm_cfg->slot_cfg), slot_cfg, sizeof(i2s_tdm_slot_config_t));
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -160,6 +154,11 @@ static esp_err_t i2s_tdm_set_gpio(i2s_chan_handle_t handle, const i2s_tdm_gpio_c
|
||||
/* Set data input GPIO */
|
||||
i2s_gpio_check_and_set(gpio_cfg->din, i2s_periph_signal[id].data_in_sig, true);
|
||||
}
|
||||
/* Loopback if dout = din */
|
||||
if (gpio_cfg->dout != -1 &&
|
||||
gpio_cfg->dout == gpio_cfg->din) {
|
||||
gpio_set_direction(gpio_cfg->dout, GPIO_MODE_INPUT_OUTPUT);
|
||||
}
|
||||
|
||||
if (handle->role == I2S_ROLE_SLAVE) {
|
||||
/* For "tx + slave" mode, select TX signal index for ws and bck */
|
||||
@ -190,6 +189,9 @@ static esp_err_t i2s_tdm_set_gpio(i2s_chan_handle_t handle, const i2s_tdm_gpio_c
|
||||
i2s_gpio_check_and_set(gpio_cfg->bclk, i2s_periph_signal[id].m_tx_bck_sig, false);
|
||||
}
|
||||
}
|
||||
/* Update the mode info: gpio configuration */
|
||||
i2s_tdm_config_t *tdm_cfg = (i2s_tdm_config_t*)(handle->mode_info);
|
||||
memcpy(&(tdm_cfg->gpio_cfg), gpio_cfg, sizeof(i2s_tdm_gpio_config_t));
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -202,16 +204,25 @@ esp_err_t i2s_init_tdm_channel(i2s_chan_handle_t handle, const i2s_tdm_config_t
|
||||
|
||||
xSemaphoreTake(handle->mutex, portMAX_DELAY);
|
||||
ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_REGISTER, ESP_ERR_INVALID_STATE, err, TAG, "the channel has initialized already");
|
||||
handle->mode = I2S_COMM_MODE_TDM;
|
||||
/* Allocate memory for storing the configurations of TDM mode */
|
||||
if (handle->mode_info) {
|
||||
free(handle->mode_info);
|
||||
}
|
||||
handle->mode_info = calloc(1, sizeof(i2s_tdm_config_t));
|
||||
ESP_GOTO_ON_FALSE(handle->mode_info, ESP_ERR_NO_MEM, err, TAG, "no memory for storing the configurations");
|
||||
ESP_GOTO_ON_ERROR(i2s_tdm_set_gpio(handle, &tdm_cfg->gpio_cfg), err, TAG, "initialize channel failed while setting gpio pins");
|
||||
/* i2s_set_slot should be called before i2s_set_clock while initializing, because clock is relay on the slot */
|
||||
ESP_GOTO_ON_ERROR(i2s_tdm_set_slot(handle, &tdm_cfg->slot_cfg), err, TAG, "initialize channel failed while setting slot");
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
/* Enable APLL and acquire its lock when the clock source is APLL */
|
||||
if (tdm_cfg->clk_cfg.clk_src == I2S_CLK_APLL) {
|
||||
periph_rtc_apll_acquire();
|
||||
handle->apll_en = true;
|
||||
}
|
||||
ESP_GOTO_ON_ERROR(i2s_tdm_set_clock(handle, &tdm_cfg->clk_cfg), err, TAG, "initialize channel failed while setting clock");
|
||||
ESP_GOTO_ON_ERROR(i2s_init_dma_intr(handle, ESP_INTR_FLAG_LEVEL1), err, TAG, "initialize dma interrupt failed");
|
||||
/* Store the configurations of standard mode */
|
||||
i2s_tdm_config_t *mode_info = calloc(1, sizeof(i2s_tdm_config_t));
|
||||
ESP_GOTO_ON_FALSE(mode_info, ESP_ERR_NO_MEM, err, TAG, "no memory for storing the configurations");
|
||||
memcpy(mode_info, tdm_cfg, sizeof(i2s_tdm_config_t));
|
||||
handle->mode_info = mode_info;
|
||||
#endif
|
||||
|
||||
#if SOC_I2S_HW_VERSION_2
|
||||
/* Enable clock to start outputting mclk signal. Some codecs will reset once mclk stop */
|
||||
@ -245,12 +256,22 @@ esp_err_t i2s_reconfig_tdm_clock(i2s_chan_handle_t handle, const i2s_tdm_clk_con
|
||||
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_TDM, ESP_ERR_INVALID_ARG, err, TAG, "this handle is not working in standard moded");
|
||||
ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "invalid state, I2S should be stopped before reconfiguring the clock");
|
||||
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
i2s_tdm_config_t *tdm_cfg = (i2s_tdm_config_t*)handle->mode_info;
|
||||
ESP_GOTO_ON_FALSE(tdm_cfg, ESP_ERR_INVALID_STATE, err, TAG, "initialization not complete");
|
||||
/* Enable APLL and acquire its lock when the clock source is changed to APLL */
|
||||
if (clk_cfg->clk_src == I2S_CLK_APLL && clk_cfg->clk_cfg.clk_src == I2S_CLK_PLL_160M) {
|
||||
periph_rtc_apll_acquire();
|
||||
handle->apll_en = true;
|
||||
}
|
||||
/* Disable APLL and release its lock when clock source is changed to 160M_PLL */
|
||||
if (clk_cfg->clk_src == I2S_CLK_PLL_160M && clk_cfg->clk_cfg.clk_src == I2S_CLK_APLL) {
|
||||
periph_rtc_apll_release();
|
||||
handle->apll_en = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
ESP_GOTO_ON_ERROR(i2s_tdm_set_clock(handle, &tdm_cfg->clk_cfg), err, TAG, "update clock failed");
|
||||
/* Update the stored clock information */
|
||||
memcpy(&tdm_cfg->clk_cfg, clk_cfg, sizeof(i2s_tdm_clk_config_t));
|
||||
ESP_GOTO_ON_ERROR(i2s_tdm_set_clock(handle, clk_cfg), err, TAG, "update clock failed");
|
||||
xSemaphoreGive(handle->mutex);
|
||||
|
||||
return ESP_OK;
|
||||
@ -274,8 +295,6 @@ esp_err_t i2s_reconfig_tdm_slot(i2s_chan_handle_t handle, const i2s_tdm_slot_con
|
||||
ESP_GOTO_ON_FALSE(tdm_cfg, ESP_ERR_INVALID_STATE, err, TAG, "initialization not complete");
|
||||
|
||||
ESP_GOTO_ON_ERROR(i2s_tdm_set_slot(handle, slot_cfg), err, TAG, "set i2s standard slot failed");
|
||||
/* Update the stored slot information */
|
||||
memcpy(&tdm_cfg->slot_cfg, slot_cfg, sizeof(i2s_tdm_slot_config_t));
|
||||
|
||||
/* If the slot bit width changed, then need to update the clock */
|
||||
uint32_t slot_bits = slot_cfg->slot_bit_width == I2S_SLOT_BIT_WIDTH_AUTO ? slot_cfg->data_bit_width : slot_cfg->slot_bit_width;
|
||||
@ -301,13 +320,7 @@ esp_err_t i2s_reconfig_tdm_gpio(i2s_chan_handle_t handle, const i2s_tdm_gpio_con
|
||||
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_TDM, ESP_ERR_INVALID_ARG, err, TAG, "This handle is not working in standard moded");
|
||||
ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "Invalid state, I2S should be stopped before reconfiguring the gpio");
|
||||
|
||||
i2s_tdm_config_t *tdm_cfg = (i2s_tdm_config_t*)handle->mode_info;
|
||||
ESP_GOTO_ON_FALSE(tdm_cfg, ESP_ERR_INVALID_STATE, err, TAG, "initialization not complete");
|
||||
|
||||
ESP_GOTO_ON_ERROR(i2s_tdm_set_gpio(handle, gpio_cfg), err, TAG, "set i2s standard slot failed");
|
||||
|
||||
/* Update the stored slot information */
|
||||
memcpy(&tdm_cfg->gpio_cfg, gpio_cfg, sizeof(i2s_tdm_gpio_config_t));
|
||||
xSemaphoreGive(handle->mutex);
|
||||
|
||||
return ESP_OK;
|
||||
|
@ -27,11 +27,12 @@ extern "C" {
|
||||
/**
|
||||
* @brief get default I2S property
|
||||
*/
|
||||
#define I2S_CHANNEL_CONFIG(i2s_role, i2s_mode, pin_config) { \
|
||||
.id = I2S_NUM_AUTO, \
|
||||
#define I2S_CHANNEL_DEFAULT_CONFIG(i2s_num, i2s_role) { \
|
||||
.id = i2s_num, \
|
||||
.role = i2s_role, \
|
||||
.mode = i2s_mode, \
|
||||
.io = pin_config, \
|
||||
.dma_desc_num = 3, \
|
||||
.dma_frame_num = 500, \
|
||||
.auto_clear = false, \
|
||||
}
|
||||
|
||||
#define I2S_GPIO_UNUSED GPIO_NUM_NC /*!< Used in i2s_gpio_config_t for signals which are not used */
|
||||
@ -107,7 +108,7 @@ esp_err_t i2s_del_channel(i2s_chan_handle_t handle);
|
||||
* - ESP_ERR_INVALID_ARG NULL pointer
|
||||
* - ESP_ERR_INVALID_STATE This channel is not registered
|
||||
*/
|
||||
esp_err_t i2s_init_channel(i2s_chan_handle_t handle, const void *clk_config, const void *slot_config);
|
||||
// esp_err_t i2s_init_channel(i2s_chan_handle_t handle, const void *clk_config, const void *slot_config);
|
||||
|
||||
/**
|
||||
* @brief Reconfigure the I2S clock
|
||||
@ -128,7 +129,7 @@ esp_err_t i2s_init_channel(i2s_chan_handle_t handle, const void *clk_config, con
|
||||
* - ESP_ERR_INVALID_ARG NULL pointer
|
||||
* - ESP_ERR_INVALID_STATE This channel is not initialized
|
||||
*/
|
||||
esp_err_t i2s_set_clock(i2s_chan_handle_t handle, const void *clk_config);
|
||||
// esp_err_t i2s_set_clock(i2s_chan_handle_t handle, const void *clk_config);
|
||||
|
||||
/**
|
||||
* @brief Reconfigure the I2S slot
|
||||
@ -148,7 +149,7 @@ esp_err_t i2s_set_clock(i2s_chan_handle_t handle, const void *clk_config);
|
||||
* - ESP_ERR_INVALID_ARG NULL pointer or unmatched slot configuration type
|
||||
* - ESP_ERR_INVALID_STATE This channel is not initialized
|
||||
*/
|
||||
esp_err_t i2s_set_slot(i2s_chan_handle_t handle, const void *slot_config);
|
||||
// esp_err_t i2s_set_slot(i2s_chan_handle_t handle, const void *slot_config);
|
||||
|
||||
/**
|
||||
* @brief Get I2S event queue handler
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include "hal/i2s_types.h"
|
||||
#include "hal/gpio_types.h"
|
||||
#include "driver/i2s_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -40,7 +41,7 @@ extern "C" {
|
||||
*/
|
||||
#define I2S_PDM_RX_CLK_DEFAULT_CONFIG(rate) { \
|
||||
.sample_rate_hz = rate, \
|
||||
.clk_src = I2S_CLK_160M_PLL, \
|
||||
.clk_src = I2S_CLK_PLL_160M, \
|
||||
.mclk_multiple = I2S_MCLK_MULTIPLE_256, \
|
||||
.dn_sample_mode = I2S_PDM_DSR_8S \
|
||||
}
|
||||
@ -85,6 +86,16 @@ typedef struct
|
||||
i2s_pdm_rx_gpio_config_t gpio_cfg;
|
||||
} i2s_pdm_rx_config_t;
|
||||
|
||||
|
||||
esp_err_t i2s_init_pdm_rx_channel(i2s_chan_handle_t handle, const i2s_pdm_rx_config_t *pdm_rx_cfg);
|
||||
|
||||
esp_err_t i2s_reconfig_pdm_rx_clock(i2s_chan_handle_t handle, const i2s_pdm_rx_clk_config_t *clk_cfg);
|
||||
|
||||
esp_err_t i2s_reconfig_pdm_rx_slot(i2s_chan_handle_t handle, const i2s_pdm_rx_slot_config_t *slot_cfg);
|
||||
|
||||
esp_err_t i2s_reconfig_pdm_rx_gpio(i2s_chan_handle_t handle, const i2s_pdm_rx_gpio_config_t *gpio_cfg);
|
||||
|
||||
|
||||
#endif // SOC_I2S_SUPPORTS_PDM_RX
|
||||
|
||||
|
||||
@ -144,7 +155,7 @@ typedef struct
|
||||
*/
|
||||
#define I2S_PDM_TX_CLK_DEFAULT_CONFIG(rate) { \
|
||||
.sample_rate_hz = rate, \
|
||||
.clk_src = I2S_CLK_160M_PLL, \
|
||||
.clk_src = I2S_CLK_PLL_160M, \
|
||||
.mclk_multiple = I2S_MCLK_MULTIPLE_256, \
|
||||
.up_sample_fp = 960, \
|
||||
.up_sample_fs = ((rate) / 100), \
|
||||
@ -219,6 +230,13 @@ typedef struct
|
||||
i2s_pdm_tx_gpio_config_t gpio_cfg;
|
||||
} i2s_pdm_tx_config_t;
|
||||
|
||||
esp_err_t i2s_init_pdm_tx_channel(i2s_chan_handle_t handle, const i2s_pdm_tx_config_t *pdm_tx_cfg);
|
||||
|
||||
esp_err_t i2s_reconfig_pdm_tx_clock(i2s_chan_handle_t handle, const i2s_pdm_tx_clk_config_t *clk_cfg);
|
||||
|
||||
esp_err_t i2s_reconfig_pdm_tx_slot(i2s_chan_handle_t handle, const i2s_pdm_tx_slot_config_t *slot_cfg);
|
||||
|
||||
esp_err_t i2s_reconfig_pdm_tx_gpio(i2s_chan_handle_t handle, const i2s_pdm_tx_gpio_config_t *gpio_cfg);
|
||||
|
||||
#endif // SOC_I2S_SUPPORTS_PDM_TX
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
#include "hal/i2s_types.h"
|
||||
#include "hal/gpio_types.h"
|
||||
#include "driver/i2s_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -140,7 +141,7 @@ extern "C" {
|
||||
*/
|
||||
#define I2S_STD_CLK_DEFAULT_CONFIG(rate) { \
|
||||
.sample_rate_hz = rate, \
|
||||
.clk_src = I2S_CLK_160M_PLL, \
|
||||
.clk_src = I2S_CLK_PLL_160M, \
|
||||
.mclk_multiple = I2S_MCLK_MULTIPLE_256, \
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include "hal/i2s_types.h"
|
||||
#include "hal/gpio_types.h"
|
||||
#include "driver/i2s_common.h"
|
||||
|
||||
#if SOC_I2S_SUPPORTS_TDM
|
||||
|
||||
@ -119,7 +120,7 @@ extern "C" {
|
||||
*/
|
||||
#define I2S_TDM_CLK_DEFAULT_CONFIG(rate) { \
|
||||
.sample_rate_hz = rate, \
|
||||
.clk_src = I2S_CLK_160M_PLL, \
|
||||
.clk_src = I2S_CLK_PLL_160M, \
|
||||
.mclk_multiple = I2S_MCLK_MULTIPLE_256, \
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
set(srcs "test_app_main.c")
|
||||
|
||||
if(CONFIG_SOC_I2S_SUPPORTED)
|
||||
list(APPEND srcs "test_i2s_controller.c"
|
||||
list(APPEND srcs "test_i2s.c"
|
||||
"test_i2s_legacy.c")
|
||||
endif()
|
||||
|
||||
@ -11,6 +11,6 @@ idf_component_register(SRCS ${srcs}
|
||||
|
||||
if(CONFIG_SOC_I2S_SUPPORTED)
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE
|
||||
"-u test_app_include_i2s_controller"
|
||||
"-u test_app_include_i2s"
|
||||
"-u test_app_include_i2s_legacy")
|
||||
endif()
|
||||
|
@ -25,11 +25,17 @@
|
||||
#include "math.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "soc/i2s_periph.h"
|
||||
#include "driver/i2s_controller.h"
|
||||
#include "driver/i2s_std.h"
|
||||
#if SOC_I2S_SUPPORTS_PDM
|
||||
#include "driver/i2s_pdm.h"
|
||||
#endif
|
||||
#if SOC_I2S_SUPPORTS_TDM
|
||||
#include "driver/i2s_tdm.h"
|
||||
#endif
|
||||
#include "hal/i2s_hal.h"
|
||||
#include "esp_private/i2s_platform.h"
|
||||
#if SOC_PCNT_SUPPORTED
|
||||
#include "driver/pcnt.h"
|
||||
#include "driver/pulse_cnt.h"
|
||||
#include "soc/pcnt_periph.h"
|
||||
#endif
|
||||
|
||||
@ -38,12 +44,12 @@
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#define MASTER_MCK_IO 0
|
||||
#define MASTER_BCK_IO 15
|
||||
#define MASTER_WS_IO 25
|
||||
#define SLAVE_BCK_IO 19
|
||||
#define SLAVE_WS_IO 26
|
||||
#define DATA_IN_IO 21
|
||||
#define DATA_OUT_IO 22
|
||||
#define MASTER_BCK_IO 4
|
||||
#define MASTER_WS_IO 5
|
||||
#define SLAVE_BCK_IO 21
|
||||
#define SLAVE_WS_IO 22
|
||||
#define DATA_IN_IO 19
|
||||
#define DATA_OUT_IO 18
|
||||
#define ADC1_CHANNEL_4_IO 32
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#define MASTER_MCK_IO 0
|
||||
@ -81,7 +87,7 @@
|
||||
.ws = MASTER_WS_IO, \
|
||||
.dout = DATA_OUT_IO, \
|
||||
.din = DATA_IN_IO \
|
||||
};
|
||||
}
|
||||
|
||||
#define I2S_TEST_SLAVE_DEFAULT_PIN { \
|
||||
.mclk = -1, \
|
||||
@ -89,10 +95,10 @@
|
||||
.ws = SLAVE_WS_IO, \
|
||||
.dout = DATA_OUT_IO, \
|
||||
.din = DATA_IN_IO \
|
||||
};
|
||||
}
|
||||
|
||||
// This empty function is used to force the compiler link this file
|
||||
void test_app_include_i2s_controller(void)
|
||||
void test_app_include_i2s(void)
|
||||
{
|
||||
}
|
||||
|
||||
@ -192,35 +198,37 @@ finish:
|
||||
// To check if the software logic of I2S driver is correct
|
||||
TEST_CASE("I2S basic driver apply, delete test", "[i2s]")
|
||||
{
|
||||
i2s_gpio_config_t i2s_pin = I2S_TEST_MASTER_DEFAULT_PIN;
|
||||
|
||||
i2s_chan_handle_t tx_handle;
|
||||
i2s_chan_handle_t rx_handle;
|
||||
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_CONFIG(I2S_ROLE_MASTER, I2S_COMM_MODE_STD, &i2s_pin);
|
||||
i2s_std_slot_config_t slot_cfg = I2S_STD_PHILIP_SLOT_CONFIG(SAMPLE_BITS, I2S_SLOT_MODE_STEREO);
|
||||
i2s_std_clk_config_t clk_cfg = I2S_STD_CLK_CONFIG(SAMPLE_RATE);
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
|
||||
i2s_std_config_t std_cfg = {
|
||||
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE),
|
||||
.slot_cfg = I2S_STD_PHILIP_SLOT_DEFAULT_CONFIG(SAMPLE_BITS, I2S_SLOT_MODE_STEREO),
|
||||
.gpio_cfg = I2S_TEST_MASTER_DEFAULT_PIN,
|
||||
};
|
||||
|
||||
/* TX channel basic test */
|
||||
TEST_ESP_OK(i2s_new_channel(&chan_cfg, &tx_handle, NULL));
|
||||
|
||||
TEST_ESP_OK(i2s_init_channel(tx_handle, &clk_cfg, &slot_cfg));
|
||||
slot_cfg.data_bit_width = I2S_DATA_BIT_WIDTH_32BIT;
|
||||
TEST_ESP_OK(i2s_set_slot(tx_handle, &slot_cfg));
|
||||
clk_cfg.sample_rate = 44100;
|
||||
TEST_ESP_OK(i2s_set_clock(tx_handle, &clk_cfg));
|
||||
TEST_ESP_OK(i2s_init_std_channel(tx_handle, &std_cfg));
|
||||
std_cfg.slot_cfg.data_bit_width = I2S_DATA_BIT_WIDTH_32BIT;
|
||||
TEST_ESP_OK(i2s_reconfig_std_slot(tx_handle, &std_cfg.slot_cfg));
|
||||
std_cfg.clk_cfg.sample_rate_hz = 44100;
|
||||
TEST_ESP_OK(i2s_reconfig_std_clock(tx_handle, &std_cfg.clk_cfg));
|
||||
TEST_ESP_OK(i2s_start_channel(tx_handle));
|
||||
TEST_ESP_OK(i2s_del_channel(tx_handle));
|
||||
|
||||
/* Duplex channel basic test */
|
||||
chan_cfg.id = I2S_NUM_0; // Specify port id to I2S port 0
|
||||
TEST_ESP_OK(i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle));
|
||||
TEST_ESP_OK(i2s_init_channel(tx_handle, &clk_cfg, &slot_cfg));
|
||||
TEST_ESP_OK(i2s_init_channel(rx_handle, &clk_cfg, &slot_cfg));
|
||||
TEST_ESP_OK(i2s_init_std_channel(tx_handle, &std_cfg));
|
||||
TEST_ESP_OK(i2s_init_std_channel(rx_handle, &std_cfg));
|
||||
TEST_ESP_OK(i2s_del_channel(tx_handle));
|
||||
TEST_ESP_OK(i2s_del_channel(rx_handle));
|
||||
|
||||
/* Repeat to check if a same port can be applied again */
|
||||
/* Repeat to check if a same port can be allocated again */
|
||||
TEST_ESP_OK(i2s_new_channel(&chan_cfg, NULL, &rx_handle));
|
||||
TEST_ESP_OK(i2s_del_channel(rx_handle));
|
||||
|
||||
@ -235,15 +243,20 @@ TEST_CASE("I2S basic driver apply, delete test", "[i2s]")
|
||||
|
||||
TEST_CASE("I2S memory leak test", "[i2s]")
|
||||
{
|
||||
i2s_gpio_config_t i2s_pin = I2S_TEST_MASTER_DEFAULT_PIN;
|
||||
|
||||
i2s_chan_handle_t tx_handle;
|
||||
i2s_chan_handle_t rx_handle;
|
||||
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_CONFIG(I2S_ROLE_MASTER, I2S_COMM_MODE_STD, &i2s_pin);
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
|
||||
i2s_std_config_t std_cfg = {
|
||||
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE),
|
||||
.slot_cfg = I2S_STD_PHILIP_SLOT_DEFAULT_CONFIG(SAMPLE_BITS, I2S_SLOT_MODE_STEREO),
|
||||
.gpio_cfg = I2S_TEST_MASTER_DEFAULT_PIN,
|
||||
};
|
||||
|
||||
/* The first operation will always take some memory */
|
||||
TEST_ESP_OK(i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle));
|
||||
TEST_ESP_OK(i2s_init_std_channel(tx_handle, &std_cfg));
|
||||
TEST_ESP_OK(i2s_init_std_channel(rx_handle, &std_cfg));
|
||||
TEST_ESP_OK(i2s_del_channel(tx_handle));
|
||||
TEST_ESP_OK(i2s_del_channel(rx_handle));
|
||||
|
||||
@ -251,6 +264,8 @@ TEST_CASE("I2S memory leak test", "[i2s]")
|
||||
printf("\r\nHeap size before: %d\n", memory_left);
|
||||
for (int i = 0; i < 100; i++) {
|
||||
TEST_ESP_OK(i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle));
|
||||
TEST_ESP_OK(i2s_init_std_channel(tx_handle, &std_cfg));
|
||||
TEST_ESP_OK(i2s_init_std_channel(rx_handle, &std_cfg));
|
||||
TEST_ESP_OK(i2s_del_channel(tx_handle));
|
||||
TEST_ESP_OK(i2s_del_channel(rx_handle));
|
||||
TEST_ASSERT(memory_left == esp_get_free_heap_size());
|
||||
@ -260,18 +275,18 @@ TEST_CASE("I2S memory leak test", "[i2s]")
|
||||
|
||||
TEST_CASE("I2S loopback test", "[i2s]")
|
||||
{
|
||||
i2s_gpio_config_t i2s_pin = I2S_TEST_MASTER_DEFAULT_PIN;
|
||||
|
||||
i2s_chan_handle_t tx_handle;
|
||||
i2s_chan_handle_t rx_handle;
|
||||
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_CONFIG(I2S_ROLE_MASTER, I2S_COMM_MODE_STD, &i2s_pin);
|
||||
i2s_std_slot_config_t slot_cfg = I2S_STD_PHILIP_SLOT_CONFIG(SAMPLE_BITS, I2S_SLOT_MODE_STEREO);
|
||||
i2s_std_clk_config_t clk_cfg = I2S_STD_CLK_CONFIG(SAMPLE_RATE);
|
||||
chan_cfg.id = I2S_NUM_0;
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
|
||||
i2s_std_config_t std_cfg = {
|
||||
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE),
|
||||
.slot_cfg = I2S_STD_PHILIP_SLOT_DEFAULT_CONFIG(SAMPLE_BITS, I2S_SLOT_MODE_STEREO),
|
||||
.gpio_cfg = I2S_TEST_MASTER_DEFAULT_PIN,
|
||||
};
|
||||
TEST_ESP_OK(i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle));
|
||||
TEST_ESP_OK(i2s_init_channel(tx_handle, &clk_cfg, &slot_cfg));
|
||||
TEST_ESP_OK(i2s_init_channel(rx_handle, &clk_cfg, &slot_cfg));
|
||||
TEST_ESP_OK(i2s_init_std_channel(tx_handle, &std_cfg));
|
||||
TEST_ESP_OK(i2s_init_std_channel(rx_handle, &std_cfg));
|
||||
i2s_test_io_config(I2S_TEST_MODE_LOOPBACK);
|
||||
|
||||
TEST_ESP_OK(i2s_start_channel(tx_handle));
|
||||
@ -286,23 +301,28 @@ TEST_CASE("I2S loopback test", "[i2s]")
|
||||
#if SOC_I2S_NUM > 1
|
||||
TEST_CASE("I2S master write slave read test", "[i2s]")
|
||||
{
|
||||
i2s_gpio_config_t mst_pin = I2S_TEST_MASTER_DEFAULT_PIN;
|
||||
i2s_gpio_config_t slv_pin = I2S_TEST_SLAVE_DEFAULT_PIN;
|
||||
|
||||
i2s_chan_handle_t tx_handle;
|
||||
i2s_chan_handle_t rx_handle;
|
||||
|
||||
i2s_chan_config_t mst_chan_cfg = I2S_CHANNEL_CONFIG(I2S_ROLE_MASTER, I2S_COMM_MODE_STD, &mst_pin);
|
||||
mst_chan_cfg.id = I2S_NUM_0;
|
||||
i2s_chan_config_t slv_chan_cfg = I2S_CHANNEL_CONFIG(I2S_ROLE_SLAVE, I2S_COMM_MODE_STD, &slv_pin);
|
||||
slv_chan_cfg.id = I2S_NUM_1;
|
||||
i2s_std_slot_config_t slot_cfg = I2S_STD_PHILIP_SLOT_CONFIG(SAMPLE_BITS, I2S_SLOT_MODE_STEREO);
|
||||
i2s_std_clk_config_t clk_cfg = I2S_STD_CLK_CONFIG(SAMPLE_RATE);
|
||||
i2s_chan_config_t mst_chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
|
||||
i2s_chan_config_t slv_chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_1, I2S_ROLE_SLAVE);
|
||||
|
||||
i2s_std_config_t std_mst_cfg = {
|
||||
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE),
|
||||
.slot_cfg = I2S_STD_PHILIP_SLOT_DEFAULT_CONFIG(SAMPLE_BITS, I2S_SLOT_MODE_STEREO),
|
||||
.gpio_cfg = I2S_TEST_MASTER_DEFAULT_PIN,
|
||||
};
|
||||
|
||||
i2s_std_config_t std_slv_cfg = {
|
||||
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE),
|
||||
.slot_cfg = I2S_STD_PHILIP_SLOT_DEFAULT_CONFIG(SAMPLE_BITS, I2S_SLOT_MODE_STEREO),
|
||||
.gpio_cfg = I2S_TEST_SLAVE_DEFAULT_PIN,
|
||||
};
|
||||
|
||||
TEST_ESP_OK(i2s_new_channel(&mst_chan_cfg, &tx_handle, NULL));
|
||||
TEST_ESP_OK(i2s_new_channel(&slv_chan_cfg, NULL, &rx_handle));
|
||||
TEST_ESP_OK(i2s_init_channel(tx_handle, &clk_cfg, &slot_cfg));
|
||||
TEST_ESP_OK(i2s_init_channel(rx_handle, &clk_cfg, &slot_cfg));
|
||||
TEST_ESP_OK(i2s_init_std_channel(tx_handle, &std_mst_cfg));
|
||||
TEST_ESP_OK(i2s_init_std_channel(rx_handle, &std_slv_cfg));
|
||||
i2s_test_io_config(I2S_TEST_MODE_MASTER_TO_SLAVE);
|
||||
|
||||
TEST_ESP_OK(i2s_start_channel(tx_handle));
|
||||
@ -316,23 +336,27 @@ TEST_CASE("I2S master write slave read test", "[i2s]")
|
||||
|
||||
TEST_CASE("I2S master read slave write test", "[i2s]")
|
||||
{
|
||||
i2s_gpio_config_t mst_pin = I2S_TEST_MASTER_DEFAULT_PIN;
|
||||
i2s_gpio_config_t slv_pin = I2S_TEST_SLAVE_DEFAULT_PIN;
|
||||
|
||||
i2s_chan_handle_t tx_handle;
|
||||
i2s_chan_handle_t rx_handle;
|
||||
|
||||
i2s_chan_config_t mst_chan_cfg = I2S_CHANNEL_CONFIG(I2S_ROLE_MASTER, I2S_COMM_MODE_STD, &mst_pin);
|
||||
mst_chan_cfg.id = I2S_NUM_0;
|
||||
i2s_chan_config_t slv_chan_cfg = I2S_CHANNEL_CONFIG(I2S_ROLE_SLAVE, I2S_COMM_MODE_STD, &slv_pin);
|
||||
slv_chan_cfg.id = I2S_NUM_1;
|
||||
i2s_std_slot_config_t slot_cfg = I2S_STD_PHILIP_SLOT_CONFIG(SAMPLE_BITS, I2S_SLOT_MODE_STEREO);
|
||||
i2s_std_clk_config_t clk_cfg = I2S_STD_CLK_CONFIG(SAMPLE_RATE);
|
||||
i2s_chan_config_t mst_chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
|
||||
i2s_chan_config_t slv_chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_1, I2S_ROLE_SLAVE);
|
||||
i2s_std_config_t std_mst_cfg = {
|
||||
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE),
|
||||
.slot_cfg = I2S_STD_PHILIP_SLOT_DEFAULT_CONFIG(SAMPLE_BITS, I2S_SLOT_MODE_STEREO),
|
||||
.gpio_cfg = I2S_TEST_MASTER_DEFAULT_PIN,
|
||||
};
|
||||
|
||||
i2s_std_config_t std_slv_cfg = {
|
||||
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE),
|
||||
.slot_cfg = I2S_STD_PHILIP_SLOT_DEFAULT_CONFIG(SAMPLE_BITS, I2S_SLOT_MODE_STEREO),
|
||||
.gpio_cfg = I2S_TEST_SLAVE_DEFAULT_PIN,
|
||||
};
|
||||
|
||||
TEST_ESP_OK(i2s_new_channel(&mst_chan_cfg, NULL, &rx_handle));
|
||||
TEST_ESP_OK(i2s_new_channel(&slv_chan_cfg, &tx_handle, NULL));
|
||||
TEST_ESP_OK(i2s_init_channel(tx_handle, &clk_cfg, &slot_cfg));
|
||||
TEST_ESP_OK(i2s_init_channel(rx_handle, &clk_cfg, &slot_cfg));
|
||||
TEST_ESP_OK(i2s_init_std_channel(tx_handle, &std_slv_cfg));
|
||||
TEST_ESP_OK(i2s_init_std_channel(rx_handle, &std_mst_cfg));
|
||||
i2s_test_io_config(I2S_TEST_MODE_SLAVE_TO_MASTER);
|
||||
|
||||
TEST_ESP_OK(i2s_start_channel(tx_handle));
|
||||
@ -348,26 +372,28 @@ TEST_CASE("I2S master read slave write test", "[i2s]")
|
||||
/*------------------------------ Clock Test --------------------------------*/
|
||||
#if SOC_PCNT_SUPPORTED
|
||||
#define TEST_I2S_PERIOD_MS 100
|
||||
static void i2s_test_common_sample_rate(i2s_chan_handle_t rx_chan, i2s_clk_config_t* clk_cfg)
|
||||
static void i2s_test_common_sample_rate(i2s_chan_handle_t rx_chan, i2s_std_clk_config_t* clk_cfg)
|
||||
{
|
||||
TEST_ASSERT_NOT_NULL(rx_chan);
|
||||
TEST_ASSERT_NOT_NULL(clk_cfg);
|
||||
|
||||
/* Prepare configuration for the PCNT unit */
|
||||
pcnt_config_t pcnt_cfg = {
|
||||
// Set PCNT input signal and control GPIOs
|
||||
.pulse_gpio_num = MASTER_WS_IO,
|
||||
.ctrl_gpio_num = -1,
|
||||
.channel = PCNT_CHANNEL_0,
|
||||
.unit = PCNT_UNIT_0,
|
||||
.pos_mode = PCNT_COUNT_INC, // Count up on the positive edge
|
||||
.neg_mode = PCNT_COUNT_DIS, // Keep the counter value on the negative edge
|
||||
.lctrl_mode = PCNT_MODE_KEEP,
|
||||
.hctrl_mode = PCNT_MODE_KEEP,
|
||||
.counter_h_lim = (int16_t)0x7fff,
|
||||
.counter_l_lim = (int16_t)0x8000,
|
||||
pcnt_unit_handle_t pcnt_unit = NULL;
|
||||
pcnt_channel_handle_t pcnt_chan = NULL;
|
||||
|
||||
pcnt_unit_config_t unit_config = {
|
||||
.high_limit = (int16_t)0x7fff,
|
||||
.low_limit = (int16_t)0x8000,
|
||||
};
|
||||
TEST_ESP_OK(pcnt_unit_config(&pcnt_cfg));
|
||||
pcnt_chan_config_t chan_config = {
|
||||
.edge_gpio_num = MASTER_WS_IO,
|
||||
.level_gpio_num = -1,
|
||||
};
|
||||
TEST_ESP_OK(pcnt_new_unit(&unit_config, &pcnt_unit));
|
||||
TEST_ESP_OK(pcnt_unit_set_glitch_filter(pcnt_unit, NULL));
|
||||
TEST_ESP_OK(pcnt_new_channel(pcnt_unit, &chan_config, &pcnt_chan));
|
||||
TEST_ESP_OK(pcnt_channel_set_edge_action(pcnt_chan, PCNT_CHANNEL_EDGE_ACTION_INCREASE, PCNT_CHANNEL_EDGE_ACTION_HOLD));
|
||||
TEST_ESP_OK(pcnt_channel_set_level_action(pcnt_chan, PCNT_CHANNEL_LEVEL_ACTION_KEEP, PCNT_CHANNEL_LEVEL_ACTION_KEEP));
|
||||
|
||||
// Reconfig GPIO signal
|
||||
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[MASTER_WS_IO], PIN_FUNC_GPIO);
|
||||
@ -375,26 +401,23 @@ static void i2s_test_common_sample_rate(i2s_chan_handle_t rx_chan, i2s_clk_confi
|
||||
esp_rom_gpio_connect_out_signal(MASTER_WS_IO, i2s_periph_signal[0].m_rx_ws_sig, 0, 0);
|
||||
esp_rom_gpio_connect_in_signal(MASTER_WS_IO, pcnt_periph_signals.groups[0].units[0].channels[0].pulse_sig, 0);
|
||||
|
||||
// pcnt_set_filter_value(PCNT_UNIT_0, 10);
|
||||
pcnt_filter_disable(PCNT_UNIT_0);
|
||||
|
||||
// Test common sample rate
|
||||
uint32_t test_freq[15] = {8000, 11025, 12000, 16000, 22050, 24000,
|
||||
32000, 44100, 48000, 64000, 88200, 96000,
|
||||
128000, 144000, 196000};
|
||||
int16_t real_pulse = 0;
|
||||
int real_pulse = 0;
|
||||
for (int i = 0; i < 15; i++) {
|
||||
int16_t expt_pulse = (int16_t)((float)test_freq[i] * (TEST_I2S_PERIOD_MS / 1000.0));
|
||||
clk_cfg->sample_rate = test_freq[i];
|
||||
TEST_ESP_OK(i2s_set_clock(rx_chan, clk_cfg));
|
||||
int expt_pulse = (int)((float)test_freq[i] * (TEST_I2S_PERIOD_MS / 1000.0));
|
||||
clk_cfg->sample_rate_hz = test_freq[i];
|
||||
TEST_ESP_OK(i2s_reconfig_std_clock(rx_chan, clk_cfg));
|
||||
TEST_ESP_OK(i2s_start_channel(rx_chan));
|
||||
vTaskDelay(1); // Waiting for hardware totally started
|
||||
// pcnt will count the pulse number on WS signal in 100ms
|
||||
TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
|
||||
TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
|
||||
TEST_ESP_OK(pcnt_unit_clear_count(pcnt_unit));
|
||||
TEST_ESP_OK(pcnt_unit_start(pcnt_unit));
|
||||
vTaskDelay(pdMS_TO_TICKS(TEST_I2S_PERIOD_MS));
|
||||
TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
|
||||
TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &real_pulse));
|
||||
TEST_ESP_OK(pcnt_unit_stop(pcnt_unit));
|
||||
TEST_ESP_OK(pcnt_unit_get_count(pcnt_unit, &real_pulse));
|
||||
printf("[%d Hz] %d pulses, expected %d, err %d\n", test_freq[i], real_pulse, expt_pulse, real_pulse - expt_pulse);
|
||||
TEST_ESP_OK(i2s_stop_channel(rx_chan));
|
||||
// Check if the error between real pulse number and expected pulse number is within 1%
|
||||
@ -404,39 +427,39 @@ static void i2s_test_common_sample_rate(i2s_chan_handle_t rx_chan, i2s_clk_confi
|
||||
|
||||
TEST_CASE("I2S D2CLK clock test", "[i2s]")
|
||||
{
|
||||
i2s_gpio_config_t i2s_pin = I2S_TEST_MASTER_DEFAULT_PIN;
|
||||
|
||||
i2s_chan_handle_t rx_handle;
|
||||
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_CONFIG(I2S_ROLE_MASTER, I2S_COMM_MODE_STD, &i2s_pin);
|
||||
i2s_std_slot_config_t slot_cfg = I2S_STD_PHILIP_SLOT_CONFIG(SAMPLE_BITS, I2S_SLOT_MODE_STEREO);
|
||||
i2s_std_clk_config_t clk_cfg = I2S_STD_CLK_CONFIG(SAMPLE_RATE);
|
||||
chan_cfg.id = I2S_NUM_0;
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
|
||||
i2s_std_config_t std_cfg = {
|
||||
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE),
|
||||
.slot_cfg = I2S_STD_PHILIP_SLOT_DEFAULT_CONFIG(SAMPLE_BITS, I2S_SLOT_MODE_STEREO),
|
||||
.gpio_cfg = I2S_TEST_MASTER_DEFAULT_PIN,
|
||||
};
|
||||
|
||||
TEST_ESP_OK(i2s_new_channel(&chan_cfg, NULL, &rx_handle));
|
||||
TEST_ESP_OK(i2s_init_channel(rx_handle, &clk_cfg, &slot_cfg));
|
||||
TEST_ESP_OK(i2s_init_std_channel(rx_handle, &std_cfg));
|
||||
|
||||
i2s_test_common_sample_rate(rx_handle, (i2s_clk_config_t *)&clk_cfg);
|
||||
i2s_test_common_sample_rate(rx_handle, &std_cfg.clk_cfg);
|
||||
TEST_ESP_OK(i2s_del_channel(rx_handle));
|
||||
}
|
||||
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
TEST_CASE("I2S APLL clock test", "[i2s]")
|
||||
{
|
||||
i2s_gpio_config_t i2s_pin = I2S_TEST_MASTER_DEFAULT_PIN;
|
||||
|
||||
i2s_chan_handle_t rx_handle;
|
||||
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_CONFIG(I2S_ROLE_MASTER, I2S_COMM_MODE_STD, &i2s_pin);
|
||||
i2s_std_slot_config_t slot_cfg = I2S_STD_PHILIP_SLOT_CONFIG(SAMPLE_BITS, I2S_SLOT_MODE_STEREO);
|
||||
i2s_std_clk_config_t clk_cfg = I2S_STD_CLK_CONFIG(SAMPLE_RATE);
|
||||
chan_cfg.id = I2S_NUM_0;
|
||||
clk_cfg.clk_src = I2S_CLK_APLL;
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
|
||||
i2s_std_config_t std_cfg = {
|
||||
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE),
|
||||
.slot_cfg = I2S_STD_PHILIP_SLOT_DEFAULT_CONFIG(SAMPLE_BITS, I2S_SLOT_MODE_STEREO),
|
||||
.gpio_cfg = I2S_TEST_MASTER_DEFAULT_PIN,
|
||||
};
|
||||
std_cfg.clk_cfg.clk_src = I2S_CLK_APLL;
|
||||
|
||||
TEST_ESP_OK(i2s_new_channel(&chan_cfg, NULL, &rx_handle));
|
||||
TEST_ESP_OK(i2s_init_channel(rx_handle, &clk_cfg, &slot_cfg));
|
||||
TEST_ESP_OK(i2s_init_std_channel(rx_handle, &std_cfg));
|
||||
|
||||
i2s_test_common_sample_rate(rx_handle, (i2s_clk_config_t *)&clk_cfg);
|
||||
i2s_test_common_sample_rate(rx_handle, &std_cfg.clk_cfg);
|
||||
TEST_ESP_OK(i2s_del_channel(rx_handle));
|
||||
}
|
||||
#endif // SOC_I2S_SUPPORTS_APLL
|
||||
@ -467,17 +490,19 @@ TEST_CASE("I2S package lost test", "[i2s]")
|
||||
* 2. dma_desc_num > polling_cycle / interrupt_interval = cell(2.818) = 3
|
||||
* 3. recv_buffer_size > dma_desc_num * dma_buffer_size = 3 * 4092 = 12276 bytes */
|
||||
#define TEST_RECV_BUF_LEN 12276
|
||||
i2s_gpio_config_t i2s_pin = I2S_TEST_MASTER_DEFAULT_PIN;
|
||||
i2s_chan_handle_t rx_handle;
|
||||
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_CONFIG(I2S_ROLE_MASTER, I2S_COMM_MODE_STD, &i2s_pin);
|
||||
i2s_std_slot_config_t slot_cfg = I2S_STD_PHILIP_SLOT_CONFIG(I2S_DATA_BIT_WIDTH_32BIT, I2S_SLOT_MODE_STEREO);
|
||||
slot_cfg.dma_desc_num = 3;
|
||||
slot_cfg.dma_frame_num = 511;
|
||||
i2s_std_clk_config_t clk_cfg = I2S_STD_CLK_CONFIG(SAMPLE_RATE);
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
|
||||
chan_cfg.dma_desc_num = 3;
|
||||
chan_cfg.dma_frame_num = 511;
|
||||
i2s_std_config_t std_cfg = {
|
||||
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(SAMPLE_RATE),
|
||||
.slot_cfg = I2S_STD_PHILIP_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_32BIT, I2S_SLOT_MODE_STEREO),
|
||||
.gpio_cfg = I2S_TEST_MASTER_DEFAULT_PIN,
|
||||
};
|
||||
|
||||
TEST_ESP_OK(i2s_new_channel(&chan_cfg, NULL, &rx_handle));
|
||||
TEST_ESP_OK(i2s_init_channel(rx_handle, &clk_cfg, &slot_cfg));
|
||||
TEST_ESP_OK(i2s_init_std_channel(rx_handle, &std_cfg));
|
||||
|
||||
TaskHandle_t h_monitor_task;
|
||||
xTaskCreate(i2s_event_monitor, "event monitor task", 4096, &rx_handle, 5, &h_monitor_task);
|
||||
@ -489,8 +514,9 @@ TEST_CASE("I2S package lost test", "[i2s]")
|
||||
int i;
|
||||
for (i = 0; i < test_num; i++) {
|
||||
printf("Testing %d Hz sample rate\n", test_freq[i]);
|
||||
clk_cfg.sample_rate = test_freq[i];
|
||||
TEST_ESP_OK(i2s_set_clock(rx_handle, &clk_cfg));
|
||||
std_cfg.clk_cfg.sample_rate_hz = test_freq[i];
|
||||
std_cfg.clk_cfg.sample_rate_hz = test_freq[i];
|
||||
TEST_ESP_OK(i2s_reconfig_std_clock(rx_handle, &std_cfg.clk_cfg));
|
||||
TEST_ESP_OK(i2s_start_channel(rx_handle));
|
||||
for (int j = 0; j < 10; j++) {
|
||||
TEST_ESP_OK(i2s_read_channel(rx_handle, (void *)data, TEST_RECV_BUF_LEN, &bytes_read, portMAX_DELAY));
|
@ -593,7 +593,7 @@ static esp_err_t i2s_lcd_select_periph_clock(esp_lcd_i80_bus_handle_t bus, lcd_c
|
||||
switch (src) {
|
||||
case LCD_CLK_SRC_PLL160M:
|
||||
bus->resolution_hz = 160000000 / LCD_PERIPH_CLOCK_PRE_SCALE;
|
||||
i2s_ll_tx_clk_set_src(bus->hal.dev, I2S_CLK_160M_PLL);
|
||||
i2s_ll_tx_clk_set_src(bus->hal.dev, I2S_CLK_PLL_160M);
|
||||
#if CONFIG_PM_ENABLE
|
||||
ret = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "i2s_controller_lcd", &bus->pm_lock);
|
||||
ESP_RETURN_ON_ERROR(ret, TAG, "create ESP_PM_APB_FREQ_MAX lock failed");
|
||||
|
@ -18,7 +18,7 @@
|
||||
#include "test_i80_board.h"
|
||||
|
||||
#if SOC_I2S_LCD_I80_VARIANT
|
||||
#include "driver/i2s_controller.h"
|
||||
#include "driver/i2s_std.h"
|
||||
|
||||
TEST_CASE("i80_and_i2s_driver_co-existence", "[lcd][i2s]")
|
||||
{
|
||||
@ -44,15 +44,7 @@ TEST_CASE("i80_and_i2s_driver_co-existence", "[lcd][i2s]")
|
||||
|
||||
|
||||
i2s_chan_handle_t tx_handle = NULL;
|
||||
i2s_gpio_config_t i2s_pin = {
|
||||
.mclk = I2S_GPIO_UNUSED,
|
||||
.bclk = I2S_GPIO_UNUSED,
|
||||
.ws = I2S_GPIO_UNUSED,
|
||||
.dout = I2S_GPIO_UNUSED,
|
||||
.din = I2S_GPIO_UNUSED
|
||||
};
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_CONFIG(I2S_ROLE_MASTER, I2S_COMM_MODE_STD, &i2s_pin);
|
||||
chan_cfg.id = 0;
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
|
||||
// I2S driver won't be installed as the same I2S port has been used by LCD
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, i2s_new_channel(&chan_cfg, &tx_handle, NULL));
|
||||
TEST_ESP_OK(esp_lcd_del_i80_bus(i80_bus));
|
||||
@ -463,7 +455,7 @@ TEST_CASE("lcd_panel_with_i80_interface_(st7789, 8bits)", "[lcd]")
|
||||
}
|
||||
|
||||
#if SOC_I2S_LCD_I80_VARIANT
|
||||
#include "driver/i2s_controller.h"
|
||||
#include "driver/i2s_std.h"
|
||||
|
||||
TEST_CASE("i80 and i2s driver coexistance", "[lcd][i2s]")
|
||||
{
|
||||
@ -486,15 +478,7 @@ TEST_CASE("i80 and i2s driver coexistance", "[lcd][i2s]")
|
||||
};
|
||||
TEST_ESP_OK(esp_lcd_new_i80_bus(&bus_config, &i80_bus));
|
||||
|
||||
i2s_gpio_config_t i2s_pin = {
|
||||
.mclk = 0,
|
||||
.bclk = 15,
|
||||
.ws = 25,
|
||||
.dout = 21,
|
||||
.din = 22
|
||||
};
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_CONFIG(I2S_ROLE_MASTER, I2S_COMM_MODE_STD, &i2s_pin);
|
||||
chan_cfg.id = I2S_NUM_0;
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
|
||||
i2s_chan_handle_t tx_handle;
|
||||
// I2S driver won't be installed as the same I2S port has been used by LCD
|
||||
TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, i2s_new_channel(&chan_cfg, &tx_handle, NULL));
|
||||
|
@ -189,7 +189,7 @@ static void adc_hal_digi_sample_freq_config(adc_hal_dma_ctx_t *hal, uint32_t fre
|
||||
adc_ll_digi_controller_clk_div(ADC_LL_CLKM_DIV_NUM_DEFAULT, ADC_LL_CLKM_DIV_B_DEFAULT, ADC_LL_CLKM_DIV_A_DEFAULT);
|
||||
adc_ll_digi_clk_sel(0); //use APB
|
||||
#else
|
||||
i2s_ll_rx_clk_set_src(hal->dev, I2S_CLK_160M_PLL); /*!< Clock from PLL_D2_CLK(160M)*/
|
||||
i2s_ll_rx_clk_set_src(hal->dev, I2S_CLK_PLL_160M); /*!< Clock from PLL_D2_CLK(160M)*/
|
||||
uint32_t bck = I2S_BASE_CLK / (ADC_LL_CLKM_DIV_NUM_DEFAULT + ADC_LL_CLKM_DIV_B_DEFAULT / ADC_LL_CLKM_DIV_A_DEFAULT) / 2 / freq;
|
||||
i2s_ll_set_raw_mclk_div(hal->dev, ADC_LL_CLKM_DIV_NUM_DEFAULT, ADC_LL_CLKM_DIV_A_DEFAULT, ADC_LL_CLKM_DIV_B_DEFAULT);
|
||||
i2s_ll_rx_set_bck_div_num(hal->dev, bck);
|
||||
|
@ -200,7 +200,7 @@ static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
|
||||
* @brief Set RX source clock
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param src I2S source clock, ESP32-C3 only support `I2S_CLK_160M_PLL`
|
||||
* @param src I2S source clock, ESP32-C3 only support `I2S_CLK_PLL_160M`
|
||||
*/
|
||||
static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
|
||||
{
|
||||
|
@ -201,7 +201,7 @@ static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
|
||||
* @brief Set RX source clock
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param src I2S source clock, ESP32-H2 only support `I2S_CLK_160M_PLL`
|
||||
* @param src I2S source clock, ESP32-H2 only support `I2S_CLK_PLL_160M`
|
||||
*/
|
||||
static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
|
||||
{
|
||||
|
@ -190,7 +190,7 @@ static inline void i2s_ll_rx_reset_fifo(i2s_dev_t *hw)
|
||||
* @brief Set TX source clock
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param src I2S source clock, ESP32-S3 only support `I2S_CLK_160M_PLL`
|
||||
* @param src I2S source clock, ESP32-S3 only support `I2S_CLK_PLL_160M`
|
||||
* TX and RX share the same clock setting
|
||||
*/
|
||||
static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
|
||||
@ -202,7 +202,7 @@ static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
|
||||
* @brief Set RX source clock
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param src I2S source clock, ESP32-S3 only support `I2S_CLK_160M_PLL`
|
||||
* @param src I2S source clock, ESP32-S3 only support `I2S_CLK_PLL_160M`
|
||||
* TX and RX share the same clock setting
|
||||
*/
|
||||
static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
|
||||
|
@ -206,7 +206,7 @@ void i2s_hal_tdm_set_tx_slot(i2s_hal_context_t *hal, bool is_slave, const i2s_ha
|
||||
i2s_ll_tx_set_sample_bit(hal->dev, slot_bit_width, slot_cfg->data_bit_width);
|
||||
i2s_ll_tx_enable_mono_mode(hal->dev, slot_cfg->slot_mode == I2S_SLOT_MODE_MONO);
|
||||
i2s_ll_tx_enable_msb_shift(hal->dev, slot_cfg->tdm.bit_shift);
|
||||
if (slot_cfg->tdm.ws_width == I2S_TDM_AUTO_WS_WIDTH) {
|
||||
if (slot_cfg->tdm.ws_width == 0) { // 0: I2S_TDM_AUTO_WS_WIDTH
|
||||
i2s_ll_tx_set_ws_width(hal->dev, (total_slot * slot_bit_width) / 2);
|
||||
} else {
|
||||
i2s_ll_tx_set_ws_width(hal->dev, slot_cfg->tdm.ws_width);
|
||||
@ -241,7 +241,7 @@ void i2s_hal_tdm_set_rx_slot(i2s_hal_context_t *hal, bool is_slave, const i2s_ha
|
||||
i2s_ll_rx_set_sample_bit(hal->dev, slot_bit_width, slot_cfg->data_bit_width);
|
||||
i2s_ll_rx_enable_mono_mode(hal->dev, slot_cfg->slot_mode == I2S_SLOT_MODE_MONO);
|
||||
i2s_ll_rx_enable_msb_shift(hal->dev, slot_cfg->tdm.bit_shift);
|
||||
if (slot_cfg->tdm.ws_width == I2S_TDM_AUTO_WS_WIDTH) {
|
||||
if (slot_cfg->tdm.ws_width == 0) { // 0: I2S_TDM_AUTO_WS_WIDTH
|
||||
i2s_ll_rx_set_ws_width(hal->dev, (total_slot * slot_bit_width) / 2);
|
||||
} else {
|
||||
i2s_ll_rx_set_ws_width(hal->dev, slot_cfg->tdm.ws_width);
|
||||
|
@ -28,7 +28,6 @@ extern "C" {
|
||||
* @note It is a general purpose struct, not supposed to be used directly by user
|
||||
*/
|
||||
typedef struct {
|
||||
i2s_comm_mode_t mode; /*!< I2S communication mode, this field is for identification (MUST match the communication mode that applied) */
|
||||
i2s_data_bit_width_t data_bit_width; /*!< I2S sample data bit width (valid data bits per sample) */
|
||||
i2s_slot_bit_width_t slot_bit_width; /*!< I2S slot bit width (total bits per slot) */
|
||||
i2s_slot_mode_t slot_mode; /*!< Set mono or stereo mode with I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO */
|
||||
|
@ -108,7 +108,7 @@ typedef enum {
|
||||
} i2s_mclk_multiple_t;
|
||||
|
||||
typedef enum {
|
||||
I2S_CLK_160M_PLL = 0, /*!< I2S controller clock source PLL_D2_CLK(160M)*/
|
||||
I2S_CLK_PLL_160M = 0, /*!< I2S controller clock source PLL_D2_CLK(160M)*/
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
I2S_CLK_APLL, /*!< I2S controller clock source APLL*/
|
||||
#endif
|
||||
|
@ -158,11 +158,12 @@ INPUT = \
|
||||
$(PROJECT_PATH)/components/hal/include/hal/i2c_types.h \
|
||||
$(PROJECT_PATH)/components/hal/include/hal/i2s_types.h \
|
||||
$(PROJECT_PATH)/components/hal/include/hal/lcd_types.h \
|
||||
$(PROJECT_PATH)/components/driver/include/driver/i2s_controller.h \
|
||||
$(PROJECT_PATH)/components/hal/include/hal/i2s_std.h \
|
||||
$(PROJECT_PATH)/components/hal/include/hal/i2s_pdm.h \
|
||||
$(PROJECT_PATH)/components/hal/include/hal/i2s_tdm.h \
|
||||
$(PROJECT_PATH)/components/driver/include/driver/i2s_common.h \
|
||||
$(PROJECT_PATH)/components/driver/include/driver/i2s_std.h \
|
||||
$(PROJECT_PATH)/components/driver/include/driver/i2s_pdm.h \
|
||||
$(PROJECT_PATH)/components/driver/include/driver/i2s_tdm.h \
|
||||
$(PROJECT_PATH)/components/hal/include/hal/ledc_types.h \
|
||||
$(PROJECT_PATH)/components/hal/include/hal/rmt_types.h \
|
||||
$(PROJECT_PATH)/components/hal/include/hal/rtc_io_types.h \
|
||||
$(PROJECT_PATH)/components/hal/include/hal/sdio_slave_types.h \
|
||||
$(PROJECT_PATH)/components/hal/include/hal/sigmadelta_types.h \
|
||||
|
@ -147,11 +147,11 @@ I2S Clock
|
||||
Clock Source
|
||||
^^^^^^^^^^^^
|
||||
|
||||
- :cpp:member:`i2s_clock_src_t::I2S_CLK_160M_PLL`: 160 MHz PLL clock.
|
||||
- :cpp:member:`i2s_clock_src_t::I2S_CLK_PLL_160M`: 160 MHz PLL clock.
|
||||
|
||||
.. only:: SOC_I2S_SUPPORTS_APLL
|
||||
|
||||
- :cpp:member:`i2s_clock_src_t::I2S_CLK_APLL`: Audio PLL clock, more precise than ``I2S_CLK_160M_PLL`` in high sample rate applications. Its frequency is configurable according to the sample rate, but if APLL has been occupied by emac or other channels already, the APLL frequency is not allowed to change, the driver will try to work under this APLL frequency, if this APLL frequency can't meet the requirements of I2S, the clock configuration will fail.
|
||||
- :cpp:member:`i2s_clock_src_t::I2S_CLK_APLL`: Audio PLL clock, more precise than ``I2S_CLK_PLL_160M`` in high sample rate applications. Its frequency is configurable according to the sample rate, but if APLL has been occupied by emac or other channels already, the APLL frequency is not allowed to change, the driver will try to work under this APLL frequency, if this APLL frequency can't meet the requirements of I2S, the clock configuration will fail.
|
||||
|
||||
Clock Concepts
|
||||
^^^^^^^^^^^^^^
|
||||
|
@ -24,7 +24,7 @@
|
||||
// DAC DMA mode is only supported by the legacy I2S driver, it will be replaced once DAC has its own DMA dirver
|
||||
#include "driver/i2s.h"
|
||||
#else
|
||||
#include "driver/i2s_controller.h"
|
||||
#include "driver/i2s_std.h"
|
||||
#endif
|
||||
|
||||
#include "sys/lock.h"
|
||||
@ -187,21 +187,22 @@ void bt_i2s_driver_install(void)
|
||||
i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN);
|
||||
i2s_set_pin(0, NULL);
|
||||
#else
|
||||
i2s_gpio_config_t i2s_pin = {
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
|
||||
chan_cfg.auto_clear = true;
|
||||
i2s_std_config_t std_cfg = {
|
||||
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(44100),
|
||||
.slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO),
|
||||
.gpio_cfg = {
|
||||
.mclk = I2S_GPIO_UNUSED,
|
||||
.bclk = CONFIG_EXAMPLE_I2S_BCK_PIN,
|
||||
.ws = CONFIG_EXAMPLE_I2S_LRCK_PIN,
|
||||
.dout = CONFIG_EXAMPLE_I2S_DATA_PIN,
|
||||
.din = I2S_GPIO_UNUSED
|
||||
.din = I2S_GPIO_UNUSED,
|
||||
},
|
||||
};
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_CONFIG(I2S_ROLE_MASTER, I2S_COMM_MODE_STD, &i2s_pin);
|
||||
chan_cfg.id = I2S_NUM_0;
|
||||
i2s_std_slot_config_t slot_cfg = I2S_STD_MSB_SLOT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO);
|
||||
slot_cfg.auto_clear = true;
|
||||
i2s_std_clk_config_t clk_cfg = I2S_STD_CLK_CONFIG(44100);
|
||||
/* enable I2S */
|
||||
i2s_new_channel(&chan_cfg, &tx_chan, NULL);
|
||||
i2s_init_channel(tx_chan, &clk_cfg, &slot_cfg);
|
||||
i2s_init_std_channel(tx_chan, &std_cfg);
|
||||
i2s_start_channel(tx_chan);
|
||||
#endif
|
||||
}
|
||||
@ -306,8 +307,8 @@ static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param)
|
||||
#ifdef CONFIG_EXAMPLE_A2DP_SINK_OUTPUT_INTERNAL_DAC
|
||||
i2s_set_clk(0, sample_rate, 16, 2);
|
||||
#else
|
||||
i2s_std_clk_config_t clk_cfg = I2S_STD_CLK_CONFIG(sample_rate);
|
||||
i2s_set_clock(tx_chan, &clk_cfg);
|
||||
i2s_std_clk_config_t clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(sample_rate);
|
||||
i2s_reconfig_std_clock(tx_chan, &clk_cfg);
|
||||
#endif
|
||||
ESP_LOGI(BT_AV_TAG, "Configure audio player: %x-%x-%x-%x",
|
||||
a2d->audio_cfg.mcc.cie.sbc[0],
|
||||
|
@ -18,7 +18,7 @@
|
||||
// DAC DMA mode is only supported by the legacy I2S driver, it will be replaced once DAC has its own DMA dirver
|
||||
#include "driver/i2s.h"
|
||||
#else
|
||||
#include "driver/i2s_controller.h"
|
||||
#include "driver/i2s_std.h"
|
||||
#endif
|
||||
#include "freertos/ringbuf.h"
|
||||
|
||||
|
@ -87,30 +87,44 @@ For example, after executing `esp_bt_gap_start_discovery()`, an event of `ESP_BT
|
||||
The main function installs I2S to play the audio. A loudspeaker, additional ADC or hardware requirements and possibly an external I2S codec may be needed.
|
||||
|
||||
```c
|
||||
/* I2S configuration parameters */
|
||||
#ifdef CONFIG_EXAMPLE_A2DP_SINK_OUTPUT_INTERNAL_DAC
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_CONFIG(I2S_ROLE_MASTER, I2S_COMM_MODE_ADC_DAC, NULL);
|
||||
chan_cfg.id = I2S_NUM_0;
|
||||
i2s_dac_slot_config_t slot_cfg = I2S_DAC_SLOT_CONFIG(I2S_DAC_CHAN_BOTH);
|
||||
i2s_adc_dac_clk_config_t clk_cfg = I2S_ADC_DAC_CLK_CONFIG(44100);
|
||||
/* I2S configuration parameters */
|
||||
i2s_config_t i2s_config = {
|
||||
.mode = I2S_MODE_MASTER | I2S_MODE_TX | I2S_MODE_DAC_BUILT_IN,
|
||||
.sample_rate = 44100,
|
||||
.bits_per_sample = 16,
|
||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, /* 2-channels */
|
||||
.communication_format = I2S_COMM_FORMAT_STAND_MSB,
|
||||
.dma_buf_count = 6,
|
||||
.dma_buf_len = 60,
|
||||
.intr_alloc_flags = 0, /* default interrupt priority */
|
||||
.tx_desc_auto_clear = true /* auto clear tx descriptor on underflow */
|
||||
};
|
||||
|
||||
/* enable I2S */
|
||||
i2s_driver_install(0, &i2s_config, 0, NULL);
|
||||
i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN);
|
||||
i2s_set_pin(0, NULL);
|
||||
#else
|
||||
i2s_gpio_config_t i2s_pin = {
|
||||
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
|
||||
chan_cfg.auto_clear = true;
|
||||
i2s_std_config_t std_cfg = {
|
||||
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(44100),
|
||||
.slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO),
|
||||
.gpio_cfg = {
|
||||
.mclk = I2S_GPIO_UNUSED,
|
||||
.bclk = CONFIG_EXAMPLE_I2S_BCK_PIN,
|
||||
.ws = CONFIG_EXAMPLE_I2S_LRCK_PIN,
|
||||
.dout = CONFIG_EXAMPLE_I2S_DATA_PIN,
|
||||
.din = I2S_GPIO_UNUSED
|
||||
.din = I2S_GPIO_UNUSED,
|
||||
},
|
||||
};
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_CONFIG(I2S_ROLE_MASTER, I2S_COMM_MODE_STD, &i2s_pin);
|
||||
chan_cfg.id = I2S_NUM_0;
|
||||
i2s_std_slot_config_t slot_cfg = I2S_STD_MSB_SLOT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO);
|
||||
slot_cfg.auto_clear = true;
|
||||
i2s_std_clk_config_t clk_cfg = I2S_STD_CLK_CONFIG(44100);
|
||||
#endif
|
||||
/* enable I2S */
|
||||
i2s_new_channel(&chan_cfg, &tx_chan, NULL);
|
||||
i2s_init_channel(tx_chan, &clk_cfg, &slot_cfg);
|
||||
i2s_init_std_channel(tx_chan, &std_cfg);
|
||||
i2s_start_channel(tx_chan);
|
||||
#endif
|
||||
```
|
||||
|
||||
### Paring Parameter Settings
|
||||
|
@ -25,7 +25,7 @@
|
||||
// DAC DMA mode is only supported by the legacy I2S driver, it will be replaced once DAC has its own DMA dirver
|
||||
#include "driver/i2s.h"
|
||||
#else
|
||||
#include "driver/i2s_controller.h"
|
||||
#include "driver/i2s_std.h"
|
||||
#endif
|
||||
|
||||
#include "sys/lock.h"
|
||||
@ -173,8 +173,8 @@ static void bt_av_hdl_a2d_evt(uint16_t event, void *p_param)
|
||||
#ifdef CONFIG_EXAMPLE_A2DP_SINK_OUTPUT_INTERNAL_DAC
|
||||
i2s_set_clk(0, sample_rate, 16, 2);
|
||||
#else
|
||||
i2s_std_clk_config_t clk_cfg = I2S_STD_CLK_CONFIG(sample_rate);
|
||||
i2s_set_clock(tx_chan, &clk_cfg);
|
||||
i2s_std_clk_config_t clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(sample_rate);
|
||||
i2s_reconfig_clock(tx_chan, &clk_cfg);
|
||||
#endif
|
||||
|
||||
ESP_LOGI(BT_AV_TAG, "Configure audio player %x-%x-%x-%x",
|
||||
|
@ -19,7 +19,7 @@
|
||||
// DAC DMA mode is only supported by the legacy I2S driver, it will be replaced once DAC has its own DMA dirver
|
||||
#include "driver/i2s.h"
|
||||
#else
|
||||
#include "driver/i2s_controller.h"
|
||||
#include "driver/i2s_std.h"
|
||||
#endif
|
||||
|
||||
static void bt_app_task_handler(void *arg);
|
||||
|
@ -39,7 +39,7 @@
|
||||
// DAC DMA mode is only supported by the legacy I2S driver, it will be replaced once DAC has its own DMA dirver
|
||||
#include "driver/i2s.h"
|
||||
#else
|
||||
#include "driver/i2s_controller.h"
|
||||
#include "driver/i2s_std.h"
|
||||
#endif
|
||||
|
||||
#include "esp_gap_ble_api.h"
|
||||
@ -709,21 +709,22 @@ void app_main(void)
|
||||
i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN);
|
||||
i2s_set_pin(0, NULL);
|
||||
#else
|
||||
i2s_gpio_config_t i2s_pin = {
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
|
||||
chan_cfg.auto_clear = true;
|
||||
i2s_std_config_t std_cfg = {
|
||||
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(44100),
|
||||
.slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO),
|
||||
.gpio_cfg = {
|
||||
.mclk = I2S_GPIO_UNUSED,
|
||||
.bclk = CONFIG_EXAMPLE_I2S_BCK_PIN,
|
||||
.ws = CONFIG_EXAMPLE_I2S_LRCK_PIN,
|
||||
.dout = CONFIG_EXAMPLE_I2S_DATA_PIN,
|
||||
.din = I2S_GPIO_UNUSED
|
||||
.din = I2S_GPIO_UNUSED,
|
||||
},
|
||||
};
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_CONFIG(I2S_ROLE_MASTER, I2S_COMM_MODE_STD, &i2s_pin);
|
||||
chan_cfg.id = I2S_NUM_0;
|
||||
i2s_std_slot_config_t slot_cfg = I2S_STD_MSB_SLOT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO);
|
||||
slot_cfg.auto_clear = true;
|
||||
i2s_std_clk_config_t clk_cfg = I2S_STD_CLK_CONFIG(44100);
|
||||
/* enable I2S */
|
||||
i2s_new_channel(&chan_cfg, &tx_chan, NULL);
|
||||
i2s_init_channel(tx_chan, &clk_cfg, &slot_cfg);
|
||||
i2s_init_std_channel(tx_chan, &std_cfg);
|
||||
i2s_start_channel(tx_chan);
|
||||
#endif
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include "esp_vfs_fat.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/i2s_controller.h"
|
||||
#include "driver/i2s_pdm.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/spi_common.h"
|
||||
#include "sdmmc_cmd.h"
|
||||
@ -170,19 +170,18 @@ void record_wav(uint32_t rec_time)
|
||||
|
||||
void init_microphone(void)
|
||||
{
|
||||
i2s_gpio_config_t i2s_pin = {
|
||||
.mclk = I2S_GPIO_UNUSED,
|
||||
.bclk = I2S_GPIO_UNUSED,
|
||||
.ws = CONFIG_EXAMPLE_I2S_CLK_GPIO,
|
||||
.dout = I2S_GPIO_UNUSED,
|
||||
.din = CONFIG_EXAMPLE_I2S_DATA_GPIO
|
||||
};
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_CONFIG(I2S_ROLE_MASTER, I2S_COMM_MODE_PDM, &i2s_pin);
|
||||
chan_cfg.id = CONFIG_EXAMPLE_I2S_CH;
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(CONFIG_EXAMPLE_I2S_CH, I2S_ROLE_MASTER);
|
||||
i2s_new_channel(&chan_cfg, NULL, &rx_handle);
|
||||
i2s_pdm_rx_slot_config_t rx_slot_cfg = I2S_PDM_RX_SLOT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO);
|
||||
i2s_pdm_rx_clk_config_t rx_clk_cfg = I2S_PDM_RX_CLK_CONFIG(CONFIG_EXAMPLE_SAMPLE_RATE);
|
||||
i2s_init_channel(rx_handle, &rx_clk_cfg, &rx_slot_cfg);
|
||||
|
||||
i2s_pdm_rx_config_t pdm_rx_cfg = {
|
||||
.clk_cfg = I2S_PDM_RX_CLK_DEFAULT_CONFIG(CONFIG_EXAMPLE_SAMPLE_RATE),
|
||||
.slot_cfg = I2S_PDM_RX_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO),
|
||||
.gpio_cfg = {
|
||||
.clk = CONFIG_EXAMPLE_I2S_CLK_GPIO,
|
||||
.din = CONFIG_EXAMPLE_I2S_DATA_GPIO,
|
||||
},
|
||||
};
|
||||
i2s_init_pdm_rx_channel(rx_handle, &pdm_rx_cfg);
|
||||
i2s_start_channel(rx_handle);
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include <stdio.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/i2s_controller.h"
|
||||
#include "driver/i2s.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
@ -29,7 +29,6 @@
|
||||
#define SAMPLE_PER_CYCLE (SAMPLE_RATE/WAVE_FREQ_HZ)
|
||||
|
||||
static const char* TAG = "i2s_example";
|
||||
static i2s_chan_handle_t tx_handle = NULL;
|
||||
|
||||
static void setup_triangle_sine_waves(int bits)
|
||||
{
|
||||
@ -37,8 +36,6 @@ static void setup_triangle_sine_waves(int bits)
|
||||
unsigned int i, sample_val;
|
||||
double sin_float, triangle_float, triangle_step = (double) pow(2, bits) / SAMPLE_PER_CYCLE;
|
||||
size_t i2s_bytes_write = 0;
|
||||
static i2s_std_slot_config_t slot_cfg = I2S_STD_PHILIP_SLOT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO);
|
||||
static i2s_std_clk_config_t clk_cfg = I2S_STD_CLK_CONFIG(SAMPLE_RATE);
|
||||
|
||||
printf("\r\nTest bits=%d free mem=%d, written data=%d\n", bits, esp_get_free_heap_size(), ((bits+8)/16)*SAMPLE_PER_CYCLE*4);
|
||||
|
||||
@ -46,11 +43,10 @@ static void setup_triangle_sine_waves(int bits)
|
||||
|
||||
for(i = 0; i < SAMPLE_PER_CYCLE; i++) {
|
||||
sin_float = sin(i * 2 * PI / SAMPLE_PER_CYCLE);
|
||||
if (sin_float >= 0) {
|
||||
if(sin_float >= 0)
|
||||
triangle_float += triangle_step;
|
||||
} else {
|
||||
else
|
||||
triangle_float -= triangle_step;
|
||||
}
|
||||
|
||||
sin_float *= (pow(2, bits)/2 - 1);
|
||||
|
||||
@ -69,26 +65,18 @@ static void setup_triangle_sine_waves(int bits)
|
||||
}
|
||||
|
||||
}
|
||||
ESP_LOGI(TAG, "set data bit width to %d", bits);
|
||||
/* Updata clock and slot information */
|
||||
slot_cfg.data_bit_width = bits;
|
||||
i2s_stop_channel(tx_handle);
|
||||
i2s_set_slot(tx_handle, &slot_cfg);
|
||||
if (bits == 24) {
|
||||
/**
|
||||
* Because '24' has factor '3'
|
||||
* The mclk multiple must be able to divide by '3' as well
|
||||
* Otherwise the sample rate won't be accurate */
|
||||
clk_cfg.mclk_multiple = I2S_MCLK_MULTIPLE_384;
|
||||
i2s_set_clock(tx_handle, &clk_cfg);
|
||||
} else {
|
||||
clk_cfg.mclk_multiple = I2S_MCLK_MULTIPLE_256;
|
||||
i2s_set_clock(tx_handle, &clk_cfg);
|
||||
}
|
||||
i2s_start_channel(tx_handle);
|
||||
|
||||
ESP_LOGI(TAG, "set clock");
|
||||
i2s_set_clk(I2S_NUM, SAMPLE_RATE, bits, 2);
|
||||
//Using push
|
||||
// for(i = 0; i < SAMPLE_PER_CYCLE; i++) {
|
||||
// if (bits == 16)
|
||||
// i2s_push_sample(0, &samples_data[i], 100);
|
||||
// else
|
||||
// i2s_push_sample(0, &samples_data[i*2], 100);
|
||||
// }
|
||||
// or write
|
||||
ESP_LOGI(TAG, "write data");
|
||||
i2s_write_channel(tx_handle, samples_data, ((bits + 8) / 16)*SAMPLE_PER_CYCLE * 4, &i2s_bytes_write, 100);
|
||||
i2s_write(I2S_NUM, samples_data, ((bits+8)/16)*SAMPLE_PER_CYCLE*4, &i2s_bytes_write, 100);
|
||||
|
||||
free(samples_data);
|
||||
}
|
||||
@ -100,32 +88,35 @@ void app_main(void)
|
||||
//using 6 buffers, we need 60-samples per buffer
|
||||
//if 2-channels, 16-bit each channel, total buffer is 360*4 = 1440 bytes
|
||||
//if 2-channels, 24/32-bit each channel, total buffer is 360*8 = 2880 bytes
|
||||
i2s_gpio_config_t i2s_pin = {
|
||||
.mclk = I2S_GPIO_UNUSED,
|
||||
.bclk = I2S_BCK_IO,
|
||||
.ws = I2S_WS_IO,
|
||||
.dout = I2S_DO_IO,
|
||||
.din = I2S_DI_IO
|
||||
i2s_config_t i2s_config = {
|
||||
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
|
||||
.sample_rate = SAMPLE_RATE,
|
||||
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
|
||||
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
|
||||
.communication_format = I2S_COMM_FORMAT_STAND_MSB,
|
||||
.dma_desc_num = 6,
|
||||
.dma_frame_num = 60,
|
||||
.use_apll = false,
|
||||
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 //Interrupt level 1
|
||||
};
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_CONFIG(I2S_ROLE_MASTER, I2S_COMM_MODE_STD, &i2s_pin);
|
||||
chan_cfg.id = I2S_NUM;
|
||||
i2s_new_channel(&chan_cfg, &tx_handle, NULL);
|
||||
i2s_std_slot_config_t slot_cfg = I2S_STD_PHILIP_SLOT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO);
|
||||
i2s_std_clk_config_t clk_cfg = I2S_STD_CLK_CONFIG(SAMPLE_RATE);
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
// APLL clock is more accurate when sample rate is high
|
||||
clk_cfg.clk_src = I2S_CLK_APLL;
|
||||
#endif
|
||||
i2s_init_channel(tx_handle, &clk_cfg, &slot_cfg);
|
||||
i2s_start_channel(tx_handle);
|
||||
i2s_pin_config_t pin_config = {
|
||||
.mck_io_num = I2S_PIN_NO_CHANGE,
|
||||
.bck_io_num = I2S_BCK_IO,
|
||||
.ws_io_num = I2S_WS_IO,
|
||||
.data_out_num = I2S_DO_IO,
|
||||
.data_in_num = I2S_DI_IO //Not used
|
||||
};
|
||||
i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL);
|
||||
i2s_set_pin(I2S_NUM, &pin_config);
|
||||
|
||||
int test_bits = 16;
|
||||
while (1) {
|
||||
setup_triangle_sine_waves(test_bits);
|
||||
vTaskDelay(pdMS_TO_TICKS(5000));
|
||||
vTaskDelay(5000/portTICK_PERIOD_MS);
|
||||
test_bits += 8;
|
||||
if (test_bits > 32) {
|
||||
if(test_bits > 32)
|
||||
test_bits = 16;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
1
examples/peripherals/i2s/i2s_basic/sdkconfig.defaults
Normal file
1
examples/peripherals/i2s/i2s_basic/sdkconfig.defaults
Normal file
@ -0,0 +1 @@
|
||||
CONFIG_I2S_SUPPRESS_DEPRECATE_WARN=y
|
6
examples/peripherals/i2s/i2s_basic_new/CMakeLists.txt
Normal file
6
examples/peripherals/i2s/i2s_basic_new/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(esp32_i2s_driver_example)
|
98
examples/peripherals/i2s/i2s_basic_new/README.md
Normal file
98
examples/peripherals/i2s/i2s_basic_new/README.md
Normal file
@ -0,0 +1,98 @@
|
||||
| Supported Targets | ESP32 | ESP32-S2 | ESP32-C3 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- |
|
||||
|
||||
# I2S Example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
In this example, we generate a 100Hz triangle and sine wave and send it out from left and right channels at a sample rate of 36kHz through the I2S bus.
|
||||
|
||||
## How to Use Example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
* A development board with ESP32/ESP32-S2/ESP32-C3/ESP32-S3 SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.)
|
||||
* A USB cable for power supply and programming
|
||||
|
||||
### Configure the Project
|
||||
|
||||
```
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
Running this example, you will see I2S start to read and write data, and only the first 4 elements in the receive buffer will be displayed. The output log can be seen below:
|
||||
|
||||
```
|
||||
[i2s write] 1440 bytes are written successfully
|
||||
|
||||
[i2s read] 8192 bytes are read successfully
|
||||
----------------------------------------------
|
||||
[0] 0 [1] 0 [2] 0 [3] 0
|
||||
|
||||
[i2s write] 1440 bytes are written successfully
|
||||
[i2s write] 1440 bytes are written successfully
|
||||
[i2s write] 1440 bytes are written successfully
|
||||
|
||||
[i2s read] 8192 bytes are read successfully
|
||||
----------------------------------------------
|
||||
[0] a7d468d9 [1] a88a6a1d [2] a9406b58 [3] a9f66c8b
|
||||
|
||||
[i2s write] 1440 bytes are written successfully
|
||||
[i2s write] 1440 bytes are written successfully
|
||||
|
||||
[i2s read] 8192 bytes are read successfully
|
||||
----------------------------------------------
|
||||
[0] 8b622120 [1] 8c182347 [2] 8cce256c [3] 8d84278d
|
||||
```
|
||||
|
||||
There is a abnormal case that printing `Data dropped`, it is caused by a long polling time of `i2s_read_channel`, please refer to the `Application Notes` section in I2S API reference.
|
||||
|
||||
```
|
||||
[i2s read] 8192 bytes are read successfully
|
||||
----------------------------------------------
|
||||
[0] a7d468d9 [1] a88a6a1d [2] a9406b58 [3] a9f66c8b
|
||||
|
||||
|
||||
[i2s monitor] Data dropped
|
||||
|
||||
|
||||
[i2s monitor] Data dropped
|
||||
|
||||
|
||||
[i2s monitor] Data dropped
|
||||
|
||||
[i2s write] 1440 bytes are written successfully
|
||||
|
||||
[i2s monitor] Data dropped
|
||||
```
|
||||
|
||||
If you have a logic analyzer, you can use a logic analyzer to grab online data. The following table describes the pins we use by default (Note that you can also use other pins for the same purpose).
|
||||
|
||||
| pin name| function | gpio_num |
|
||||
|:---:|:---:|:---:|
|
||||
| WS |word select| GPIO_NUM_15 |
|
||||
| SCK |continuous serial clock| GPIO_NUM_13 |
|
||||
| SD |serial data| GPIO_NUM_21 |
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
* Program upload failure
|
||||
|
||||
* Hardware connection is not correct: run `idf.py -p PORT monitor`, and reboot your board to see if there are any output logs.
|
||||
* The baud rate for downloading is too high: lower your baud rate in the `menuconfig` menu, and try again.
|
||||
|
||||
For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.
|
@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "i2s_example_main.c"
|
||||
INCLUDE_DIRS ".")
|
166
examples/peripherals/i2s/i2s_basic_new/main/i2s_example_main.c
Normal file
166
examples/peripherals/i2s/i2s_basic_new/main/i2s_example_main.c
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
/* I2S Example
|
||||
* This example code will output 100Hz sine wave and triangle wave to 2-channel of I2S driver
|
||||
* Every 5 seconds, it will change bits_per_sample [16, 24, 32] for i2s data
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/i2s_std.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
#include <math.h>
|
||||
|
||||
#define EXAMPLE_SAMPLE_RATE (36000)
|
||||
#define EXAMPLE_DATA_BIT_WIDTH (I2S_DATA_BIT_WIDTH_16BIT)
|
||||
|
||||
#define I2S_NUM (0)
|
||||
#define WAVE_FREQ_HZ (100)
|
||||
#define PI (3.14159265)
|
||||
#define I2S_BCK_IO (GPIO_NUM_4)
|
||||
#define I2S_WS_IO (GPIO_NUM_5)
|
||||
#define I2S_DO_IO (GPIO_NUM_18)
|
||||
#define I2S_DI_IO (GPIO_NUM_18) /// Loopback internally if data_out and data_in signal are bound to a same GPIO
|
||||
|
||||
#define SAMPLE_PER_CYCLE (EXAMPLE_SAMPLE_RATE/WAVE_FREQ_HZ)
|
||||
|
||||
static i2s_chan_handle_t tx_handle = NULL;
|
||||
static i2s_chan_handle_t rx_handle = NULL;
|
||||
|
||||
static uint32_t* example_generate_triangle_sine_waves(int bits, uint32_t *buf_len)
|
||||
{
|
||||
uint32_t len = ((bits + 8) / 16)*SAMPLE_PER_CYCLE * 4;
|
||||
uint32_t *samples_data = malloc(len);
|
||||
|
||||
double triangle_float = -(pow(2, bits) / 2 - 1);
|
||||
double triangle_step = (double) pow(2, bits) / SAMPLE_PER_CYCLE;
|
||||
|
||||
for (int i = 0; i < SAMPLE_PER_CYCLE; i++) {
|
||||
double sin_float = sin(i * 2 * PI / SAMPLE_PER_CYCLE);
|
||||
if (sin_float >= 0) {
|
||||
triangle_float += triangle_step;
|
||||
} else {
|
||||
triangle_float -= triangle_step;
|
||||
}
|
||||
sin_float *= (pow(2, bits) / 2 - 1);
|
||||
if (bits == 16) {
|
||||
samples_data[i] = ((short)triangle_float << 16) | (short)sin_float;
|
||||
} else if (bits == 24) { //1-bytes unused
|
||||
samples_data[i * 2] = ((int) triangle_float) << 8;
|
||||
samples_data[i * 2 + 1] = ((int) sin_float) << 8;
|
||||
} else {
|
||||
samples_data[i * 2] = ((int) triangle_float);
|
||||
samples_data[i * 2 + 1] = ((int) sin_float);
|
||||
}
|
||||
|
||||
}
|
||||
*buf_len = len;
|
||||
return samples_data;
|
||||
}
|
||||
|
||||
static void example_i2s_monitor_task(void * args)
|
||||
{
|
||||
QueueHandle_t evt_que = *(QueueHandle_t*)args;
|
||||
i2s_event_t event;
|
||||
while (1) {
|
||||
if (xQueueReceive(evt_que, &event, portMAX_DELAY) == pdTRUE) {
|
||||
if (event.type == I2S_EVENT_RX_Q_OVF) {
|
||||
/* When the rx message queue is overflow, the data in oldest DMA buffer will be dropped */
|
||||
printf("\n[i2s monitor] Data dropped\n\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static void example_i2s_read_task(void * args)
|
||||
{
|
||||
uint32_t *rx_buf = calloc(1, 8192);
|
||||
uint32_t bytes_read = 0;
|
||||
uint32_t cnt = 0;
|
||||
|
||||
while (1) {
|
||||
if (i2s_read_channel(rx_handle, rx_buf, 8192, &bytes_read, 100) == ESP_OK) {
|
||||
if (cnt == 0) {
|
||||
printf("\n[i2s read] %d bytes are read successfully\n", bytes_read);
|
||||
printf("----------------------------------------------\n");
|
||||
printf("[0] %4x [1] %4x [2] %4x [3] %4x\n\n", rx_buf[0], rx_buf[1], rx_buf[2], rx_buf[3]);
|
||||
}
|
||||
cnt++;
|
||||
cnt %= 10;
|
||||
/* If the polling time is too long, there will be data dropped event */
|
||||
// vTaskDelay(10);
|
||||
} else {
|
||||
printf("[i2s read] %d bytes are read, timeout triggered\n\n", bytes_read);
|
||||
}
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static void example_i2s_write_task(void * args)
|
||||
{
|
||||
uint32_t buf_len = 0;
|
||||
uint32_t *tx_buf = example_generate_triangle_sine_waves(EXAMPLE_DATA_BIT_WIDTH, &buf_len);
|
||||
uint32_t bytes_written = 0;
|
||||
uint32_t cnt = 0;
|
||||
|
||||
while (1) {
|
||||
if (i2s_write_channel(tx_handle, tx_buf, buf_len, &bytes_written, 1000) == ESP_OK) {
|
||||
if (cnt == 0) {
|
||||
printf("[i2s write] %d bytes are written successfully\n", bytes_written);
|
||||
}
|
||||
cnt++;
|
||||
cnt %= 20;
|
||||
} else {
|
||||
printf("[i2s write] %d bytes are written, timeout triggered\n", bytes_written);
|
||||
}
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static void example_i2s_init_std_duplex(void)
|
||||
{
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
|
||||
/* Giving both tx and rx handle will make the i2s works in full-duplex mode and can share the bclk and ws signal */
|
||||
ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle));
|
||||
i2s_std_config_t std_cfg = {
|
||||
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(EXAMPLE_SAMPLE_RATE),
|
||||
.slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(EXAMPLE_DATA_BIT_WIDTH, I2S_SLOT_MODE_STEREO),
|
||||
.gpio_cfg = {
|
||||
.mclk = I2S_GPIO_UNUSED,
|
||||
.bclk = I2S_BCK_IO,
|
||||
.ws = I2S_WS_IO,
|
||||
.dout = I2S_DO_IO,
|
||||
.din = I2S_DI_IO,
|
||||
},
|
||||
};
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
// APLL clock is more accurate when sample rate is high
|
||||
std_cfg.clk_cfg.clk_src = I2S_CLK_APLL;
|
||||
#endif
|
||||
/* Initialize the tx channel handle to standard mode */
|
||||
ESP_ERROR_CHECK(i2s_init_std_channel(tx_handle, &std_cfg));
|
||||
/* Initialize the rx channel handle to standard mode */
|
||||
ESP_ERROR_CHECK(i2s_init_std_channel(rx_handle, &std_cfg));
|
||||
|
||||
ESP_ERROR_CHECK(i2s_start_channel(tx_handle));
|
||||
ESP_ERROR_CHECK(i2s_start_channel(rx_handle));
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
//for 36Khz sample rates, we create 100Hz sine wave, every cycle need 36000/100 = 360 samples (4-bytes or 8-bytes each sample)
|
||||
example_i2s_init_std_duplex();
|
||||
|
||||
// Acquire I2S rx channel event queue handle for monitoring whether the received data dropped
|
||||
QueueHandle_t evt_que = i2s_get_event_queue(rx_handle, 16);
|
||||
|
||||
xTaskCreate(example_i2s_write_task, "i2s write task", 4096, NULL, 5, NULL);
|
||||
xTaskCreate(example_i2s_read_task, "i2s read task", 8192, NULL, 5, NULL);
|
||||
xTaskCreate(example_i2s_monitor_task, "i2s monitor task", 4096, &evt_que, 5, NULL);
|
||||
}
|
@ -8,7 +8,7 @@
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "driver/i2s_controller.h"
|
||||
#include "driver/i2s_std.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_check.h"
|
||||
#include "es8311.h"
|
||||
@ -87,21 +87,22 @@ static esp_err_t es8311_codec_init(void)
|
||||
|
||||
static esp_err_t i2s_driver_init(void)
|
||||
{
|
||||
i2s_gpio_config_t i2s_pin = {
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM, I2S_ROLE_MASTER);
|
||||
ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle));
|
||||
i2s_std_config_t std_cfg = {
|
||||
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(EXAMPLE_SAMPLE_RATE),
|
||||
.slot_cfg = I2S_STD_PHILIP_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO),
|
||||
.gpio_cfg = {
|
||||
.mclk = GPIO_NUM_0,
|
||||
.bclk = GPIO_NUM_4,
|
||||
.ws = GPIO_NUM_5,
|
||||
.dout = GPIO_NUM_18,
|
||||
.din = GPIO_NUM_19
|
||||
},
|
||||
};
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_CONFIG(I2S_ROLE_MASTER, I2S_COMM_MODE_STD, &i2s_pin);
|
||||
chan_cfg.id = I2S_NUM;
|
||||
ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle));
|
||||
i2s_std_slot_config_t slot_cfg = I2S_STD_PHILIP_SLOT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO);
|
||||
slot_cfg.auto_clear = true;
|
||||
i2s_std_clk_config_t clk_cfg = I2S_STD_CLK_CONFIG(EXAMPLE_SAMPLE_RATE);
|
||||
ESP_ERROR_CHECK(i2s_init_channel(tx_handle, &clk_cfg, &slot_cfg));
|
||||
ESP_ERROR_CHECK(i2s_init_channel(rx_handle, &clk_cfg, &slot_cfg));
|
||||
|
||||
ESP_ERROR_CHECK(i2s_init_std_channel(tx_handle, &std_cfg));
|
||||
ESP_ERROR_CHECK(i2s_init_std_channel(rx_handle, &std_cfg));
|
||||
ESP_ERROR_CHECK(i2s_start_channel(tx_handle));
|
||||
ESP_ERROR_CHECK(i2s_start_channel(rx_handle));
|
||||
return ESP_OK;
|
||||
|
Loading…
x
Reference in New Issue
Block a user