mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/i2s_support_pre_load_dma_data' into 'master'
i2s: support preload data Closes IDFGH-6847 See merge request espressif/esp-idf!21927
This commit is contained in:
commit
0f15d4a2c1
@ -285,6 +285,8 @@ static esp_err_t i2s_register_channel(i2s_controller_t *i2s_obj, i2s_dir_t dir,
|
||||
new_chan->callbacks.on_recv_q_ovf = NULL;
|
||||
new_chan->callbacks.on_sent = NULL;
|
||||
new_chan->callbacks.on_send_q_ovf = NULL;
|
||||
new_chan->dma.rw_pos = 0;
|
||||
new_chan->dma.curr_ptr = NULL;
|
||||
new_chan->start = NULL;
|
||||
new_chan->stop = NULL;
|
||||
|
||||
@ -1014,8 +1016,6 @@ esp_err_t i2s_channel_enable(i2s_chan_handle_t handle)
|
||||
#if CONFIG_PM_ENABLE
|
||||
esp_pm_lock_acquire(handle->pm_lock);
|
||||
#endif
|
||||
handle->dma.curr_ptr = NULL;
|
||||
handle->dma.rw_pos = 0;
|
||||
handle->start(handle);
|
||||
handle->state = I2S_CHAN_STATE_RUNNING;
|
||||
/* Reset queue */
|
||||
@ -1039,8 +1039,11 @@ esp_err_t i2s_channel_disable(i2s_chan_handle_t handle)
|
||||
|
||||
xSemaphoreTake(handle->mutex, portMAX_DELAY);
|
||||
ESP_GOTO_ON_FALSE(handle->state > I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "the channel has not been enabled yet");
|
||||
/* Update the state to force quit the current reading/wrinting operation */
|
||||
/* Update the state to force quit the current reading/writing operation */
|
||||
handle->state = I2S_CHAN_STATE_READY;
|
||||
/* Reset the descriptor pointer */
|
||||
handle->dma.curr_ptr = NULL;
|
||||
handle->dma.rw_pos = 0;
|
||||
/* Waiting for reading/wrinting operation quit */
|
||||
xSemaphoreTake(handle->binary, portMAX_DELAY);
|
||||
handle->stop(handle);
|
||||
@ -1056,6 +1059,60 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
esp_err_t i2s_channel_preload_data(i2s_chan_handle_t tx_handle, const void *src, size_t size, size_t *bytes_loaded)
|
||||
{
|
||||
I2S_NULL_POINTER_CHECK(TAG, tx_handle);
|
||||
ESP_RETURN_ON_FALSE(tx_handle->dir == I2S_DIR_TX, ESP_ERR_INVALID_ARG, TAG, "this channel is not tx channel");
|
||||
ESP_RETURN_ON_FALSE(tx_handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, TAG, "data can only be preloaded when the channel is READY");
|
||||
|
||||
uint8_t *data_ptr = (uint8_t *)src;
|
||||
size_t remain_bytes = size;
|
||||
size_t total_loaded_bytes = 0;
|
||||
|
||||
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];
|
||||
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) {
|
||||
size_t bytes_can_load = remain_bytes > (tx_handle->dma.buf_size - tx_handle->dma.rw_pos) ?
|
||||
(tx_handle->dma.buf_size - tx_handle->dma.rw_pos) : remain_bytes;
|
||||
/* When all the descriptors has loaded data, no more bytes can be loaded, break directly */
|
||||
if (bytes_can_load == 0) {
|
||||
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);
|
||||
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
|
||||
tx_handle->dma.rw_pos += bytes_can_load; // Move forward the dma buffer position
|
||||
/* When the current position reach the end of the dma buffer */
|
||||
if (tx_handle->dma.rw_pos == tx_handle->dma.buf_size) {
|
||||
/* 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 (desc_ptr->empty != (uint32_t)tx_handle->dma.desc[0]) {
|
||||
desc_ptr = (lldesc_t *)desc_ptr->empty;
|
||||
tx_handle->dma.curr_ptr = (void *)desc_ptr;
|
||||
tx_handle->dma.rw_pos = 0;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
*bytes_loaded = total_loaded_bytes;
|
||||
|
||||
xSemaphoreGive(tx_handle->mutex);
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t i2s_channel_write(i2s_chan_handle_t handle, const void *src, size_t size, size_t *bytes_written, uint32_t timeout_ms)
|
||||
{
|
||||
I2S_NULL_POINTER_CHECK(TAG, handle);
|
||||
@ -1065,7 +1122,9 @@ esp_err_t i2s_channel_write(i2s_chan_handle_t handle, const void *src, size_t si
|
||||
char *data_ptr;
|
||||
char *src_byte;
|
||||
size_t bytes_can_write;
|
||||
*bytes_written = 0;
|
||||
if (bytes_written) {
|
||||
*bytes_written = 0;
|
||||
}
|
||||
|
||||
/* The binary semaphore can only be taken when the channel has been enabled and no other writing operation in progress */
|
||||
ESP_RETURN_ON_FALSE(xSemaphoreTake(handle->binary, pdMS_TO_TICKS(timeout_ms)) == pdTRUE, ESP_ERR_INVALID_STATE, TAG, "The channel is not enabled");
|
||||
@ -1088,7 +1147,9 @@ esp_err_t i2s_channel_write(i2s_chan_handle_t handle, const void *src, size_t si
|
||||
size -= bytes_can_write;
|
||||
src_byte += bytes_can_write;
|
||||
handle->dma.rw_pos += bytes_can_write;
|
||||
(*bytes_written) += bytes_can_write;
|
||||
if (bytes_written) {
|
||||
(*bytes_written) += bytes_can_write;
|
||||
}
|
||||
}
|
||||
xSemaphoreGive(handle->binary);
|
||||
|
||||
@ -1104,7 +1165,9 @@ esp_err_t i2s_channel_read(i2s_chan_handle_t handle, void *dest, size_t size, si
|
||||
uint8_t *data_ptr;
|
||||
uint8_t *dest_byte;
|
||||
int bytes_can_read;
|
||||
*bytes_read = 0;
|
||||
if (bytes_read) {
|
||||
*bytes_read = 0;
|
||||
}
|
||||
dest_byte = (uint8_t *)dest;
|
||||
/* The binary semaphore can only be taken when the channel has been enabled and no other reading operation in progress */
|
||||
ESP_RETURN_ON_FALSE(xSemaphoreTake(handle->binary, pdMS_TO_TICKS(timeout_ms)) == pdTRUE, ESP_ERR_INVALID_STATE, TAG, "The channel is not enabled");
|
||||
@ -1126,7 +1189,9 @@ esp_err_t i2s_channel_read(i2s_chan_handle_t handle, void *dest, size_t size, si
|
||||
size -= bytes_can_read;
|
||||
dest_byte += bytes_can_read;
|
||||
handle->dma.rw_pos += bytes_can_read;
|
||||
(*bytes_read) += bytes_can_read;
|
||||
if (bytes_read) {
|
||||
(*bytes_read) += bytes_can_read;
|
||||
}
|
||||
}
|
||||
xSemaphoreGive(handle->binary);
|
||||
|
||||
|
@ -142,7 +142,7 @@ esp_err_t i2s_channel_enable(i2s_chan_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Disable the i2s channel
|
||||
* @note Only allowed to be called when the channel state is READY / RUNNING, (i.e., channel has been initialized)
|
||||
* @note Only allowed to be called when the channel state is RUNNING, (i.e., channel has been started)
|
||||
* the channel will enter READY state once it is disabled successfully.
|
||||
* @note Disable the channel can stop the I2S communication on hardware. It will stop bclk and ws signal but not mclk signal
|
||||
*
|
||||
@ -154,6 +154,28 @@ esp_err_t i2s_channel_enable(i2s_chan_handle_t handle);
|
||||
*/
|
||||
esp_err_t i2s_channel_disable(i2s_chan_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Preload the data into TX DMA buffer
|
||||
* @note Only allowed to be called when the channel state is READY, (i.e., channel has been initialized, but not started)
|
||||
* @note As the initial DMA buffer has no data inside, it will transmit the empty buffer after enabled the channel,
|
||||
* this function is used to preload the data into the DMA buffer, so that the valid data can be transmitted immediately
|
||||
* after the channel is enabled.
|
||||
* @note This function can be called multiple times before enabling the channel, the buffer that loaded later will be concatenated
|
||||
* behind the former loaded buffer. But when all the DMA buffers have been loaded, no more data can be preload then, please
|
||||
* check the `bytes_loaded` parameter to see how many bytes are loaded successfully, when the `bytes_loaded` is smaller than
|
||||
* the `size`, it means the DMA buffers are full.
|
||||
*
|
||||
* @param[in] tx_handle I2S TX channel handler
|
||||
* @param[in] src The pointer of the source buffer to be loaded
|
||||
* @param[in] size The source buffer size
|
||||
* @param[out] bytes_loaded The bytes that successfully been loaded into the TX DMA buffer
|
||||
* @return
|
||||
* - ESP_OK Load data successful
|
||||
* - ESP_ERR_INVALID_ARG NULL pointer or not TX direction
|
||||
* - ESP_ERR_INVALID_STATE This channel has not stated
|
||||
*/
|
||||
esp_err_t i2s_channel_preload_data(i2s_chan_handle_t tx_handle, const void *src, size_t size, size_t *bytes_loaded);
|
||||
|
||||
/**
|
||||
* @brief I2S write data
|
||||
* @note Only allowed to be called when the channel state is RUNNING, (i.e., tx channel has been started and is not writing now)
|
||||
@ -162,7 +184,7 @@ esp_err_t i2s_channel_disable(i2s_chan_handle_t handle);
|
||||
* @param[in] handle I2S channel handler
|
||||
* @param[in] src The pointer of sent data buffer
|
||||
* @param[in] size Max data buffer length
|
||||
* @param[out] bytes_written Byte number that actually be sent
|
||||
* @param[out] bytes_written Byte number that actually be sent, can be NULL if not needed
|
||||
* @param[in] timeout_ms Max block time
|
||||
* @return
|
||||
* - ESP_OK Write successfully
|
||||
@ -180,7 +202,7 @@ esp_err_t i2s_channel_write(i2s_chan_handle_t handle, const void *src, size_t si
|
||||
* @param[in] handle I2S channel handler
|
||||
* @param[in] dest The pointer of receiving data buffer
|
||||
* @param[in] size Max data buffer length
|
||||
* @param[out] bytes_read Byte number that actually be read
|
||||
* @param[out] bytes_read Byte number that actually be read, can be NULL if not needed
|
||||
* @param[in] timeout_ms Max block time
|
||||
* @return
|
||||
* - ESP_OK Read successfully
|
||||
@ -193,7 +215,7 @@ esp_err_t i2s_channel_read(i2s_chan_handle_t handle, void *dest, size_t size, si
|
||||
/**
|
||||
* @brief Set event callbacks for I2S channel
|
||||
*
|
||||
* @note Only allowed to be called when the channel state is REGISTARED / READY, (i.e., before channel starts)
|
||||
* @note Only allowed to be called when the channel state is REGISTERED / READY, (i.e., before channel starts)
|
||||
* @note User can deregister a previously registered callback by calling this function and setting the callback member in the `callbacks` structure to NULL.
|
||||
* @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. The `user_data` should also reside in SRAM or internal RAM as well.
|
||||
@ -204,7 +226,7 @@ esp_err_t i2s_channel_read(i2s_chan_handle_t handle, void *dest, size_t size, si
|
||||
* @return
|
||||
* - ESP_OK Set event callbacks successfully
|
||||
* - ESP_ERR_INVALID_ARG Set event callbacks failed because of invalid argument
|
||||
* - ESP_ERR_INVALID_STATE Set event callbacks failed because the current channel state is not REGISTARED or READY
|
||||
* - ESP_ERR_INVALID_STATE Set event callbacks failed because the current channel state is not REGISTERED or READY
|
||||
*/
|
||||
esp_err_t i2s_channel_register_event_callback(i2s_chan_handle_t handle, const i2s_event_callbacks_t *callbacks, void *user_data);
|
||||
|
||||
|
@ -53,6 +53,10 @@ static void i2s_example_read_task(void *args)
|
||||
uint8_t *r_buf = (uint8_t *)calloc(1, EXAMPLE_BUFF_SIZE);
|
||||
assert(r_buf); // Check if r_buf allocation success
|
||||
size_t r_bytes = 0;
|
||||
|
||||
/* Enable the RX channel */
|
||||
ESP_ERROR_CHECK(i2s_channel_enable(rx_chan));
|
||||
|
||||
/* ATTENTION: The print and delay in the read task only for monitoring the data by human,
|
||||
* Normally there shouldn't be any delays to ensure a short polling time,
|
||||
* Otherwise the dma buffer will overflow and lead to the data lost */
|
||||
@ -88,7 +92,16 @@ static void i2s_example_write_task(void *args)
|
||||
w_buf[i + 7] = 0xF0;
|
||||
}
|
||||
|
||||
size_t w_bytes = 0;
|
||||
size_t w_bytes = EXAMPLE_BUFF_SIZE;
|
||||
|
||||
/* (Optional) Preload the data before enabling the TX channel, so that the valid data can be transmitted immediately */
|
||||
while (w_bytes == EXAMPLE_BUFF_SIZE) {
|
||||
/* Here we load the target buffer repeatedly, until all the DMA buffers are preloaded */
|
||||
ESP_ERROR_CHECK(i2s_channel_preload_data(tx_chan, w_buf, EXAMPLE_BUFF_SIZE, &w_bytes));
|
||||
}
|
||||
|
||||
/* Enable the TX channel */
|
||||
ESP_ERROR_CHECK(i2s_channel_enable(tx_chan));
|
||||
while (1) {
|
||||
/* Write i2s data */
|
||||
if (i2s_channel_write(tx_chan, w_buf, EXAMPLE_BUFF_SIZE, &w_bytes, 1000) == ESP_OK) {
|
||||
@ -203,11 +216,7 @@ void app_main(void)
|
||||
i2s_example_init_std_simplex();
|
||||
#endif
|
||||
|
||||
/* Step 3: Enable the tx and rx channels before writing or reading data */
|
||||
ESP_ERROR_CHECK(i2s_channel_enable(tx_chan));
|
||||
ESP_ERROR_CHECK(i2s_channel_enable(rx_chan));
|
||||
|
||||
/* Step 4: Create writing and reading task */
|
||||
/* Step 3: Create writing and reading task, enable and start the channels */
|
||||
xTaskCreate(i2s_example_read_task, "i2s_example_read_task", 4096, NULL, 5, NULL);
|
||||
xTaskCreate(i2s_example_write_task, "i2s_example_write_task", 4096, NULL, 5, NULL);
|
||||
}
|
||||
|
@ -26,12 +26,14 @@ def test_i2s_basic_example(dut: Dut) -> None:
|
||||
dut.expect(r'D \(([0-9]+)\) i2s_std: Clock division info: \[sclk\] ([0-9]+) Hz '
|
||||
r'\[mdiv\] ([0-9]+) \[mclk\] ([0-9]+) Hz \[bdiv\] ([0-9]+) \[bclk\] ([0-9]+) Hz', timeout=5)
|
||||
dut.expect(r'D \(([0-9]+)\) i2s_std: The rx channel on I2S0 has been initialized to STD mode successfully', timeout=5)
|
||||
dut.expect(r'D \(([0-9]+)\) i2s_common: i2s tx channel enabled', timeout=5)
|
||||
dut.expect(r'D \(([0-9]+)\) i2s_common: i2s rx channel enabled', timeout=5)
|
||||
chan_enable_pattern = [
|
||||
r'D \(([0-9]+)\) i2s_common: i2s tx channel enabled',
|
||||
r'D \(([0-9]+)\) i2s_common: i2s rx channel enabled'
|
||||
]
|
||||
dut.expect(chan_enable_pattern, timeout=5)
|
||||
dut.expect(chan_enable_pattern, timeout=5)
|
||||
dut.expect(r'Write Task: i2s write ([0-9]+) bytes', timeout=5)
|
||||
dut.expect(r'Read Task: i2s read ([0-9]+) bytes', timeout=5)
|
||||
dut.expect(r'-----------------------------------', timeout=5)
|
||||
dut.expect(r'\[0\] 0 \[1\] 0 \[2\] 0 \[3\] 0', timeout=5)
|
||||
dut.expect(r'\[4\] 0 \[5\] 0 \[6\] 0 \[7\] 0', timeout=5)
|
||||
dut.expect(r'\[0\] 12 \[1\] 34 \[2\] 56 \[3\] 78', timeout=10)
|
||||
dut.expect(r'\[4\] 9a \[5\] bc \[6\] de \[7\] f0', timeout=10)
|
||||
|
@ -38,6 +38,10 @@ static void i2s_example_read_task(void *args)
|
||||
uint8_t *r_buf = (uint8_t *)calloc(1, EXAMPLE_BUFF_SIZE);
|
||||
assert(r_buf); // Check if r_buf allocation success
|
||||
size_t r_bytes = 0;
|
||||
|
||||
/* Enable the RX channel */
|
||||
ESP_ERROR_CHECK(i2s_channel_enable(rx_chan));
|
||||
|
||||
/* ATTENTION: The print and delay in the read task only for monitoring the data by human,
|
||||
* Normally there shouldn't be any delays to ensure a short polling time,
|
||||
* Otherwise the dma buffer will overflow and lead to the data lost */
|
||||
@ -73,7 +77,16 @@ static void i2s_example_write_task(void *args)
|
||||
w_buf[i + 7] = 0xF0;
|
||||
}
|
||||
|
||||
size_t w_bytes = 0;
|
||||
size_t w_bytes = EXAMPLE_BUFF_SIZE;
|
||||
|
||||
/* (Optional) Preload the data before enabling the TX channel, so that the valid data can be transmitted immediately */
|
||||
while (w_bytes == EXAMPLE_BUFF_SIZE) {
|
||||
/* Here we load the target buffer repeatedly, until all the DMA buffers are preloaded */
|
||||
ESP_ERROR_CHECK(i2s_channel_preload_data(tx_chan, w_buf, EXAMPLE_BUFF_SIZE, &w_bytes));
|
||||
}
|
||||
|
||||
/* Enable the TX channel */
|
||||
ESP_ERROR_CHECK(i2s_channel_enable(tx_chan));
|
||||
while (1) {
|
||||
/* Write i2s data */
|
||||
if (i2s_channel_write(tx_chan, w_buf, EXAMPLE_BUFF_SIZE, &w_bytes, 1000) == ESP_OK) {
|
||||
@ -203,11 +216,7 @@ void app_main(void)
|
||||
i2s_example_init_tdm_simplex();
|
||||
#endif
|
||||
|
||||
/* Step 3: Enable the tx and rx channels before writing or reading data */
|
||||
ESP_ERROR_CHECK(i2s_channel_enable(tx_chan));
|
||||
ESP_ERROR_CHECK(i2s_channel_enable(rx_chan));
|
||||
|
||||
/* Step 4: Create writing and reading task */
|
||||
/* Step 3: Create writing and reading task, enable and start the channels */
|
||||
xTaskCreate(i2s_example_read_task, "i2s_example_read_task", 4096, NULL, 5, NULL);
|
||||
xTaskCreate(i2s_example_write_task, "i2s_example_write_task", 4096, NULL, 5, NULL);
|
||||
}
|
||||
|
@ -24,12 +24,14 @@ def test_i2s_tdm_example(dut: Dut) -> None:
|
||||
dut.expect(r'D \(([0-9]+)\) i2s_tdm: Clock division info: \[sclk\] ([0-9]+) Hz '
|
||||
r'\[mdiv\] ([0-9]+) \[mclk\] ([0-9]+) Hz \[bdiv\] ([0-9]+) \[bclk\] ([0-9]+) Hz', timeout=5)
|
||||
dut.expect(r'D \(([0-9]+)\) i2s_tdm: The rx channel on I2S0 has been initialized to TDM mode successfully', timeout=5)
|
||||
dut.expect(r'D \(([0-9]+)\) i2s_common: i2s tx channel enabled', timeout=5)
|
||||
dut.expect(r'D \(([0-9]+)\) i2s_common: i2s rx channel enabled', timeout=5)
|
||||
chan_enable_pattern = [
|
||||
r'D \(([0-9]+)\) i2s_common: i2s tx channel enabled',
|
||||
r'D \(([0-9]+)\) i2s_common: i2s rx channel enabled'
|
||||
]
|
||||
dut.expect(chan_enable_pattern, timeout=5)
|
||||
dut.expect(chan_enable_pattern, timeout=5)
|
||||
dut.expect(r'Write Task: i2s write ([0-9]+) bytes', timeout=5)
|
||||
dut.expect(r'Read Task: i2s read ([0-9]+) bytes', timeout=5)
|
||||
dut.expect(r'-----------------------------------', timeout=5)
|
||||
dut.expect(r'\[0\] 0 \[1\] 0 \[2\] 0 \[3\] 0', timeout=5)
|
||||
dut.expect(r'\[4\] 0 \[5\] 0 \[6\] 0 \[7\] 0', timeout=5)
|
||||
dut.expect(r'\[0\] 12 \[1\] 34 \[2\] 56 \[3\] 78', timeout=10)
|
||||
dut.expect(r'\[4\] 9a \[5\] bc \[6\] de \[7\] f0', timeout=10)
|
||||
|
@ -115,9 +115,19 @@ static void i2s_music(void *args)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
size_t bytes_write = 0;
|
||||
uint8_t *data_ptr = (uint8_t *)music_pcm_start;
|
||||
|
||||
/* (Optional) Disable TX channel and preload the data before enabling the TX channel,
|
||||
* so that the valid data can be transmitted immediately */
|
||||
ESP_ERROR_CHECK(i2s_channel_disable(tx_handle));
|
||||
ESP_ERROR_CHECK(i2s_channel_preload_data(tx_handle, data_ptr, music_pcm_end - data_ptr, &bytes_write));
|
||||
data_ptr += bytes_write; // Move forward the data pointer
|
||||
|
||||
/* Enable the TX channel */
|
||||
ESP_ERROR_CHECK(i2s_channel_enable(tx_handle));
|
||||
while (1) {
|
||||
/* Write music to earphone */
|
||||
ret = i2s_channel_write(tx_handle, music_pcm_start, music_pcm_end - music_pcm_start, &bytes_write, portMAX_DELAY);
|
||||
ret = i2s_channel_write(tx_handle, data_ptr, music_pcm_end - data_ptr, &bytes_write, portMAX_DELAY);
|
||||
if (ret != ESP_OK) {
|
||||
/* Since we set timeout to 'portMAX_DELAY' in 'i2s_channel_write'
|
||||
so you won't reach here unless you set other timeout value,
|
||||
@ -131,6 +141,7 @@ static void i2s_music(void *args)
|
||||
ESP_LOGE(TAG, "[music] i2s music play failed.");
|
||||
abort();
|
||||
}
|
||||
data_ptr = (uint8_t *)music_pcm_start;
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
|
Loading…
x
Reference in New Issue
Block a user