Skip to content

Commit

Permalink
Merge branch 'feature/lp_i2s' into 'master'
Browse files Browse the repository at this point in the history
lp_i2s: support lp_i2s driver

Closes IDF-10355

See merge request espressif/esp-idf!31494
  • Loading branch information
Icarus113 committed Aug 5, 2024
2 parents 41b7b55 + 20e6650 commit d16bb64
Show file tree
Hide file tree
Showing 39 changed files with 1,885 additions and 61 deletions.
4 changes: 2 additions & 2 deletions components/driver/deprecated/adc_dma_legacy.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate posi
#define adc_dma_disable_intr(adc_dma) i2s_ll_enable_intr(s_adc_digi_ctx->adc_i2s_dev, ADC_DMA_INTR_MASK, false);
#define adc_dma_deinit(adc_dma) do { \
esp_intr_free(s_adc_digi_ctx->intr_hdl); \
i2s_platform_release_occupation(ADC_DMA_I2S_HOST); \
i2s_platform_release_occupation(I2S_CTLR_HP, ADC_DMA_I2S_HOST); \
} while (0)
#endif

Expand Down Expand Up @@ -328,7 +328,7 @@ esp_err_t adc_digi_initialize(const adc_digi_init_config_t *init_config)
s_adc_digi_ctx->adc_spi_dev = SPI_LL_GET_HW(ADC_DMA_SPI_HOST);
#elif CONFIG_IDF_TARGET_ESP32
//ADC utilises I2S0 DMA on ESP32
ret = i2s_platform_acquire_occupation(ADC_DMA_I2S_HOST, "adc");
ret = i2s_platform_acquire_occupation(I2S_CTLR_HP, ADC_DMA_I2S_HOST, "adc");
if (ret != ESP_OK) {
ret = ESP_ERR_NOT_FOUND;
goto cleanup;
Expand Down
4 changes: 2 additions & 2 deletions components/driver/deprecated/i2s_legacy.c
Original file line number Diff line number Diff line change
Expand Up @@ -1637,7 +1637,7 @@ esp_err_t i2s_driver_uninstall(i2s_port_t i2s_num)
}
#endif
/* Disable module clock */
i2s_platform_release_occupation(i2s_num);
i2s_platform_release_occupation(I2S_CTLR_HP, i2s_num);
free(obj);
p_i2s[i2s_num] = NULL;
return ESP_OK;
Expand All @@ -1656,7 +1656,7 @@ esp_err_t i2s_driver_install(i2s_port_t i2s_num, const i2s_config_t *i2s_config,
/* Step 2: Allocate driver object and register to platform */
i2s_obj_t *i2s_obj = calloc(1, sizeof(i2s_obj_t));
ESP_RETURN_ON_FALSE(i2s_obj, ESP_ERR_NO_MEM, TAG, "no mem for I2S driver");
if (i2s_platform_acquire_occupation(i2s_num, "i2s_legacy") != ESP_OK) {
if (i2s_platform_acquire_occupation(I2S_CTLR_HP, i2s_num, "i2s_legacy") != ESP_OK) {
free(i2s_obj);
ESP_LOGE(TAG, "register I2S object to platform failed");
return ESP_ERR_INVALID_STATE;
Expand Down
4 changes: 2 additions & 2 deletions components/esp_adc/esp32/adc_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ esp_err_t adc_dma_init(adc_dma_t *adc_dma)
{
esp_err_t ret = ESP_OK;
//ADC utilises I2S0 DMA on ESP32
ret = i2s_platform_acquire_occupation(ADC_DMA_I2S_HOST, "adc");
ret = i2s_platform_acquire_occupation(I2S_CTLR_HP, ADC_DMA_I2S_HOST, "adc");
if (ret != ESP_OK) {
return ESP_ERR_NOT_FOUND;
}
Expand All @@ -62,7 +62,7 @@ esp_err_t adc_dma_init(adc_dma_t *adc_dma)
esp_err_t adc_dma_deinit(adc_dma_t adc_dma)
{
esp_intr_free(adc_dma.dma_intr_hdl);
i2s_platform_release_occupation(ADC_DMA_I2S_HOST);
i2s_platform_release_occupation(I2S_CTLR_HP, ADC_DMA_I2S_HOST);
return ESP_OK;
}

Expand Down
4 changes: 2 additions & 2 deletions components/esp_driver_dac/esp32/dac_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ esp_err_t dac_dma_periph_init(uint32_t freq_hz, bool is_alternate, bool is_apll)
#endif
esp_err_t ret = ESP_OK;
/* Acquire DMA peripheral */
ESP_RETURN_ON_ERROR(i2s_platform_acquire_occupation(DAC_DMA_PERIPH_I2S_NUM, "dac_dma"), TAG, "Failed to acquire DAC DMA peripheral");
ESP_RETURN_ON_ERROR(i2s_platform_acquire_occupation(I2S_CTLR_HP, DAC_DMA_PERIPH_I2S_NUM, "dac_dma"), TAG, "Failed to acquire DAC DMA peripheral");
/* Allocate DAC DMA peripheral object */
s_ddp = (dac_dma_periph_i2s_t *)heap_caps_calloc(1, sizeof(dac_dma_periph_i2s_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
ESP_GOTO_ON_FALSE(s_ddp, ESP_ERR_NO_MEM, err, TAG, "No memory for DAC DMA object");
Expand Down Expand Up @@ -150,7 +150,7 @@ esp_err_t dac_dma_periph_init(uint32_t freq_hz, bool is_alternate, bool is_apll)
esp_err_t dac_dma_periph_deinit(void)
{
ESP_RETURN_ON_FALSE(s_ddp->intr_handle == NULL, ESP_ERR_INVALID_STATE, TAG, "The interrupt is not deregistered yet");
ESP_RETURN_ON_ERROR(i2s_platform_release_occupation(DAC_DMA_PERIPH_I2S_NUM), TAG, "Failed to release DAC DMA peripheral");
ESP_RETURN_ON_ERROR(i2s_platform_release_occupation(I2S_CTLR_HP, DAC_DMA_PERIPH_I2S_NUM), TAG, "Failed to release DAC DMA peripheral");
i2s_ll_enable_intr(s_ddp->periph_dev, I2S_LL_EVENT_TX_EOF | I2S_LL_EVENT_TX_TEOF, false);
if (s_ddp) {
if (s_ddp->use_apll) {
Expand Down
4 changes: 2 additions & 2 deletions components/esp_driver_dac/test_apps/dac/main/test_dac.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,13 @@ TEST_CASE("DAC_API_basic_logic_test", "[dac]")
};
/* DMA peripheral availability test */
#if CONFIG_IDF_TARGET_ESP32
TEST_ESP_OK(i2s_platform_acquire_occupation(0, "dac_test"));
TEST_ESP_OK(i2s_platform_acquire_occupation(I2S_CTLR_HP, 0, "dac_test"));
#elif CONFIG_IDF_TARGET_ESP32S2
TEST_ASSERT(spicommon_periph_claim(SPI3_HOST, "dac_test"));
#endif
TEST_ASSERT(dac_continuous_new_channels(&cont_cfg, &cont_handle) == ESP_ERR_NOT_FOUND);
#if CONFIG_IDF_TARGET_ESP32
TEST_ESP_OK(i2s_platform_release_occupation(0));
TEST_ESP_OK(i2s_platform_release_occupation(I2S_CTLR_HP, 0));
#elif CONFIG_IDF_TARGET_ESP32S2
TEST_ASSERT(spicommon_periph_free(SPI3_HOST));
#endif
Expand Down
9 changes: 8 additions & 1 deletion components/esp_driver_i2s/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ set(include "include")
# I2S related source files
if(CONFIG_SOC_I2S_SUPPORTED)
list(APPEND srcs "i2s_common.c"
"i2s_platform.c"
"i2s_std.c")
if(CONFIG_SOC_I2S_SUPPORTS_PDM)
list(APPEND srcs "i2s_pdm.c")
Expand All @@ -23,6 +22,14 @@ if(CONFIG_SOC_I2S_SUPPORTED)
endif()
endif()

if(CONFIG_SOC_I2S_SUPPORTED OR CONFIG_SOC_LP_I2S_SUPPORTED)
list(APPEND srcs "i2s_platform.c")
endif()

if(CONFIG_SOC_LP_I2S_SUPPORTED)
list(APPEND srcs "lp_i2s.c" "lp_i2s_std.c" "lp_i2s_pdm.c")
endif()

idf_component_register(SRCS ${srcs}
INCLUDE_DIRS ${include}
PRIV_REQUIRES esp_driver_gpio esp_pm esp_mm
Expand Down
4 changes: 2 additions & 2 deletions components/esp_driver_i2s/i2s_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ static esp_err_t i2s_destroy_controller_obj(i2s_controller_t **i2s_obj)
#endif
free(*i2s_obj);
*i2s_obj = NULL;
return i2s_platform_release_occupation(id);
return i2s_platform_release_occupation(I2S_CTLR_HP, id);
}

/**
Expand Down Expand Up @@ -196,7 +196,7 @@ static i2s_controller_t *i2s_acquire_controller_obj(int id)

i2s_controller_t *i2s_obj = NULL;
/* Try to occupy this i2s controller */
if (i2s_platform_acquire_occupation(id, "i2s_driver") == ESP_OK) {
if (i2s_platform_acquire_occupation(I2S_CTLR_HP, id, "i2s_driver") == ESP_OK) {
portENTER_CRITICAL(&g_i2s.spinlock);
i2s_obj = pre_alloc;
g_i2s.controller[id] = i2s_obj;
Expand Down
95 changes: 70 additions & 25 deletions components/esp_driver_i2s/i2s_platform.c
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
/*
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

#include "esp_check.h"
#include "i2s_private.h"
#include "esp_private/i2s_platform.h"

static const char *TAG = "i2s_platform";

Expand All @@ -17,6 +18,10 @@ 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,
#if SOC_LP_I2S_SUPPORTED
.lp_controller[0 ...(SOC_LP_I2S_NUM - 1)] = NULL,
.lp_comp_name[0 ...(SOC_LP_I2S_NUM - 1)] = NULL,
#endif
};

/*---------------------------------------------------------------------------
Expand All @@ -25,47 +30,87 @@ i2s_platform_t g_i2s = {
Scope: This file and ADC/DAC/LCD driver
----------------------------------------------------------------------------*/

esp_err_t i2s_platform_acquire_occupation(int id, const char *comp_name)
esp_err_t i2s_platform_acquire_occupation(i2s_ctlr_t type, 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);

if (type == I2S_CTLR_HP) {
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 SOC_LP_I2S_SUPPORTED
else {
portENTER_CRITICAL(&g_i2s.spinlock);
if ((!g_i2s.lp_controller[id]) && (g_i2s.lp_comp_name[id] == NULL)) {
g_i2s.lp_comp_name[id] = comp_name;
/* Enable module clock */
I2S_RCC_ATOMIC() {
lp_i2s_ll_enable_module_clock(id, true);
lp_i2s_ll_reset_module_clock(id);
lp_i2s_ll_enable_rx_module_clock(id, true);
}
} else {
occupied_comp = g_i2s.lp_comp_name[id];
ret = ESP_ERR_NOT_FOUND;
}
} else {
occupied_comp = g_i2s.comp_name[id];
ret = ESP_ERR_NOT_FOUND;
portEXIT_CRITICAL(&g_i2s.spinlock);
}
portEXIT_CRITICAL(&g_i2s.spinlock);
#endif
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 i2s_platform_release_occupation(i2s_ctlr_t type, 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);

if (type == I2S_CTLR_HP) {
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);
}
#if SOC_LP_I2S_SUPPORTED
else {
portENTER_CRITICAL(&g_i2s.spinlock);
if (!g_i2s.lp_controller[id]) {
g_i2s.lp_comp_name[id] = NULL;
/* Disable module clock */
I2S_RCC_ATOMIC() {
lp_i2s_ll_enable_module_clock(id, false);
lp_i2s_ll_enable_rx_module_clock(id, false);
}
} else {
ret = ESP_ERR_INVALID_STATE;
}
} else {
ret = ESP_ERR_INVALID_STATE;
portEXIT_CRITICAL(&g_i2s.spinlock);
}
portEXIT_CRITICAL(&g_i2s.spinlock);
#endif
return ret;
}

Expand Down
50 changes: 47 additions & 3 deletions components/esp_driver_i2s/i2s_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
#include "soc/lldesc.h"
#include "soc/soc_caps.h"
#include "hal/i2s_hal.h"
#include "hal/lp_i2s_hal.h"
#if SOC_LP_I2S_SUPPORTED
#include "hal/lp_i2s_ll.h"
#endif
#include "driver/i2s_types.h"
#if CONFIG_IDF_TARGET_ESP32
#include "esp_clock_output.h"
Expand Down Expand Up @@ -85,6 +89,14 @@ typedef struct {
*/
} i2s_event_callbacks_internal_t;

/**
* @brief LP I2S callbacks
*/
typedef struct {
lp_i2s_callback_t on_thresh_met; ///< Triggered when the received bytes are bigger than `lp_i2s_chan_config_t:threshold`
lp_i2s_callback_t on_request_new_trans; ///< Triggered when a new transaction buffer is needed, when this callback is registered, you don't need to use `lp_i2s_channel_read` to get data, you can get data via this callback asynchronously
} lp_i2s_evt_cbs_internal_t;

/**
* @brief i2s channel level configurations
* @note It performs as channel handle
Expand Down Expand Up @@ -154,14 +166,46 @@ struct i2s_channel_obj_t {
void (*stop)(i2s_chan_handle_t); /*!< stop tx/rx channel */
};

/**
* @brief lp i2s controller type
*/
typedef struct {
int id; /*!< lp i2s port id */
lp_i2s_hal_context_t hal; /*!< hal context */
uint32_t chan_occupancy; /*!< channel occupancy (rx/tx) */
lp_i2s_chan_handle_t rx_chan; /*!< rx channel handle */
intr_handle_t intr; /*!< interrupt handle */
} lp_i2s_controller_t;

/**
* @brief lp i2s channel object type
*/
struct lp_i2s_channel_obj_t {
/* Channel basic information */
lp_i2s_controller_t *ctlr; /*!< Parent pointer to controller object */
i2s_comm_mode_t mode; /*!< lp i2s channel communication mode */
i2s_role_t role; /*!< lp i2s role */
i2s_dir_t dir; /*!< lp i2s channel direction */
i2s_state_t state; /*!< lp i2s driver state. Ensuring the driver working in a correct sequence */
SemaphoreHandle_t semphr; /*!< lp i2s event semphr*/
lp_i2s_trans_t trans; /*!< transaction */
size_t threshold; /*!< lp i2s threshold*/
lp_i2s_evt_cbs_internal_t cbs; /*!< callbacks */
void *user_data; /*!< user data */
};

/**
* @brief i2s platform level configurations
* @note All i2s controllers' resources are involved
*/
typedef struct {
portMUX_TYPE spinlock; /*!< Platform level lock */
i2s_controller_t *controller[SOC_I2S_NUM]; /*!< Controller object */
const char *comp_name[SOC_I2S_NUM]; /*!< The component name that occupied i2s controller */
portMUX_TYPE spinlock; /*!< Platform level lock */
i2s_controller_t *controller[SOC_I2S_NUM]; /*!< Controller object */
const char *comp_name[SOC_I2S_NUM]; /*!< The component name that occupied i2s controller */
#if SOC_LP_I2S_SUPPORTED
lp_i2s_controller_t *lp_controller[SOC_LP_I2S_NUM]; /*!< LP controller object*/
const char *lp_comp_name[SOC_I2S_NUM]; /*!< The component name that occupied lp i2s controller */
#endif
} i2s_platform_t;

extern i2s_platform_t g_i2s; /*!< Global i2s instance for driver internal use */
Expand Down
30 changes: 29 additions & 1 deletion components/esp_driver_i2s/include/driver/i2s_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ typedef enum {
I2S_MCLK_MULTIPLE_1152 = 1152, /*!< MCLK = sample_rate * 1152 (24-bit compatible) */
} i2s_mclk_multiple_t;

/**
* @brief LP I2S transaction type
*/
typedef struct {
void *buffer; ///< Pointer to buffer
size_t buflen; ///< Buffer len, this should be in the multiple of 4
size_t received_size; ///< Received size
} lp_i2s_trans_t;

/**
* @brief Event structure used in I2S event queue
*/
Expand All @@ -78,7 +87,15 @@ typedef struct {
*/
} i2s_event_data_t;

typedef struct i2s_channel_obj_t *i2s_chan_handle_t; /*!< I2S channel object handle, the control unit of the I2S driver*/
/**
* @brief Event data structure for LP I2S
*/
typedef struct {
lp_i2s_trans_t trans; ///< LP I2S transaction
} lp_i2s_evt_data_t;

typedef struct i2s_channel_obj_t *i2s_chan_handle_t; /*!< I2S channel object handle, the control unit of the I2S driver*/
typedef struct lp_i2s_channel_obj_t *lp_i2s_chan_handle_t; /*!< I2S channel object handle, the control unit of the I2S driver*/

/**
* @brief I2S event callback
Expand All @@ -90,6 +107,17 @@ typedef struct i2s_channel_obj_t *i2s_chan_handle_t; /*!< I2S channel object
*/
typedef bool (*i2s_isr_callback_t)(i2s_chan_handle_t handle, i2s_event_data_t *event, void *user_ctx);

/**
* @brief LP I2S event callback type
*
* @param[in] handle LP I2S channel handle
* @param[in] event Event data
* @param[in] user_ctx User data
*
* @return Whether a high priority task has been waken up by this callback function
*/
typedef bool (*lp_i2s_callback_t)(lp_i2s_chan_handle_t handle, lp_i2s_evt_data_t *event, void *user_ctx);

#ifdef __cplusplus
}
#endif
Loading

0 comments on commit d16bb64

Please sign in to comment.