Merge branch 'feature/support_i2s_on_p4' into 'master'

feat(i2s): support i2s on esp32p4

Closes IDF-6508

See merge request espressif/esp-idf!24280
This commit is contained in:
Kevin (Lao Kaiyao) 2023-09-29 00:50:04 +08:00
commit 4c6f4b39f1
58 changed files with 2560 additions and 736 deletions

View File

@ -111,6 +111,7 @@ endif()
# I2S related source files
if(CONFIG_SOC_I2S_SUPPORTED)
list(APPEND srcs "i2s/i2s_common.c"
"i2s/i2s_platform.c"
"i2s/i2s_std.c"
"deprecated/i2s_legacy.c")
if(CONFIG_SOC_I2S_SUPPORTS_PDM)
@ -236,7 +237,7 @@ else()
# Can be removed together with legacy drivers)
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS ${includes}
PRIV_REQUIRES efuse esp_timer
PRIV_REQUIRES efuse esp_timer esp_mm
REQUIRES esp_pm esp_ringbuf freertos soc hal esp_hw_support
LDFRAGMENTS ${ldfragments}
)

View File

@ -17,6 +17,7 @@
#include "hal/adc_ll.h"
#include "hal/i2s_hal.h"
#include "hal/i2s_types.h"
#include "hal/clk_tree_ll.h"
#include "soc/i2s_periph.h"
#include "../dac_priv_dma.h"
#include "esp_private/i2s_platform.h"
@ -46,7 +47,7 @@ static const char *TAG = "DAC_DMA";
static uint32_t s_dac_set_apll_freq(uint32_t mclk)
{
/* Calculate the expected APLL */
int div = (int)((SOC_APLL_MIN_HZ / mclk) + 1);
int div = (int)((CLK_LL_APLL_MIN_HZ / mclk) + 1);
/* apll_freq = mclk * div
* when div = 1, hardware will still divide 2
* when div = 0, hardware will divide 255

View File

@ -19,6 +19,7 @@
#include "hal/dac_ll.h"
#include "hal/adc_ll.h"
#include "hal/hal_utils.h"
#include "hal/clk_tree_ll.h"
#include "soc/lldesc.h"
#include "soc/soc.h"
#include "soc/soc_caps.h"
@ -75,9 +76,9 @@ static esp_err_t s_dac_dma_periph_set_clock(uint32_t freq_hz, bool is_apll){
uint32_t digi_ctrl_freq; // Digital controller clock
if (is_apll) {
/* Theoretical frequency range (due to the limitation of DAC, the maximum frequency may not reach):
* SOC_APLL_MAX_HZ: 119.24 Hz ~ 67.5 MHz
* SOC_APLL_MIN_HZ: 5.06 Hz ~ 2.65 MHz */
digi_ctrl_freq = s_dac_set_apll_freq(freq_hz < 120 ? SOC_APLL_MIN_HZ :SOC_APLL_MAX_HZ);
* CLK_LL_APLL_MAX_HZ: 119.24 Hz ~ 67.5 MHz
* CLK_LL_APLL_MIN_HZ: 5.06 Hz ~ 2.65 MHz */
digi_ctrl_freq = s_dac_set_apll_freq(freq_hz < 120 ? CLK_LL_APLL_MIN_HZ :CLK_LL_APLL_MAX_HZ);
ESP_RETURN_ON_FALSE(digi_ctrl_freq, ESP_ERR_INVALID_ARG, TAG, "set APLL coefficients failed");
} else {
digi_ctrl_freq = APB_CLK_FREQ;

View File

@ -25,6 +25,10 @@
#include "hal/gpio_hal.h"
#include "driver/i2s_types_legacy.h"
#include "hal/i2s_hal.h"
#if SOC_I2S_SUPPORTS_APLL
#include "hal/clk_tree_ll.h"
#endif
#if SOC_I2S_SUPPORTS_DAC
#include "hal/dac_ll.h"
#include "hal/dac_types.h"
@ -48,6 +52,7 @@
#include "esp_pm.h"
#include "esp_efuse.h"
#include "esp_rom_gpio.h"
#include "esp_private/i2s_platform.h"
#include "esp_private/periph_ctrl.h"
#include "esp_private/esp_clk.h"
@ -58,6 +63,18 @@ static const char *TAG = "i2s(legacy)";
#define I2S_ENTER_CRITICAL(i2s_num) portENTER_CRITICAL(&i2s_spinlock[i2s_num])
#define I2S_EXIT_CRITICAL(i2s_num) portEXIT_CRITICAL(&i2s_spinlock[i2s_num])
#if SOC_PERIPH_CLK_CTRL_SHARED
#define I2S_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC()
#else
#define I2S_CLOCK_SRC_ATOMIC()
#endif
#if !SOC_RCC_IS_INDEPENDENT
#define I2S_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
#else
#define I2S_RCC_ATOMIC()
#endif
#define I2S_DMA_BUFFER_MAX_SIZE 4092
#if SOC_I2S_SUPPORTS_ADC_DAC
@ -134,9 +151,6 @@ typedef struct {
uint32_t total_slot; /*!< Total slot number */
} i2s_obj_t;
// Record the component name that using I2S peripheral
static const char *comp_using_i2s[SOC_I2S_NUM] = {[0 ... SOC_I2S_NUM - 1] = NULL};
// Global I2S object pointer
static i2s_obj_t *p_i2s[SOC_I2S_NUM] = {
[0 ... SOC_I2S_NUM - 1] = NULL,
@ -147,11 +161,6 @@ static portMUX_TYPE i2s_spinlock[SOC_I2S_NUM] = {
[0 ... SOC_I2S_NUM - 1] = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED,
};
__attribute__((weak)) esp_err_t i2s_platform_acquire_occupation(int id, const char *comp_name);
__attribute__((weak)) esp_err_t i2s_platform_release_occupation(int id);
/*-------------------------------------------------------------
I2S DMA operation
-------------------------------------------------------------*/
@ -633,7 +642,7 @@ static uint32_t i2s_config_source_clock(i2s_port_t i2s_num, bool use_apll, uint3
#if SOC_I2S_SUPPORTS_APLL
if (use_apll) {
/* Calculate the expected APLL */
int div = (int)((SOC_APLL_MIN_HZ / mclk) + 1);
int div = (int)((CLK_LL_APLL_MIN_HZ / mclk) + 1);
/* apll_freq = mclk * div
* when div = 1, hardware will still divide 2
* when div = 0, the final mclk will be unpredictable
@ -654,12 +663,12 @@ static uint32_t i2s_config_source_clock(i2s_port_t i2s_num, bool use_apll, uint3
/* In APLL mode, there is no sclk but only mclk, so return 0 here to indicate APLL mode */
return real_freq;
}
return I2S_LL_DEFAULT_PLL_CLK_FREQ;
return I2S_LL_DEFAULT_CLK_FREQ;
#else
if (use_apll) {
ESP_LOGW(TAG, "APLL not supported on current chip, use I2S_CLK_SRC_DEFAULT as default clock source");
}
return I2S_LL_DEFAULT_PLL_CLK_FREQ;
return I2S_LL_DEFAULT_CLK_FREQ;
#endif
}
@ -1021,11 +1030,13 @@ static void i2s_set_clock_legacy(i2s_port_t i2s_num)
i2s_clk_config_t *clk_cfg = &p_i2s[i2s_num]->clk_cfg;
i2s_hal_clock_info_t clk_info;
i2s_calculate_clock(i2s_num, &clk_info);
if (p_i2s[i2s_num]->dir & I2S_DIR_TX) {
i2s_hal_set_tx_clock(&(p_i2s[i2s_num]->hal), &clk_info, clk_cfg->clk_src);
}
if (p_i2s[i2s_num]->dir & I2S_DIR_RX) {
i2s_hal_set_rx_clock(&(p_i2s[i2s_num]->hal), &clk_info, clk_cfg->clk_src);
I2S_CLOCK_SRC_ATOMIC() {
if (p_i2s[i2s_num]->dir & I2S_DIR_TX) {
i2s_hal_set_tx_clock(&(p_i2s[i2s_num]->hal), &clk_info, clk_cfg->clk_src);
}
if (p_i2s[i2s_num]->dir & I2S_DIR_RX) {
i2s_hal_set_rx_clock(&(p_i2s[i2s_num]->hal), &clk_info, clk_cfg->clk_src);
}
}
}
@ -1479,17 +1490,6 @@ static esp_err_t i2s_init_legacy(i2s_port_t i2s_num, int intr_alloc_flag)
ESP_RETURN_ON_ERROR(i2s_realloc_dma_buffer(i2s_num, p_i2s[i2s_num]->rx), TAG, "Allocate I2S dma rx buffer failed");
}
/* Initialize I2S DMA object */
#if SOC_I2S_HW_VERSION_2
/* Enable tx/rx submodule clock */
if (p_i2s[i2s_num]->dir & I2S_DIR_TX) {
i2s_ll_tx_enable_clock(p_i2s[i2s_num]->hal.dev);
}
if (p_i2s[i2s_num]->dir & I2S_DIR_RX) {
i2s_ll_rx_enable_clock(p_i2s[i2s_num]->hal.dev);
}
#endif
return ESP_OK;
}
@ -1538,12 +1538,14 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num)
#if SOC_I2S_SUPPORTS_APLL
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_SRC_DEFAULT);
}
if (obj->dir & I2S_DIR_RX) {
i2s_ll_rx_clk_set_src(obj->hal.dev, I2S_CLK_SRC_DEFAULT);
I2S_CLOCK_SRC_ATOMIC() {
// switch back to PLL clock source
if (obj->dir & I2S_DIR_TX) {
i2s_hal_set_tx_clock(&obj->hal, NULL, I2S_CLK_SRC_DEFAULT);
}
if (obj->dir & I2S_DIR_RX) {
i2s_hal_set_rx_clock(&obj->hal, NULL, I2S_CLK_SRC_DEFAULT);
}
}
periph_rtc_apll_release();
}
@ -1556,11 +1558,13 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num)
}
#endif
#if SOC_I2S_HW_VERSION_2
if (obj->dir & I2S_DIR_TX) {
i2s_ll_tx_disable_clock(obj->hal.dev);
}
if (obj->dir & I2S_DIR_RX) {
i2s_ll_rx_disable_clock(obj->hal.dev);
I2S_CLOCK_SRC_ATOMIC() {
if (obj->dir & I2S_DIR_TX) {
i2s_ll_tx_disable_clock(obj->hal.dev);
}
if (obj->dir & I2S_DIR_RX) {
i2s_ll_rx_disable_clock(obj->hal.dev);
}
}
#endif
/* Disable module clock */
@ -1896,37 +1900,6 @@ esp_err_t i2s_set_pin(i2s_port_t i2s_num, const i2s_pin_config_t *pin)
return ESP_OK;
}
esp_err_t i2s_platform_acquire_occupation(int id, const char *comp_name)
{
esp_err_t ret = ESP_ERR_NOT_FOUND;
ESP_RETURN_ON_FALSE(id < SOC_I2S_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid i2s port id");
portENTER_CRITICAL(&i2s_spinlock[id]);
if (!comp_using_i2s[id]) {
ret = ESP_OK;
comp_using_i2s[id] = comp_name;
periph_module_enable(i2s_periph_signal[id].module);
i2s_ll_enable_clock(I2S_LL_GET_HW(id));
}
portEXIT_CRITICAL(&i2s_spinlock[id]);
return ret;
}
esp_err_t i2s_platform_release_occupation(int id)
{
esp_err_t ret = ESP_ERR_INVALID_STATE;
ESP_RETURN_ON_FALSE(id < SOC_I2S_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid i2s port id");
portENTER_CRITICAL(&i2s_spinlock[id]);
if (comp_using_i2s[id]) {
ret = ESP_OK;
comp_using_i2s[id] = NULL;
/* Disable module clock */
periph_module_disable(i2s_periph_signal[id].module);
i2s_ll_disable_clock(I2S_LL_GET_HW(id));
}
portEXIT_CRITICAL(&i2s_spinlock[id]);
return ret;
}
/**
* @brief This function will be called during start up, to check that the new i2s driver is not running along with the legacy i2s driver
*/

View File

@ -25,17 +25,21 @@
#include "soc/soc_caps.h"
#include "hal/gpio_hal.h"
#include "hal/i2s_hal.h"
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"
#endif
#if SOC_I2S_SUPPORTS_ADC_DAC
#include "hal/adc_ll.h"
#include "driver/adc_i2s_legacy.h"
#endif
#if SOC_I2S_SUPPORTS_APLL
#include "hal/clk_tree_ll.h"
#include "clk_ctrl_os.h"
#endif
#include "esp_private/i2s_platform.h"
#include "esp_private/periph_ctrl.h"
#include "esp_private/esp_clk.h"
#include "driver/gpio.h"
@ -47,6 +51,10 @@
#include "esp_intr_alloc.h"
#include "esp_check.h"
#include "esp_attr.h"
#include "esp_dma_utils.h"
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
#include "esp_cache.h"
#endif
#include "esp_rom_gpio.h"
#include "esp_memory_utils.h"
@ -55,18 +63,15 @@
* Set 4092 here to align with 4-byte, so that the position of the slot data in the buffer will be relatively fixed */
#define I2S_DMA_BUFFER_MAX_SIZE (4092)
/**
* @brief Global i2s platform object
* @note For saving all the I2S related information
*/
i2s_platform_t g_i2s = {
.spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED,
.controller[0 ... (SOC_I2S_NUM - 1)] = NULL, // groups will be lazy installed
.comp_name[0 ... (SOC_I2S_NUM - 1)] = NULL,
};
static const char *TAG = "i2s_common";
__attribute__((always_inline))
inline void *i2s_dma_calloc(size_t num, size_t size, uint32_t caps, size_t *actual_size) {
void *ptr = NULL;
esp_dma_calloc(num, size, caps, &ptr, actual_size);
return ptr;
}
/*---------------------------------------------------------------------------
I2S Static APIs
----------------------------------------------------------------------------
@ -261,6 +266,7 @@ static esp_err_t i2s_register_channel(i2s_controller_t *i2s_obj, i2s_dir_t dir,
new_chan->callbacks.on_send_q_ovf = NULL;
new_chan->dma.rw_pos = 0;
new_chan->dma.curr_ptr = NULL;
new_chan->dma.curr_desc = NULL;
new_chan->start = NULL;
new_chan->stop = NULL;
@ -292,6 +298,11 @@ err:
return ret;
}
#ifndef __cplusplus
/* To make sure the i2s_event_callbacks_t is same size as i2s_event_callbacks_internal_t */
_Static_assert(sizeof(i2s_event_callbacks_t) == sizeof(i2s_event_callbacks_internal_t), "Invalid size of i2s_event_callbacks_t structure");
#endif
esp_err_t i2s_channel_register_event_callback(i2s_chan_handle_t handle, const i2s_event_callbacks_t *callbacks, void *user_data)
{
I2S_NULL_POINTER_CHECK(TAG, handle);
@ -330,6 +341,26 @@ uint32_t i2s_get_buf_size(i2s_chan_handle_t handle, uint32_t data_bit_width, uin
uint32_t bytes_per_sample = ((data_bit_width + 15) / 16) * 2;
uint32_t bytes_per_frame = bytes_per_sample * active_chan;
uint32_t bufsize = dma_frame_num * bytes_per_frame;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
/* bufsize need to align with cache line size */
uint32_t alignment = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA);
uint32_t aligned_frame_num = dma_frame_num;
/* To make the buffer aligned with the cache line size, search for the ceil aligned size first,
If the buffer size exceed the max DMA buffer size, toggle the sign to search for the floor aligned size */
for (int sign = 1; bufsize % alignment != 0; aligned_frame_num += sign) {
bufsize = aligned_frame_num * bytes_per_frame;
/* If the buffer size exceed the max dma size */
if (bufsize > I2S_DMA_BUFFER_MAX_SIZE) {
sign = -1; // toggle the search sign
aligned_frame_num = dma_frame_num; // Reset the frame num
bufsize = aligned_frame_num * bytes_per_frame; // Reset the bufsize
}
}
if (bufsize / bytes_per_frame != dma_frame_num) {
ESP_LOGW(TAG, "dma frame num is adjusted to %"PRIu32" to algin the dma buffer with %"PRIu32
", bufsize = %"PRIu32, bufsize / bytes_per_frame, alignment, bufsize);
}
#endif
/* Limit DMA buffer size if it is out of range (DMA buffer limitation is 4092 bytes) */
if (bufsize > I2S_DMA_BUFFER_MAX_SIZE) {
uint32_t frame_num = I2S_DMA_BUFFER_MAX_SIZE / bytes_per_frame;
@ -348,18 +379,21 @@ esp_err_t i2s_free_dma_desc(i2s_chan_handle_t handle)
for (int i = 0; i < handle->dma.desc_num; i++) {
if (handle->dma.bufs[i]) {
free(handle->dma.bufs[i]);
handle->dma.bufs[i] = NULL;
}
if (handle->dma.desc[i]) {
free(handle->dma.desc[i]);
handle->dma.desc[i] = NULL;
}
}
if (handle->dma.bufs) {
free(handle->dma.bufs);
handle->dma.bufs = NULL;
}
if (handle->dma.desc) {
free(handle->dma.desc);
handle->dma.desc = NULL;
}
handle->dma.desc = NULL;
return ESP_OK;
}
@ -376,9 +410,10 @@ esp_err_t i2s_alloc_dma_desc(i2s_chan_handle_t handle, uint32_t num, uint32_t bu
handle->dma.desc = (lldesc_t **)heap_caps_calloc(num, sizeof(lldesc_t *), I2S_MEM_ALLOC_CAPS);
ESP_GOTO_ON_FALSE(handle->dma.desc, ESP_ERR_NO_MEM, err, TAG, "create I2S DMA decriptor array failed");
handle->dma.bufs = (uint8_t **)heap_caps_calloc(num, sizeof(uint8_t *), I2S_MEM_ALLOC_CAPS);
size_t desc_size = 0;
for (int i = 0; i < num; i++) {
/* Allocate DMA descriptor */
handle->dma.desc[i] = (lldesc_t *) heap_caps_calloc(1, sizeof(lldesc_t), I2S_DMA_ALLOC_CAPS);
handle->dma.desc[i] = (lldesc_t *) i2s_dma_calloc(1, sizeof(lldesc_t), I2S_DMA_ALLOC_CAPS, &desc_size);
ESP_GOTO_ON_FALSE(handle->dma.desc[i], ESP_ERR_NO_MEM, err, TAG, "allocate DMA description failed");
handle->dma.desc[i]->owner = 1;
handle->dma.desc[i]->eof = 1;
@ -386,15 +421,18 @@ esp_err_t i2s_alloc_dma_desc(i2s_chan_handle_t handle, uint32_t num, uint32_t bu
handle->dma.desc[i]->length = bufsize;
handle->dma.desc[i]->size = bufsize;
handle->dma.desc[i]->offset = 0;
handle->dma.bufs[i] = (uint8_t *) heap_caps_calloc(1, bufsize * sizeof(uint8_t), I2S_DMA_ALLOC_CAPS);
handle->dma.bufs[i] = (uint8_t *) i2s_dma_calloc(1, bufsize * sizeof(uint8_t), I2S_DMA_ALLOC_CAPS, NULL);
ESP_GOTO_ON_FALSE(handle->dma.bufs[i], ESP_ERR_NO_MEM, err, TAG, "allocate DMA buffer failed");
handle->dma.desc[i]->buf = handle->dma.bufs[i];
ESP_GOTO_ON_FALSE(handle->dma.desc[i]->buf, ESP_ERR_NO_MEM, err, TAG, "allocate DMA buffer failed");
ESP_LOGV(TAG, "desc addr: %8p\tbuffer addr:%8p", handle->dma.desc[i], handle->dma.bufs[i]);
}
/* Connect DMA descriptor as a circle */
for (int i = 0; i < num; i++) {
/* Link to the next descriptor */
STAILQ_NEXT(handle->dma.desc[i], qe) = (i < (num - 1)) ? (handle->dma.desc[i + 1]) : handle->dma.desc[0];
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
esp_cache_msync(handle->dma.desc[i], desc_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
#endif
}
if (handle->dir == I2S_DIR_RX) {
i2s_ll_rx_set_eof_num(handle->controller->hal.dev, bufsize);
@ -410,14 +448,14 @@ err:
static uint32_t i2s_set_get_apll_freq(uint32_t mclk_freq_hz)
{
/* Calculate the expected APLL */
int mclk_div = (int)((SOC_APLL_MIN_HZ / mclk_freq_hz) + 1);
int mclk_div = (int)((CLK_LL_APLL_MIN_HZ / mclk_freq_hz) + 1);
/* apll_freq = mclk * div
* when div = 1, hardware will still divide 2
* when div = 0, the final mclk will be unpredictable
* So the div here should be at least 2 */
mclk_div = mclk_div < 2 ? 2 : mclk_div;
uint32_t expt_freq = mclk_freq_hz * mclk_div;
if (expt_freq > SOC_APLL_MAX_HZ) {
if (expt_freq > CLK_LL_APLL_MAX_HZ) {
ESP_LOGE(TAG, "The required APLL frequency exceed its maximum value");
return 0;
}
@ -459,6 +497,9 @@ static bool IRAM_ATTR i2s_dma_rx_callback(gdma_channel_handle_t dma_chan, gdma_e
uint32_t dummy;
finish_desc = (lldesc_t *)event_data->rx_eof_desc_addr;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
esp_cache_msync((void *)finish_desc->buf, handle->dma.buf_size, ESP_CACHE_MSYNC_FLAG_INVALIDATE);
#endif
i2s_event_data_t evt = {
.data = &(finish_desc->buf),
.size = handle->dma.buf_size,
@ -487,7 +528,7 @@ static bool IRAM_ATTR i2s_dma_tx_callback(gdma_channel_handle_t dma_chan, gdma_e
lldesc_t *finish_desc;
uint32_t dummy;
finish_desc = (lldesc_t *)(event_data->tx_eof_desc_addr);
finish_desc = (lldesc_t *)event_data->tx_eof_desc_addr;
i2s_event_data_t evt = {
.data = &(finish_desc->buf),
.size = handle->dma.buf_size,
@ -505,6 +546,9 @@ static bool IRAM_ATTR i2s_dma_tx_callback(gdma_channel_handle_t dma_chan, gdma_e
if (handle->dma.auto_clear) {
uint8_t *sent_buf = (uint8_t *)finish_desc->buf;
memset(sent_buf, 0, handle->dma.buf_size);
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
esp_cache_msync(sent_buf, handle->dma.buf_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
#endif
}
xQueueSendFromISR(handle->msg_queue, &(finish_desc->buf), &need_yield2);
@ -646,7 +690,7 @@ esp_err_t i2s_init_dma_intr(i2s_chan_handle_t handle, int intr_flag)
gdma_register_rx_event_callbacks(handle->dma.dma_chan, &cb, handle);
}
#else
intr_flag |= ESP_INTR_FLAG_SHARED;
intr_flag |= handle->intr_prio_flags;
/* Initialize I2S module interrupt */
if (handle->dir == I2S_DIR_TX) {
esp_intr_alloc_intrstatus(i2s_periph_signal[port_id].irq, intr_flag,
@ -663,10 +707,10 @@ esp_err_t i2s_init_dma_intr(i2s_chan_handle_t handle, int intr_flag)
return ESP_OK;
}
void i2s_gpio_check_and_set(gpio_num_t gpio, uint32_t signal_idx, bool is_input, bool is_invert)
void i2s_gpio_check_and_set(int gpio, uint32_t signal_idx, bool is_input, bool is_invert)
{
/* Ignore the pin if pin = I2S_GPIO_UNUSED */
if (gpio != I2S_GPIO_UNUSED) {
if (gpio != (int)I2S_GPIO_UNUSED) {
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO);
if (is_input) {
/* Set direction, for some GPIOs, the input function are not enabled as default */
@ -679,9 +723,9 @@ void i2s_gpio_check_and_set(gpio_num_t gpio, uint32_t signal_idx, bool is_input,
}
}
void i2s_gpio_loopback_set(gpio_num_t gpio, uint32_t out_sig_idx, uint32_t in_sig_idx)
void i2s_gpio_loopback_set(int gpio, uint32_t out_sig_idx, uint32_t in_sig_idx)
{
if (gpio != I2S_GPIO_UNUSED) {
if (gpio != (int)I2S_GPIO_UNUSED) {
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO);
gpio_set_direction(gpio, GPIO_MODE_INPUT_OUTPUT);
esp_rom_gpio_connect_out_signal(gpio, out_sig_idx, 0, 0);
@ -689,9 +733,9 @@ 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, i2s_clock_src_t clk_src, bool is_invert)
esp_err_t i2s_check_set_mclk(i2s_port_t id, int gpio_num, i2s_clock_src_t clk_src, bool is_invert)
{
if (gpio_num == I2S_GPIO_UNUSED) {
if (gpio_num == (int)I2S_GPIO_UNUSED) {
return ESP_OK;
}
#if CONFIG_IDF_TARGET_ESP32
@ -740,6 +784,7 @@ esp_err_t i2s_new_channel(const i2s_chan_config_t *chan_cfg, i2s_chan_handle_t *
I2S_NULL_POINTER_CHECK(TAG, tx_handle || rx_handle);
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_RETURN_ON_FALSE(chan_cfg->intr_priority >= 0 && chan_cfg->intr_priority <= 7, ESP_ERR_INVALID_ARG, TAG, "intr_priority should be within 0~7");
esp_err_t ret = ESP_OK;
i2s_controller_t *i2s_obj = NULL;
@ -771,6 +816,7 @@ esp_err_t i2s_new_channel(const i2s_chan_config_t *chan_cfg, i2s_chan_handle_t *
ESP_GOTO_ON_ERROR(i2s_register_channel(i2s_obj, I2S_DIR_TX, chan_cfg->dma_desc_num),
err, TAG, "register I2S tx channel failed");
i2s_obj->tx_chan->role = chan_cfg->role;
i2s_obj->tx_chan->intr_prio_flags = chan_cfg->intr_priority ? BIT(chan_cfg->intr_priority) : ESP_INTR_FLAG_LOWMED;
i2s_obj->tx_chan->dma.auto_clear = chan_cfg->auto_clear;
i2s_obj->tx_chan->dma.desc_num = chan_cfg->dma_desc_num;
i2s_obj->tx_chan->dma.frame_num = chan_cfg->dma_frame_num;
@ -784,6 +830,7 @@ esp_err_t i2s_new_channel(const i2s_chan_config_t *chan_cfg, i2s_chan_handle_t *
ESP_GOTO_ON_ERROR(i2s_register_channel(i2s_obj, I2S_DIR_RX, chan_cfg->dma_desc_num),
err, TAG, "register I2S rx channel failed");
i2s_obj->rx_chan->role = chan_cfg->role;
i2s_obj->rx_chan->intr_prio_flags = chan_cfg->intr_priority ? BIT(chan_cfg->intr_priority) : ESP_INTR_FLAG_LOWMED;
i2s_obj->rx_chan->dma.desc_num = chan_cfg->dma_desc_num;
i2s_obj->rx_chan->dma.frame_num = chan_cfg->dma_frame_num;
i2s_obj->rx_chan->start = i2s_rx_channel_start;
@ -821,10 +868,12 @@ esp_err_t i2s_del_channel(i2s_chan_handle_t handle)
bool is_bound = true;
#if SOC_I2S_HW_VERSION_2
if (dir == I2S_DIR_TX) {
i2s_ll_tx_disable_clock(handle->controller->hal.dev);
} else {
i2s_ll_rx_disable_clock(handle->controller->hal.dev);
I2S_CLOCK_SRC_ATOMIC() {
if (dir == I2S_DIR_TX) {
i2s_ll_tx_disable_clock(handle->controller->hal.dev);
} else {
i2s_ll_rx_disable_clock(handle->controller->hal.dev);
}
}
#endif
#if SOC_I2S_SUPPORTS_APLL
@ -978,6 +1027,7 @@ esp_err_t i2s_channel_disable(i2s_chan_handle_t handle)
xSemaphoreTake(handle->binary, portMAX_DELAY);
/* Reset the descriptor pointer */
handle->dma.curr_ptr = NULL;
handle->dma.curr_desc = NULL;
handle->dma.rw_pos = 0;
handle->stop(handle);
#if CONFIG_PM_ENABLE
@ -1005,11 +1055,11 @@ esp_err_t i2s_channel_preload_data(i2s_chan_handle_t tx_handle, const void *src,
xSemaphoreTake(tx_handle->mutex, portMAX_DELAY);
/* The pre-load data will be loaded from the first descriptor */
if (tx_handle->dma.curr_ptr == NULL) {
tx_handle->dma.curr_ptr = tx_handle->dma.desc[0];
if (tx_handle->dma.curr_desc == NULL) {
tx_handle->dma.curr_desc = tx_handle->dma.desc[0];
tx_handle->dma.curr_ptr = (void *)tx_handle->dma.desc[0]->buf;
tx_handle->dma.rw_pos = 0;
}
lldesc_t *desc_ptr = (lldesc_t *)tx_handle->dma.curr_ptr;
/* Loop until no bytes in source buff remain or the descriptors are full */
while (remain_bytes) {
@ -1020,7 +1070,10 @@ esp_err_t i2s_channel_preload_data(i2s_chan_handle_t tx_handle, const void *src,
break;
}
/* Load the data from the last loaded position */
memcpy((uint8_t *)(desc_ptr->buf + tx_handle->dma.rw_pos), data_ptr, bytes_can_load);
memcpy((uint8_t *)(tx_handle->dma.curr_ptr + tx_handle->dma.rw_pos), data_ptr, bytes_can_load);
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
esp_cache_msync(tx_handle->dma.curr_ptr + tx_handle->dma.rw_pos, bytes_can_load, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
#endif
data_ptr += bytes_can_load; // Move forward the data pointer
total_loaded_bytes += bytes_can_load; // Add to the total loaded bytes
remain_bytes -= bytes_can_load; // Update the remaining bytes to be loaded
@ -1030,9 +1083,9 @@ esp_err_t i2s_channel_preload_data(i2s_chan_handle_t tx_handle, const void *src,
/* If the next descriptor is not the first descriptor, keep load to the first descriptor
* otherwise all descriptor has been loaded, break directly, the dma buffer position
* will remain at the end of the last dma buffer */
if (STAILQ_NEXT(desc_ptr, qe) != tx_handle->dma.desc[0]) {
desc_ptr = STAILQ_NEXT(desc_ptr, qe);
tx_handle->dma.curr_ptr = (void *)desc_ptr;
if (STAILQ_NEXT((lldesc_t *)tx_handle->dma.curr_desc, qe) != tx_handle->dma.desc[0]) {
tx_handle->dma.curr_desc = STAILQ_NEXT((lldesc_t *)tx_handle->dma.curr_desc, qe);
tx_handle->dma.curr_ptr = (void *)(((lldesc_t *)tx_handle->dma.curr_desc)->buf);
tx_handle->dma.rw_pos = 0;
} else {
break;
@ -1077,6 +1130,9 @@ esp_err_t i2s_channel_write(i2s_chan_handle_t handle, const void *src, size_t si
bytes_can_write = size;
}
memcpy(data_ptr, src_byte, bytes_can_write);
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
esp_cache_msync(data_ptr, bytes_can_write, ESP_CACHE_MSYNC_FLAG_DIR_C2M);
#endif
size -= bytes_can_write;
src_byte += bytes_can_write;
handle->dma.rw_pos += bytes_can_write;
@ -1131,55 +1187,24 @@ esp_err_t i2s_channel_read(i2s_chan_handle_t handle, void *dest, size_t size, si
return ret;
}
/*---------------------------------------------------------------------------
I2S Platform APIs
----------------------------------------------------------------------------
Scope: This file and ADC/DAC/LCD driver
----------------------------------------------------------------------------*/
esp_err_t i2s_platform_acquire_occupation(int id, const char *comp_name)
#if SOC_I2S_SUPPORTS_TX_SYNC_CNT
uint32_t i2s_sync_get_bclk_count(i2s_chan_handle_t tx_handle)
{
esp_err_t ret = ESP_OK;
const char *occupied_comp = NULL;
ESP_RETURN_ON_FALSE(id < SOC_I2S_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid i2s port id");
portENTER_CRITICAL(&g_i2s.spinlock);
if ((!g_i2s.controller[id]) && (g_i2s.comp_name[id] == NULL)) {
g_i2s.comp_name[id] = comp_name;
/* Enable module clock */
periph_module_enable(i2s_periph_signal[id].module);
i2s_ll_enable_clock(I2S_LL_GET_HW(id));
} else {
occupied_comp = g_i2s.comp_name[id];
ret = ESP_ERR_NOT_FOUND;
}
portEXIT_CRITICAL(&g_i2s.spinlock);
if (occupied_comp != NULL) {
ESP_LOGW(TAG, "i2s controller %d has been occupied by %s", id, occupied_comp);
}
return ret;
return i2s_ll_tx_get_bclk_sync_count(tx_handle->controller->hal.dev);
}
esp_err_t i2s_platform_release_occupation(int id)
uint32_t i2s_sync_get_fifo_count(i2s_chan_handle_t tx_handle)
{
esp_err_t ret = ESP_OK;
ESP_RETURN_ON_FALSE(id < SOC_I2S_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid i2s port id");
portENTER_CRITICAL(&g_i2s.spinlock);
if (!g_i2s.controller[id]) {
g_i2s.comp_name[id] = NULL;
/* Disable module clock */
periph_module_disable(i2s_periph_signal[id].module);
i2s_ll_disable_clock(I2S_LL_GET_HW(id));
} else {
ret = ESP_ERR_INVALID_STATE;
}
portEXIT_CRITICAL(&g_i2s.spinlock);
return ret;
return i2s_ll_tx_get_fifo_sync_count(tx_handle->controller->hal.dev);
}
// Only used in `test_i2s_iram.c` to write DMA buffer directly
size_t inline i2s_platform_get_dma_buffer_offset(void)
void i2s_sync_reset_bclk_count(i2s_chan_handle_t tx_handle)
{
/* Force to transfer address '0' into 'i2s_chan_handle_t' type,
* then find the corresponding field , the address of this field is the offset of this type */
return (size_t)&(((i2s_chan_handle_t)0)->dma.bufs);
i2s_ll_tx_reset_bclk_sync_counter(tx_handle->controller->hal.dev);
}
void i2s_sync_reset_fifo_count(i2s_chan_handle_t tx_handle)
{
i2s_ll_tx_reset_fifo_sync_counter(tx_handle->controller->hal.dev);
}
#endif // SOC_I2S_SUPPORTS_TX_SYNC_CNT

View File

@ -70,7 +70,9 @@ static esp_err_t i2s_pdm_tx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_tx
portENTER_CRITICAL(&g_i2s.spinlock);
/* Set clock configurations in HAL*/
i2s_hal_set_tx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src);
I2S_CLOCK_SRC_ATOMIC() {
i2s_hal_set_tx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src);
}
#if SOC_I2S_HW_VERSION_2
/* Work around for PDM TX clock, overwrite the raw division directly to reduce the noise
* This set of coefficients is a special division to reduce the background noise in PDM TX mode */
@ -187,10 +189,7 @@ esp_err_t i2s_channel_init_pdm_tx_mode(i2s_chan_handle_t handle, const i2s_pdm_t
ESP_GOTO_ON_ERROR(i2s_init_dma_intr(handle, I2S_INTR_ALLOC_FLAGS), err, TAG, "initialize dma interrupt failed");
i2s_ll_tx_enable_pdm(handle->controller->hal.dev);
#if SOC_I2S_HW_VERSION_2
/* Enable clock to start outputting mclk signal. Some codecs will reset once mclk stop */
i2s_ll_tx_enable_clock(handle->controller->hal.dev);
#endif
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX;
#if SOC_I2S_SUPPORTS_APLL
@ -357,7 +356,9 @@ static esp_err_t i2s_pdm_rx_set_clock(i2s_chan_handle_t handle, const i2s_pdm_rx
portENTER_CRITICAL(&g_i2s.spinlock);
/* Set clock configurations in HAL*/
i2s_hal_set_rx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src);
I2S_CLOCK_SRC_ATOMIC() {
i2s_hal_set_rx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src);
}
portEXIT_CRITICAL(&g_i2s.spinlock);
/* Update the mode info: clock configuration */
@ -467,10 +468,7 @@ esp_err_t i2s_channel_init_pdm_rx_mode(i2s_chan_handle_t handle, const i2s_pdm_r
ESP_GOTO_ON_ERROR(i2s_init_dma_intr(handle, I2S_INTR_ALLOC_FLAGS), err, TAG, "initialize dma interrupt failed");
i2s_ll_rx_enable_pdm(handle->controller->hal.dev);
#if SOC_I2S_HW_VERSION_2
/* Enable clock to start outputting mclk signal. Some codecs will reset once mclk stop */
i2s_ll_rx_enable_clock(handle->controller->hal.dev);
#endif
#ifdef CONFIG_PM_ENABLE
esp_pm_lock_type_t pm_type = ESP_PM_APB_FREQ_MAX;
#if SOC_I2S_SUPPORTS_APLL

View File

@ -0,0 +1,78 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "esp_check.h"
#include "i2s_private.h"
static const char *TAG = "i2s_platform";
/**
* @brief Global i2s platform object
* @note For saving all the I2S related information
*/
i2s_platform_t g_i2s = {
.spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED,
.controller[0 ... (SOC_I2S_NUM - 1)] = NULL, // groups will be lazy installed
.comp_name[0 ... (SOC_I2S_NUM - 1)] = NULL,
};
/*---------------------------------------------------------------------------
I2S Platform APIs
----------------------------------------------------------------------------
Scope: This file and ADC/DAC/LCD driver
----------------------------------------------------------------------------*/
esp_err_t i2s_platform_acquire_occupation(int id, const char *comp_name)
{
esp_err_t ret = ESP_OK;
const char *occupied_comp = NULL;
ESP_RETURN_ON_FALSE(id < SOC_I2S_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid i2s port id");
portENTER_CRITICAL(&g_i2s.spinlock);
if ((!g_i2s.controller[id]) && (g_i2s.comp_name[id] == NULL)) {
g_i2s.comp_name[id] = comp_name;
/* Enable module clock */
I2S_RCC_ATOMIC() {
i2s_ll_enable_bus_clock(id, true);
i2s_ll_reset_register(id);
i2s_ll_enable_core_clock(I2S_LL_GET_HW(id), true);
}
} else {
occupied_comp = g_i2s.comp_name[id];
ret = ESP_ERR_NOT_FOUND;
}
portEXIT_CRITICAL(&g_i2s.spinlock);
if (occupied_comp != NULL) {
ESP_LOGW(TAG, "i2s controller %d has been occupied by %s", id, occupied_comp);
}
return ret;
}
esp_err_t i2s_platform_release_occupation(int id)
{
esp_err_t ret = ESP_OK;
ESP_RETURN_ON_FALSE(id < SOC_I2S_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid i2s port id");
portENTER_CRITICAL(&g_i2s.spinlock);
if (!g_i2s.controller[id]) {
g_i2s.comp_name[id] = NULL;
/* Disable module clock */
I2S_RCC_ATOMIC() {
i2s_ll_enable_bus_clock(id, false);
i2s_ll_enable_core_clock(I2S_LL_GET_HW(id), false);
}
} else {
ret = ESP_ERR_INVALID_STATE;
}
portEXIT_CRITICAL(&g_i2s.spinlock);
return ret;
}
// Only used in `test_i2s_iram.c` to write DMA buffer directly
size_t i2s_platform_get_dma_buffer_offset(void)
{
/* Force to transfer address '0' into 'i2s_chan_handle_t' type,
* then find the corresponding field , the address of this field is the offset of this type */
return (size_t)&(((i2s_chan_handle_t)0)->dma.bufs);
}

View File

@ -9,15 +9,17 @@
#include "freertos/FreeRTOS.h"
#include "soc/lldesc.h"
#include "soc/soc_caps.h"
#include "hal/i2s_types.h"
#include "hal/i2s_hal.h"
#include "driver/i2s_types.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#if SOC_GDMA_SUPPORTED
#include "esp_private/gdma.h"
#endif
#include "esp_private/periph_ctrl.h"
#include "esp_pm.h"
#include "esp_err.h"
#include "sdkconfig.h"
#ifdef __cplusplus
extern "C" {
@ -26,14 +28,26 @@ extern "C" {
// If ISR handler is allowed to run whilst cache is disabled,
// Make sure all the code and related variables used by the handler are in the SRAM
#if CONFIG_I2S_ISR_IRAM_SAFE
#define I2S_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED)
#define I2S_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED)
#define I2S_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
#else
#define I2S_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_LOWMED)
#define I2S_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_SHARED)
#define I2S_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT
#endif //CONFIG_I2S_ISR_IRAM_SAFE
#define I2S_DMA_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA)
#if SOC_PERIPH_CLK_CTRL_SHARED
#define I2S_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC()
#else
#define I2S_CLOCK_SRC_ATOMIC()
#endif
#if !SOC_RCC_IS_INDEPENDENT
#define I2S_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
#else
#define I2S_RCC_ATOMIC()
#endif
#define I2S_NULL_POINTER_CHECK(tag, p) ESP_RETURN_ON_FALSE((p), ESP_ERR_INVALID_ARG, tag, "input parameter '"#p"' is NULL")
/**
@ -45,6 +59,28 @@ typedef enum {
I2S_CHAN_STATE_RUNNING, /*!< i2s channel is idling (initialized and enabled) */
} i2s_state_t;
/**
* @brief Group of I2S callbacks
* @note The callbacks are all running under ISR environment
* @note When CONFIG_I2S_ISR_IRAM_SAFE is enabled, the callback itself and functions called by it should be placed in IRAM.
* The variables used in the function should be in the SRAM as well.
* @note Declare the internal type to remove the dependency of `i2s_common.h`
*/
typedef struct {
i2s_isr_callback_t on_recv; /**< Callback of data received event, only for rx channel
* The event data includes DMA buffer address and size that just finished receiving data
*/
i2s_isr_callback_t on_recv_q_ovf; /**< Callback of receiving queue overflowed event, only for rx channel
* The event data includes buffer size that has been overwritten
*/
i2s_isr_callback_t on_sent; /**< Callback of data sent event, only for tx channel
* The event data includes DMA buffer address and size that just finished sending data
*/
i2s_isr_callback_t on_send_q_ovf; /**< Callback of sending queue overflowed event, only for tx channel
* The event data includes buffer size that has been overwritten
*/
} i2s_event_callbacks_internal_t;
/**
* @brief i2s channel level configurations
* @note It performs as channel handle
@ -61,6 +97,7 @@ typedef struct {
bool auto_clear; /*!< Set to auto clear DMA TX descriptor, i2s will always send zero automatically if no data to send */
uint32_t rw_pos; /*!< reading/writing pointer position */
void *curr_ptr; /*!< Pointer to current dma buffer */
void *curr_desc; /*!< Pointer to current dma descriptor used for pre-load */
lldesc_t **desc; /*!< dma descriptor array */
uint8_t **bufs; /*!< dma buffer array */
} i2s_dma_t;
@ -88,6 +125,7 @@ struct i2s_channel_obj_t {
i2s_dma_t dma; /*!< i2s dma object */
i2s_state_t state; /*!< i2s driver state. Ensuring the driver working in a correct sequence */
/* Stored configurations */
int intr_prio_flags;/*!< i2s interrupt priority flags */
void *mode_info; /*!< Slot, clock and gpio information of each mode */
#if SOC_I2S_SUPPORTS_APLL
bool apll_en; /*!< Flag of wether APLL enabled */
@ -101,7 +139,7 @@ struct i2s_channel_obj_t {
esp_pm_lock_handle_t pm_lock; /*!< Power management lock, to avoid apb clock frequency changes while i2s is working */
#endif
QueueHandle_t msg_queue; /*!< Message queue handler, used for transporting data between interrupt and read/write task */
i2s_event_callbacks_t callbacks; /*!< Callback functions */
i2s_event_callbacks_internal_t callbacks; /*!< Callback functions */
void *user_data; /*!< User data for callback functions */
void (*start)(i2s_chan_handle_t); /*!< start tx/rx channel */
void (*stop)(i2s_chan_handle_t); /*!< stop tx/rx channel */
@ -117,7 +155,7 @@ typedef struct {
const char *comp_name[SOC_I2S_NUM]; /*!< The component name that occupied i2s controller */
} i2s_platform_t;
extern i2s_platform_t g_i2s;
extern i2s_platform_t g_i2s; /*!< Global i2s instance for driver internal use */
/**
* @brief Initialize I2S DMA interrupt
@ -184,7 +222,7 @@ uint32_t i2s_get_source_clk_freq(i2s_clock_src_t clk_src, uint32_t mclk_freq_hz)
* @param is_input Is input gpio
* @param is_invert Is invert gpio
*/
void i2s_gpio_check_and_set(gpio_num_t gpio, uint32_t signal_idx, bool is_input, bool is_invert);
void i2s_gpio_check_and_set(int gpio, uint32_t signal_idx, bool is_input, bool is_invert);
/**
* @brief Check gpio validity and output mclk signal
@ -197,7 +235,7 @@ void i2s_gpio_check_and_set(gpio_num_t gpio, uint32_t signal_idx, bool is_input,
* - 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, i2s_clock_src_t clk_src, bool is_invert);
esp_err_t i2s_check_set_mclk(i2s_port_t id, int gpio_num, i2s_clock_src_t clk_src, bool is_invert);
/**
* @brief Attach data out signal and data in signal to a same gpio
@ -206,7 +244,7 @@ esp_err_t i2s_check_set_mclk(i2s_port_t id, gpio_num_t gpio_num, i2s_clock_src_t
* @param out_sig_idx Data out signal index
* @param in_sig_idx Data in signal index
*/
void i2s_gpio_loopback_set(gpio_num_t gpio, uint32_t out_sig_idx, uint32_t in_sig_idx);
void i2s_gpio_loopback_set(int gpio, uint32_t out_sig_idx, uint32_t in_sig_idx);
#ifdef __cplusplus
}

View File

@ -77,10 +77,12 @@ static esp_err_t i2s_std_set_clock(i2s_chan_handle_t handle, const i2s_std_clk_c
portENTER_CRITICAL(&g_i2s.spinlock);
/* Set clock configurations in HAL*/
if (handle->dir == I2S_DIR_TX) {
i2s_hal_set_tx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src);
} else {
i2s_hal_set_rx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src);
I2S_CLOCK_SRC_ATOMIC() {
if (handle->dir == I2S_DIR_TX) {
i2s_hal_set_tx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src);
} else {
i2s_hal_set_rx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src);
}
}
portEXIT_CRITICAL(&g_i2s.spinlock);
@ -226,10 +228,8 @@ esp_err_t i2s_channel_init_std_mode(i2s_chan_handle_t handle, const i2s_std_conf
/* Enable clock to start outputting mclk signal. Some codecs will reset once mclk stop */
if (handle->dir == I2S_DIR_TX) {
i2s_ll_tx_enable_std(handle->controller->hal.dev);
i2s_ll_tx_enable_clock(handle->controller->hal.dev);
} else {
i2s_ll_rx_enable_std(handle->controller->hal.dev);
i2s_ll_rx_enable_clock(handle->controller->hal.dev);
}
#endif

View File

@ -79,10 +79,12 @@ static esp_err_t i2s_tdm_set_clock(i2s_chan_handle_t handle, const i2s_tdm_clk_c
portENTER_CRITICAL(&g_i2s.spinlock);
/* Set clock configurations in HAL*/
if (handle->dir == I2S_DIR_TX) {
i2s_hal_set_tx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src);
} else {
i2s_hal_set_rx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src);
I2S_CLOCK_SRC_ATOMIC() {
if (handle->dir == I2S_DIR_TX) {
i2s_hal_set_tx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src);
} else {
i2s_hal_set_rx_clock(&handle->controller->hal, &clk_info, clk_cfg->clk_src);
}
}
portEXIT_CRITICAL(&g_i2s.spinlock);
@ -232,10 +234,8 @@ esp_err_t i2s_channel_init_tdm_mode(i2s_chan_handle_t handle, const i2s_tdm_conf
/* Enable clock to start outputting mclk signal. Some codecs will reset once mclk stop */
if (handle->dir == I2S_DIR_TX) {
i2s_ll_tx_enable_tdm(handle->controller->hal.dev);
i2s_ll_tx_enable_clock(handle->controller->hal.dev);
} else {
i2s_ll_rx_enable_tdm(handle->controller->hal.dev);
i2s_ll_rx_enable_clock(handle->controller->hal.dev);
}
#endif
#ifdef CONFIG_PM_ENABLE
@ -275,12 +275,12 @@ esp_err_t i2s_channel_reconfig_tdm_clock(i2s_chan_handle_t handle, const i2s_tdm
#if SOC_I2S_SUPPORTS_APLL
/* Enable APLL and acquire its lock when the clock source is changed to APLL */
if (clk_cfg->clk_src == I2S_CLK_SRC_APLL && clk_cfg->clk_cfg.clk_src != I2S_CLK_SRC_APLL) {
if (clk_cfg->clk_src == I2S_CLK_SRC_APLL && tdm_cfg->clk_cfg.clk_src != I2S_CLK_SRC_APLL) {
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_SRC_APLL && clk_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) {
if (clk_cfg->clk_src != I2S_CLK_SRC_APLL && tdm_cfg->clk_cfg.clk_src == I2S_CLK_SRC_APLL) {
periph_rtc_apll_release();
handle->apll_en = false;
}

View File

@ -25,6 +25,7 @@ extern "C" {
.dma_desc_num = 6, \
.dma_frame_num = 240, \
.auto_clear = false, \
.intr_priority = 0, \
}
#define I2S_GPIO_UNUSED GPIO_NUM_NC /*!< Used in i2s_gpio_config_t for signals which are not used */
@ -63,6 +64,7 @@ typedef struct {
* it should be the multiple of '3' when the data bit width is 24.
*/
bool auto_clear; /*!< Set to auto clear DMA TX buffer, i2s will always send zero automatically if no data to send */
int intr_priority; /*!< I2S interrupt priority, range [0, 7], if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3) */
} i2s_chan_config_t;
/**

View File

@ -23,6 +23,23 @@ extern "C" {
#if SOC_I2S_SUPPORTS_PDM_RX
#if SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER
/**
* @brief PDM format in 2 slots(RX)
* @param bits_per_sample i2s data bit width, only support 16 bits for PDM mode
* @param mono_or_stereo I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO
*/
#define I2S_PDM_RX_SLOT_DEFAULT_CONFIG(bits_per_sample, mono_or_stereo) { \
.data_bit_width = bits_per_sample, \
.slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO, \
.slot_mode = mono_or_stereo, \
.slot_mask = (mono_or_stereo == I2S_SLOT_MODE_MONO) ? \
I2S_PDM_SLOT_LEFT : I2S_PDM_SLOT_BOTH, \
.hp_en = true, \
.hp_cut_off_freq_hz = 35.5, \
.amplify_num = 1, \
}
#else
/**
* @brief PDM format in 2 slots(RX)
* @param bits_per_sample i2s data bit width, only support 16 bits for PDM mode
@ -35,6 +52,7 @@ extern "C" {
.slot_mask = (mono_or_stereo == I2S_SLOT_MODE_MONO) ? \
I2S_PDM_SLOT_LEFT : I2S_PDM_SLOT_BOTH, \
}
#endif // SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER
/**
* @brief i2s default pdm rx clock configuration
@ -48,6 +66,8 @@ extern "C" {
.bclk_div = 8, \
}
/**
* @brief I2S slot configuration for pdm rx mode
*/
@ -58,6 +78,15 @@ typedef struct {
i2s_slot_mode_t slot_mode; /*!< Set mono or stereo mode with I2S_SLOT_MODE_MONO or I2S_SLOT_MODE_STEREO */
/* Particular fields */
i2s_pdm_slot_mask_t slot_mask; /*!< Choose the slots to activate */
#if SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER
bool hp_en; /*!< High pass filter enable */
float hp_cut_off_freq_hz; /*!< High pass filter cut-off frequency, range 23.3Hz ~ 185Hz, see cut-off frequency sheet above */
uint32_t amplify_num; /*!< The amplification number of the final conversion result.
* The data that have converted from PDM to PCM module, will time 'amplify_num' additionally to amplify the final result.
* Note that it's only a multiplier of the digital PCM data, not the gain of the analog signal
* range 1~15, default 1 */
#endif // SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER
} i2s_pdm_rx_slot_config_t;
/**

View File

@ -0,0 +1,71 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
// DO NOT USE THESE APIS IN YOUR APPLICATIONS
// The following APIs are for internal use, public to other IDF components, but not for users' applications.
/**
* This file is used for getting the bclk and fifo sending count
* for the synchronization among different I2S ports.
*
* The APIs in this file might be called frequently, so they are made light-weight and flexible to be called
*
* NOTE: These APIs are private for ESP internal usages.
* Please be aware of the risk that APIs might be changed regarding the use case.
*/
#pragma once
#include <stdint.h>
#include "driver/i2s_types.h"
#ifdef __cplusplus
extern "C" {
#endif
#if SOC_I2S_SUPPORTS_TX_SYNC_CNT
/**
* @brief Get the counter number of BCLK ticks
* @note The BCLK tick count reflects the real data that have sent on line
*
* @param[in] tx_handle The I2S tx channel handle
* @return
* - BCLK tick count
*/
uint32_t i2s_sync_get_bclk_count(i2s_chan_handle_t tx_handle);
/**
* @brief Get the counter number of fifo
* @note The FIFO count reflects how many slots have processed
* Normally, fifo_cnt = slot_bit_width * bclk_cnt
* If fifo_cnt < slot_bit_width * bclk_cnt, that means some data are still stuck in the I2S controller
*
* @param[in] tx_handle The I2S tx channel handle
* @return
* - FIFO slot count
*/
uint32_t i2s_sync_get_fifo_count(i2s_chan_handle_t tx_handle);
/**
* @brief Reset the bclk counter
*
* @param[in] tx_handle The I2S tx channel handle
*/
void i2s_sync_reset_bclk_count(i2s_chan_handle_t tx_handle);
/**
* @brief Reset the fifo counter
*
* @param[in] tx_handle The I2S tx channel handle
*/
void i2s_sync_reset_fifo_count(i2s_chan_handle_t tx_handle);
#endif // SOC_I2S_SUPPORTS_TX_SYNC_CNT
#ifdef __cplusplus
}
#endif

View File

@ -33,15 +33,27 @@ components/driver/test_apps/i2c_test_apps:
components/driver/test_apps/i2s_test_apps:
disable:
- if: SOC_I2S_SUPPORTED != 1
disable_test:
- if: IDF_TARGET == "esp32p4"
temporary: true
reason: lack of runners
components/driver/test_apps/i2s_test_apps/i2s:
disable:
- if: SOC_I2S_SUPPORTED != 1
disable_test:
- if: IDF_TARGET == "esp32p4"
temporary: true
reason: lack of runners
components/driver/test_apps/i2s_test_apps/i2s_multi_dev:
disable:
- if: SOC_I2S_SUPPORTED != 1
- if: SOC_I2S_HW_VERSION_2 != 1
disable_test:
- if: IDF_TARGET == "esp32p4"
temporary: true
reason: lack of runners
components/driver/test_apps/i2s_test_apps/legacy_i2s_adc_dac:
disable:
@ -50,6 +62,10 @@ components/driver/test_apps/i2s_test_apps/legacy_i2s_adc_dac:
components/driver/test_apps/i2s_test_apps/legacy_i2s_driver:
disable:
- if: SOC_I2S_SUPPORTED != 1
disable_test:
- if: IDF_TARGET == "esp32p4"
temporary: true
reason: lack of runners
components/driver/test_apps/ledc:
disable:

View File

@ -1,2 +1,2 @@
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |

View File

@ -11,6 +11,7 @@
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "sdkconfig.h"
#include "driver/gpio.h"
#include "hal/gpio_hal.h"
#include "esp_err.h"
@ -775,7 +776,7 @@ static void i2s_test_common_sample_rate(i2s_chan_handle_t rx_chan, i2s_std_clk_c
// pcnt will count the pulse number on WS signal in 100ms
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));
esp_rom_delay_us(100 * 1000);
TEST_ESP_OK(pcnt_unit_stop(pcnt_unit));
TEST_ESP_OK(pcnt_unit_get_count(pcnt_unit, &real_pulse));
printf("[%"PRIu32" Hz] %d pulses, expected %d, err %d\n", test_freq[i], real_pulse, expt_pulse, real_pulse - expt_pulse);
@ -803,7 +804,10 @@ TEST_CASE("I2S_default_PLL_clock_test", "[i2s]")
TEST_ESP_OK(i2s_new_channel(&chan_cfg, NULL, &rx_handle));
TEST_ESP_OK(i2s_channel_init_std_mode(rx_handle, &std_cfg));
// ESP32-P4 has no PLL except XTAL
#if !CONFIG_IDF_TARGET_ESP32P4
i2s_test_common_sample_rate(rx_handle, &std_cfg.clk_cfg);
#endif // CONFIG_IDF_TARGET_ESP32P4
#if SOC_I2S_SUPPORTS_XTAL
std_cfg.clk_cfg.clk_src = I2S_CLK_SRC_XTAL;
i2s_test_common_sample_rate(rx_handle, &std_cfg.clk_cfg);
@ -880,7 +884,6 @@ TEST_CASE("I2S_package_lost_test", "[i2s]")
for (i = 0; i < test_num; i++) {
printf("Testing %"PRIu32" Hz sample rate\n", test_freq[i]);
std_cfg.clk_cfg.sample_rate_hz = test_freq[i];
std_cfg.clk_cfg.sample_rate_hz = test_freq[i];
TEST_ESP_OK(i2s_channel_reconfig_std_clock(rx_handle, &std_cfg.clk_cfg));
TEST_ESP_OK(i2s_channel_enable(rx_handle));
for (int j = 0; j < 10; j++) {

View File

@ -13,6 +13,9 @@
#include "driver/i2s_std.h"
#include "esp_attr.h"
#include "soc/soc_caps.h"
#if CONFIG_IDF_TARGET_ESP32P4
#include "rom/cache.h"
#endif
#include "esp_private/i2s_platform.h"
#include "esp_private/spi_flash_os.h"
#include "../../test_inc/test_i2s.h"
@ -39,9 +42,13 @@ static void IRAM_ATTR test_i2s_iram_write(i2s_chan_handle_t tx_handle)
// disable cache and non-iram ISR handlers
spi_flash_guard_get()->start();
// write data into dma buffer directly, the data in dma buffer will be sent automatically
for (int i=0; i < 100; i++) {
dma_bufs[0][i] = i + 1;
for (int i = 0; i < 400; i++) {
dma_bufs[0][i] = i % 100 + 1;
}
#if CONFIG_IDF_TARGET_ESP32P4
// TODO: need to consider PSRAM if I2S driver supports EDMA
Cache_WriteBack_Addr(CACHE_MAP_L1_DCACHE, (uint32_t)dma_bufs[0], 400);
#endif
// enable cache and non-iram ISR handlers
spi_flash_guard_get()->end();
}
@ -52,8 +59,8 @@ TEST_CASE("i2s_iram_interrupt_safe", "[i2s]")
i2s_chan_handle_t rx_chan = NULL;
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
chan_cfg.dma_desc_num = 6;
chan_cfg.dma_frame_num = 200;
chan_cfg.dma_desc_num = 2;
chan_cfg.dma_frame_num = 100;
TEST_ESP_OK(i2s_new_channel(&chan_cfg, &tx_chan, &rx_chan));
i2s_std_config_t std_cfg = {
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(16000),
@ -73,14 +80,14 @@ TEST_CASE("i2s_iram_interrupt_safe", "[i2s]")
};
TEST_ESP_OK(i2s_channel_init_std_mode(tx_chan, &std_cfg));
TEST_ESP_OK(i2s_channel_init_std_mode(rx_chan, &std_cfg));
int is_triggerred = 0;
int is_triggered = 0;
i2s_event_callbacks_t cbs = {
.on_recv = NULL,
.on_recv_q_ovf = NULL,
.on_sent = test_i2s_tx_done_callback,
.on_send_q_ovf = NULL,
};
TEST_ESP_OK(i2s_channel_register_event_callback(tx_chan, &cbs, &is_triggerred));
TEST_ESP_OK(i2s_channel_register_event_callback(tx_chan, &cbs, &is_triggered));
TEST_ESP_OK(i2s_channel_enable(tx_chan));
TEST_ESP_OK(i2s_channel_enable(rx_chan));
@ -92,7 +99,7 @@ TEST_CASE("i2s_iram_interrupt_safe", "[i2s]")
for (int retry = 0; retry < 3; retry++) {
i2s_channel_read(rx_chan, recv_buf, 2000, &r_bytes, pdMS_TO_TICKS(1000));
for (i = 0; i < 2000 - 100; i++) {
if (recv_buf[i] != 0) {
if (recv_buf[i] == 1 && recv_buf[i + 1] == 2) {
goto finish;
}
}
@ -107,7 +114,7 @@ finish:
for (int j = 1; j <= 100; j++) {
TEST_ASSERT_EQUAL_UINT8(recv_buf[i++], j);
}
TEST_ASSERT(is_triggerred);
TEST_ASSERT(is_triggered);
free(recv_buf);
}

View File

@ -1,3 +1,3 @@
| Supported Targets | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S3 |
| ----------------- | -------- | -------- | -------- | -------- |
| Supported Targets | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S3 |
| ----------------- | -------- | -------- | -------- | -------- | -------- |

View File

@ -1,2 +1,2 @@
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -44,6 +44,14 @@ extern "C" {
#define SLAVE_WS_IO 15
#define DATA_IN_IO 19
#define DATA_OUT_IO 18
#elif CONFIG_IDF_TARGET_ESP32P4
#define MASTER_MCK_IO 34
#define MASTER_BCK_IO 35
#define MASTER_WS_IO 48
#define SLAVE_BCK_IO 10
#define SLAVE_WS_IO 11
#define DATA_IN_IO 12
#define DATA_OUT_IO 49
#else
#define MASTER_MCK_IO 0
#define MASTER_BCK_IO 4

View File

@ -54,7 +54,7 @@ void periph_rtc_apll_release(void);
* @brief Calculate and set APLL coefficients by given frequency
* @note Have to call 'periph_rtc_apll_acquire' to enable APLL power before setting frequency
* @note This calculation is based on the inequality:
* xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) >= SOC_APLL_MULTIPLIER_OUT_MIN_HZ(350 MHz)
* xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) >= CLK_LL_APLL_MULTIPLIER_MIN_HZ(350 MHz)
* It will always calculate the minimum coefficients that can satisfy the inequality above, instead of loop them one by one.
* which means more appropriate coefficients are likely to exist.
* But this algorithm can meet almost all the cases and the accuracy can be guaranteed as well.

View File

@ -217,7 +217,7 @@ uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm
* i.e. xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) >= 350 MHz, '+1' in the following code is to get the ceil value.
* With this condition, as we know the 'o_div' can't be greater than 31, then we can calculate the APLL minimum support frequency is
* 350 MHz / ((31 + 2) * 2) = 5303031 Hz (for ceil) */
o_div = (int)(SOC_APLL_MULTIPLIER_OUT_MIN_HZ / (float)(freq * 2) + 1) - 2;
o_div = (int)(CLK_LL_APLL_MULTIPLIER_MIN_HZ / (float)(freq * 2) + 1) - 2;
if (o_div > 31) {
ESP_HW_LOGE(TAG, "Expected frequency is too small");
return 0;
@ -227,7 +227,7 @@ uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm
* i.e. xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) <= 500 MHz, we need to get the floor value in the following code.
* With this condition, as we know the 'o_div' can't be smaller than 0, then we can calculate the APLL maximum support frequency is
* 500 MHz / ((0 + 2) * 2) = 125000000 Hz */
o_div = (int)(SOC_APLL_MULTIPLIER_OUT_MAX_HZ / (float)(freq * 2)) - 2;
o_div = (int)(CLK_LL_APLL_MULTIPLIER_MAX_HZ / (float)(freq * 2)) - 2;
if (o_div < 0) {
ESP_HW_LOGE(TAG, "Expected frequency is too big");
return 0;

View File

@ -368,6 +368,22 @@ uint32_t rtc_clk_apb_freq_get(void)
return rtc_clk_ahb_freq_get() / clk_ll_apb_get_divider() * MHZ;
}
void rtc_clk_apll_enable(bool enable)
{
// TODO: IDF-7526
}
uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm0, uint32_t *_sdm1, uint32_t *_sdm2)
{
// TODO: IDF-7526
return 0;
}
void rtc_clk_apll_coeff_set(uint32_t o_div, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2)
{
// TODO: IDF-7526
}
void rtc_dig_clk8m_enable(void)
{
clk_ll_rc_fast_digi_enable();

View File

@ -119,7 +119,7 @@ uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm
* i.e. xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) >= 350 MHz, '+1' in the following code is to get the ceil value.
* With this condition, as we know the 'o_div' can't be greater than 31, then we can calculate the APLL minimum support frequency is
* 350 MHz / ((31 + 2) * 2) = 5303031 Hz (for ceil) */
o_div = (int)(SOC_APLL_MULTIPLIER_OUT_MIN_HZ / (float)(freq * 2) + 1) - 2;
o_div = (int)(CLK_LL_APLL_MULTIPLIER_MIN_HZ / (float)(freq * 2) + 1) - 2;
if (o_div > 31) {
ESP_HW_LOGE(TAG, "Expected frequency is too small");
return 0;
@ -129,7 +129,7 @@ uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm
* i.e. xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536) <= 500 MHz, we need to get the floor value in the following code.
* With this condition, as we know the 'o_div' can't be smaller than 0, then we can calculate the APLL maximum support frequency is
* 500 MHz / ((0 + 2) * 2) = 125000000 Hz */
o_div = (int)(SOC_APLL_MULTIPLIER_OUT_MAX_HZ / (float)(freq * 2)) - 2;
o_div = (int)(CLK_LL_APLL_MULTIPLIER_MAX_HZ / (float)(freq * 2)) - 2;
if (o_div < 0) {
ESP_HW_LOGE(TAG, "Expected frequency is too big");
return 0;

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -73,6 +73,15 @@ extern "C" {
#define CLK_LL_XTAL_32K_BOOTSTRAP_DRES_VAL 3
#define CLK_LL_XTAL_32K_BOOTSTRAP_DBIAS_VAL 0
/* APLL multiplier output frequency range */
// apll_multiplier_out = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)
#define CLK_LL_APLL_MULTIPLIER_MIN_HZ (350000000) // 350 MHz
#define CLK_LL_APLL_MULTIPLIER_MAX_HZ (500000000) // 500 MHz
/* APLL output frequency range */
#define CLK_LL_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
#define CLK_LL_APLL_MAX_HZ (125000000) // 125MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
/**
* @brief XTAL32K_CLK enable modes
*/

View File

@ -18,6 +18,7 @@
#include "hal/misc.h"
#include "soc/i2s_periph.h"
#include "soc/i2s_struct.h"
#include "soc/dport_reg.h"
#include "hal/i2s_types.h"
#include "hal/hal_utils.h"
@ -48,7 +49,7 @@ extern "C" {
#define I2S_LL_RX_EVENT_MASK I2S_LL_EVENT_RX_EOF
#define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz
#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
#define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
/**
* @brief Enable DMA descriptor owner check
@ -84,30 +85,73 @@ static inline void i2s_ll_dma_enable_eof_on_fifo_empty(i2s_dev_t *hw, bool en)
}
/**
* @brief I2S module general init, enable I2S clock.
* @brief Enable the bus clock for I2S module
*
* @param hw Peripheral I2S hardware instance address.
* @param i2s_id The port id of I2S
* @param enable Set true to enable the buf clock
*/
static inline void i2s_ll_enable_clock(i2s_dev_t *hw)
static inline void i2s_ll_enable_bus_clock(int i2s_id, bool enable)
{
if (hw->clkm_conf.clk_en == 0) {
hw->clkm_conf.clk_en = 1;
hw->conf2.val = 0;
if (enable) {
if (i2s_id == 0) {
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
} else {
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN);
}
} else if (i2s_id == 1) {
if (i2s_id == 0) {
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
} else {
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN);
}
}
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define i2s_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_bus_clock(__VA_ARGS__)
/**
* @brief I2S module disable clock.
* @brief Reset the I2S module
*
* @param i2s_id The port id of I2S
*/
static inline void i2s_ll_reset_register(int i2s_id)
{
if (i2s_id == 0) {
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST);
} else if (i2s_id == 1) {
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST);
}
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define i2s_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_reset_register(__VA_ARGS__)
/**
* @brief I2S module general init, enable I2S clock.
*
* @param hw Peripheral I2S hardware instance address.
* @param enable set true to enable the core clock
*/
static inline void i2s_ll_disable_clock(i2s_dev_t *hw)
static inline void i2s_ll_enable_core_clock(i2s_dev_t *hw, bool enable)
{
if (hw->clkm_conf.clk_en == 1) {
if (enable && !hw->clkm_conf.clk_en) {
hw->clkm_conf.clk_en = 1;
hw->conf2.val = 0;
} else if (!enable && hw->clkm_conf.clk_en) {
hw->clkm_conf.clk_en = 0;
}
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define i2s_ll_enable_core_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_core_clock(__VA_ARGS__)
/**
* @brief I2S tx msb right enable
*

View File

@ -17,6 +17,7 @@
#include "hal/assert.h"
#include "soc/i2s_periph.h"
#include "soc/i2s_struct.h"
#include "soc/system_struct.h"
#include "hal/i2s_types.h"
#include "hal/hal_utils.h"
@ -34,27 +35,56 @@ extern "C" {
#define I2S_LL_CLK_FRAC_DIV_AB_MAX 512 // I2S_MCLK = I2S_SRC_CLK / (N + b/a), the a/b register is 9 bit-width
#define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz
#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
#define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
/**
* @brief Enable the bus clock for I2S module
*
* @param i2s_id The port id of I2S
* @param enable Set true to enable the buf clock
*/
static inline void i2s_ll_enable_bus_clock(int i2s_id, bool enable)
{
(void)i2s_id;
SYSTEM.perip_clk_en0.reg_i2s1_clk_en = enable;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define i2s_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_bus_clock(__VA_ARGS__)
/**
* @brief Reset the I2S module
*
* @param i2s_id The port id of I2S
*/
static inline void i2s_ll_reset_register(int i2s_id)
{
(void)i2s_id;
SYSTEM.perip_rst_en0.reg_i2s1_rst = 1;
SYSTEM.perip_rst_en0.reg_i2s1_rst = 0;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define i2s_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_reset_register(__VA_ARGS__)
/**
* @brief I2S module general init, enable I2S clock.
*
* @param hw Peripheral I2S hardware instance address.
* @param enable set true to enable the core clock
*/
static inline void i2s_ll_enable_clock(i2s_dev_t *hw)
static inline void i2s_ll_enable_core_clock(i2s_dev_t *hw, bool enable)
{
hw->tx_clkm_conf.clk_en = 1;
hw->tx_clkm_conf.clk_en = enable;
}
/**
* @brief I2S module disable I2S clock.
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_disable_clock(i2s_dev_t *hw)
{
hw->tx_clkm_conf.clk_en = 0;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define i2s_ll_enable_core_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_core_clock(__VA_ARGS__)
/**
* @brief Enable I2S tx module clock

View File

@ -35,28 +35,42 @@ extern "C" {
#define I2S_LL_CLK_FRAC_DIV_AB_MAX 512 // I2S_MCLK = I2S_SRC_CLK / (N + b/a), the a/b register is 9 bit-width
#define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz
#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
#define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
/**
*
* @param i2s_id The port id of I2S
* @param enable Set true to enable the buf clock
*/
static inline void i2s_ll_enable_bus_clock(int i2s_id, bool enable)
{
(void)i2s_id;
PCR.i2s_conf.i2s_clk_en = enable;
}
/**
* @brief Reset the I2S module
*
* @param i2s_id The port id of I2S
*/
static inline void i2s_ll_reset_register(int i2s_id)
{
(void)i2s_id;
PCR.i2s_conf.i2s_rst_en = 1;
PCR.i2s_conf.i2s_rst_en = 0;
}
/**
* @brief I2S module general init, enable I2S clock.
*
* @param hw Peripheral I2S hardware instance address.
* @param enable set true to enable the core clock
*/
static inline void i2s_ll_enable_clock(i2s_dev_t *hw)
static inline void i2s_ll_enable_core_clock(i2s_dev_t *hw, bool enable)
{
// The clock gate enabling is moved to `periph_module_enable`
(void)hw;
}
/**
* @brief I2S module disable I2S clock.
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_disable_clock(i2s_dev_t *hw)
{
// The clock gate disabling is moved to `periph_module_disable`
(void)hw;
(void)enable;
// No need to do anything
}
/**

View File

@ -36,28 +36,42 @@ extern "C" {
#define I2S_LL_PLL_F96M_CLK_FREQ (96 * 1000000) // PLL_F96M_CLK: 96MHz
#define I2S_LL_PLL_F64M_CLK_FREQ (64 * 1000000) // PLL_F64M_CLK: 64MHz
#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F96M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
#define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F96M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
/**
*
* @param i2s_id The port id of I2S
* @param enable Set true to enable the buf clock
*/
static inline void i2s_ll_enable_bus_clock(int i2s_id, bool enable)
{
(void)i2s_id;
PCR.i2s_conf.i2s_clk_en = enable;
}
/**
* @brief Reset the I2S module
*
* @param i2s_id The port id of I2S
*/
static inline void i2s_ll_reset_register(int i2s_id)
{
(void)i2s_id;
PCR.i2s_conf.i2s_rst_en = 1;
PCR.i2s_conf.i2s_rst_en = 0;
}
/**
* @brief I2S module general init, enable I2S clock.
*
* @param hw Peripheral I2S hardware instance address.
* @param enable set true to enable the core clock
*/
static inline void i2s_ll_enable_clock(i2s_dev_t *hw)
static inline void i2s_ll_enable_core_clock(i2s_dev_t *hw, bool enable)
{
// The clock gate enabling is moved to `periph_module_enable`
(void)hw;
}
/**
* @brief I2S module disable I2S clock.
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_disable_clock(i2s_dev_t *hw)
{
// The clock gate disabling is moved to `periph_module_disable`
(void)hw;
(void)enable;
// No need to do anything
}
/**

View File

@ -36,12 +36,6 @@ static inline uint32_t periph_ll_get_clk_en_mask(periph_module_t periph)
return HP_SYS_CLKRST_REG_I2C0_APB_CLK_EN;
case PERIPH_I2C1_MODULE:
return HP_SYS_CLKRST_REG_I2C1_APB_CLK_EN;
case PERIPH_I2S0_MODULE:
return HP_SYS_CLKRST_REG_I2S0_TX_CLK_EN | HP_SYS_CLKRST_REG_I2S0_RX_CLK_EN;
case PERIPH_I2S1_MODULE:
return HP_SYS_CLKRST_REG_I2S1_RX_CLK_EN | HP_SYS_CLKRST_REG_I2S1_TX_CLK_EN;
case PERIPH_I2S2_MODULE:
return HP_SYS_CLKRST_REG_I2S2_RX_CLK_EN | HP_SYS_CLKRST_REG_I2S2_TX_CLK_EN;
case PERIPH_LCD_MODULE:
return HP_SYS_CLKRST_REG_LCD_CLK_EN;
case PERIPH_UART0_MODULE:
@ -151,12 +145,6 @@ static inline uint32_t periph_ll_get_rst_en_mask(periph_module_t periph, bool en
return HP_SYS_CLKRST_REG_RST_EN_CAN2;
case PERIPH_LEDC_MODULE:
return HP_SYS_CLKRST_REG_RST_EN_LEDC;
case PERIPH_I2S0_MODULE:
return HP_SYS_CLKRST_REG_RST_EN_I2S0_APB;
case PERIPH_I2S1_MODULE:
return HP_SYS_CLKRST_REG_RST_EN_I2S1_APB;
case PERIPH_I2S2_MODULE:
return HP_SYS_CLKRST_REG_RST_EN_I2S2_APB;
case PERIPH_GPSPI2_MODULE:
return HP_SYS_CLKRST_REG_RST_EN_SPI2;
case PERIPH_GPSPI3_MODULE:
@ -294,10 +282,6 @@ static inline uint32_t periph_ll_get_rst_en_reg(periph_module_t periph)
case PERIPH_TWAI1_MODULE:
case PERIPH_TWAI2_MODULE:
case PERIPH_LEDC_MODULE:
case PERIPH_I2S0_MODULE:
return HP_SYS_CLKRST_HP_RST_EN1_REG;
case PERIPH_I2S1_MODULE:
case PERIPH_I2S2_MODULE:
case PERIPH_GPSPI2_MODULE:
case PERIPH_GPSPI3_MODULE:
case PERIPH_CAM_MODULE:

View File

@ -30,6 +30,16 @@ extern "C" {
#define CLK_LL_PLL_480M_FREQ_MHZ (480)
/* APLL multiplier output frequency range */
// TODO: IDF-7526 check if the APLL frequency range is same as before
// apll_multiplier_out = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)
#define CLK_LL_APLL_MULTIPLIER_MIN_HZ (350000000) // 350 MHz
#define CLK_LL_APLL_MULTIPLIER_MAX_HZ (500000000) // 500 MHz
/* APLL output frequency range */
#define CLK_LL_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
#define CLK_LL_APLL_MAX_HZ (125000000) // 125MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
#define CLK_LL_XTAL32K_CONFIG_DEFAULT() { \
.dac = 3, \
.dres = 3, \

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -47,6 +47,15 @@ extern "C" {
#define CLK_LL_APLL_CAL_DELAY_2 0x3f
#define CLK_LL_APLL_CAL_DELAY_3 0x1f
/* APLL multiplier output frequency range */
// apll_multiplier_out = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)
#define CLK_LL_APLL_MULTIPLIER_MIN_HZ (350000000) // 350 MHz
#define CLK_LL_APLL_MULTIPLIER_MAX_HZ (500000000) // 500 MHz
/* APLL output frequency range */
#define CLK_LL_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
#define CLK_LL_APLL_MAX_HZ (125000000) // 125MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
#define CLK_LL_XTAL32K_CONFIG_DEFAULT() { \
.dac = 3, \
.dres = 3, \

View File

@ -18,6 +18,8 @@
#include "hal/misc.h"
#include "soc/i2s_periph.h"
#include "soc/i2s_struct.h"
#include "soc/system_reg.h"
#include "soc/dport_access.h"
#include "hal/i2s_types.h"
#include "hal/hal_utils.h"
@ -45,7 +47,7 @@ extern "C" {
#define I2S_LL_RX_EVENT_MASK I2S_LL_EVENT_RX_EOF
#define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz
#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
#define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
/**
* @brief Enable DMA descriptor owner check
@ -81,31 +83,73 @@ static inline void i2s_ll_dma_enable_eof_on_fifo_empty(i2s_dev_t *hw, bool en)
}
/**
* @brief I2S module general init, enable I2S clock.
* @brief Enable the bus clock for I2S module
*
* @param hw Peripheral I2S hardware instance address.
* @param i2s_id The port id of I2S
* @param enable Set true to enable the buf clock
*/
static inline void i2s_ll_enable_clock(i2s_dev_t *hw)
static inline void i2s_ll_enable_bus_clock(int i2s_id, bool enable)
{
if (hw->clkm_conf.clk_en == 0) {
hw->clkm_conf.clk_sel = 2;
hw->clkm_conf.clk_en = 1;
hw->conf2.val = 0;
if (enable) {
if (i2s_id == 0) {
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
} else {
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN);
}
} else {
if (i2s_id == 0) {
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
} else {
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN);
}
}
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define i2s_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_bus_clock(__VA_ARGS__)
/**
* @brief I2S module disable clock.
* @brief Reset the I2S module
*
* @param i2s_id The port id of I2S
*/
static inline void i2s_ll_reset_register(int i2s_id)
{
if (i2s_id == 0) {
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST);
} else {
DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST);
DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST);
}
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define i2s_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_reset_register(__VA_ARGS__)
/**
* @brief I2S module general init, enable I2S clock.
*
* @param hw Peripheral I2S hardware instance address.
* @param enable set true to enable the core clock
*/
static inline void i2s_ll_disable_clock(i2s_dev_t *hw)
static inline void i2s_ll_enable_core_clock(i2s_dev_t *hw, bool enable)
{
if (hw->clkm_conf.clk_en == 1) {
if (enable && !hw->clkm_conf.clk_en) {
hw->clkm_conf.clk_sel = 2;
hw->clkm_conf.clk_en = 1;
hw->conf2.val = 0;
} else if (!enable && hw->clkm_conf.clk_en) {
hw->clkm_conf.clk_en = 0;
}
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define i2s_ll_enable_core_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_core_clock(__VA_ARGS__)
/**
* @brief I2S tx msb right enable
*

View File

@ -17,6 +17,7 @@
#include "hal/assert.h"
#include "soc/i2s_periph.h"
#include "soc/i2s_struct.h"
#include "soc/system_struct.h"
#include "hal/i2s_types.h"
#include "hal/hal_utils.h"
@ -35,27 +36,62 @@ extern "C" {
#define I2S_LL_CLK_FRAC_DIV_AB_MAX 512 // I2S_MCLK = I2S_SRC_CLK / (N + b/a), the a/b register is 9 bit-width
#define I2S_LL_PLL_F160M_CLK_FREQ (160 * 1000000) // PLL_F160M_CLK: 160MHz
#define I2S_LL_DEFAULT_PLL_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
#define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_PLL_F160M_CLK_FREQ // The default PLL clock frequency while using I2S_CLK_SRC_DEFAULT
/**
* @brief Enable the bus clock for I2S module
*
* @param i2s_id The port id of I2S
* @param enable Set true to enable the buf clock
*/
static inline void i2s_ll_enable_bus_clock(int i2s_id, bool enable)
{
if (i2s_id == 0) {
SYSTEM.perip_clk_en0.i2s0_clk_en = enable;
} else if (i2s_id == 1) {
SYSTEM.perip_clk_en0.i2s1_clk_en = enable;
}
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define i2s_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_bus_clock(__VA_ARGS__)
/**
* @brief Reset the I2S module
*
* @param i2s_id The port id of I2S
*/
static inline void i2s_ll_reset_register(int i2s_id)
{
if (i2s_id == 0) {
SYSTEM.perip_rst_en0.i2s0_rst = 1;
SYSTEM.perip_rst_en0.i2s0_rst = 0;
} else if (i2s_id == 1) {
SYSTEM.perip_rst_en0.i2s1_rst = 1;
SYSTEM.perip_rst_en0.i2s1_rst = 0;
}
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define i2s_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_reset_register(__VA_ARGS__)
/**
* @brief I2S module general init, enable I2S clock.
*
* @param hw Peripheral I2S hardware instance address.
* @param enable set true to enable the core clock
*/
static inline void i2s_ll_enable_clock(i2s_dev_t *hw)
static inline void i2s_ll_enable_core_clock(i2s_dev_t *hw, bool enable)
{
hw->tx_clkm_conf.clk_en = 1;
hw->tx_clkm_conf.clk_en = enable;
}
/**
* @brief I2S module disable I2S clock.
*
* @param hw Peripheral I2S hardware instance address.
*/
static inline void i2s_ll_disable_clock(i2s_dev_t *hw)
{
hw->tx_clkm_conf.clk_en = 0;
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define i2s_ll_enable_core_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; i2s_ll_enable_core_clock(__VA_ARGS__)
/**
* @brief Enable I2S tx module clock

View File

@ -10,7 +10,7 @@
#include "soc/soc.h"
#include "hal/i2s_hal.h"
#if SOC_I2S_HW_VERSION_2 && SOC_I2S_SUPPORTS_PDM_TX
#if SOC_I2S_HW_VERSION_2 && (SOC_I2S_SUPPORTS_PDM_TX || SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER)
/* PDM tx high pass filter cut-off frequency and coefficients list
* [0]: cut-off frequency; [1]: param0; [2]: param5 */
static const float cut_off_coef[21][3] = {
@ -22,6 +22,22 @@ static const float cut_off_coef[21][3] = {
{63, 4, 7}, {58, 5, 6}, {49, 5, 7},
{46, 6, 6}, {35.5, 6, 7}, {23.3, 7, 7}
};
static void s_i2s_hal_get_cut_off_coef(float freq, uint32_t *param0, uint32_t *param5)
{
uint8_t cnt = 0;
float min = 1000;
/* Find the closest cut-off frequency and its coefficients */
for (int i = 0; i < 21; i++) {
float tmp = cut_off_coef[i][0] < freq ? freq - cut_off_coef[i][0] : cut_off_coef[i][0] - freq;
if (tmp < min) {
min = tmp;
cnt = i;
}
}
*param0 = (uint32_t)cut_off_coef[cnt][1];
*param5 = (uint32_t)cut_off_coef[cnt][2];
}
#endif
/**
@ -49,30 +65,38 @@ void i2s_hal_init(i2s_hal_context_t *hal, int port_id)
hal->dev = I2S_LL_GET_HW(port_id);
}
void i2s_hal_set_tx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src)
void _i2s_hal_set_tx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src)
{
hal_utils_clk_div_t mclk_div = {};
if (clk_info) {
hal_utils_clk_div_t mclk_div = {};
#if SOC_I2S_HW_VERSION_2
i2s_ll_tx_enable_clock(hal->dev);
i2s_ll_mclk_bind_to_tx_clk(hal->dev);
i2s_ll_tx_enable_clock(hal->dev);
i2s_ll_mclk_bind_to_tx_clk(hal->dev);
#endif
i2s_ll_tx_clk_set_src(hal->dev, clk_src);
i2s_hal_calc_mclk_precise_division(clk_info->sclk, clk_info->mclk, &mclk_div);
i2s_ll_tx_set_mclk(hal->dev, &mclk_div);
i2s_ll_tx_set_bck_div_num(hal->dev, clk_info->bclk_div);
i2s_ll_tx_clk_set_src(hal->dev, clk_src);
i2s_hal_calc_mclk_precise_division(clk_info->sclk, clk_info->mclk, &mclk_div);
i2s_ll_tx_set_mclk(hal->dev, &mclk_div);
i2s_ll_tx_set_bck_div_num(hal->dev, clk_info->bclk_div);
} else {
i2s_ll_tx_clk_set_src(hal->dev, clk_src);
}
}
void i2s_hal_set_rx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src)
void _i2s_hal_set_rx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src)
{
hal_utils_clk_div_t mclk_div = {};
if (clk_info) {
hal_utils_clk_div_t mclk_div = {};
#if SOC_I2S_HW_VERSION_2
i2s_ll_rx_enable_clock(hal->dev);
i2s_ll_mclk_bind_to_rx_clk(hal->dev);
i2s_ll_rx_enable_clock(hal->dev);
i2s_ll_mclk_bind_to_rx_clk(hal->dev);
#endif
i2s_ll_rx_clk_set_src(hal->dev, clk_src);
i2s_hal_calc_mclk_precise_division(clk_info->sclk, clk_info->mclk, &mclk_div);
i2s_ll_rx_set_mclk(hal->dev, &mclk_div);
i2s_ll_rx_set_bck_div_num(hal->dev, clk_info->bclk_div);
i2s_ll_rx_clk_set_src(hal->dev, clk_src);
i2s_hal_calc_mclk_precise_division(clk_info->sclk, clk_info->mclk, &mclk_div);
i2s_ll_rx_set_mclk(hal->dev, &mclk_div);
i2s_ll_rx_set_bck_div_num(hal->dev, clk_info->bclk_div);
} else {
i2s_ll_rx_clk_set_src(hal->dev, clk_src);
}
}
/*-------------------------------------------------------------------------
@ -183,20 +207,12 @@ void i2s_hal_pdm_set_tx_slot(i2s_hal_context_t *hal, bool is_slave, const i2s_ha
i2s_ll_tx_set_ws_idle_pol(hal->dev, false);
/* Slot mode seems not take effect according to the test, leave it default here */
i2s_ll_tx_pdm_slot_mode(hal->dev, is_mono, false, I2S_PDM_SLOT_BOTH);
uint8_t cnt = 0;
float min = 1000;
float expt_cut_off = slot_cfg->pdm_tx.hp_cut_off_freq_hz;
/* Find the closest cut-off frequency and its coefficients */
for (int i = 0; i < 21; i++) {
float tmp = cut_off_coef[i][0] < expt_cut_off ? expt_cut_off - cut_off_coef[i][0] : cut_off_coef[i][0] - expt_cut_off;
if (tmp < min) {
min = tmp;
cnt = i;
}
}
uint32_t param0;
uint32_t param5;
s_i2s_hal_get_cut_off_coef(slot_cfg->pdm_tx.hp_cut_off_freq_hz, &param0, &param5);
i2s_ll_tx_enable_pdm_hp_filter(hal->dev, slot_cfg->pdm_tx.hp_en);
i2s_ll_tx_set_pdm_hp_filter_param0(hal->dev, cut_off_coef[cnt][1]);
i2s_ll_tx_set_pdm_hp_filter_param5(hal->dev, cut_off_coef[cnt][2]);
i2s_ll_tx_set_pdm_hp_filter_param0(hal->dev, param0);
i2s_ll_tx_set_pdm_hp_filter_param5(hal->dev, param5);
i2s_ll_tx_set_pdm_sd_dither(hal->dev, slot_cfg->pdm_tx.sd_dither);
i2s_ll_tx_set_pdm_sd_dither2(hal->dev, slot_cfg->pdm_tx.sd_dither2);
#endif
@ -233,7 +249,18 @@ void i2s_hal_pdm_set_rx_slot(i2s_hal_context_t *hal, bool is_slave, const i2s_ha
uint32_t slot_mask = slot_cfg->slot_mode == I2S_SLOT_MODE_STEREO ? I2S_PDM_SLOT_BOTH : slot_cfg->pdm_rx.slot_mask;
#endif // SOC_I2S_SUPPORTS_PDM_RX > 1
i2s_ll_rx_set_active_chan_mask(hal->dev, slot_mask);
#endif // SOC_I2S_SUPPORTS_PDM_RX
#endif // SOC_I2S_HW_VERSION_1
#if SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER
uint32_t param0;
uint32_t param5;
s_i2s_hal_get_cut_off_coef(slot_cfg->pdm_rx.hp_cut_off_freq_hz, &param0, &param5);
i2s_ll_rx_enable_pdm_hp_filter(hal->dev, slot_cfg->pdm_rx.hp_en);
i2s_ll_rx_set_pdm_hp_filter_param0(hal->dev, param0);
i2s_ll_rx_set_pdm_hp_filter_param5(hal->dev, param5);
/* Set the amplification number, the default and the minimum value is 1. 0 will mute the channel */
i2s_ll_rx_set_pdm_amplify_num(hal->dev, slot_cfg->pdm_rx.amplify_num ? slot_cfg->pdm_rx.amplify_num : 1);
#endif // SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER
}
void i2s_hal_pdm_enable_rx_channel(i2s_hal_context_t *hal)

View File

@ -91,7 +91,13 @@ typedef struct {
/* PDM TX configurations */
struct {
i2s_pdm_slot_mask_t slot_mask; /*!< Choose the slots to activate */
} pdm_rx; /*!< Specific configurations for PDM TX mode */
#if SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER
bool hp_en; /*!< High pass filter enable */
float hp_cut_off_freq_hz; /*!< High pass filter cut-off frequency, range 23.3Hz ~ 185Hz, see cut-off frequency sheet above */
uint32_t amplify_num; /*!< The amplification number of the final conversion result */
#endif // SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER
} pdm_rx; /*!< Specific configurations for PDM RX mode */
#endif
};
@ -136,20 +142,35 @@ void i2s_hal_calc_mclk_precise_division(uint32_t sclk, uint32_t mclk, hal_utils_
* @brief Set tx channel clock
*
* @param hal Context of the HAL layer
* @param clk_info clock information
* @param clk_info clock information, if it is NULL, only set the clock source
* @param clk_src clock source
*/
void i2s_hal_set_tx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src);
void _i2s_hal_set_tx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src);
#if SOC_PERIPH_CLK_CTRL_SHARED
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define i2s_hal_set_tx_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _i2s_hal_set_tx_clock(__VA_ARGS__)
#else
#define i2s_hal_set_tx_clock(...) _i2s_hal_set_tx_clock(__VA_ARGS__)
#endif
/**
* @brief Set rx channel clock
*
* @param hal Context of the HAL layer
* @param clk_info clock information
* @param clk_info clock information, if it is NULL, only set the clock source
* @param clk_src clock source
*/
void i2s_hal_set_rx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src);
void _i2s_hal_set_rx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *clk_info, i2s_clock_src_t clk_src);
#if SOC_PERIPH_CLK_CTRL_SHARED
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define i2s_hal_set_rx_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; _i2s_hal_set_rx_clock(__VA_ARGS__)
#else
#define i2s_hal_set_rx_clock(...) _i2s_hal_set_rx_clock(__VA_ARGS__)
#endif
/*-------------------------------------------------------------------------
| STD configuration |

View File

@ -811,22 +811,6 @@ config SOC_CLK_APLL_SUPPORTED
bool
default y
config SOC_APLL_MULTIPLIER_OUT_MIN_HZ
int
default 350000000
config SOC_APLL_MULTIPLIER_OUT_MAX_HZ
int
default 500000000
config SOC_APLL_MIN_HZ
int
default 5303031
config SOC_APLL_MAX_HZ
int
default 125000000
config SOC_CLK_RC_FAST_D256_SUPPORTED
bool
default y

View File

@ -1,6 +1,6 @@
/*
* SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -399,11 +399,6 @@
/*-------------------------- CLOCK SUBSYSTEM CAPS ----------------------------------------*/
#define SOC_CLK_APLL_SUPPORTED (1)
// apll_multiplier_out = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)
#define SOC_APLL_MULTIPLIER_OUT_MIN_HZ (350000000) // 350 MHz
#define SOC_APLL_MULTIPLIER_OUT_MAX_HZ (500000000) // 500 MHz
#define SOC_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
#define SOC_APLL_MAX_HZ (125000000) // 125MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
#define SOC_CLK_RC_FAST_D256_SUPPORTED (1)
#define SOC_RTC_SLOW_CLK_SUPPORT_RC_FAST_D256 (1)

View File

@ -29,7 +29,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
.data_out_sigs[1] = I2SO_SD1_OUT_IDX,
.data_in_sig = I2SI_SD_IN_IDX,
.irq = -1,
.irq = ETS_I2S1_INTR_SOURCE,
.module = PERIPH_I2S1_MODULE,
}
};

View File

@ -29,7 +29,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
.data_out_sigs[1] = I2SO_SD1_OUT_IDX,
.data_in_sig = I2SI_SD_IN_IDX,
.irq = -1,
.irq = ETS_I2S1_INTR_SOURCE,
.module = PERIPH_I2S1_MODULE,
}
};

View File

@ -240,34 +240,6 @@ typedef union {
uint32_t val;
} i2s_rx_conf1_reg_t;
/** Type of rx_clkm_conf register
* I2S RX clock configure register
*/
typedef union {
struct {
/** rx_clkm_div_num : R/W; bitpos: [7:0]; default: 2;
* Integral I2S clock divider value
*/
uint32_t rx_clkm_div_num:8;
uint32_t reserved_8:18;
/** rx_clk_active : R/W; bitpos: [26]; default: 0;
* I2S Rx module clock enable signal.
*/
uint32_t rx_clk_active:1;
/** rx_clk_sel : R/W; bitpos: [28:27]; default: 0;
* Select I2S Rx module source clock. 0: XTAL clock. 1: PLL240M. 2: PLL160M. 3: I2S_MCLK_in.
*/
uint32_t rx_clk_sel:2;
/** mclk_sel : R/W; bitpos: [29]; default: 0;
* 0: UseI2S Tx module clock as I2S_MCLK_OUT. 1: UseI2S Rx module clock as
* I2S_MCLK_OUT.
*/
uint32_t mclk_sel:1;
uint32_t reserved_30:2;
};
uint32_t val;
} i2s_rx_clkm_conf_reg_t;
/** Type of tx_pcm2pdm_conf register
* I2S TX PCM2PDM configuration register
*/
@ -609,37 +581,6 @@ typedef union {
uint32_t val;
} i2s_tx_conf1_reg_t;
/** Type of tx_clkm_conf register
* I2S TX clock configure register
*/
typedef union {
struct {
/** tx_clkm_div_num : R/W; bitpos: [7:0]; default: 2;
* Integral I2S TX clock divider value. f_I2S_CLK = f_I2S_CLK_S/(N+b/a). There will be
* (a-b) * n-div and b * (n+1)-div. So the average combination will be: for b <=
* a/2, z * [x * n-div + (n+1)-div] + y * n-div. For b > a/2, z * [n-div + x *
* (n+1)-div] + y * (n+1)-div.
*/
uint32_t tx_clkm_div_num:8;
uint32_t reserved_8:18;
/** tx_clk_active : R/W; bitpos: [26]; default: 0;
* I2S Tx module clock enable signal.
*/
uint32_t tx_clk_active:1;
/** tx_clk_sel : R/W; bitpos: [28:27]; default: 0;
* Select I2S Tx module source clock. 0: XTAL clock. 1: PLL240M. 2: PLL160M. 3:
* I2S_MCLK_in.
*/
uint32_t tx_clk_sel:2;
/** clk_en : R/W; bitpos: [29]; default: 0;
* Set this bit to enable clk gate
*/
uint32_t clk_en:1;
uint32_t reserved_30:2;
};
uint32_t val;
} i2s_tx_clkm_conf_reg_t;
/** Type of tx_tdm_ctrl register
* I2S TX TDM mode control register
*/
@ -742,36 +683,6 @@ typedef union {
/** Group: RX clock and timing registers */
/** Type of rx_clkm_div_conf register
* I2S RX module clock divider configure register
*/
typedef union {
struct {
/** rx_clkm_div_z : R/W; bitpos: [8:0]; default: 0;
* For b <= a/2, the value of I2S_RX_CLKM_DIV_Z is b. For b > a/2, the value of
* I2S_RX_CLKM_DIV_Z is (a-b).
*/
uint32_t rx_clkm_div_z:9;
/** rx_clkm_div_y : R/W; bitpos: [17:9]; default: 1;
* For b <= a/2, the value of I2S_RX_CLKM_DIV_Y is (a%b) . For b > a/2, the value of
* I2S_RX_CLKM_DIV_Y is (a%(a-b)).
*/
uint32_t rx_clkm_div_y:9;
/** rx_clkm_div_x : R/W; bitpos: [26:18]; default: 0;
* For b <= a/2, the value of I2S_RX_CLKM_DIV_X is (a/b) - 1. For b > a/2, the value
* of I2S_RX_CLKM_DIV_X is (a/(a-b)) - 1.
*/
uint32_t rx_clkm_div_x:9;
/** rx_clkm_div_yn1 : R/W; bitpos: [27]; default: 0;
* For b <= a/2, the value of I2S_RX_CLKM_DIV_YN1 is 0 . For b > a/2, the value of
* I2S_RX_CLKM_DIV_YN1 is 1.
*/
uint32_t rx_clkm_div_yn1:1;
uint32_t reserved_28:4;
};
uint32_t val;
} i2s_rx_clkm_div_conf_reg_t;
/** Type of rx_timing register
* I2S RX timing control register
*/
@ -813,36 +724,6 @@ typedef union {
/** Group: TX clock and timing registers */
/** Type of tx_clkm_div_conf register
* I2S TX module clock divider configure register
*/
typedef union {
struct {
/** tx_clkm_div_z : R/W; bitpos: [8:0]; default: 0;
* For b <= a/2, the value of I2S_TX_CLKM_DIV_Z is b. For b > a/2, the value of
* I2S_TX_CLKM_DIV_Z is (a-b).
*/
uint32_t tx_clkm_div_z:9;
/** tx_clkm_div_y : R/W; bitpos: [17:9]; default: 1;
* For b <= a/2, the value of I2S_TX_CLKM_DIV_Y is (a%b) . For b > a/2, the value of
* I2S_TX_CLKM_DIV_Y is (a%(a-b)).
*/
uint32_t tx_clkm_div_y:9;
/** tx_clkm_div_x : R/W; bitpos: [26:18]; default: 0;
* For b <= a/2, the value of I2S_TX_CLKM_DIV_X is (a/b) - 1. For b > a/2, the value
* of I2S_TX_CLKM_DIV_X is (a/(a-b)) - 1.
*/
uint32_t tx_clkm_div_x:9;
/** tx_clkm_div_yn1 : R/W; bitpos: [27]; default: 0;
* For b <= a/2, the value of I2S_TX_CLKM_DIV_YN1 is 0 . For b > a/2, the value of
* I2S_TX_CLKM_DIV_YN1 is 1.
*/
uint32_t tx_clkm_div_yn1:1;
uint32_t reserved_28:4;
};
uint32_t val;
} i2s_tx_clkm_div_conf_reg_t;
/** Type of tx_timing register
* I2S TX timing control register
*/
@ -993,10 +874,7 @@ typedef struct i2s_dev_t {
volatile i2s_tx_conf_reg_t tx_conf;
volatile i2s_rx_conf1_reg_t rx_conf1;
volatile i2s_tx_conf1_reg_t tx_conf1;
volatile i2s_rx_clkm_conf_reg_t rx_clkm_conf;
volatile i2s_tx_clkm_conf_reg_t tx_clkm_conf;
volatile i2s_rx_clkm_div_conf_reg_t rx_clkm_div_conf;
volatile i2s_tx_clkm_div_conf_reg_t tx_clkm_div_conf;
uint32_t reserved_030[4];
volatile i2s_tx_pcm2pdm_conf_reg_t tx_pcm2pdm_conf;
volatile i2s_tx_pcm2pdm_conf1_reg_t tx_pcm2pdm_conf1;
uint32_t reserved_048[2];

View File

@ -28,7 +28,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
.data_out_sig = I2SO_SD_OUT_IDX,
.data_in_sig = I2SI_SD_IN_IDX,
.irq = -1,
.irq = ETS_I2S1_INTR_SOURCE,
.module = PERIPH_I2S1_MODULE,
}
};

View File

@ -240,34 +240,6 @@ typedef union {
uint32_t val;
} i2s_rx_conf1_reg_t;
/** Type of rx_clkm_conf register
* I2S RX clock configure register
*/
typedef union {
struct {
/** rx_clkm_div_num : R/W; bitpos: [7:0]; default: 2;
* Integral I2S clock divider value
*/
uint32_t rx_clkm_div_num:8;
uint32_t reserved_8:18;
/** rx_clk_active : R/W; bitpos: [26]; default: 0;
* I2S Rx module clock enable signal.
*/
uint32_t rx_clk_active:1;
/** rx_clk_sel : R/W; bitpos: [28:27]; default: 0;
* Select I2S Rx module source clock. 0: no clock. 1: APLL. 2: CLK160. 3: I2S_MCLK_in.
*/
uint32_t rx_clk_sel:2;
/** mclk_sel : R/W; bitpos: [29]; default: 0;
* 0: UseI2S Tx module clock as I2S_MCLK_OUT. 1: UseI2S Rx module clock as
* I2S_MCLK_OUT.
*/
uint32_t mclk_sel:1;
uint32_t reserved_30:2;
};
uint32_t val;
} i2s_rx_clkm_conf_reg_t;
/** Type of tx_pcm2pdm_conf register
* I2S TX PCM2PDM configuration register
*/
@ -607,37 +579,6 @@ typedef union {
uint32_t val;
} i2s_tx_conf1_reg_t;
/** Type of tx_clkm_conf register
* I2S TX clock configure register
*/
typedef union {
struct {
/** tx_clkm_div_num : R/W; bitpos: [7:0]; default: 2;
* Integral I2S TX clock divider value. f_I2S_CLK = f_I2S_CLK_S/(N+b/a). There will be
* (a-b) * n-div and b * (n+1)-div. So the average combination will be: for b <=
* a/2, z * [x * n-div + (n+1)-div] + y * n-div. For b > a/2, z * [n-div + x *
* (n+1)-div] + y * (n+1)-div.
*/
uint32_t tx_clkm_div_num:8;
uint32_t reserved_8:18;
/** tx_clk_active : R/W; bitpos: [26]; default: 0;
* I2S Tx module clock enable signal.
*/
uint32_t tx_clk_active:1;
/** tx_clk_sel : R/W; bitpos: [28:27]; default: 0;
* Select I2S Tx module source clock. 0: XTAL clock. 1: APLL. 2: CLK160. 3:
* I2S_MCLK_in.
*/
uint32_t tx_clk_sel:2;
/** clk_en : R/W; bitpos: [29]; default: 0;
* Set this bit to enable clk gate
*/
uint32_t clk_en:1;
uint32_t reserved_30:2;
};
uint32_t val;
} i2s_tx_clkm_conf_reg_t;
/** Type of tx_tdm_ctrl register
* I2S TX TDM mode control register
*/
@ -740,36 +681,6 @@ typedef union {
/** Group: RX clock and timing registers */
/** Type of rx_clkm_div_conf register
* I2S RX module clock divider configure register
*/
typedef union {
struct {
/** rx_clkm_div_z : R/W; bitpos: [8:0]; default: 0;
* For b <= a/2, the value of I2S_RX_CLKM_DIV_Z is b. For b > a/2, the value of
* I2S_RX_CLKM_DIV_Z is (a-b).
*/
uint32_t rx_clkm_div_z:9;
/** rx_clkm_div_y : R/W; bitpos: [17:9]; default: 1;
* For b <= a/2, the value of I2S_RX_CLKM_DIV_Y is (a%b) . For b > a/2, the value of
* I2S_RX_CLKM_DIV_Y is (a%(a-b)).
*/
uint32_t rx_clkm_div_y:9;
/** rx_clkm_div_x : R/W; bitpos: [26:18]; default: 0;
* For b <= a/2, the value of I2S_RX_CLKM_DIV_X is (a/b) - 1. For b > a/2, the value
* of I2S_RX_CLKM_DIV_X is (a/(a-b)) - 1.
*/
uint32_t rx_clkm_div_x:9;
/** rx_clkm_div_yn1 : R/W; bitpos: [27]; default: 0;
* For b <= a/2, the value of I2S_RX_CLKM_DIV_YN1 is 0 . For b > a/2, the value of
* I2S_RX_CLKM_DIV_YN1 is 1.
*/
uint32_t rx_clkm_div_yn1:1;
uint32_t reserved_28:4;
};
uint32_t val;
} i2s_rx_clkm_div_conf_reg_t;
/** Type of rx_timing register
* I2S RX timing control register
*/
@ -811,36 +722,6 @@ typedef union {
/** Group: TX clock and timing registers */
/** Type of tx_clkm_div_conf register
* I2S TX module clock divider configure register
*/
typedef union {
struct {
/** tx_clkm_div_z : R/W; bitpos: [8:0]; default: 0;
* For b <= a/2, the value of I2S_TX_CLKM_DIV_Z is b. For b > a/2, the value of
* I2S_TX_CLKM_DIV_Z is (a-b).
*/
uint32_t tx_clkm_div_z:9;
/** tx_clkm_div_y : R/W; bitpos: [17:9]; default: 1;
* For b <= a/2, the value of I2S_TX_CLKM_DIV_Y is (a%b) . For b > a/2, the value of
* I2S_TX_CLKM_DIV_Y is (a%(a-b)).
*/
uint32_t tx_clkm_div_y:9;
/** tx_clkm_div_x : R/W; bitpos: [26:18]; default: 0;
* For b <= a/2, the value of I2S_TX_CLKM_DIV_X is (a/b) - 1. For b > a/2, the value
* of I2S_TX_CLKM_DIV_X is (a/(a-b)) - 1.
*/
uint32_t tx_clkm_div_x:9;
/** tx_clkm_div_yn1 : R/W; bitpos: [27]; default: 0;
* For b <= a/2, the value of I2S_TX_CLKM_DIV_YN1 is 0 . For b > a/2, the value of
* I2S_TX_CLKM_DIV_YN1 is 1.
*/
uint32_t tx_clkm_div_yn1:1;
uint32_t reserved_28:4;
};
uint32_t val;
} i2s_tx_clkm_div_conf_reg_t;
/** Type of tx_timing register
* I2S TX timing control register
*/
@ -991,10 +872,7 @@ typedef struct {
volatile i2s_tx_conf_reg_t tx_conf;
volatile i2s_rx_conf1_reg_t rx_conf1;
volatile i2s_tx_conf1_reg_t tx_conf1;
volatile i2s_rx_clkm_conf_reg_t rx_clkm_conf;
volatile i2s_tx_clkm_conf_reg_t tx_clkm_conf;
volatile i2s_rx_clkm_div_conf_reg_t rx_clkm_div_conf;
volatile i2s_tx_clkm_div_conf_reg_t tx_clkm_div_conf;
uint32_t reserved_030[4];
volatile i2s_tx_pcm2pdm_conf_reg_t tx_pcm2pdm_conf;
volatile i2s_tx_pcm2pdm_conf1_reg_t tx_pcm2pdm_conf1;
uint32_t reserved_048[2];

View File

@ -11,4 +11,76 @@
Bunch of constants for every I2S peripheral: GPIO signals, irqs, hw addr of registers etc
*/
const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
[0] = {
.mck_out_sig = I2S0_MCLK_PAD_OUT_IDX,
.mck_in_sig = I2S0_MCLK_PAD_IN_IDX,
.m_tx_bck_sig = I2S0_O_BCK_PAD_OUT_IDX,
.m_rx_bck_sig = I2S0_I_BCK_PAD_OUT_IDX,
.m_tx_ws_sig = I2S0_O_WS_PAD_OUT_IDX,
.m_rx_ws_sig = I2S0_I_WS_PAD_OUT_IDX,
.s_tx_bck_sig = I2S0_O_BCK_PAD_IN_IDX,
.s_rx_bck_sig = I2S0_I_BCK_PAD_IN_IDX,
.s_tx_ws_sig = I2S0_O_WS_PAD_IN_IDX,
.s_rx_ws_sig = I2S0_I_WS_PAD_IN_IDX,
.data_out_sigs[0] = I2S0_O_SD_PAD_OUT_IDX,
.data_out_sigs[1] = I2S0_O_SD1_PAD_OUT_IDX,
.data_in_sigs[0] = I2S0_I_SD_PAD_IN_IDX,
.data_in_sigs[1] = I2S0_I_SD1_PAD_IN_IDX,
.data_in_sigs[2] = I2S0_I_SD2_PAD_IN_IDX,
.data_in_sigs[3] = I2S0_I_SD3_PAD_IN_IDX,
.irq = ETS_I2S0_INTR_SOURCE,
.module = PERIPH_I2S0_MODULE,
},
[1] = {
.mck_out_sig = I2S1_MCLK_PAD_OUT_IDX,
.mck_in_sig = I2S1_MCLK_PAD_IN_IDX,
.m_tx_bck_sig = I2S1_O_BCK_PAD_OUT_IDX,
.m_rx_bck_sig = I2S1_I_BCK_PAD_OUT_IDX,
.m_tx_ws_sig = I2S1_O_WS_PAD_OUT_IDX,
.m_rx_ws_sig = I2S1_I_WS_PAD_OUT_IDX,
.s_tx_bck_sig = I2S1_O_BCK_PAD_IN_IDX,
.s_rx_bck_sig = I2S1_I_BCK_PAD_IN_IDX,
.s_tx_ws_sig = I2S1_O_WS_PAD_IN_IDX,
.s_rx_ws_sig = I2S1_I_WS_PAD_IN_IDX,
.data_out_sigs[0] = I2S1_O_SD_PAD_OUT_IDX,
.data_out_sigs[1] = -1,
.data_in_sigs[0] = I2S1_I_SD_PAD_IN_IDX,
.data_in_sigs[1] = -1,
.data_in_sigs[2] = -1,
.data_in_sigs[3] = -1,
.irq = ETS_I2S1_INTR_SOURCE,
.module = PERIPH_I2S1_MODULE,
},
[2] = {
.mck_out_sig = I2S2_MCLK_PAD_OUT_IDX,
.mck_in_sig = I2S2_MCLK_PAD_IN_IDX,
.m_tx_bck_sig = I2S2_O_BCK_PAD_OUT_IDX,
.m_rx_bck_sig = I2S2_I_BCK_PAD_OUT_IDX,
.m_tx_ws_sig = I2S2_O_WS_PAD_OUT_IDX,
.m_rx_ws_sig = I2S2_I_WS_PAD_OUT_IDX,
.s_tx_bck_sig = I2S2_O_BCK_PAD_IN_IDX,
.s_rx_bck_sig = I2S2_I_BCK_PAD_IN_IDX,
.s_tx_ws_sig = I2S2_O_WS_PAD_IN_IDX,
.s_rx_ws_sig = I2S2_I_WS_PAD_IN_IDX,
.data_out_sigs[0] = I2S2_O_SD_PAD_OUT_IDX,
.data_out_sigs[1] = -1,
.data_in_sigs[0] = I2S2_I_SD_PAD_IN_IDX,
.data_in_sigs[1] = -1,
.data_in_sigs[2] = -1,
.data_in_sigs[3] = -1,
.irq = ETS_I2S2_INTR_SOURCE,
.module = PERIPH_I2S2_MODULE,
},
};

View File

@ -67,6 +67,10 @@ config SOC_RMT_SUPPORTED
bool
default y
config SOC_I2S_SUPPORTED
bool
default y
config SOC_I2C_SUPPORTED
bool
default y
@ -433,7 +437,7 @@ config SOC_I2C_SUPPORT_RTC
config SOC_I2S_NUM
int
default 1
default 3
config SOC_I2S_HW_VERSION_2
bool
@ -443,7 +447,7 @@ config SOC_I2S_SUPPORTS_XTAL
bool
default y
config SOC_I2S_SUPPORTS_PLL_F160M
config SOC_I2S_SUPPORTS_APLL
bool
default y
@ -451,10 +455,42 @@ config SOC_I2S_SUPPORTS_PCM
bool
default y
config SOC_I2S_SUPPORTS_PDM
bool
default y
config SOC_I2S_SUPPORTS_PDM_TX
bool
default y
config SOC_I2S_SUPPORTS_PDM_RX
bool
default y
config SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER
bool
default y
config SOC_I2S_SUPPORTS_TX_SYNC_CNT
bool
default y
config SOC_I2S_SUPPORTS_TDM
bool
default y
config SOC_I2S_PDM_MAX_TX_LINES
int
default 2
config SOC_I2S_PDM_MAX_RX_LINES
int
default 4
config SOC_I2S_TDM_FULL_DATA_WIDTH
bool
default y
config SOC_LEDC_SUPPORT_PLL_DIV_CLOCK
bool
default y
@ -1095,6 +1131,10 @@ config SOC_MODEM_CLOCK_IS_INDEPENDENT
bool
default n
config SOC_CLK_APLL_SUPPORTED
bool
default y
config SOC_CLK_XTAL32K_SUPPORTED
bool
default y

View File

@ -150,6 +150,7 @@ typedef enum {
SOC_MOD_CLK_XTAL32K, /*!< XTAL32K_CLK comes from the external 32kHz crystal, passing a clock gating to the peripherals */
SOC_MOD_CLK_RC_FAST, /*!< RC_FAST_CLK comes from the internal 20MHz rc oscillator, passing a clock gating to the peripherals */
SOC_MOD_CLK_XTAL, /*!< XTAL_CLK comes from the external 40MHz crystal */
SOC_MOD_CLK_APLL, /*!< Audio PLL is sourced from PLL, and its frequency is configurable through APLL configuration registers */
SOC_MOD_CLK_INVALID, /*!< Indication of the end of the available module clock sources */
} soc_module_clk_t;
@ -334,6 +335,21 @@ typedef enum {
///////////////////////////////////////////////// I2S //////////////////////////////////////////////////////////////
/**
* @brief Array initializer for all supported clock sources of I2S
*/
#define SOC_I2S_CLKS {SOC_MOD_CLK_XTAL, SOC_MOD_CLK_APLL, I2S_CLK_SRC_EXTERNAL}
/**
* @brief I2S clock source enum
*/
typedef enum {
I2S_CLK_SRC_DEFAULT = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the default source clock */
I2S_CLK_SRC_XTAL = SOC_MOD_CLK_XTAL, /*!< Select XTAL as the source clock */
I2S_CLK_SRC_APLL = SOC_MOD_CLK_APLL, /*!< Select APLL as the source clock */
I2S_CLK_SRC_EXTERNAL = -1, /*!< Select external clock as source clock */
} soc_periph_i2s_clk_src_t;
/////////////////////////////////////////////////I2C////////////////////////////////////////////////////////////////////
/**

View File

@ -277,6 +277,92 @@ typedef union {
uint32_t val;
} i2s_rx_pdm2pcm_conf_reg_t;
/** Type of tx_pcm2pdm_conf register
* I2S TX PCM2PDM configuration register
*/
typedef union {
struct {
/** tx_pdm_hp_bypass : R/W; bitpos: [0]; default: 0;
* I2S TX PDM bypass hp filter or not. The option has been removed.
*/
uint32_t tx_pdm_hp_bypass:1;
/** tx_pdm_sinc_osr2 : R/W; bitpos: [4:1]; default: 2;
* I2S TX PDM OSR2 value
*/
uint32_t tx_pdm_sinc_osr2:4;
/** tx_pdm_prescale : R/W; bitpos: [12:5]; default: 0;
* I2S TX PDM prescale for sigmadelta
*/
uint32_t tx_pdm_prescale:8;
/** tx_pdm_hp_in_shift : R/W; bitpos: [14:13]; default: 1;
* I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4
*/
uint32_t tx_pdm_hp_in_shift:2;
/** tx_pdm_lp_in_shift : R/W; bitpos: [16:15]; default: 1;
* I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4
*/
uint32_t tx_pdm_lp_in_shift:2;
/** tx_pdm_sinc_in_shift : R/W; bitpos: [18:17]; default: 1;
* I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4
*/
uint32_t tx_pdm_sinc_in_shift:2;
/** tx_pdm_sigmadelta_in_shift : R/W; bitpos: [20:19]; default: 1;
* I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4
*/
uint32_t tx_pdm_sigmadelta_in_shift:2;
/** tx_pdm_sigmadelta_dither2 : R/W; bitpos: [21]; default: 0;
* I2S TX PDM sigmadelta dither2 value
*/
uint32_t tx_pdm_sigmadelta_dither2:1;
/** tx_pdm_sigmadelta_dither : R/W; bitpos: [22]; default: 1;
* I2S TX PDM sigmadelta dither value
*/
uint32_t tx_pdm_sigmadelta_dither:1;
/** tx_pdm_dac_2out_en : R/W; bitpos: [23]; default: 0;
* I2S TX PDM dac mode enable
*/
uint32_t tx_pdm_dac_2out_en:1;
/** tx_pdm_dac_mode_en : R/W; bitpos: [24]; default: 0;
* I2S TX PDM dac 2channel enable
*/
uint32_t tx_pdm_dac_mode_en:1;
/** pcm2pdm_conv_en : R/W; bitpos: [25]; default: 0;
* I2S TX PDM Converter enable
*/
uint32_t pcm2pdm_conv_en:1;
uint32_t reserved_26:6;
};
uint32_t val;
} i2s_tx_pcm2pdm_conf_reg_t;
/** Type of tx_pcm2pdm_conf1 register
* I2S TX PCM2PDM configuration register
*/
typedef union {
struct {
/** tx_pdm_fp : R/W; bitpos: [9:0]; default: 960;
* I2S TX PDM Fp
*/
uint32_t tx_pdm_fp:10;
/** tx_pdm_fs : R/W; bitpos: [19:10]; default: 480;
* I2S TX PDM Fs
*/
uint32_t tx_pdm_fs:10;
/** tx_iir_hp_mult12_5 : R/W; bitpos: [22:20]; default: 7;
* The fourth parameter of PDM TX IIR_HP filter stage 2 is (504 +
* I2S_TX_IIR_HP_MULT12_5[2:0])
*/
uint32_t tx_iir_hp_mult12_5:3;
/** tx_iir_hp_mult12_0 : R/W; bitpos: [25:23]; default: 7;
* The fourth parameter of PDM TX IIR_HP filter stage 1 is (504 +
* I2S_TX_IIR_HP_MULT12_0[2:0])
*/
uint32_t tx_iir_hp_mult12_0:3;
uint32_t reserved_26:6;
};
uint32_t val;
} i2s_tx_pcm2pdm_conf1_reg_t;
/** Type of rx_tdm_ctrl register
* I2S TX TDM mode control register
*/
@ -371,7 +457,7 @@ typedef union {
uint32_t val;
} i2s_rx_tdm_ctrl_reg_t;
/** Type of rxeof_num register
/** Type of rx_eof_num register
* I2S RX data number control register.
*/
typedef union {
@ -384,7 +470,7 @@ typedef union {
uint32_t reserved_12:20;
};
uint32_t val;
} i2s_rxeof_num_reg_t;
} i2s_rx_eof_num_reg_t;
/** Group: TX Control and configuration registers */
@ -530,89 +616,6 @@ typedef union {
uint32_t val;
} i2s_tx_conf1_reg_t;
/** Type of tx_pcm2pdm_conf register
* I2S TX PCM2PDM configuration register
*/
typedef union {
struct {
uint32_t reserved_0:1;
/** tx_pdm_sinc_osr2 : R/W; bitpos: [4:1]; default: 2;
* I2S TX PDM OSR2 value
*/
uint32_t tx_pdm_sinc_osr2:4;
/** tx_pdm_prescale : R/W; bitpos: [12:5]; default: 0;
* I2S TX PDM prescale for sigmadelta
*/
uint32_t tx_pdm_prescale:8;
/** tx_pdm_hp_in_shift : R/W; bitpos: [14:13]; default: 1;
* I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4
*/
uint32_t tx_pdm_hp_in_shift:2;
/** tx_pdm_lp_in_shift : R/W; bitpos: [16:15]; default: 1;
* I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4
*/
uint32_t tx_pdm_lp_in_shift:2;
/** tx_pdm_sinc_in_shift : R/W; bitpos: [18:17]; default: 1;
* I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4
*/
uint32_t tx_pdm_sinc_in_shift:2;
/** tx_pdm_sigmadelta_in_shift : R/W; bitpos: [20:19]; default: 1;
* I2S TX PDM sigmadelta scale shift number: 0:/2 , 1:x1 , 2:x2 , 3: x4
*/
uint32_t tx_pdm_sigmadelta_in_shift:2;
/** tx_pdm_sigmadelta_dither2 : R/W; bitpos: [21]; default: 0;
* I2S TX PDM sigmadelta dither2 value
*/
uint32_t tx_pdm_sigmadelta_dither2:1;
/** tx_pdm_sigmadelta_dither : R/W; bitpos: [22]; default: 1;
* I2S TX PDM sigmadelta dither value
*/
uint32_t tx_pdm_sigmadelta_dither:1;
/** tx_pdm_dac_2out_en : R/W; bitpos: [23]; default: 0;
* I2S TX PDM dac mode enable
*/
uint32_t tx_pdm_dac_2out_en:1;
/** tx_pdm_dac_mode_en : R/W; bitpos: [24]; default: 0;
* I2S TX PDM dac 2channel enable
*/
uint32_t tx_pdm_dac_mode_en:1;
/** pcm2pdm_conv_en : R/W; bitpos: [25]; default: 0;
* I2S TX PDM Converter enable
*/
uint32_t pcm2pdm_conv_en:1;
uint32_t reserved_26:6;
};
uint32_t val;
} i2s_tx_pcm2pdm_conf_reg_t;
/** Type of tx_pcm2pdm_conf1 register
* I2S TX PCM2PDM configuration register
*/
typedef union {
struct {
/** tx_pdm_fp : R/W; bitpos: [9:0]; default: 960;
* I2S TX PDM Fp
*/
uint32_t tx_pdm_fp:10;
/** tx_pdm_fs : R/W; bitpos: [19:10]; default: 480;
* I2S TX PDM Fs
*/
uint32_t tx_pdm_fs:10;
/** tx_iir_hp_mult12_5 : R/W; bitpos: [22:20]; default: 7;
* The fourth parameter of PDM TX IIR_HP filter stage 2 is (504 +
* I2S_TX_IIR_HP_MULT12_5[2:0])
*/
uint32_t tx_iir_hp_mult12_5:3;
/** tx_iir_hp_mult12_0 : R/W; bitpos: [25:23]; default: 7;
* The fourth parameter of PDM TX IIR_HP filter stage 1 is (504 +
* I2S_TX_IIR_HP_MULT12_0[2:0])
*/
uint32_t tx_iir_hp_mult12_0:3;
uint32_t reserved_26:6;
};
uint32_t val;
} i2s_tx_pcm2pdm_conf1_reg_t;
/** Type of tx_tdm_ctrl register
* I2S TX TDM mode control register
*/
@ -845,7 +848,7 @@ typedef union {
uint32_t val;
} i2s_lc_hung_conf_reg_t;
/** Type of conf_sigle_data register
/** Type of conf_single_data register
* I2S signal data register
*/
typedef union {
@ -856,7 +859,7 @@ typedef union {
uint32_t single_data:32;
};
uint32_t val;
} i2s_conf_sigle_data_reg_t;
} i2s_conf_single_data_reg_t;
/** Group: TX status registers */
@ -986,8 +989,8 @@ typedef struct {
volatile i2s_rx_timing_reg_t rx_timing;
volatile i2s_tx_timing_reg_t tx_timing;
volatile i2s_lc_hung_conf_reg_t lc_hung_conf;
volatile i2s_rxeof_num_reg_t rxeof_num;
volatile i2s_conf_sigle_data_reg_t conf_sigle_data;
volatile i2s_rx_eof_num_reg_t rx_eof_num;
volatile i2s_conf_single_data_reg_t conf_single_data;
volatile i2s_state_reg_t state;
volatile i2s_etm_conf_reg_t etm_conf;
volatile i2s_fifo_cnt_reg_t fifo_cnt;
@ -996,6 +999,9 @@ typedef struct {
volatile i2s_date_reg_t date;
} i2s_dev_t;
extern i2s_dev_t I2S0;
extern i2s_dev_t I2S1;
extern i2s_dev_t I2S2;
#ifndef __cplusplus
_Static_assert(sizeof(i2s_dev_t) == 0x84, "Invalid size of i2s_dev_t structure");

View File

@ -486,6 +486,44 @@ bool rtc_dig_8m_enabled(void);
*/
uint32_t rtc_clk_freq_cal(uint32_t cal_val);
/**
* @brief Enable or disable APLL
*
* Output frequency is given by the formula:
* apll_freq = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)/((o_div + 2) * 2)
*
* The dividend in this expression should be in the range of 240 - 600 MHz.
*
* In rev. 0 of ESP32, sdm0 and sdm1 are unused and always set to 0.
*
* @param enable true to enable, false to disable
*/
void rtc_clk_apll_enable(bool enable);
/**
* @brief Calculate APLL clock coeffifcients
*
* @param freq expected APLL frequency
* @param o_div frequency divider, 0..31
* @param sdm0 frequency adjustment parameter, 0..255
* @param sdm1 frequency adjustment parameter, 0..255
* @param sdm2 frequency adjustment parameter, 0..63
*
* @return
* - 0 Failed
* - else Sucess
*/
uint32_t rtc_clk_apll_coeff_calc(uint32_t freq, uint32_t *_o_div, uint32_t *_sdm0, uint32_t *_sdm1, uint32_t *_sdm2);
/**
* @brief Set APLL clock coeffifcients
*
* @param o_div frequency divider, 0..31
* @param sdm0 frequency adjustment parameter, 0..255
* @param sdm1 frequency adjustment parameter, 0..255
* @param sdm2 frequency adjustment parameter, 0..63
*/
void rtc_clk_apll_coeff_set(uint32_t o_div, uint32_t sdm0, uint32_t sdm1, uint32_t sdm2);
// -------------------------- CLOCK TREE DEFS ALIAS ----------------------------
// **WARNING**: The following are only for backwards compatibility.

View File

@ -48,8 +48,9 @@
// #define SOC_EFUSE_SUPPORTED 1 //TODO: IDF-7512
#define SOC_RTC_FAST_MEM_SUPPORTED 1
#define SOC_RTC_MEM_SUPPORTED 1
// #define SOC_I2S_SUPPORTED 1 //TODO: IDF-6508
#define SOC_RMT_SUPPORTED 1
#define SOC_I2S_SUPPORTED 1
// #define SOC_RMT_SUPPORTED 1 //TODO: IDF-7476
// #define SOC_SDM_SUPPORTED 1 //TODO: IDF-7551
// #define SOC_GPSPI_SUPPORTED 1 //TODO: IDF-7502, TODO: IDF-7503
// #define SOC_LEDC_SUPPORTED 1 //TODO: IDF-6510
@ -240,16 +241,20 @@
#define SOC_I2C_SUPPORT_RTC (1)
/*-------------------------- I2S CAPS ----------------------------------------*/
//TODO: IDF-6508
#define SOC_I2S_NUM (1U)
#define SOC_I2S_NUM (3U)
#define SOC_I2S_HW_VERSION_2 (1)
#define SOC_I2S_SUPPORTS_XTAL (1)
#define SOC_I2S_SUPPORTS_PLL_F160M (1)
#define SOC_I2S_SUPPORTS_APLL (1)
#define SOC_I2S_SUPPORTS_PCM (1)
// #define SOC_I2S_SUPPORTS_PDM (1)
// #define SOC_I2S_SUPPORTS_PDM_TX (1)
#define SOC_I2S_PDM_MAX_TX_LINES (2)
// #define SOC_I2S_SUPPORTS_TDM (1)
#define SOC_I2S_SUPPORTS_PDM (1)
#define SOC_I2S_SUPPORTS_PDM_TX (1)
#define SOC_I2S_SUPPORTS_PDM_RX (1)
#define SOC_I2S_SUPPORTS_PDM_RX_HP_FILTER (1)
#define SOC_I2S_SUPPORTS_TX_SYNC_CNT (1)
#define SOC_I2S_SUPPORTS_TDM (1)
#define SOC_I2S_PDM_MAX_TX_LINES (2) // On I2S0
#define SOC_I2S_PDM_MAX_RX_LINES (4) // On I2S0
#define SOC_I2S_TDM_FULL_DATA_WIDTH (1) /*!< No limitation to data bit width when using multiple slots */
/*-------------------------- LEDC CAPS ---------------------------------------*/
#define SOC_LEDC_SUPPORT_PLL_DIV_CLOCK (1)
@ -510,6 +515,7 @@
#define SOC_CLK_RC_FAST_SUPPORT_CALIBRATION (0)
#define SOC_MODEM_CLOCK_IS_INDEPENDENT (0)
#define SOC_CLK_APLL_SUPPORTED (1) /*!< Support Audio PLL */
#define SOC_CLK_XTAL32K_SUPPORTED (1) /*!< Support to connect an external low frequency crystal */
#define SOC_CLK_OSC_SLOW_SUPPORTED (1) /*!< Support to connect an external oscillator, not a crystal */
#define SOC_CLK_RC32K_SUPPORTED (1) /*!< Support an internal 32kHz RC oscillator */

View File

@ -1035,22 +1035,6 @@ config SOC_CLK_APLL_SUPPORTED
bool
default y
config SOC_APLL_MULTIPLIER_OUT_MIN_HZ
int
default 350000000
config SOC_APLL_MULTIPLIER_OUT_MAX_HZ
int
default 500000000
config SOC_APLL_MIN_HZ
int
default 5303031
config SOC_APLL_MAX_HZ
int
default 125000000
config SOC_CLK_RC_FAST_D256_SUPPORTED
bool
default y

View File

@ -446,11 +446,6 @@
/*-------------------------- CLOCK SUBSYSTEM CAPS ----------------------------------------*/
#define SOC_CLK_APLL_SUPPORTED (1)
// apll_multiplier_out = xtal_freq * (4 + sdm2 + sdm1/256 + sdm0/65536)
#define SOC_APLL_MULTIPLIER_OUT_MIN_HZ (350000000) // 350 MHz
#define SOC_APLL_MULTIPLIER_OUT_MAX_HZ (500000000) // 500 MHz
#define SOC_APLL_MIN_HZ (5303031) // 5.303031 MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
#define SOC_APLL_MAX_HZ (125000000) // 125MHz, refer to 'periph_rtc_apll_freq_set' for the calculation
#define SOC_CLK_RC_FAST_D256_SUPPORTED (1)
#define SOC_RTC_SLOW_CLK_SUPPORT_RC_FAST_D256 (1)

View File

@ -32,7 +32,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
.data_in_sigs[2] = I2S0I_SD2_IN_IDX,
.data_in_sigs[3] = I2S0I_SD3_IN_IDX,
.irq = -1,
.irq = ETS_I2S0_INTR_SOURCE,
.module = PERIPH_I2S0_MODULE,
},
{
@ -56,7 +56,7 @@ const i2s_signal_conn_t i2s_periph_signal[SOC_I2S_NUM] = {
.data_in_sigs[2] = -1,
.data_in_sigs[3] = -1,
.irq = -1,
.irq = ETS_I2S1_INTR_SOURCE,
.module = PERIPH_I2S1_MODULE,
}
};

View File

@ -3,7 +3,6 @@ api-guides/coexist
api-guides/cplusplus
api-guides/dfu
api-guides/index
api-reference/peripherals/i2s
api-reference/peripherals/spi_features
api-reference/peripherals/sdio_slave
api-reference/peripherals/adc_calibration

View File

@ -111,7 +111,6 @@ api-reference/peripherals/gpio.rst
api-reference/peripherals/sdspi_host.rst
api-reference/peripherals/dac.rst
api-reference/peripherals/spi_slave.rst
api-reference/peripherals/i2s.rst
api-reference/peripherals/touch_element.rst
api-reference/peripherals/lcd.rst
api-reference/peripherals/ana_cmpr.rst

View File

@ -116,6 +116,7 @@ ESP32-C3 I2S 0 I2S 0 none I2S 0 none none
ESP32-C6 I2S 0 I2S 0 none I2S 0 none none
ESP32-S3 I2S 0/1 I2S 0 I2S 0 I2S 0/1 none none
ESP32-H2 I2S 0 I2S 0 none I2S 0 none none
ESP32-P4 I2S 0~2 I2S 0 I2S 0 I2S 0~2 none none
========= ======== ======== ======== ======== ======== ==========
Standard Mode

View File

@ -54,27 +54,49 @@ examples/peripherals/i2c/i2c_tools:
examples/peripherals/i2s/i2s_basic/i2s_pdm:
disable:
- if: SOC_I2S_SUPPORTS_PDM != 1
- if: SOC_I2S_SUPPORTS_PDM != 1 or IDF_TARGET == "esp32p4"
disable_test:
- if: IDF_TARGET == "esp32p4"
temporary: true
reason: lack of runners
examples/peripherals/i2s/i2s_basic/i2s_std:
disable:
- if: SOC_I2S_SUPPORTED != 1
- if: SOC_I2S_SUPPORTED != 1 or IDF_TARGET == "esp32p4"
disable_test:
- if: IDF_TARGET == "esp32p4"
temporary: true
reason: lack of runners
examples/peripherals/i2s/i2s_basic/i2s_tdm:
disable:
- if: SOC_I2S_SUPPORTS_TDM != 1
- if: SOC_I2S_SUPPORTS_TDM != 1 or IDF_TARGET == "esp32p4"
disable_test:
- if: IDF_TARGET == "esp32p4"
temporary: true
reason: lack of runners
examples/peripherals/i2s/i2s_codec/i2s_es7210_tdm:
disable:
- if: SOC_I2S_SUPPORTS_TDM != 1 or (SOC_I2C_SUPPORTED != 1 or SOC_GPSPI_SUPPORTED != 1)
reason: rely on I2S TDM mode to receive audio, I2C to config es7210 and SPI to save audio to SD card
disable_test:
- if: IDF_TARGET == "esp32p4"
temporary: true
reason: lack of runners
examples/peripherals/i2s/i2s_codec/i2s_es8311:
disable:
- if: SOC_I2S_SUPPORTED != 1 or SOC_I2C_SUPPORTED != 1
- if: (SOC_I2S_SUPPORTED != 1 or SOC_I2C_SUPPORTED != 1)
reason: rely on I2S STD mode and I2C to config es7210
disable_test:
- if: IDF_TARGET == "esp32p4"
temporary: true
reason: lack of runners
examples/peripherals/i2s/i2s_recorder:
disable:
- if: SOC_SDMMC_HOST_SUPPORTED != 1 or IDF_TARGET == "esp32p4"
enable:
- if: SOC_I2S_SUPPORTS_PDM_RX > 0

View File

@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |
# I2S ES8311 Example