mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-01 03:34:32 +02:00
feat(i2s): support new sync feature on H4
This commit is contained in:
@@ -8,6 +8,13 @@ menu "ESP-Driver:I2S Configurations"
|
||||
Ensure the I2S interrupt is IRAM-Safe by allowing the interrupt handler to be
|
||||
executable when the cache is disabled (e.g. SPI Flash write).
|
||||
|
||||
config I2S_CTRL_FUNC_IN_IRAM
|
||||
bool "Place I2S control functions into IRAM"
|
||||
default n
|
||||
help
|
||||
Place I2S control functions into IRAM,
|
||||
so that these functions can be IRAM-safe and able to be called in the other IRAM interrupt context.
|
||||
|
||||
config I2S_ENABLE_DEBUG_LOG
|
||||
bool "Enable I2S debug log"
|
||||
default n
|
||||
|
@@ -47,6 +47,7 @@
|
||||
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_private/gpio.h"
|
||||
#include "esp_private/i2s_sync.h"
|
||||
#include "driver/i2s_common.h"
|
||||
#include "i2s_private.h"
|
||||
|
||||
@@ -1483,3 +1484,46 @@ 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
|
||||
|
||||
#if SOC_I2S_SUPPORTS_ETM_SYNC
|
||||
uint32_t i2s_sync_get_fifo_sync_diff_count(i2s_chan_handle_t tx_handle)
|
||||
{
|
||||
return i2s_ll_tx_get_fifo_sync_diff_count(tx_handle->controller->hal.dev);
|
||||
}
|
||||
|
||||
void i2s_sync_reset_fifo_sync_diff_count(i2s_chan_handle_t tx_handle)
|
||||
{
|
||||
i2s_ll_tx_reset_fifo_sync_diff_counter(tx_handle->controller->hal.dev);
|
||||
}
|
||||
|
||||
esp_err_t i2s_sync_enable_hw_fifo_sync(i2s_chan_handle_t tx_handle, bool enable)
|
||||
{
|
||||
if (tx_handle->dir == I2S_DIR_RX) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
i2s_ll_tx_enable_hw_fifo_sync(tx_handle->controller->hal.dev, enable);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2s_sync_config_hw_fifo_sync(i2s_chan_handle_t tx_handle, const i2s_sync_fifo_sync_config_t *config)
|
||||
{
|
||||
if (!(tx_handle && config)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
if (tx_handle->dir == I2S_DIR_RX) {
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
if (config->sw_high_thresh < config->hw_low_thresh) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
i2s_ll_tx_set_etm_sync_ideal_cnt(tx_handle->controller->hal.dev, config->ideal_cnt);
|
||||
i2s_ll_tx_set_fifo_sync_diff_conter_sw_threshold(tx_handle->controller->hal.dev, config->sw_high_thresh);
|
||||
i2s_ll_tx_set_fifo_sync_diff_conter_hw_threshold(tx_handle->controller->hal.dev, config->hw_low_thresh);
|
||||
i2s_ll_tx_set_hw_fifo_sync_suppl_mode(tx_handle->controller->hal.dev, (uint32_t)config->suppl_mode);
|
||||
if (config->suppl_mode == I2S_SYNC_SUPPL_MODE_STATIC_DATA) {
|
||||
i2s_ll_tx_set_hw_fifo_sync_static_suppl_data(tx_handle->controller->hal.dev, config->suppl_data);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -84,6 +84,11 @@ esp_err_t i2s_new_etm_task(i2s_chan_handle_t handle, const i2s_etm_task_config_t
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(handle && config && out_task, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
ESP_RETURN_ON_FALSE(config->task_type < I2S_ETM_TASK_MAX, ESP_ERR_INVALID_ARG, TAG, "invalid task type");
|
||||
#if SOC_I2S_SUPPORTS_ETM_SYNC
|
||||
ESP_RETURN_ON_FALSE(config->task_type != I2S_ETM_TASK_SYNC_CHECK || handle->dir == I2S_DIR_TX,
|
||||
ESP_ERR_NOT_SUPPORTED, TAG, "rx is not supported");
|
||||
#endif
|
||||
|
||||
i2s_etm_task_t *task = heap_caps_calloc(1, sizeof(i2s_etm_task_t), ETM_MEM_ALLOC_CAPS);
|
||||
ESP_RETURN_ON_FALSE(task, ESP_ERR_NO_MEM, TAG, "no memory for ETM task");
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -31,6 +31,7 @@ extern "C" {
|
||||
/**
|
||||
* @brief Get the counter number of BCLK ticks
|
||||
* @note The BCLK tick count reflects the real data that have sent on line
|
||||
* @note It will be reset automatically when `I2S_ETM_TASK_SYNC_CHECK` is triggered
|
||||
*
|
||||
* @param[in] tx_handle The I2S tx channel handle
|
||||
* @return
|
||||
@@ -43,6 +44,7 @@ uint32_t i2s_sync_get_bclk_count(i2s_chan_handle_t tx_handle);
|
||||
* @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
|
||||
* @note It will be reset automatically when `I2S_ETM_TASK_SYNC_CHECK` is triggered
|
||||
*
|
||||
* @param[in] tx_handle The I2S tx channel handle
|
||||
* @return
|
||||
@@ -66,6 +68,78 @@ void i2s_sync_reset_fifo_count(i2s_chan_handle_t tx_handle);
|
||||
|
||||
#endif // SOC_I2S_SUPPORTS_TX_SYNC_CNT
|
||||
|
||||
#if SOC_I2S_SUPPORTS_ETM_SYNC
|
||||
/**
|
||||
* @brief I2S hardware FIFO synchronization supplement mode
|
||||
* @note When the FIFO sync difference count is out of threshold, the hardware will supplement data automatically
|
||||
* This type is to specify which data will be supplemented
|
||||
*/
|
||||
typedef enum {
|
||||
I2S_SYNC_SUPPL_MODE_LAST_DATA = 0, /*!< Supplement with the last transmitted data */
|
||||
I2S_SYNC_SUPPL_MODE_STATIC_DATA = 1, /*!< Supplement with static data specified in config */
|
||||
} i2s_sync_suppl_mode_t;
|
||||
|
||||
/**
|
||||
* @brief I2S hardware FIFO synchronization configuration
|
||||
* @note This configuration is used for multi I2S port synchronization via ETM
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t hw_low_thresh; /*!< Lower threshold for FIFO sync difference counter
|
||||
- If difference count < hw_low_thresh, do nothing
|
||||
- If difference count >= hw_low_thresh, the hardware will supplement data automatically */
|
||||
uint32_t sw_high_thresh; /*!< Upper threshold for FIFO sync difference counter
|
||||
- If difference count <= sw_high_thresh, the hardware supplement data automatically
|
||||
- If difference count > sw_high_thresh, sync interrupt triggered and
|
||||
the software is responsible to decide how to handle this severe asynchronization */
|
||||
uint32_t ideal_cnt; /*!< Ideal count for FIFO sync difference counter, it depends on the ETM sync task interval and the data rate */
|
||||
i2s_sync_suppl_mode_t suppl_mode; /*!< Data supplement mode when FIFO sync difference is out of threshold */
|
||||
uint32_t suppl_data; /*!< Static supplement data, only valid when suppl_mode is I2S_SYNC_SUPPL_MODE_STATIC_DATA */
|
||||
} i2s_sync_fifo_sync_config_t;
|
||||
|
||||
/**
|
||||
* @brief Get the counter number of FIFO sync difference
|
||||
* @note The FIFO sync difference count reflects the difference between current FIFO count and ideal count
|
||||
*
|
||||
* @param[in] tx_handle The I2S tx channel handle
|
||||
* @return
|
||||
* - FIFO sync difference count
|
||||
*/
|
||||
uint32_t i2s_sync_get_fifo_sync_diff_count(i2s_chan_handle_t tx_handle);
|
||||
|
||||
/**
|
||||
* @brief Reset the FIFO sync difference counter
|
||||
*
|
||||
* @param[in] tx_handle The I2S tx channel handle
|
||||
*/
|
||||
void i2s_sync_reset_fifo_sync_diff_count(i2s_chan_handle_t tx_handle);
|
||||
|
||||
/**
|
||||
* @brief Enable or disable hardware FIFO synchronization
|
||||
* @note When enabled, hardware will automatically supplement data when FIFO sync difference is greater than hw_low_thresh
|
||||
*
|
||||
* @param[in] tx_handle The I2S tx channel handle
|
||||
* @param[in] enable true to enable, false to disable
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_NOT_SUPPORTED if called on RX channel
|
||||
*/
|
||||
esp_err_t i2s_sync_enable_hw_fifo_sync(i2s_chan_handle_t tx_handle, bool enable);
|
||||
|
||||
/**
|
||||
* @brief Configure hardware FIFO synchronization parameters
|
||||
* @note This function configures the thresholds and supplement mode for hardware FIFO sync
|
||||
*
|
||||
* @param[in] tx_handle The I2S tx channel handle
|
||||
* @param[in] config Configuration for hardware FIFO synchronization
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_ERR_INVALID_ARG if invalid arguments
|
||||
* - ESP_ERR_NOT_SUPPORTED if called on RX channel
|
||||
*/
|
||||
esp_err_t i2s_sync_config_hw_fifo_sync(i2s_chan_handle_t tx_handle, const i2s_sync_fifo_sync_config_t *config);
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
14
components/esp_driver_i2s/linker.lf
Normal file
14
components/esp_driver_i2s/linker.lf
Normal file
@@ -0,0 +1,14 @@
|
||||
[mapping:i2s_driver]
|
||||
archive: libesp_driver_i2s.a
|
||||
entries:
|
||||
if I2S_CTRL_FUNC_IN_IRAM = y:
|
||||
if SOC_I2S_SUPPORTS_TX_SYNC_CNT = y:
|
||||
i2s_common: i2s_sync_get_bclk_count (noflash)
|
||||
i2s_common: i2s_sync_get_fifo_count (noflash)
|
||||
i2s_common: i2s_sync_reset_bclk_count (noflash)
|
||||
i2s_common: i2s_sync_reset_fifo_count (noflash)
|
||||
if SOC_I2S_SUPPORTS_ETM_SYNC = y:
|
||||
i2s_common: i2s_sync_get_fifo_sync_diff_count (noflash)
|
||||
i2s_common: i2s_sync_reset_fifo_sync_diff_count (noflash)
|
||||
i2s_common: i2s_sync_enable_hw_fifo_sync (noflash)
|
||||
i2s_common: i2s_sync_config_hw_fifo_sync (noflash)
|
@@ -60,7 +60,7 @@ extern "C" {
|
||||
[I2S_DIR_RX - 1] = { \
|
||||
[I2S_ETM_TASK_START] = I2S0_TASK_START_RX, \
|
||||
[I2S_ETM_TASK_STOP] = I2S0_TASK_STOP_RX, \
|
||||
[I2S_ETM_TASK_SYNC_CHECK] = I2S0_TASK_SYNC_CHECK, \
|
||||
[I2S_ETM_TASK_SYNC_CHECK] = -1, \
|
||||
}, \
|
||||
[I2S_DIR_TX - 1] = { \
|
||||
[I2S_ETM_TASK_START] = I2S0_TASK_START_TX, \
|
||||
@@ -1245,6 +1245,113 @@ static inline uint32_t i2s_ll_tx_get_bclk_sync_count(i2s_dev_t *hw)
|
||||
return hw->bck_cnt.tx_bck_cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enable TX FIFO synchronization hardware mode
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param enable Set true to enable hardware mode
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void i2s_ll_tx_enable_hw_fifo_sync(i2s_dev_t *hw, bool enable)
|
||||
{
|
||||
hw->hw_sync_conf.tx_hw_sync_en = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get TX FIFO synchronization difference count value
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @return
|
||||
* fifo count value
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline uint32_t i2s_ll_tx_get_fifo_sync_diff_count(i2s_dev_t *hw)
|
||||
{
|
||||
return hw->cnt_diff.tx_cnt_diff;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reset TX FIFO synchronization difference counter
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void i2s_ll_tx_reset_fifo_sync_diff_counter(i2s_dev_t *hw)
|
||||
{
|
||||
hw->cnt_diff.tx_cnt_diff_rst = 1;
|
||||
hw->cnt_diff.tx_cnt_diff_rst = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set TX FIFO synchronization difference counter software threshold
|
||||
* @note It determines the up threshold that the hardware synchronize the data automatically.
|
||||
* - If diff_count <= sw_threshold, the hardware will synchronize the data automatically.
|
||||
* - If diff_count > sw_threshold, the automatic synchronization is not proper for this case,
|
||||
* interrupt will be triggered to let the software decide how to handle this case.
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param thresh The threshold that send
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void i2s_ll_tx_set_fifo_sync_diff_conter_sw_threshold(i2s_dev_t *hw, uint32_t thresh)
|
||||
{
|
||||
hw->sync_sw_thres.tx_cnt_diff_sw_thres = thresh;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set TX FIFO synchronization difference counter hardware threshold
|
||||
* @note It determines the down threshold that the hardware synchronize the data automatically.
|
||||
* - If diff_count < hw_threshold, synchronization check pass, do nothing
|
||||
* - If diff_count >= hw_threshold, the hardware will synchronize the data automatically.
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param thresh The threshold that send
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void i2s_ll_tx_set_fifo_sync_diff_conter_hw_threshold(i2s_dev_t *hw, uint32_t thresh)
|
||||
{
|
||||
hw->sync_hw_thres.tx_cnt_diff_hw_thres = thresh;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set TX FIFO synchronization hardware data supplementation mode
|
||||
* @note It determines the supplementation data when the actual sent data is less than the `diff_count - threshold`
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param mode Data supplementation mode
|
||||
* - 0: Supplement the last data
|
||||
* - 1: Supplement the data configured in `hw_sync_data` reg
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void i2s_ll_tx_set_hw_fifo_sync_suppl_mode(i2s_dev_t *hw, uint32_t mode)
|
||||
{
|
||||
hw->hw_sync_conf.tx_hw_sync_suppl_mode = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set TX FIFO synchronization hardware supplementation data when `tx_hw_sync_suppl_mode` is 1
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param data Data to be supplemented when `tx_hw_sync_suppl_mode` is 1
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void i2s_ll_tx_set_hw_fifo_sync_static_suppl_data(i2s_dev_t *hw, uint32_t data)
|
||||
{
|
||||
hw->hw_sync_data.tx_hw_sync_suppl_data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the TX ETM synchronization ideal count
|
||||
*
|
||||
* @param hw Peripheral I2S hardware instance address.
|
||||
* @param ideal_cnt The ideal FIFO count when I2S_ETM_TASK_SYNC_CHECK triggered.
|
||||
*/
|
||||
__attribute__((always_inline))
|
||||
static inline void i2s_ll_tx_set_etm_sync_ideal_cnt(i2s_dev_t *hw, uint32_t ideal_cnt)
|
||||
{
|
||||
hw->ideal_cnt.tx_ideal_cnt = ideal_cnt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the TX ETM threshold of REACH_THRESH event
|
||||
*
|
||||
|
@@ -234,7 +234,7 @@ typedef enum {
|
||||
I2S_ETM_TASK_START, /*!< Start the I2S channel */
|
||||
I2S_ETM_TASK_STOP, /*!< Stop the I2S channel */
|
||||
#if SOC_I2S_SUPPORTS_ETM_SYNC
|
||||
I2S_ETM_TASK_SYNC_CHECK, /*!< Stop the I2S channel */
|
||||
I2S_ETM_TASK_SYNC_CHECK, /*!< Check the I2S TX channel sync status */
|
||||
#endif
|
||||
I2S_ETM_TASK_MAX, /*!< Maximum number of tasks */
|
||||
} i2s_etm_task_type_t;
|
||||
|
Reference in New Issue
Block a user