mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/i2s_support_mclk_input' into 'master'
feat(i2s): supported external clock source input Closes IDF-7889 See merge request espressif/esp-idf!24942
This commit is contained in:
commit
f629c4b7e9
@ -24,9 +24,9 @@ components/driver/test_apps/i2s_test_apps/i2s:
|
||||
disable:
|
||||
- if: SOC_I2S_SUPPORTED != 1
|
||||
|
||||
components/driver/test_apps/i2s_test_apps/i2s_tdm:
|
||||
components/driver/test_apps/i2s_test_apps/i2s_multi_dev:
|
||||
disable:
|
||||
- if: SOC_I2S_SUPPORTS_TDM != 1
|
||||
- if: SOC_I2S_HW_VERSION_2 != 1
|
||||
|
||||
components/driver/test_apps/i2s_test_apps/legacy_i2s_adc_dac:
|
||||
disable:
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "i2s_private.h"
|
||||
|
||||
#include "clk_ctrl_os.h"
|
||||
#include "esp_clk_tree.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_check.h"
|
||||
#include "esp_attr.h"
|
||||
@ -435,39 +436,16 @@ static uint32_t i2s_set_get_apll_freq(uint32_t mclk_freq_hz)
|
||||
}
|
||||
#endif
|
||||
|
||||
// [clk_tree] TODO: replace the following switch table by clk_tree API
|
||||
uint32_t i2s_get_source_clk_freq(i2s_clock_src_t clk_src, uint32_t mclk_freq_hz)
|
||||
{
|
||||
switch (clk_src)
|
||||
{
|
||||
uint32_t clk_freq = 0;
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
case I2S_CLK_SRC_APLL:
|
||||
if (clk_src == I2S_CLK_SRC_APLL) {
|
||||
return i2s_set_get_apll_freq(mclk_freq_hz);
|
||||
#endif
|
||||
#if SOC_I2S_SUPPORTS_XTAL
|
||||
case I2S_CLK_SRC_XTAL:
|
||||
(void)mclk_freq_hz;
|
||||
return esp_clk_xtal_freq();
|
||||
#endif
|
||||
#if SOC_I2S_SUPPORTS_PLL_F160M
|
||||
case I2S_CLK_SRC_PLL_160M:
|
||||
(void)mclk_freq_hz;
|
||||
return I2S_LL_PLL_F160M_CLK_FREQ;
|
||||
#endif
|
||||
#if SOC_I2S_SUPPORTS_PLL_F96M
|
||||
case I2S_CLK_SRC_PLL_96M:
|
||||
(void)mclk_freq_hz;
|
||||
return I2S_LL_PLL_F96M_CLK_FREQ;
|
||||
#endif
|
||||
#if SOC_I2S_SUPPORTS_PLL_F64M
|
||||
case I2S_CLK_SRC_PLL_64M:
|
||||
(void)mclk_freq_hz;
|
||||
return I2S_LL_PLL_F64M_CLK_FREQ;
|
||||
#endif
|
||||
default:
|
||||
// Invalid clock source
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
esp_clk_tree_src_get_freq_hz(clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clk_freq);
|
||||
return clk_freq;
|
||||
}
|
||||
|
||||
#if SOC_GDMA_SUPPORTED
|
||||
@ -711,7 +689,7 @@ void i2s_gpio_loopback_set(gpio_num_t gpio, uint32_t out_sig_idx, uint32_t in_si
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t i2s_check_set_mclk(i2s_port_t id, gpio_num_t gpio_num, bool is_apll, bool is_invert)
|
||||
esp_err_t i2s_check_set_mclk(i2s_port_t id, gpio_num_t gpio_num, i2s_clock_src_t clk_src, bool is_invert)
|
||||
{
|
||||
if (gpio_num == I2S_GPIO_UNUSED) {
|
||||
return ESP_OK;
|
||||
@ -721,6 +699,7 @@ esp_err_t i2s_check_set_mclk(i2s_port_t id, gpio_num_t gpio_num, bool is_apll, b
|
||||
ESP_ERR_INVALID_ARG, TAG,
|
||||
"ESP32 only support to set GPIO0/GPIO1/GPIO3 as mclk signal, error GPIO number:%d", gpio_num);
|
||||
bool is_i2s0 = id == I2S_NUM_0;
|
||||
bool is_apll = clk_src == I2S_CLK_SRC_APLL;
|
||||
if (gpio_num == GPIO_NUM_0) {
|
||||
gpio_hal_iomux_func_sel(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1);
|
||||
gpio_ll_iomux_pin_ctrl(is_apll ? 0xFFF6 : (is_i2s0 ? 0xFFF0 : 0xFFFF));
|
||||
@ -733,9 +712,16 @@ esp_err_t i2s_check_set_mclk(i2s_port_t id, gpio_num_t gpio_num, bool is_apll, b
|
||||
}
|
||||
#else
|
||||
ESP_RETURN_ON_FALSE(GPIO_IS_VALID_GPIO(gpio_num), ESP_ERR_INVALID_ARG, TAG, "mck_io_num invalid");
|
||||
i2s_gpio_check_and_set(gpio_num, i2s_periph_signal[id].mck_out_sig, false, is_invert);
|
||||
#endif
|
||||
ESP_LOGD(TAG, "MCLK is pinned to GPIO%d on I2S%d", id, gpio_num);
|
||||
#if SOC_I2S_HW_VERSION_2
|
||||
if (clk_src == I2S_CLK_SRC_EXTERNAL) {
|
||||
i2s_gpio_check_and_set(gpio_num, i2s_periph_signal[id].mck_in_sig, true, is_invert);
|
||||
} else
|
||||
#endif // SOC_I2S_HW_VERSION_2
|
||||
{
|
||||
i2s_gpio_check_and_set(gpio_num, i2s_periph_signal[id].mck_out_sig, false, is_invert);
|
||||
}
|
||||
#endif // CONFIG_IDF_TARGET_ESP32
|
||||
ESP_LOGD(TAG, "MCLK is pinned to GPIO%d on I2S%d", gpio_num, id);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
@ -57,6 +57,9 @@ static esp_err_t i2s_pdm_tx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_tx
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
i2s_pdm_tx_config_t *pdm_tx_cfg = (i2s_pdm_tx_config_t *)(handle->mode_info);
|
||||
#if SOC_I2S_HW_VERSION_2
|
||||
ESP_RETURN_ON_FALSE(clk_cfg->clk_src != I2S_CLK_SRC_EXTERNAL, ESP_ERR_INVALID_ARG, TAG, "not support external clock source in pdm mode");
|
||||
#endif
|
||||
ESP_RETURN_ON_FALSE(clk_cfg->up_sample_fs <= 480, ESP_ERR_INVALID_ARG, TAG, "up_sample_fs should be within 480");
|
||||
|
||||
i2s_hal_clock_info_t clk_info;
|
||||
@ -342,6 +345,9 @@ static esp_err_t i2s_pdm_rx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_rx
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
i2s_pdm_rx_config_t *pdm_rx_cfg = (i2s_pdm_rx_config_t *)(handle->mode_info);
|
||||
#if SOC_I2S_HW_VERSION_2
|
||||
ESP_RETURN_ON_FALSE(clk_cfg->clk_src != I2S_CLK_SRC_EXTERNAL, ESP_ERR_INVALID_ARG, TAG, "not support external clock source in pdm mode");
|
||||
#endif
|
||||
|
||||
i2s_hal_clock_info_t clk_info;
|
||||
/* Calculate clock parameters */
|
||||
|
@ -191,13 +191,13 @@ void i2s_gpio_check_and_set(gpio_num_t gpio, uint32_t signal_idx, bool is_input,
|
||||
*
|
||||
* @param id I2S port id
|
||||
* @param gpio_num GPIO number
|
||||
* @param is_apll Is using APLL as clock source
|
||||
* @param clk_src The clock source of this I2S port
|
||||
* @param is_invert Is invert the GPIO
|
||||
* @return
|
||||
* - ESP_OK Set mclk output gpio success
|
||||
* - ESP_ERR_INVALID_ARG Invalid GPIO number
|
||||
*/
|
||||
esp_err_t i2s_check_set_mclk(i2s_port_t id, gpio_num_t gpio_num, bool is_apll, bool is_invert);
|
||||
esp_err_t i2s_check_set_mclk(i2s_port_t id, gpio_num_t gpio_num, i2s_clock_src_t clk_src, bool is_invert);
|
||||
|
||||
/**
|
||||
* @brief Attach data out signal and data in signal to a same gpio
|
||||
|
@ -45,11 +45,16 @@ static esp_err_t i2s_std_calculate_clock(i2s_chan_handle_t handle, const i2s_std
|
||||
clk_info->bclk = rate * handle->total_slot * slot_bits;
|
||||
clk_info->mclk = clk_info->bclk * clk_info->bclk_div;
|
||||
}
|
||||
#if SOC_I2S_HW_VERSION_2
|
||||
clk_info->sclk = clk_cfg->clk_src == I2S_CLK_SRC_EXTERNAL ?
|
||||
clk_cfg->ext_clk_freq_hz : i2s_get_source_clk_freq(clk_cfg->clk_src, clk_info->mclk);
|
||||
#else
|
||||
clk_info->sclk = i2s_get_source_clk_freq(clk_cfg->clk_src, clk_info->mclk);
|
||||
#endif
|
||||
clk_info->mclk_div = clk_info->sclk / clk_info->mclk;
|
||||
|
||||
/* Check if the configuration is correct */
|
||||
ESP_RETURN_ON_FALSE(clk_info->mclk_div, ESP_ERR_INVALID_ARG, TAG, "sample rate is too large");
|
||||
ESP_RETURN_ON_FALSE(clk_info->mclk_div, ESP_ERR_INVALID_ARG, TAG, "sample rate is too large for the current clock source");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -151,6 +156,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->din, i2s_periph_signal[id].data_in_sig, true, false);
|
||||
}
|
||||
|
||||
/* Set mclk pin */
|
||||
ESP_RETURN_ON_ERROR(i2s_check_set_mclk(id, gpio_cfg->mclk, std_cfg->clk_cfg.clk_src, gpio_cfg->invert_flags.mclk_inv), TAG, "mclk config failed");
|
||||
|
||||
if (handle->role == I2S_ROLE_SLAVE) {
|
||||
/* For "tx + slave" mode, select TX signal index for ws and bck */
|
||||
if (handle->dir == I2S_DIR_TX && !handle->controller->full_duplex) {
|
||||
@ -165,13 +173,6 @@ 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].s_rx_bck_sig, true, gpio_cfg->invert_flags.bclk_inv);
|
||||
}
|
||||
} else {
|
||||
/* mclk only available in master mode */
|
||||
#if SOC_I2S_SUPPORTS_APLL
|
||||
bool is_apll = std_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL;
|
||||
#else
|
||||
bool is_apll = false;
|
||||
#endif
|
||||
ESP_RETURN_ON_ERROR(i2s_check_set_mclk(id, gpio_cfg->mclk, is_apll, gpio_cfg->invert_flags.mclk_inv), TAG, "mclk config failed");
|
||||
/* For "rx + master" mode, select RX signal index for ws and bck */
|
||||
if (handle->dir == I2S_DIR_RX && !handle->controller->full_duplex) {
|
||||
#if SOC_I2S_HW_VERSION_2
|
||||
@ -208,7 +209,6 @@ esp_err_t i2s_channel_init_std_mode(i2s_chan_handle_t handle, const i2s_std_conf
|
||||
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_std_slot should be called before i2s_set_std_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
|
||||
@ -219,6 +219,8 @@ esp_err_t i2s_channel_init_std_mode(i2s_chan_handle_t handle, const i2s_std_conf
|
||||
}
|
||||
#endif
|
||||
ESP_GOTO_ON_ERROR(i2s_std_set_clock(handle, &std_cfg->clk_cfg), err, TAG, "initialize channel failed while setting clock");
|
||||
/* i2s_std_set_gpio should be called after i2s_std_set_clock as mclk relies on the clock source */
|
||||
ESP_GOTO_ON_ERROR(i2s_std_set_gpio(handle, &std_cfg->gpio_cfg), err, TAG, "initialize channel failed while setting gpio pins");
|
||||
ESP_GOTO_ON_ERROR(i2s_init_dma_intr(handle, I2S_INTR_ALLOC_FLAGS), err, TAG, "initialize dma interrupt failed");
|
||||
#if SOC_I2S_HW_VERSION_2
|
||||
/* Enable clock to start outputting mclk signal. Some codecs will reset once mclk stop */
|
||||
|
@ -56,11 +56,12 @@ static esp_err_t i2s_tdm_calculate_clock(i2s_chan_handle_t handle, const i2s_tdm
|
||||
clk_info->bclk = rate * handle->total_slot * slot_bits;
|
||||
clk_info->mclk = clk_info->bclk * clk_info->bclk_div;
|
||||
}
|
||||
clk_info->sclk = i2s_get_source_clk_freq(clk_cfg->clk_src, clk_info->mclk);
|
||||
clk_info->sclk = clk_cfg->clk_src == I2S_CLK_SRC_EXTERNAL ?
|
||||
clk_cfg->ext_clk_freq_hz : i2s_get_source_clk_freq(clk_cfg->clk_src, clk_info->mclk);
|
||||
clk_info->mclk_div = clk_info->sclk / clk_info->mclk;
|
||||
|
||||
/* Check if the configuration is correct */
|
||||
ESP_RETURN_ON_FALSE(clk_info->mclk_div, ESP_ERR_INVALID_ARG, TAG, "sample rate is too large");
|
||||
ESP_RETURN_ON_FALSE(clk_info->mclk_div, ESP_ERR_INVALID_ARG, TAG, "sample rate is too large for the current clock source");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@ -146,6 +147,7 @@ static esp_err_t i2s_tdm_set_gpio(i2s_chan_handle_t handle, const i2s_tdm_gpio_c
|
||||
ESP_ERR_INVALID_ARG, TAG, "bclk invalid");
|
||||
ESP_RETURN_ON_FALSE((gpio_cfg->ws == -1 || GPIO_IS_VALID_GPIO(gpio_cfg->ws)),
|
||||
ESP_ERR_INVALID_ARG, TAG, "ws invalid");
|
||||
i2s_tdm_config_t *tdm_cfg = (i2s_tdm_config_t *)(handle->mode_info);
|
||||
/* Loopback if dout = din */
|
||||
if (gpio_cfg->dout != -1 &&
|
||||
gpio_cfg->dout == gpio_cfg->din) {
|
||||
@ -158,6 +160,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->din, i2s_periph_signal[id].data_in_sig, true, false);
|
||||
}
|
||||
|
||||
/* Set mclk pin */
|
||||
ESP_RETURN_ON_ERROR(i2s_check_set_mclk(id, gpio_cfg->mclk, tdm_cfg->clk_cfg.clk_src, gpio_cfg->invert_flags.mclk_inv), TAG, "mclk config failed");
|
||||
|
||||
if (handle->role == I2S_ROLE_SLAVE) {
|
||||
/* For "tx + slave" mode, select TX signal index for ws and bck */
|
||||
if (handle->dir == I2S_DIR_TX && !handle->controller->full_duplex) {
|
||||
@ -172,8 +177,6 @@ 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].s_rx_bck_sig, true, gpio_cfg->invert_flags.bclk_inv);
|
||||
}
|
||||
} else {
|
||||
/* mclk only available in master mode */
|
||||
ESP_RETURN_ON_ERROR(i2s_check_set_mclk(id, gpio_cfg->mclk, false, gpio_cfg->invert_flags.mclk_inv), TAG, "mclk config failed");
|
||||
/* For "rx + master" mode, select RX signal index for ws and bck */
|
||||
if (handle->dir == I2S_DIR_RX && !handle->controller->full_duplex) {
|
||||
#if SOC_I2S_HW_VERSION_2
|
||||
@ -188,7 +191,6 @@ static esp_err_t i2s_tdm_set_gpio(i2s_chan_handle_t handle, const i2s_tdm_gpio_c
|
||||
}
|
||||
}
|
||||
/* 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;
|
||||
@ -212,7 +214,6 @@ esp_err_t i2s_channel_init_tdm_mode(i2s_chan_handle_t handle, const i2s_tdm_conf
|
||||
}
|
||||
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_tdm_slot should be called before i2s_set_tdm_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
|
||||
@ -223,6 +224,8 @@ esp_err_t i2s_channel_init_tdm_mode(i2s_chan_handle_t handle, const i2s_tdm_conf
|
||||
}
|
||||
#endif
|
||||
ESP_GOTO_ON_ERROR(i2s_tdm_set_clock(handle, &tdm_cfg->clk_cfg), err, TAG, "initialize channel failed while setting clock");
|
||||
/* i2s_tdm_set_gpio should be called after i2s_tdm_set_clock as mclk relies on the clock source */
|
||||
ESP_GOTO_ON_ERROR(i2s_tdm_set_gpio(handle, &tdm_cfg->gpio_cfg), err, TAG, "initialize channel failed while setting gpio pins");
|
||||
ESP_GOTO_ON_ERROR(i2s_init_dma_intr(handle, I2S_INTR_ALLOC_FLAGS), err, TAG, "initialize dma interrupt failed");
|
||||
|
||||
#if SOC_I2S_HW_VERSION_2
|
||||
|
@ -237,7 +237,14 @@ typedef struct {
|
||||
typedef struct {
|
||||
/* General fields */
|
||||
uint32_t sample_rate_hz; /*!< I2S sample rate */
|
||||
i2s_clock_src_t clk_src; /*!< Choose clock source */
|
||||
i2s_clock_src_t clk_src; /*!< Choose clock source, see 'soc_periph_i2s_clk_src_t' for the supported clock sources.
|
||||
* selected 'I2S_CLK_SRC_EXTERNAL'(if supports) to enable the external source clock input via MCLK pin,
|
||||
*/
|
||||
#if SOC_I2S_HW_VERSION_2
|
||||
uint32_t ext_clk_freq_hz; /*!< External clock source frequency in Hz, only take effect when 'clk_src = I2S_CLK_SRC_EXTERNAL', otherwise this field will be ignored,
|
||||
* Please make sure the frequency input is equal or greater than bclk, i.e. 'sample_rate_hz * slot_bits * 2'
|
||||
*/
|
||||
#endif
|
||||
i2s_mclk_multiple_t mclk_multiple; /*!< The multiple of mclk to the sample rate
|
||||
* Default is 256 in the helper macro, it can satisfy most of cases,
|
||||
* but please set this field a multiple of '3' (like 384) when using 24-bit data width,
|
||||
@ -249,7 +256,7 @@ typedef struct {
|
||||
* @brief I2S standard mode GPIO pins configuration
|
||||
*/
|
||||
typedef struct {
|
||||
gpio_num_t mclk; /*!< MCK pin, output */
|
||||
gpio_num_t mclk; /*!< MCK pin, output by default, input if the clock source is selected to 'I2S_CLK_SRC_EXTERNAL' */
|
||||
gpio_num_t bclk; /*!< BCK pin, input in slave role, output in master role */
|
||||
gpio_num_t ws; /*!< WS pin, input in slave role, output in master role */
|
||||
gpio_num_t dout; /*!< DATA pin, output */
|
||||
|
@ -156,7 +156,13 @@ typedef struct {
|
||||
typedef struct {
|
||||
/* General fields */
|
||||
uint32_t sample_rate_hz; /*!< I2S sample rate */
|
||||
i2s_clock_src_t clk_src; /*!< Choose clock source */
|
||||
i2s_clock_src_t clk_src; /*!< Choose clock source, see 'soc_periph_i2s_clk_src_t' for the supported clock sources.
|
||||
* selected 'I2S_CLK_SRC_EXTERNAL'(if supports) to enable the external source clock inputted via MCLK pin,
|
||||
* please make sure the frequency inputted is equal or greater than 'sample_rate_hz * mclk_multiple'
|
||||
*/
|
||||
uint32_t ext_clk_freq_hz; /*!< External clock source frequency in Hz, only take effect when 'clk_src = I2S_CLK_SRC_EXTERNAL', otherwise this field will be ignored
|
||||
* Please make sure the frequency inputted is equal or greater than bclk, i.e. 'sample_rate_hz * slot_bits * slot_num'
|
||||
*/
|
||||
i2s_mclk_multiple_t mclk_multiple; /*!< The multiple of mclk to the sample rate, only take effect for master role */
|
||||
uint32_t bclk_div; /*!< The division from mclk to bclk, only take effect for slave role, it shouldn't be smaller than 8. Increase this field when data sent by slave lag behind */
|
||||
} i2s_tdm_clk_config_t;
|
||||
@ -165,7 +171,7 @@ typedef struct {
|
||||
* @brief I2S TDM mode GPIO pins configuration
|
||||
*/
|
||||
typedef struct {
|
||||
gpio_num_t mclk; /*!< MCK pin, output */
|
||||
gpio_num_t mclk; /*!< MCK pin, output by default, input if the clock source is selected to 'I2S_CLK_SRC_EXTERNAL' */
|
||||
gpio_num_t bclk; /*!< BCK pin, input in slave role, output in master role */
|
||||
gpio_num_t ws; /*!< WS pin, input in slave role, output in master role */
|
||||
gpio_num_t dout; /*!< DATA pin, output */
|
||||
|
@ -10,4 +10,4 @@ set(EXTRA_COMPONENT_DIRS
|
||||
)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(i2s_tdm_full_duplex_test)
|
||||
project(i2s_multi_dev_test)
|
@ -1,4 +1,4 @@
|
||||
idf_component_register(SRCS "test_app_main.c" "test_i2s_tdm_full_duplex.c"
|
||||
idf_component_register(SRCS "test_app_main.c" "test_i2s_multi_dev.c"
|
||||
PRIV_REQUIRES unity driver test_utils
|
||||
INCLUDE_DIRS "."
|
||||
WHOLE_ARCHIVE
|
@ -5,6 +5,7 @@
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
@ -15,15 +16,19 @@
|
||||
#include "test_utils.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/i2s_tdm.h"
|
||||
#include "driver/i2s_std.h"
|
||||
#include "soc/i2s_struct.h"
|
||||
|
||||
static const char *TAG = "i2s_tdm_full_duplex_test";
|
||||
static const char *TAG = "i2s_multi_dev_test";
|
||||
|
||||
#define TEST_I2S_FRAME_SIZE (128) // Frame numbers in every writing / reading
|
||||
#define TEST_I2S_ARRAY_LENGTH (1024) // The loop data length for verification
|
||||
#define TEST_I2S_MAX_DATA (256) // The maximum data value in the data buffer
|
||||
#define TEST_I2S_MAX_FAIL_CNT (3) // Max broken packet count
|
||||
#define TEST_I2S_FRAME_TIMEOUT_SEC (10.0f) // Timeout seconds of waiting for a correct frame
|
||||
|
||||
#define TEST_I2S_NUM (I2S_NUM_0) // ESP32-C3 has only I2S0
|
||||
#define TEST_I2S_MCK_IO (GPIO_NUM_0)
|
||||
#define TEST_I2S_BCK_IO (GPIO_NUM_4)
|
||||
#define TEST_I2S_WS_IO (GPIO_NUM_5)
|
||||
#if CONFIG_IDF_TARGET_ESP32H2
|
||||
@ -34,53 +39,17 @@ static const char *TAG = "i2s_tdm_full_duplex_test";
|
||||
#define TEST_I2S_DI_IO (GPIO_NUM_7) // DI and DO gpio will be reversed on slave runner
|
||||
#endif // CONFIG_IDF_TARGET_ESP32H2
|
||||
|
||||
typedef struct {
|
||||
TaskHandle_t maintask_handle;
|
||||
QueueHandle_t tx_queue;
|
||||
i2s_chan_handle_t tx_channel_handle;
|
||||
i2s_data_bit_width_t tx_data_bit_width;
|
||||
i2s_tdm_slot_mask_t tdm_slot_mask;
|
||||
} test_i2s_tdm_write_task_args_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t *buffer;
|
||||
uint32_t buffer_size;
|
||||
} test_i2s_tdm_write_buffer_t;
|
||||
|
||||
static void test_i2s_tdm_master_write_task(void *args)
|
||||
{
|
||||
test_i2s_tdm_write_task_args_t *task_args = (test_i2s_tdm_write_task_args_t*)args;
|
||||
|
||||
/* Allocate I2S tx buffer */
|
||||
uint32_t channel_count = 32 - __builtin_clz(task_args->tdm_slot_mask);
|
||||
uint32_t tx_buffer_size = TEST_I2S_FRAME_SIZE * channel_count * (task_args->tx_data_bit_width / 8);
|
||||
ESP_LOGI(TAG, "Allocating I2S TDM master tx buffer, size=%ld", tx_buffer_size);
|
||||
uint32_t *tx_buffer = malloc(tx_buffer_size);
|
||||
TEST_ASSERT(tx_buffer);
|
||||
|
||||
uint32_t data_cnt = 0;
|
||||
size_t bytes_written = 0;
|
||||
|
||||
/* Block here waiting for the main thread receiving Slave Ready signals */
|
||||
xTaskNotifyWait(0, ULONG_MAX, NULL, portMAX_DELAY);
|
||||
|
||||
ESP_LOGI(TAG, "I2S TDM master send start");
|
||||
while (xTaskNotifyWait(0, ULONG_MAX, NULL, 0) == pdFALSE) { // if main task sends terminate signal, exit the loop
|
||||
/* Fill in the tx buffer */
|
||||
for (uint32_t i = 0; i < tx_buffer_size / sizeof(uint32_t); i ++) {
|
||||
tx_buffer[i] = data_cnt;
|
||||
data_cnt++;
|
||||
data_cnt %= TEST_I2S_ARRAY_LENGTH;
|
||||
}
|
||||
TEST_ESP_OK(i2s_channel_write(task_args->tx_channel_handle, tx_buffer, tx_buffer_size,
|
||||
&bytes_written, 1000));
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Freeing I2S TDM master tx buffer");
|
||||
free(tx_buffer);
|
||||
|
||||
xTaskNotifyGive(task_args->maintask_handle); // notify main task that cleanup is done
|
||||
vTaskSuspend(NULL); // wait to be deleted
|
||||
#define TEST_I2S_DEFAULT_GPIO(mclk_pin, is_master) { \
|
||||
.mclk = mclk_pin, \
|
||||
.bclk = TEST_I2S_BCK_IO, \
|
||||
.ws = TEST_I2S_WS_IO, \
|
||||
.dout = is_master ? TEST_I2S_DO_IO : TEST_I2S_DI_IO, \
|
||||
.din = is_master ? TEST_I2S_DI_IO : TEST_I2S_DO_IO, \
|
||||
}
|
||||
|
||||
static void test_i2s_tdm_master(uint32_t sample_rate, i2s_data_bit_width_t bit_width, i2s_tdm_slot_mask_t slot_mask)
|
||||
@ -102,93 +71,70 @@ static void test_i2s_tdm_master(uint32_t sample_rate, i2s_data_bit_width_t bit_w
|
||||
i2s_tdm_config_t i2s_tdm_config = {
|
||||
.clk_cfg = I2S_TDM_CLK_DEFAULT_CONFIG(sample_rate),
|
||||
.slot_cfg = I2S_TDM_PHILIPS_SLOT_DEFAULT_CONFIG(bit_width, I2S_SLOT_MODE_STEREO, slot_mask),
|
||||
.gpio_cfg = {
|
||||
.mclk = GPIO_NUM_NC,
|
||||
.bclk = TEST_I2S_BCK_IO,
|
||||
.ws = TEST_I2S_WS_IO,
|
||||
.dout = TEST_I2S_DO_IO,
|
||||
.din = TEST_I2S_DI_IO
|
||||
},
|
||||
.gpio_cfg = TEST_I2S_DEFAULT_GPIO(GPIO_NUM_NC, true),
|
||||
};
|
||||
i2s_tdm_config.clk_cfg.mclk_multiple = I2S_MCLK_MULTIPLE_384;
|
||||
TEST_ESP_OK(i2s_channel_init_tdm_mode(i2s_tdm_tx_handle, &i2s_tdm_config));
|
||||
TEST_ESP_OK(i2s_channel_init_tdm_mode(i2s_tdm_rx_handle, &i2s_tdm_config));
|
||||
|
||||
/* Create TDM write task */
|
||||
TaskHandle_t subtask_handle = NULL;
|
||||
/* Make the variable static in case it become invalid in the write task */
|
||||
static test_i2s_tdm_write_task_args_t task_args;
|
||||
task_args.tx_channel_handle = i2s_tdm_tx_handle;
|
||||
task_args.maintask_handle = xTaskGetCurrentTaskHandle();
|
||||
task_args.tx_data_bit_width = bit_width;
|
||||
task_args.tdm_slot_mask = slot_mask;
|
||||
xTaskCreate(test_i2s_tdm_master_write_task, "I2S TDM Write Task", 4096, &task_args, 5, &subtask_handle);
|
||||
|
||||
/* Allocate I2S rx buffer */
|
||||
uint32_t channel_count = 32 - __builtin_clz(slot_mask);
|
||||
uint32_t rx_buffer_size = channel_count * TEST_I2S_FRAME_SIZE * (bit_width / 8);
|
||||
ESP_LOGI(TAG, "Allocating I2S TDM master rx buffer, size=%"PRIu32, rx_buffer_size);
|
||||
uint32_t *rx_buffer = malloc(rx_buffer_size);
|
||||
size_t buf_size = channel_count * TEST_I2S_FRAME_SIZE * (bit_width / 8);
|
||||
/* Allocate I2S rx buffer */
|
||||
ESP_LOGI(TAG, "Allocating I2S TDM master rx buffer, size=%u", buf_size);
|
||||
uint32_t *rx_buffer = malloc(buf_size);
|
||||
TEST_ASSERT(rx_buffer);
|
||||
/* Allocate I2S tx buffer */
|
||||
ESP_LOGI(TAG, "Allocating I2S TDM master tx buffer, size=%u", buf_size);
|
||||
uint32_t *tx_buffer = malloc(buf_size);
|
||||
TEST_ASSERT(tx_buffer);
|
||||
/* Fill in the tx buffer */
|
||||
for (uint32_t i = 0, data_cnt = 0; i < buf_size / sizeof(uint32_t); i ++) {
|
||||
tx_buffer[i] = data_cnt;
|
||||
data_cnt++;
|
||||
data_cnt %= TEST_I2S_MAX_DATA;
|
||||
}
|
||||
size_t w_bytes = buf_size;
|
||||
while (w_bytes != 0) {
|
||||
ESP_ERROR_CHECK(i2s_channel_preload_data(i2s_tdm_tx_handle, tx_buffer, buf_size, &w_bytes));
|
||||
}
|
||||
|
||||
uint32_t count = 1;
|
||||
bool is_start = false;
|
||||
uint8_t fail_cnt = 0;
|
||||
size_t bytes_read = 0;
|
||||
float time = 0;
|
||||
unity_wait_for_signal("Slave Ready");
|
||||
TEST_ESP_OK(i2s_channel_enable(i2s_tdm_rx_handle));
|
||||
TEST_ESP_OK(i2s_channel_enable(i2s_tdm_tx_handle));
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // Waiting the data be steady on line
|
||||
unity_send_signal("Master Ready");
|
||||
unity_wait_for_signal("Slave Ready");
|
||||
|
||||
/* Slave is ready, start the writing task */
|
||||
ESP_LOGI(TAG, "I2S TDM master receive & send start");
|
||||
esp_err_t read_ret = ESP_OK;
|
||||
xTaskNotifyGive(subtask_handle);
|
||||
while (count < TEST_I2S_ARRAY_LENGTH && fail_cnt < TEST_I2S_MAX_FAIL_CNT && time < TEST_I2S_FRAME_TIMEOUT_SEC) {
|
||||
read_ret = i2s_channel_read(i2s_tdm_rx_handle, rx_buffer, rx_buffer_size, &bytes_read, 1000);
|
||||
if (read_ret != ESP_OK) {
|
||||
break;
|
||||
uint32_t count = 1;
|
||||
uint8_t fail_cnt = 0;
|
||||
size_t bytes_read = 0;
|
||||
for (fail_cnt = 0; fail_cnt < TEST_I2S_MAX_FAIL_CNT && count < TEST_I2S_MAX_DATA; fail_cnt++) {
|
||||
if (i2s_channel_read(i2s_tdm_rx_handle, rx_buffer, buf_size, &bytes_read, 1000) != ESP_OK) {
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < rx_buffer_size / sizeof(uint32_t); i++) {
|
||||
for (int i = 0; i < buf_size && count < TEST_I2S_MAX_DATA; i++) {
|
||||
if (rx_buffer[i] == count) {
|
||||
count++;
|
||||
if (count >= TEST_I2S_ARRAY_LENGTH) {
|
||||
break;
|
||||
}
|
||||
if (!is_start) {
|
||||
is_start = true;
|
||||
}
|
||||
} else if (is_start) {
|
||||
} else if (count != 1) {
|
||||
ESP_LOGE(TAG, "Failed at index: %d real: %" PRIu32 " expect: %" PRIu32, i, rx_buffer[i], count);
|
||||
is_start = false;
|
||||
count = 1;
|
||||
fail_cnt++;
|
||||
}
|
||||
}
|
||||
time += (float)TEST_I2S_MAX_FAIL_CNT / (float)sample_rate;
|
||||
}
|
||||
unity_send_signal("Master Finished");
|
||||
|
||||
ESP_LOGI(TAG, "Send signal to terminate subtask");
|
||||
xTaskNotifyGive(subtask_handle); // notify subtask to exit
|
||||
xTaskNotifyWait(0, ULONG_MAX, NULL, portMAX_DELAY); // wait subtask to do some cleanups
|
||||
ESP_LOGI(TAG, "Deleting subtask");
|
||||
unity_utils_task_delete(subtask_handle); // delete subtask
|
||||
|
||||
ESP_LOGI(TAG, "I2S TDM master send stop");
|
||||
ESP_LOGI(TAG, "I2S TDM master stop");
|
||||
TEST_ESP_OK(i2s_channel_disable(i2s_tdm_tx_handle));
|
||||
ESP_LOGI(TAG, "I2S TDM master receive stop");
|
||||
TEST_ESP_OK(i2s_channel_disable(i2s_tdm_rx_handle));
|
||||
|
||||
ESP_LOGI(TAG, "Freeing I2S TDM master rx buffer");
|
||||
free(rx_buffer);
|
||||
ESP_LOGI(TAG, "Deleting i2s tx and rx channels");
|
||||
free(tx_buffer);
|
||||
TEST_ESP_OK(i2s_del_channel(i2s_tdm_rx_handle));
|
||||
TEST_ESP_OK(i2s_del_channel(i2s_tdm_tx_handle));
|
||||
ESP_LOGI(TAG, "I2S TDM master resources freed");
|
||||
TEST_ASSERT_TRUE_MESSAGE(read_ret == ESP_OK, "Master read timeout ");
|
||||
TEST_ASSERT_TRUE_MESSAGE(fail_cnt < TEST_I2S_MAX_FAIL_CNT, "Broken data received ");
|
||||
TEST_ASSERT_TRUE_MESSAGE(time < TEST_I2S_FRAME_TIMEOUT_SEC, "Waiting for valid data timeout ");
|
||||
TEST_ASSERT_TRUE_MESSAGE(fail_cnt < TEST_I2S_MAX_FAIL_CNT, "Exceed retry times ");
|
||||
TEST_ASSERT_EQUAL_UINT32(TEST_I2S_MAX_DATA, count);
|
||||
}
|
||||
|
||||
static void test_i2s_tdm_slave(uint32_t sample_rate, i2s_data_bit_width_t bit_width, i2s_tdm_slot_mask_t slot_mask)
|
||||
@ -210,13 +156,7 @@ static void test_i2s_tdm_slave(uint32_t sample_rate, i2s_data_bit_width_t bit_wi
|
||||
i2s_tdm_config_t i2s_tdm_config = {
|
||||
.clk_cfg = I2S_TDM_CLK_DEFAULT_CONFIG(sample_rate),
|
||||
.slot_cfg = I2S_TDM_PHILIPS_SLOT_DEFAULT_CONFIG(bit_width, I2S_SLOT_MODE_STEREO, slot_mask),
|
||||
.gpio_cfg = {
|
||||
.mclk = GPIO_NUM_NC,
|
||||
.bclk = TEST_I2S_BCK_IO,
|
||||
.ws = TEST_I2S_WS_IO,
|
||||
.dout = TEST_I2S_DI_IO,
|
||||
.din = TEST_I2S_DO_IO // on slave, swap DI and DO pin
|
||||
},
|
||||
.gpio_cfg = TEST_I2S_DEFAULT_GPIO(GPIO_NUM_NC, false),
|
||||
};
|
||||
if (sample_rate >= 96000) {
|
||||
i2s_tdm_config.clk_cfg.bclk_div = 12;
|
||||
@ -226,39 +166,35 @@ static void test_i2s_tdm_slave(uint32_t sample_rate, i2s_data_bit_width_t bit_wi
|
||||
|
||||
/* Allocate I2S rx buffer */
|
||||
uint32_t channel_count = 32 - __builtin_clz(slot_mask);
|
||||
uint32_t rx_buffer_size = TEST_I2S_FRAME_SIZE * channel_count * (bit_width / 8);
|
||||
ESP_LOGI(TAG, "Allocating I2S TDM slave buffer, size=%ld", rx_buffer_size);
|
||||
uint32_t *rx_buffer = malloc(rx_buffer_size);
|
||||
TEST_ASSERT(rx_buffer);
|
||||
uint32_t buffer_size = TEST_I2S_FRAME_SIZE * channel_count * (bit_width / 8);
|
||||
ESP_LOGI(TAG, "Allocating I2S TDM slave buffer, size=%"PRIu32, buffer_size);
|
||||
uint32_t *echo_buffer = malloc(buffer_size);
|
||||
TEST_ASSERT(echo_buffer);
|
||||
|
||||
TEST_ESP_OK(i2s_channel_enable(i2s_tdm_rx_handle));
|
||||
TEST_ESP_OK(i2s_channel_enable(i2s_tdm_tx_handle));
|
||||
unity_send_signal("Slave Ready");
|
||||
unity_wait_for_signal("Master Ready");
|
||||
TEST_ESP_OK(i2s_channel_enable(i2s_tdm_rx_handle));
|
||||
TEST_ESP_OK(i2s_channel_enable(i2s_tdm_tx_handle));
|
||||
|
||||
ESP_LOGI(TAG, "I2S TDM slave receive & send start");
|
||||
size_t bytes_read = 0, bytes_written = 0;
|
||||
/* Loop until reading or writing failed, which indicates the master has finished and deleted the I2S peripheral */
|
||||
while (true) {
|
||||
if (i2s_channel_read(i2s_tdm_rx_handle, rx_buffer, rx_buffer_size, &bytes_read, 500) != ESP_OK) {
|
||||
if (i2s_channel_read(i2s_tdm_rx_handle, echo_buffer, buffer_size, &bytes_read, 500) != ESP_OK) {
|
||||
break;
|
||||
}
|
||||
if (i2s_channel_write(i2s_tdm_tx_handle, rx_buffer, rx_buffer_size, &bytes_written, 500) != ESP_OK) {
|
||||
if (i2s_channel_write(i2s_tdm_tx_handle, echo_buffer, buffer_size, &bytes_written, 500) != ESP_OK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
unity_wait_for_signal("Master Finished");
|
||||
|
||||
ESP_LOGI(TAG, "I2S TDM slave receive stop");
|
||||
TEST_ESP_OK(i2s_channel_disable(i2s_tdm_rx_handle));
|
||||
TEST_ESP_OK(i2s_channel_disable(i2s_tdm_tx_handle));
|
||||
|
||||
ESP_LOGI(TAG, "Freeing I2S TDM slave buffer");
|
||||
free(rx_buffer);
|
||||
|
||||
ESP_LOGI(TAG, "Deleting i2s tx and rx channels");
|
||||
free(echo_buffer);
|
||||
TEST_ESP_OK(i2s_del_channel(i2s_tdm_rx_handle));
|
||||
TEST_ESP_OK(i2s_del_channel(i2s_tdm_tx_handle));
|
||||
ESP_LOGI(TAG, "I2S TDM slave resources freed");
|
||||
}
|
||||
|
||||
static void test_i2s_tdm_master_48k_32bits_4slots(void)
|
||||
@ -334,3 +270,125 @@ static void test_i2s_tdm_slave_96k_16bits_4slots(void)
|
||||
TEST_CASE_MULTIPLE_DEVICES("I2S_TDM_full_duplex_test_in_96k_16bits_4slots", "[I2S_TDM]",
|
||||
test_i2s_tdm_master_96k_16bits_4slots, test_i2s_tdm_slave_96k_16bits_4slots);
|
||||
#endif // !CONFIG_IDF_TARGET_ESP32H2
|
||||
|
||||
static void test_i2s_external_clk_src(bool is_master, bool is_external)
|
||||
{
|
||||
i2s_chan_handle_t tx_handle;
|
||||
i2s_chan_handle_t rx_handle;
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, is_master ? I2S_ROLE_MASTER : I2S_ROLE_SLAVE);
|
||||
TEST_ESP_OK(i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle));
|
||||
i2s_std_config_t std_cfg = {
|
||||
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(44100),
|
||||
.slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(16, I2S_SLOT_MODE_STEREO),
|
||||
.gpio_cfg = TEST_I2S_DEFAULT_GPIO(TEST_I2S_MCK_IO, is_master),
|
||||
};
|
||||
if (is_external) {
|
||||
std_cfg.clk_cfg.clk_src = I2S_CLK_SRC_EXTERNAL;
|
||||
std_cfg.clk_cfg.ext_clk_freq_hz = 11289600;
|
||||
}
|
||||
TEST_ESP_OK(i2s_channel_init_std_mode(tx_handle, &std_cfg));
|
||||
if (is_master && !is_external) {
|
||||
i2s_std_slot_config_t slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(16, I2S_SLOT_MODE_STEREO);
|
||||
memcpy(&std_cfg.slot_cfg, &slot_cfg, sizeof(i2s_std_slot_config_t));
|
||||
}
|
||||
TEST_ESP_OK(i2s_channel_init_std_mode(rx_handle, &std_cfg));
|
||||
|
||||
if (is_master) {
|
||||
if (!is_external) {
|
||||
// Delay bclk to get compensate the data delay
|
||||
I2S0.rx_timing.rx_bck_out_dm = 1;
|
||||
}
|
||||
uint8_t mst_tx_data[4] = {0x12, 0x34, 0x56, 0x78};
|
||||
size_t w_bytes = 4;
|
||||
while (w_bytes == 4) {
|
||||
ESP_ERROR_CHECK(i2s_channel_preload_data(tx_handle, mst_tx_data, 4, &w_bytes));
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t *recv_buff = (uint8_t *)calloc(1, TEST_I2S_ARRAY_LENGTH);
|
||||
TEST_ASSERT(recv_buff);
|
||||
|
||||
unity_send_signal(is_master ? "Master Ready" : "Slave Ready");
|
||||
unity_wait_for_signal(is_master ? "Slave Ready" : "Master Ready");
|
||||
if (is_external) {
|
||||
unity_wait_for_signal("External Clock Ready");
|
||||
}
|
||||
TEST_ESP_OK(i2s_channel_enable(tx_handle));
|
||||
TEST_ESP_OK(i2s_channel_enable(rx_handle));
|
||||
if (!is_external) {
|
||||
unity_send_signal("External Clock Ready");
|
||||
}
|
||||
|
||||
bool is_success = false;
|
||||
size_t bytes_read = 0;
|
||||
if (is_master) {
|
||||
if (is_external) {
|
||||
unity_send_signal("Master Data Ready");
|
||||
}
|
||||
// Wait the Slave data ready on line
|
||||
unity_wait_for_signal("Slave Data Ready");
|
||||
vTaskDelay(pdMS_TO_TICKS(100)); // Wait another 100 ms for the data to be steady in DMA buffer
|
||||
TEST_ESP_OK(i2s_channel_read(rx_handle, recv_buff, TEST_I2S_ARRAY_LENGTH, &bytes_read, 1000));
|
||||
} else {
|
||||
if (!is_external) {
|
||||
unity_wait_for_signal("Master Data Ready");
|
||||
}
|
||||
TEST_ESP_OK(i2s_channel_read(rx_handle, recv_buff, TEST_I2S_ARRAY_LENGTH, &bytes_read, 1000));
|
||||
// Fill the DMA buffer
|
||||
for (int i = 0; i < 6; i++) {
|
||||
TEST_ESP_OK(i2s_channel_write(tx_handle, recv_buff, TEST_I2S_ARRAY_LENGTH, &bytes_read, 1000));
|
||||
}
|
||||
// Send the signal indicates the data have been ready on line
|
||||
unity_send_signal("Slave Data Ready");
|
||||
}
|
||||
// Check the data
|
||||
for (int i = 0; i < TEST_I2S_ARRAY_LENGTH; i++) {
|
||||
if (recv_buff[i] == 0x12 && recv_buff[i + 1] == 0x34 &&
|
||||
recv_buff[i + 2] == 0x56 && recv_buff[i + 3] == 0x78) {
|
||||
is_success = true;
|
||||
break;
|
||||
}
|
||||
printf("%x ", recv_buff[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if (is_master) {
|
||||
unity_send_signal("Master Finished");
|
||||
} else {
|
||||
unity_wait_for_signal("Master Finished");
|
||||
}
|
||||
// Disable and free the resources
|
||||
TEST_ESP_OK(i2s_channel_disable(rx_handle));
|
||||
TEST_ESP_OK(i2s_channel_disable(tx_handle));
|
||||
free(recv_buff);
|
||||
TEST_ESP_OK(i2s_del_channel(rx_handle));
|
||||
TEST_ESP_OK(i2s_del_channel(tx_handle));
|
||||
// Assert whether the test success
|
||||
TEST_ASSERT(is_success);
|
||||
}
|
||||
|
||||
static void test_i2s_master_clock_out(void)
|
||||
{
|
||||
test_i2s_external_clk_src(true, false);
|
||||
}
|
||||
|
||||
static void test_i2s_slave_clock_in(void)
|
||||
{
|
||||
test_i2s_external_clk_src(false, true);
|
||||
}
|
||||
|
||||
TEST_CASE_MULTIPLE_DEVICES("I2S_external_clock_master_output_slave_input", "[I2S]",
|
||||
test_i2s_master_clock_out, test_i2s_slave_clock_in);
|
||||
|
||||
static void test_i2s_master_clock_in(void)
|
||||
{
|
||||
test_i2s_external_clk_src(true, true);
|
||||
}
|
||||
|
||||
static void test_i2s_slave_clock_out(void)
|
||||
{
|
||||
test_i2s_external_clk_src(false, false);
|
||||
}
|
||||
|
||||
TEST_CASE_MULTIPLE_DEVICES("I2S_external_clock_master_input_slave_output", "[I2S]",
|
||||
test_i2s_master_clock_in, test_i2s_slave_clock_out);
|
@ -11,5 +11,5 @@ import pytest
|
||||
@pytest.mark.parametrize('count', [
|
||||
2,
|
||||
], indirect=True)
|
||||
def test_i2s_tdm_full_duplex(case_tester) -> None: # type: ignore
|
||||
case_tester.run_all_cases(timeout=30)
|
||||
def test_i2s_multi_dev(case_tester) -> None: # type: ignore
|
||||
case_tester.run_all_multi_dev_cases(reset=True, timeout=30)
|
@ -207,6 +207,9 @@ static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
|
||||
case I2S_CLK_SRC_PLL_160M:
|
||||
hw->tx_clkm_conf.tx_clk_sel = 2;
|
||||
break;
|
||||
case I2S_CLK_SRC_EXTERNAL:
|
||||
hw->tx_clkm_conf.tx_clk_sel = 3;
|
||||
break;
|
||||
default:
|
||||
HAL_ASSERT(false && "unsupported clock source");
|
||||
break;
|
||||
@ -229,6 +232,9 @@ static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
|
||||
case I2S_CLK_SRC_PLL_160M:
|
||||
hw->rx_clkm_conf.rx_clk_sel = 2;
|
||||
break;
|
||||
case I2S_CLK_SRC_EXTERNAL:
|
||||
hw->rx_clkm_conf.rx_clk_sel = 3;
|
||||
break;
|
||||
default:
|
||||
HAL_ASSERT(false && "unsupported clock source");
|
||||
break;
|
||||
|
@ -217,6 +217,9 @@ static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
|
||||
case I2S_CLK_SRC_PLL_160M:
|
||||
PCR.i2s_tx_clkm_conf.i2s_tx_clkm_sel = 2;
|
||||
break;
|
||||
case I2S_CLK_SRC_EXTERNAL:
|
||||
PCR.i2s_tx_clkm_conf.i2s_tx_clkm_sel = 3;
|
||||
break;
|
||||
default:
|
||||
HAL_ASSERT(false && "unsupported clock source");
|
||||
break;
|
||||
@ -240,6 +243,9 @@ static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
|
||||
case I2S_CLK_SRC_PLL_160M:
|
||||
PCR.i2s_rx_clkm_conf.i2s_rx_clkm_sel = 2;
|
||||
break;
|
||||
case I2S_CLK_SRC_EXTERNAL:
|
||||
PCR.i2s_rx_clkm_conf.i2s_rx_clkm_sel = 3;
|
||||
break;
|
||||
default:
|
||||
HAL_ASSERT(false && "unsupported clock source");
|
||||
break;
|
||||
|
@ -221,6 +221,9 @@ static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
|
||||
case I2S_CLK_SRC_PLL_64M:
|
||||
PCR.i2s_tx_clkm_conf.i2s_tx_clkm_sel = 2;
|
||||
break;
|
||||
case I2S_CLK_SRC_EXTERNAL:
|
||||
PCR.i2s_tx_clkm_conf.i2s_tx_clkm_sel = 3;
|
||||
break;
|
||||
default:
|
||||
HAL_ASSERT(false && "unsupported clock source");
|
||||
break;
|
||||
@ -247,6 +250,9 @@ static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
|
||||
case I2S_CLK_SRC_PLL_64M:
|
||||
PCR.i2s_rx_clkm_conf.i2s_rx_clkm_sel = 2;
|
||||
break;
|
||||
case I2S_CLK_SRC_EXTERNAL:
|
||||
PCR.i2s_rx_clkm_conf.i2s_rx_clkm_sel = 3;
|
||||
break;
|
||||
default:
|
||||
HAL_ASSERT(false && "unsupported clock source");
|
||||
break;
|
||||
|
@ -208,6 +208,9 @@ static inline void i2s_ll_tx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
|
||||
case I2S_CLK_SRC_PLL_160M:
|
||||
hw->tx_clkm_conf.tx_clk_sel = 2;
|
||||
break;
|
||||
case I2S_CLK_SRC_EXTERNAL:
|
||||
hw->tx_clkm_conf.tx_clk_sel = 3;
|
||||
break;
|
||||
default:
|
||||
HAL_ASSERT(false && "unsupported clock source");
|
||||
break;
|
||||
@ -230,6 +233,9 @@ static inline void i2s_ll_rx_clk_set_src(i2s_dev_t *hw, i2s_clock_src_t src)
|
||||
case I2S_CLK_SRC_PLL_160M:
|
||||
hw->rx_clkm_conf.rx_clk_sel = 2;
|
||||
break;
|
||||
case I2S_CLK_SRC_EXTERNAL:
|
||||
hw->rx_clkm_conf.rx_clk_sel = 3;
|
||||
break;
|
||||
default:
|
||||
HAL_ASSERT(false && "unsupported clock source");
|
||||
break;
|
||||
|
@ -13,6 +13,7 @@
|
||||
const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
|
||||
{
|
||||
.mck_out_sig = -1, // Unavailable
|
||||
.mck_in_sig = -1, // Unavailable
|
||||
|
||||
.m_tx_bck_sig = I2S0O_BCK_OUT_IDX,
|
||||
.m_rx_bck_sig = I2S0I_BCK_OUT_IDX,
|
||||
@ -32,6 +33,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
|
||||
},
|
||||
{
|
||||
.mck_out_sig = -1, // Unavailable
|
||||
.mck_in_sig = -1, // Unavailable
|
||||
|
||||
.m_tx_bck_sig = I2S1O_BCK_OUT_IDX,
|
||||
.m_rx_bck_sig = I2S1I_BCK_OUT_IDX,
|
||||
|
@ -13,6 +13,7 @@
|
||||
const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
|
||||
{
|
||||
.mck_out_sig = I2S_MCLK_OUT_IDX,
|
||||
.mck_in_sig = I2S_MCLK_IN_IDX,
|
||||
|
||||
.m_tx_bck_sig = I2SO_BCK_OUT_IDX,
|
||||
.m_rx_bck_sig = I2SI_BCK_OUT_IDX,
|
||||
|
@ -216,7 +216,7 @@ typedef enum {
|
||||
/**
|
||||
* @brief Array initializer for all supported clock sources of I2S
|
||||
*/
|
||||
#define SOC_I2S_CLKS {SOC_MOD_CLK_PLL_F160M, SOC_MOD_CLK_XTAL}
|
||||
#define SOC_I2S_CLKS {SOC_MOD_CLK_PLL_F160M, SOC_MOD_CLK_XTAL, I2S_CLK_SRC_EXTERNAL}
|
||||
|
||||
/**
|
||||
* @brief I2S clock source enum
|
||||
@ -225,6 +225,7 @@ typedef enum {
|
||||
I2S_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default source clock */
|
||||
I2S_CLK_SRC_PLL_160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the source clock */
|
||||
I2S_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */
|
||||
I2S_CLK_SRC_EXTERNAL = -1, /*!< Select external clock as source clock */
|
||||
} soc_periph_i2s_clk_src_t;
|
||||
|
||||
/////////////////////////////////////////////////I2C////////////////////////////////////////////////////////////////////
|
||||
|
@ -13,6 +13,7 @@
|
||||
const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
|
||||
{
|
||||
.mck_out_sig = I2S_MCLK_OUT_IDX,
|
||||
.mck_in_sig = I2S_MCLK_IN_IDX,
|
||||
|
||||
.m_tx_bck_sig = I2SO_BCK_OUT_IDX,
|
||||
.m_rx_bck_sig = I2SI_BCK_OUT_IDX,
|
||||
|
@ -285,7 +285,7 @@ typedef enum {
|
||||
/**
|
||||
* @brief Array initializer for all supported clock sources of I2S
|
||||
*/
|
||||
#define SOC_I2S_CLKS {SOC_MOD_CLK_PLL_F160M, SOC_MOD_CLK_XTAL}
|
||||
#define SOC_I2S_CLKS {SOC_MOD_CLK_PLL_F160M, SOC_MOD_CLK_XTAL, I2S_CLK_SRC_EXTERNAL}
|
||||
|
||||
/**
|
||||
* @brief I2S clock source enum
|
||||
@ -294,6 +294,7 @@ typedef enum {
|
||||
I2S_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default source clock */
|
||||
I2S_CLK_SRC_PLL_160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the source clock */
|
||||
I2S_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */
|
||||
I2S_CLK_SRC_EXTERNAL = -1, /*!< Select external clock as source clock */
|
||||
} soc_periph_i2s_clk_src_t;
|
||||
|
||||
/////////////////////////////////////////////////I2C////////////////////////////////////////////////////////////////////
|
||||
|
@ -13,6 +13,7 @@
|
||||
const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
|
||||
{
|
||||
.mck_out_sig = I2S_MCLK_OUT_IDX,
|
||||
.mck_in_sig = I2S_MCLK_IN_IDX,
|
||||
|
||||
.m_tx_bck_sig = I2SO_BCK_OUT_IDX,
|
||||
.m_rx_bck_sig = I2SI_BCK_OUT_IDX,
|
||||
|
@ -283,7 +283,7 @@ typedef enum {
|
||||
/**
|
||||
* @brief Array initializer for all supported clock sources of I2S
|
||||
*/
|
||||
#define SOC_I2S_CLKS {SOC_MOD_CLK_PLL_F96M, SOC_MOD_CLK_PLL_F64M, SOC_MOD_CLK_XTAL}
|
||||
#define SOC_I2S_CLKS {SOC_MOD_CLK_PLL_F96M, SOC_MOD_CLK_PLL_F64M, SOC_MOD_CLK_XTAL, I2S_CLK_SRC_EXTERNAL}
|
||||
|
||||
/**
|
||||
* @brief I2S clock source enum
|
||||
@ -293,6 +293,7 @@ typedef enum {
|
||||
I2S_CLK_SRC_PLL_96M = SOC_MOD_CLK_PLL_F96M, /*!< Select PLL_F96M as the source clock */
|
||||
I2S_CLK_SRC_PLL_64M = SOC_MOD_CLK_PLL_F64M, /*!< Select PLL_F64M as the source clock */
|
||||
I2S_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */
|
||||
I2S_CLK_SRC_EXTERNAL = -1, /*!< Select external clock as source clock */
|
||||
} soc_periph_i2s_clk_src_t;
|
||||
|
||||
/////////////////////////////////////////////////I2C////////////////////////////////////////////////////////////////////
|
||||
|
@ -13,6 +13,7 @@
|
||||
const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
|
||||
{
|
||||
.mck_out_sig = CLK_I2S_MUX_IDX,
|
||||
.mck_in_sig = -1, // Unavailable
|
||||
|
||||
.m_tx_bck_sig = I2S0O_BCK_OUT_IDX,
|
||||
.m_rx_bck_sig = I2S0I_BCK_OUT_IDX,
|
||||
|
@ -13,6 +13,7 @@
|
||||
const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
|
||||
{
|
||||
.mck_out_sig = I2S0_MCLK_OUT_IDX,
|
||||
.mck_in_sig = I2S0_MCLK_IN_IDX,
|
||||
|
||||
.m_tx_bck_sig = I2S0O_BCK_OUT_IDX,
|
||||
.m_rx_bck_sig = I2S0I_BCK_OUT_IDX,
|
||||
@ -36,6 +37,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
|
||||
},
|
||||
{
|
||||
.mck_out_sig = I2S1_MCLK_OUT_IDX,
|
||||
.mck_in_sig = I2S1_MCLK_IN_IDX,
|
||||
|
||||
.m_tx_bck_sig = I2S1O_BCK_OUT_IDX,
|
||||
.m_rx_bck_sig = I2S1I_BCK_OUT_IDX,
|
||||
|
@ -275,7 +275,7 @@ typedef enum {
|
||||
/**
|
||||
* @brief Array initializer for all supported clock sources of I2S
|
||||
*/
|
||||
#define SOC_I2S_CLKS {SOC_MOD_CLK_PLL_F160M, SOC_MOD_CLK_XTAL}
|
||||
#define SOC_I2S_CLKS {SOC_MOD_CLK_PLL_F160M, SOC_MOD_CLK_XTAL, I2S_CLK_SRC_EXTERNAL}
|
||||
|
||||
/**
|
||||
* @brief I2S clock source enum
|
||||
@ -284,6 +284,7 @@ typedef enum {
|
||||
I2S_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the default source clock */
|
||||
I2S_CLK_SRC_PLL_160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_F160M as the source clock */
|
||||
I2S_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */
|
||||
I2S_CLK_SRC_EXTERNAL = -1, /*!< Select external clock as source clock */
|
||||
} soc_periph_i2s_clk_src_t;
|
||||
|
||||
/////////////////////////////////////////////////I2C////////////////////////////////////////////////////////////////////
|
||||
|
@ -24,6 +24,7 @@ extern "C" {
|
||||
*/
|
||||
typedef struct {
|
||||
const uint8_t mck_out_sig;
|
||||
const uint8_t mck_in_sig;
|
||||
|
||||
const uint8_t m_tx_bck_sig;
|
||||
const uint8_t m_rx_bck_sig;
|
||||
|
Loading…
Reference in New Issue
Block a user