Skip to content

Commit 424991f

Browse files
committed
feat(i2s): support new sync feature on H4
1 parent 0a11047 commit 424991f

File tree

7 files changed

+255
-4
lines changed

7 files changed

+255
-4
lines changed

components/esp_driver_i2s/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ menu "ESP-Driver:I2S Configurations"
88
Ensure the I2S interrupt is IRAM-Safe by allowing the interrupt handler to be
99
executable when the cache is disabled (e.g. SPI Flash write).
1010

11+
config I2S_CTRL_FUNC_IN_IRAM
12+
bool "Place I2S control functions into IRAM"
13+
default n
14+
help
15+
Place I2S control functions into IRAM,
16+
so that these functions can be IRAM-safe and able to be called in the other IRAM interrupt context.
17+
1118
config I2S_ENABLE_DEBUG_LOG
1219
bool "Enable I2S debug log"
1320
default n

components/esp_driver_i2s/i2s_common.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747

4848
#include "driver/gpio.h"
4949
#include "esp_private/gpio.h"
50+
#include "esp_private/i2s_sync.h"
5051
#include "driver/i2s_common.h"
5152
#include "i2s_private.h"
5253

@@ -1483,3 +1484,46 @@ void i2s_sync_reset_fifo_count(i2s_chan_handle_t tx_handle)
14831484
i2s_ll_tx_reset_fifo_sync_counter(tx_handle->controller->hal.dev);
14841485
}
14851486
#endif // SOC_I2S_SUPPORTS_TX_SYNC_CNT
1487+
1488+
#if SOC_I2S_SUPPORTS_ETM_SYNC
1489+
uint32_t i2s_sync_get_fifo_sync_diff_count(i2s_chan_handle_t tx_handle)
1490+
{
1491+
return i2s_ll_tx_get_fifo_sync_diff_count(tx_handle->controller->hal.dev);
1492+
}
1493+
1494+
void i2s_sync_reset_fifo_sync_diff_count(i2s_chan_handle_t tx_handle)
1495+
{
1496+
i2s_ll_tx_reset_fifo_sync_diff_counter(tx_handle->controller->hal.dev);
1497+
}
1498+
1499+
esp_err_t i2s_sync_enable_hw_fifo_sync(i2s_chan_handle_t tx_handle, bool enable)
1500+
{
1501+
if (tx_handle->dir == I2S_DIR_RX) {
1502+
return ESP_ERR_NOT_SUPPORTED;
1503+
}
1504+
i2s_ll_tx_enable_hw_fifo_sync(tx_handle->controller->hal.dev, enable);
1505+
return ESP_OK;
1506+
}
1507+
1508+
esp_err_t i2s_sync_config_hw_fifo_sync(i2s_chan_handle_t tx_handle, const i2s_sync_fifo_sync_config_t *config)
1509+
{
1510+
if (!(tx_handle && config)) {
1511+
return ESP_ERR_INVALID_ARG;
1512+
}
1513+
if (tx_handle->dir == I2S_DIR_RX) {
1514+
return ESP_ERR_NOT_SUPPORTED;
1515+
}
1516+
if (config->sw_high_thresh < config->hw_low_thresh) {
1517+
return ESP_ERR_INVALID_ARG;
1518+
}
1519+
1520+
i2s_ll_tx_set_etm_sync_ideal_cnt(tx_handle->controller->hal.dev, config->ideal_cnt);
1521+
i2s_ll_tx_set_fifo_sync_diff_conter_sw_threshold(tx_handle->controller->hal.dev, config->sw_high_thresh);
1522+
i2s_ll_tx_set_fifo_sync_diff_conter_hw_threshold(tx_handle->controller->hal.dev, config->hw_low_thresh);
1523+
i2s_ll_tx_set_hw_fifo_sync_suppl_mode(tx_handle->controller->hal.dev, (uint32_t)config->suppl_mode);
1524+
if (config->suppl_mode == I2S_SYNC_SUPPL_MODE_STATIC_DATA) {
1525+
i2s_ll_tx_set_hw_fifo_sync_static_suppl_data(tx_handle->controller->hal.dev, config->suppl_data);
1526+
}
1527+
return ESP_OK;
1528+
}
1529+
#endif

components/esp_driver_i2s/i2s_etm.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -84,6 +84,11 @@ esp_err_t i2s_new_etm_task(i2s_chan_handle_t handle, const i2s_etm_task_config_t
8484
{
8585
ESP_RETURN_ON_FALSE(handle && config && out_task, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
8686
ESP_RETURN_ON_FALSE(config->task_type < I2S_ETM_TASK_MAX, ESP_ERR_INVALID_ARG, TAG, "invalid task type");
87+
#if SOC_I2S_SUPPORTS_ETM_SYNC
88+
ESP_RETURN_ON_FALSE(config->task_type != I2S_ETM_TASK_SYNC_CHECK || handle->dir == I2S_DIR_TX,
89+
ESP_ERR_NOT_SUPPORTED, TAG, "rx is not supported");
90+
#endif
91+
8792
i2s_etm_task_t *task = heap_caps_calloc(1, sizeof(i2s_etm_task_t), ETM_MEM_ALLOC_CAPS);
8893
ESP_RETURN_ON_FALSE(task, ESP_ERR_NO_MEM, TAG, "no memory for ETM task");
8994

components/esp_driver_i2s/include/esp_private/i2s_sync.h

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -31,6 +31,7 @@ extern "C" {
3131
/**
3232
* @brief Get the counter number of BCLK ticks
3333
* @note The BCLK tick count reflects the real data that have sent on line
34+
* @note It will be reset automatically when `I2S_ETM_TASK_SYNC_CHECK` is triggered
3435
*
3536
* @param[in] tx_handle The I2S tx channel handle
3637
* @return
@@ -43,6 +44,7 @@ uint32_t i2s_sync_get_bclk_count(i2s_chan_handle_t tx_handle);
4344
* @note The FIFO count reflects how many slots have processed
4445
* Normally, fifo_cnt = slot_bit_width * bclk_cnt
4546
* If fifo_cnt < slot_bit_width * bclk_cnt, that means some data are still stuck in the I2S controller
47+
* @note It will be reset automatically when `I2S_ETM_TASK_SYNC_CHECK` is triggered
4648
*
4749
* @param[in] tx_handle The I2S tx channel handle
4850
* @return
@@ -66,6 +68,78 @@ void i2s_sync_reset_fifo_count(i2s_chan_handle_t tx_handle);
6668

6769
#endif // SOC_I2S_SUPPORTS_TX_SYNC_CNT
6870

71+
#if SOC_I2S_SUPPORTS_ETM_SYNC
72+
/**
73+
* @brief I2S hardware FIFO synchronization supplement mode
74+
* @note When the FIFO sync difference count is out of threshold, the hardware will supplement data automatically
75+
* This type is to specify which data will be supplemented
76+
*/
77+
typedef enum {
78+
I2S_SYNC_SUPPL_MODE_LAST_DATA = 0, /*!< Supplement with the last transmitted data */
79+
I2S_SYNC_SUPPL_MODE_STATIC_DATA = 1, /*!< Supplement with static data specified in config */
80+
} i2s_sync_suppl_mode_t;
81+
82+
/**
83+
* @brief I2S hardware FIFO synchronization configuration
84+
* @note This configuration is used for multi I2S port synchronization via ETM
85+
*/
86+
typedef struct {
87+
uint32_t hw_low_thresh; /*!< Lower threshold for FIFO sync difference counter
88+
- If difference count < hw_low_thresh, do nothing
89+
- If difference count >= hw_low_thresh, the hardware will supplement data automatically */
90+
uint32_t sw_high_thresh; /*!< Upper threshold for FIFO sync difference counter
91+
- If difference count <= sw_high_thresh, the hardware supplement data automatically
92+
- If difference count > sw_high_thresh, sync interrupt triggered and
93+
the software is responsible to decide how to handle this severe asynchronization */
94+
uint32_t ideal_cnt; /*!< Ideal count for FIFO sync difference counter, it depends on the ETM sync task interval and the data rate */
95+
i2s_sync_suppl_mode_t suppl_mode; /*!< Data supplement mode when FIFO sync difference is out of threshold */
96+
uint32_t suppl_data; /*!< Static supplement data, only valid when suppl_mode is I2S_SYNC_SUPPL_MODE_STATIC_DATA */
97+
} i2s_sync_fifo_sync_config_t;
98+
99+
/**
100+
* @brief Get the counter number of FIFO sync difference
101+
* @note The FIFO sync difference count reflects the difference between current FIFO count and ideal count
102+
*
103+
* @param[in] tx_handle The I2S tx channel handle
104+
* @return
105+
* - FIFO sync difference count
106+
*/
107+
uint32_t i2s_sync_get_fifo_sync_diff_count(i2s_chan_handle_t tx_handle);
108+
109+
/**
110+
* @brief Reset the FIFO sync difference counter
111+
*
112+
* @param[in] tx_handle The I2S tx channel handle
113+
*/
114+
void i2s_sync_reset_fifo_sync_diff_count(i2s_chan_handle_t tx_handle);
115+
116+
/**
117+
* @brief Enable or disable hardware FIFO synchronization
118+
* @note When enabled, hardware will automatically supplement data when FIFO sync difference is greater than hw_low_thresh
119+
*
120+
* @param[in] tx_handle The I2S tx channel handle
121+
* @param[in] enable true to enable, false to disable
122+
* @return
123+
* - ESP_OK on success
124+
* - ESP_ERR_NOT_SUPPORTED if called on RX channel
125+
*/
126+
esp_err_t i2s_sync_enable_hw_fifo_sync(i2s_chan_handle_t tx_handle, bool enable);
127+
128+
/**
129+
* @brief Configure hardware FIFO synchronization parameters
130+
* @note This function configures the thresholds and supplement mode for hardware FIFO sync
131+
*
132+
* @param[in] tx_handle The I2S tx channel handle
133+
* @param[in] config Configuration for hardware FIFO synchronization
134+
* @return
135+
* - ESP_OK on success
136+
* - ESP_ERR_INVALID_ARG if invalid arguments
137+
* - ESP_ERR_NOT_SUPPORTED if called on RX channel
138+
*/
139+
esp_err_t i2s_sync_config_hw_fifo_sync(i2s_chan_handle_t tx_handle, const i2s_sync_fifo_sync_config_t *config);
140+
141+
#endif
142+
69143
#ifdef __cplusplus
70144
}
71145
#endif
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[mapping:i2s_driver]
2+
archive: libesp_driver_i2s.a
3+
entries:
4+
if I2S_CTRL_FUNC_IN_IRAM = y:
5+
if SOC_I2S_SUPPORTS_TX_SYNC_CNT = y:
6+
i2s_common: i2s_sync_get_bclk_count (noflash)
7+
i2s_common: i2s_sync_get_fifo_count (noflash)
8+
i2s_common: i2s_sync_reset_bclk_count (noflash)
9+
i2s_common: i2s_sync_reset_fifo_count (noflash)
10+
if SOC_I2S_SUPPORTS_ETM_SYNC = y:
11+
i2s_common: i2s_sync_get_fifo_sync_diff_count (noflash)
12+
i2s_common: i2s_sync_reset_fifo_sync_diff_count (noflash)
13+
i2s_common: i2s_sync_enable_hw_fifo_sync (noflash)
14+
i2s_common: i2s_sync_config_hw_fifo_sync (noflash)

components/hal/esp32h4/include/hal/i2s_ll.h

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ extern "C" {
6060
[I2S_DIR_RX - 1] = { \
6161
[I2S_ETM_TASK_START] = I2S0_TASK_START_RX, \
6262
[I2S_ETM_TASK_STOP] = I2S0_TASK_STOP_RX, \
63-
[I2S_ETM_TASK_SYNC_CHECK] = I2S0_TASK_SYNC_CHECK, \
63+
[I2S_ETM_TASK_SYNC_CHECK] = -1, \
6464
}, \
6565
[I2S_DIR_TX - 1] = { \
6666
[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)
12451245
return hw->bck_cnt.tx_bck_cnt;
12461246
}
12471247

1248+
/**
1249+
* @brief Enable TX FIFO synchronization hardware mode
1250+
*
1251+
* @param hw Peripheral I2S hardware instance address.
1252+
* @param enable Set true to enable hardware mode
1253+
*/
1254+
__attribute__((always_inline))
1255+
static inline void i2s_ll_tx_enable_hw_fifo_sync(i2s_dev_t *hw, bool enable)
1256+
{
1257+
hw->hw_sync_conf.tx_hw_sync_en = enable;
1258+
}
1259+
1260+
/**
1261+
* @brief Get TX FIFO synchronization difference count value
1262+
*
1263+
* @param hw Peripheral I2S hardware instance address.
1264+
* @return
1265+
* fifo count value
1266+
*/
1267+
__attribute__((always_inline))
1268+
static inline uint32_t i2s_ll_tx_get_fifo_sync_diff_count(i2s_dev_t *hw)
1269+
{
1270+
return hw->cnt_diff.tx_cnt_diff;
1271+
}
1272+
1273+
/**
1274+
* @brief Reset TX FIFO synchronization difference counter
1275+
*
1276+
* @param hw Peripheral I2S hardware instance address.
1277+
*/
1278+
__attribute__((always_inline))
1279+
static inline void i2s_ll_tx_reset_fifo_sync_diff_counter(i2s_dev_t *hw)
1280+
{
1281+
hw->cnt_diff.tx_cnt_diff_rst = 1;
1282+
hw->cnt_diff.tx_cnt_diff_rst = 0;
1283+
}
1284+
1285+
/**
1286+
* @brief Set TX FIFO synchronization difference counter software threshold
1287+
* @note It determines the up threshold that the hardware synchronize the data automatically.
1288+
* - If diff_count <= sw_threshold, the hardware will synchronize the data automatically.
1289+
* - If diff_count > sw_threshold, the automatic synchronization is not proper for this case,
1290+
* interrupt will be triggered to let the software decide how to handle this case.
1291+
*
1292+
* @param hw Peripheral I2S hardware instance address.
1293+
* @param thresh The threshold that send
1294+
*/
1295+
__attribute__((always_inline))
1296+
static inline void i2s_ll_tx_set_fifo_sync_diff_conter_sw_threshold(i2s_dev_t *hw, uint32_t thresh)
1297+
{
1298+
hw->sync_sw_thres.tx_cnt_diff_sw_thres = thresh;
1299+
}
1300+
1301+
/**
1302+
* @brief Set TX FIFO synchronization difference counter hardware threshold
1303+
* @note It determines the down threshold that the hardware synchronize the data automatically.
1304+
* - If diff_count < hw_threshold, synchronization check pass, do nothing
1305+
* - If diff_count >= hw_threshold, the hardware will synchronize the data automatically.
1306+
*
1307+
* @param hw Peripheral I2S hardware instance address.
1308+
* @param thresh The threshold that send
1309+
*/
1310+
__attribute__((always_inline))
1311+
static inline void i2s_ll_tx_set_fifo_sync_diff_conter_hw_threshold(i2s_dev_t *hw, uint32_t thresh)
1312+
{
1313+
hw->sync_hw_thres.tx_cnt_diff_hw_thres = thresh;
1314+
}
1315+
1316+
/**
1317+
* @brief Set TX FIFO synchronization hardware data supplementation mode
1318+
* @note It determines the supplementation data when the actual sent data is less than the `diff_count - threshold`
1319+
*
1320+
* @param hw Peripheral I2S hardware instance address.
1321+
* @param mode Data supplementation mode
1322+
* - 0: Supplement the last data
1323+
* - 1: Supplement the data configured in `hw_sync_data` reg
1324+
*/
1325+
__attribute__((always_inline))
1326+
static inline void i2s_ll_tx_set_hw_fifo_sync_suppl_mode(i2s_dev_t *hw, uint32_t mode)
1327+
{
1328+
hw->hw_sync_conf.tx_hw_sync_suppl_mode = mode;
1329+
}
1330+
1331+
/**
1332+
* @brief Set TX FIFO synchronization hardware supplementation data when `tx_hw_sync_suppl_mode` is 1
1333+
*
1334+
* @param hw Peripheral I2S hardware instance address.
1335+
* @param data Data to be supplemented when `tx_hw_sync_suppl_mode` is 1
1336+
*/
1337+
__attribute__((always_inline))
1338+
static inline void i2s_ll_tx_set_hw_fifo_sync_static_suppl_data(i2s_dev_t *hw, uint32_t data)
1339+
{
1340+
hw->hw_sync_data.tx_hw_sync_suppl_data = data;
1341+
}
1342+
1343+
/**
1344+
* @brief Set the TX ETM synchronization ideal count
1345+
*
1346+
* @param hw Peripheral I2S hardware instance address.
1347+
* @param ideal_cnt The ideal FIFO count when I2S_ETM_TASK_SYNC_CHECK triggered.
1348+
*/
1349+
__attribute__((always_inline))
1350+
static inline void i2s_ll_tx_set_etm_sync_ideal_cnt(i2s_dev_t *hw, uint32_t ideal_cnt)
1351+
{
1352+
hw->ideal_cnt.tx_ideal_cnt = ideal_cnt;
1353+
}
1354+
12481355
/**
12491356
* @brief Set the TX ETM threshold of REACH_THRESH event
12501357
*

components/hal/include/hal/i2s_types.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ typedef enum {
234234
I2S_ETM_TASK_START, /*!< Start the I2S channel */
235235
I2S_ETM_TASK_STOP, /*!< Stop the I2S channel */
236236
#if SOC_I2S_SUPPORTS_ETM_SYNC
237-
I2S_ETM_TASK_SYNC_CHECK, /*!< Stop the I2S channel */
237+
I2S_ETM_TASK_SYNC_CHECK, /*!< Check the I2S TX channel sync status */
238238
#endif
239239
I2S_ETM_TASK_MAX, /*!< Maximum number of tasks */
240240
} i2s_etm_task_type_t;

0 commit comments

Comments
 (0)