fix(i2s_platform): merge the i2s platform acquire API

This commit is contained in:
laokaiyao 2023-09-07 16:47:26 +08:00
parent 72a0746e62
commit e1039f9ce2
13 changed files with 177 additions and 194 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

@ -52,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"
@ -62,7 +63,7 @@ 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_SYS_DIGI_CLKRST_REG_SHARED
#if SOC_PERIPH_CLK_CTRL_SHARED
#define I2S_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC()
#else
#define I2S_CLOCK_SRC_ATOMIC()
@ -150,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,
@ -163,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
-------------------------------------------------------------*/
@ -1907,42 +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;
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);
}
}
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 */
I2S_RCC_ATOMIC() {
i2s_ll_enable_bus_clock(id, false);
i2s_ll_enable_core_clock(I2S_LL_GET_HW(id), false);
}
}
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,10 +25,9 @@
#include "soc/soc_caps.h"
#include "hal/gpio_hal.h"
#include "hal/i2s_hal.h"
#if CONFIG_IDF_TARGET_ESP32P4
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"
#include "rom/cache.h"
#endif
#if SOC_I2S_SUPPORTS_ADC_DAC
@ -52,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"
@ -60,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
----------------------------------------------------------------------------
@ -298,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);
@ -336,9 +341,9 @@ 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 CONFIG_IDF_TARGET_ESP32P4
#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_TYPE_DATA);
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 */
@ -401,20 +406,14 @@ esp_err_t i2s_alloc_dma_desc(i2s_chan_handle_t handle, uint32_t num, uint32_t bu
handle->dma.desc_num = num;
handle->dma.buf_size = bufsize;
#if SOC_GDMA_TRIG_PERIPH_I2S0_BUS == SOC_GDMA_BUS_AHB
uint32_t alignment = 64;
uint32_t desc_size = alignment;
#else
uint32_t alignment = 4;
uint32_t desc_size = sizeof(lldesc_t);
#endif
/* Descriptors must be in the internal RAM */
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_aligned_calloc(alignment, 1, desc_size, 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;
@ -422,7 +421,7 @@ 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_aligned_calloc(alignment, 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_LOGV(TAG, "desc addr: %8p\tbuffer addr:%8p", handle->dma.desc[i], handle->dma.bufs[i]);
@ -431,8 +430,8 @@ esp_err_t i2s_alloc_dma_desc(i2s_chan_handle_t handle, uint32_t num, uint32_t bu
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 CONFIG_IDF_TARGET_ESP32P4
Cache_WriteBack_Addr(CACHE_MAP_L1_DCACHE, (uint32_t)(handle->dma.desc[i]), desc_size);
#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) {
@ -498,8 +497,8 @@ 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 CONFIG_IDF_TARGET_ESP32P4
Cache_Invalidate_Addr(CACHE_MAP_L1_DCACHE, (uint32_t)finish_desc->buf, handle->dma.buf_size);
#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),
@ -547,8 +546,8 @@ 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 CONFIG_IDF_TARGET_ESP32P4
Cache_WriteBack_Addr(CACHE_MAP_L1_DCACHE, (uint32_t)sent_buf, 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);
@ -691,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 |= handle->intr_flags ? handle->intr_flags : ESP_INTR_FLAG_LOWMED;
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,
@ -708,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 */
@ -724,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);
@ -734,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
@ -785,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;
@ -816,7 +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_flags = chan_cfg->intr_flags;
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;
@ -830,7 +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_flags = chan_cfg->intr_flags;
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;
@ -1071,8 +1071,8 @@ esp_err_t i2s_channel_preload_data(i2s_chan_handle_t tx_handle, const void *src,
}
/* Load the data from the last loaded position */
memcpy((uint8_t *)(tx_handle->dma.curr_ptr + tx_handle->dma.rw_pos), data_ptr, bytes_can_load);
#if CONFIG_IDF_TARGET_ESP32P4
Cache_WriteBack_Addr(CACHE_MAP_L1_DCACHE, (uint32_t)(tx_handle->dma.curr_ptr + tx_handle->dma.rw_pos), (uint32_t)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
@ -1130,8 +1130,8 @@ 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 CONFIG_IDF_TARGET_ESP32P4
Cache_WriteBack_Addr(CACHE_MAP_L1_DCACHE, (uint32_t)data_ptr, (uint32_t)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;
@ -1187,64 +1187,6 @@ 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)
{
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 inline 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);
}
#if SOC_I2S_SUPPORTS_TX_SYNC_CNT
uint32_t i2s_sync_get_bclk_count(i2s_chan_handle_t tx_handle)
{

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,7 +9,7 @@
#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"
@ -36,7 +36,7 @@ extern "C" {
#endif //CONFIG_I2S_ISR_IRAM_SAFE
#define I2S_DMA_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA)
#if SOC_SYS_DIGI_CLKRST_REG_SHARED
#if SOC_PERIPH_CLK_CTRL_SHARED
#define I2S_CLOCK_SRC_ATOMIC() PERIPH_RCC_ATOMIC()
#else
#define I2S_CLOCK_SRC_ATOMIC()
@ -59,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
@ -103,7 +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_flags;
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 */
@ -117,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 */
@ -133,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
@ -200,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
@ -213,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
@ -222,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

@ -25,7 +25,7 @@ extern "C" {
.dma_desc_num = 6, \
.dma_frame_num = 240, \
.auto_clear = false, \
.intr_flags = 0, \
.intr_priority = 0, \
}
#define I2S_GPIO_UNUSED GPIO_NUM_NC /*!< Used in i2s_gpio_config_t for signals which are not used */
@ -64,7 +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_flags; /*!< Flags used to allocate the interrupt. One or multiple (ORred) ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info */
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

@ -19,6 +19,7 @@
#include "soc/i2s_struct.h"
#include "soc/hp_sys_clkrst_struct.h"
#include "hal/i2s_types.h"
#include "hal/hal_utils.h"
#ifdef __cplusplus
@ -31,22 +32,12 @@ extern "C" {
#define I2S_LL_TDM_CH_MASK (0xffff)
#define I2S_LL_PDM_BCK_FACTOR (64)
#define I2S_LL_MCLK_DIVIDER_BIT_WIDTH (9)
#define I2S_LL_MCLK_DIVIDER_MAX ((1 << I2S_LL_MCLK_DIVIDER_BIT_WIDTH) - 1)
#define I2S_LL_CLK_FRAC_DIV_N_MAX 256 // I2S_MCLK = I2S_SRC_CLK / (N + b/a), the N register is 8 bit-width
#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_XTAL_CLK_FREQ (40 * 1000000) // XTAL_CLK: 40MHz
#define I2S_LL_DEFAULT_CLK_FREQ I2S_LL_XTAL_CLK_FREQ // No PLL clock source on P4, use XTAL as default
/**
* @brief I2S clock configuration structure
* @note Fmclk = Fsclk /(integ+numer/denom)
*/
typedef struct {
uint16_t integ; // Integer part of I2S module clock divider
uint16_t denom; // Denominator part of I2S module clock divider
uint16_t numer; // Numerator part of I2S module clock divider
} i2s_ll_mclk_div_t;
/**
* @brief Enable the bus clock for I2S module
*
@ -328,7 +319,7 @@ static inline uint32_t i2s_ll_get_clk_src(i2s_clock_src_t src)
return 2;
default:
HAL_ASSERT(false && "unsupported clock source");
break;
return -1;
}
}
@ -471,7 +462,7 @@ static inline void i2s_ll_rx_set_raw_clk_div(i2s_dev_t *hw, uint32_t div_int, ui
* @param hw Peripheral I2S hardware instance address.
* @param mclk_div The mclk division coefficients
*/
static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, const i2s_ll_mclk_div_t *mclk_div)
static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, const hal_utils_clk_div_t *mclk_div)
{
/* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate
* Set to particular coefficients first then update to the target coefficients,
@ -484,13 +475,13 @@ static inline void i2s_ll_tx_set_mclk(i2s_dev_t *hw, const i2s_ll_mclk_div_t *mc
uint32_t div_z = 0;
uint32_t div_yn1 = 0;
/* If any of denominator and numerator is 0, set all the coefficients to 0 */
if (mclk_div->denom && mclk_div->numer) {
div_yn1 = mclk_div->numer * 2 > mclk_div->denom;
div_z = div_yn1 ? mclk_div->denom - mclk_div->numer : mclk_div->numer;
div_x = mclk_div->denom / div_z - 1;
div_y = mclk_div->denom % div_z;
if (mclk_div->denominator && mclk_div->numerator) {
div_yn1 = mclk_div->numerator * 2 > mclk_div->denominator;
div_z = div_yn1 ? mclk_div->denominator - mclk_div->numerator : mclk_div->numerator;
div_x = mclk_div->denominator / div_z - 1;
div_y = mclk_div->denominator % div_z;
}
i2s_ll_tx_set_raw_clk_div(hw, mclk_div->integ, div_x, div_y, div_z, div_yn1);
i2s_ll_tx_set_raw_clk_div(hw, mclk_div->integer, div_x, div_y, div_z, div_yn1);
}
/**
@ -511,7 +502,7 @@ static inline void i2s_ll_rx_set_bck_div_num(i2s_dev_t *hw, uint32_t val)
* @param hw Peripheral I2S hardware instance address.
* @param mclk_div The mclk division coefficients
*/
static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, const i2s_ll_mclk_div_t *mclk_div)
static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, const hal_utils_clk_div_t *mclk_div)
{
/* Workaround for inaccurate clock while switching from a relatively low sample rate to a high sample rate
* Set to particular coefficients first then update to the target coefficients,
@ -524,13 +515,13 @@ static inline void i2s_ll_rx_set_mclk(i2s_dev_t *hw, const i2s_ll_mclk_div_t *mc
uint32_t div_z = 0;
uint32_t div_yn1 = 0;
/* If any of denominator and numerator is 0, set all the coefficients to 0 */
if (mclk_div->denom && mclk_div->numer) {
div_yn1 = mclk_div->numer * 2 > mclk_div->denom;
div_z = div_yn1 ? mclk_div->denom - mclk_div->numer : mclk_div->numer;
div_x = mclk_div->denom / div_z - 1;
div_y = mclk_div->denom % div_z;
if (mclk_div->denominator && mclk_div->numerator) {
div_yn1 = mclk_div->numerator * 2 > mclk_div->denominator;
div_z = div_yn1 ? mclk_div->denominator - mclk_div->numerator : mclk_div->numerator;
div_x = mclk_div->denominator / div_z - 1;
div_y = mclk_div->denominator % div_z;
}
i2s_ll_rx_set_raw_clk_div(hw, mclk_div->integ, div_x, div_y, div_z, div_yn1);
i2s_ll_rx_set_raw_clk_div(hw, mclk_div->integer, div_x, div_y, div_z, div_yn1);
}
/**

View File

@ -147,7 +147,7 @@ void i2s_hal_calc_mclk_precise_division(uint32_t sclk, uint32_t mclk, hal_utils_
*/
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_SYS_DIGI_CLKRST_REG_SHARED
#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__)
@ -164,7 +164,7 @@ void _i2s_hal_set_tx_clock(i2s_hal_context_t *hal, const i2s_hal_clock_info_t *c
*/
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_SYS_DIGI_CLKRST_REG_SHARED
#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__)

View File

@ -1123,10 +1123,6 @@ config SOC_PM_PAU_LINK_NUM
int
default 4
config SOC_SYS_DIGI_CLKRST_REG_SHARED
bool
default y
config SOC_CLK_RC_FAST_SUPPORT_CALIBRATION
bool
default n

View File

@ -48,7 +48,6 @@
// #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
@ -154,7 +153,6 @@
#define SOC_CPU_HAS_PMA 1
#define SOC_CPU_IDRAM_SPLIT_USING_PMP 1
// TODO: IDF-5360 (Copy from esp32c3, need check)
/*-------------------------- DIGITAL SIGNATURE CAPS ----------------------------------------*/
/** The maximum length of a Digital Signature in bits. */
#define SOC_DS_SIGNATURE_MAX_BIT_LEN (4096)
@ -514,7 +512,6 @@
#define SOC_PM_PAU_LINK_NUM (4)
/*-------------------------- CLOCK SUBSYSTEM CAPS ----------------------------------------*/
#define SOC_SYS_DIGI_CLKRST_REG_SHARED (1)
#define SOC_CLK_RC_FAST_SUPPORT_CALIBRATION (0)
#define SOC_MODEM_CLOCK_IS_INDEPENDENT (0)

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