mirror of
https://github.com/espressif/esp-idf
synced 2025-03-10 09:39:10 -04:00
Merge branch 'doc/vad_programming_guide_v5.4' into 'release/v5.4'
doc: lp_i2s and vad programming guide (v5.4) See merge request espressif/esp-idf!35108
This commit is contained in:
commit
47d0a913e0
@ -7,6 +7,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <sys/lock.h>
|
#include <sys/lock.h>
|
||||||
|
#include <stdatomic.h>
|
||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/semphr.h"
|
#include "freertos/semphr.h"
|
||||||
#include "freertos/queue.h"
|
#include "freertos/queue.h"
|
||||||
@ -199,7 +200,7 @@ struct lp_i2s_channel_obj_t {
|
|||||||
i2s_comm_mode_t mode; /*!< lp i2s channel communication mode */
|
i2s_comm_mode_t mode; /*!< lp i2s channel communication mode */
|
||||||
i2s_role_t role; /*!< lp i2s role */
|
i2s_role_t role; /*!< lp i2s role */
|
||||||
i2s_dir_t dir; /*!< lp i2s channel direction */
|
i2s_dir_t dir; /*!< lp i2s channel direction */
|
||||||
i2s_state_t state; /*!< lp i2s driver state. Ensuring the driver working in a correct sequence */
|
_Atomic i2s_state_t state; /*!< lp i2s driver state. Ensuring the driver working in a correct sequence */
|
||||||
SemaphoreHandle_t semphr; /*!< lp i2s event semphr*/
|
SemaphoreHandle_t semphr; /*!< lp i2s event semphr*/
|
||||||
lp_i2s_trans_t trans; /*!< transaction */
|
lp_i2s_trans_t trans; /*!< transaction */
|
||||||
size_t threshold; /*!< lp i2s threshold*/
|
size_t threshold; /*!< lp i2s threshold*/
|
||||||
|
@ -55,7 +55,7 @@ esp_err_t lp_i2s_new_channel(const lp_i2s_chan_config_t *chan_cfg, lp_i2s_chan_h
|
|||||||
/**
|
/**
|
||||||
* @brief Register LP I2S event callbacks
|
* @brief Register LP I2S event callbacks
|
||||||
*
|
*
|
||||||
* @param[in] handle LP I2S channel handle
|
* @param[in] chan LP I2S channel handle
|
||||||
* @param[in] cbs Callbacks
|
* @param[in] cbs Callbacks
|
||||||
* @param[in] user_data User data
|
* @param[in] user_data User data
|
||||||
*
|
*
|
||||||
@ -64,12 +64,12 @@ esp_err_t lp_i2s_new_channel(const lp_i2s_chan_config_t *chan_cfg, lp_i2s_chan_h
|
|||||||
* - ESP_ERR_INVALID_ARG: Invalid argument
|
* - ESP_ERR_INVALID_ARG: Invalid argument
|
||||||
* - ESP_ERR_INVALID_STATE: Invalid state
|
* - ESP_ERR_INVALID_STATE: Invalid state
|
||||||
*/
|
*/
|
||||||
esp_err_t lp_i2s_register_event_callbacks(lp_i2s_chan_handle_t handle, const lp_i2s_evt_cbs_t *cbs, void *user_data);
|
esp_err_t lp_i2s_register_event_callbacks(lp_i2s_chan_handle_t chan, const lp_i2s_evt_cbs_t *cbs, void *user_data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Enable LP I2S driver
|
* @brief Enable LP I2S driver
|
||||||
*
|
*
|
||||||
* @param[in] handle LP I2S channel handle
|
* @param[in] chan LP I2S channel handle
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: On success
|
* - ESP_OK: On success
|
||||||
@ -81,7 +81,7 @@ esp_err_t lp_i2s_channel_enable(lp_i2s_chan_handle_t chan);
|
|||||||
/**
|
/**
|
||||||
* @brief Read LP I2S received data
|
* @brief Read LP I2S received data
|
||||||
*
|
*
|
||||||
* @param[in] handle LP I2S channel handle
|
* @param[in] chan LP I2S channel handle
|
||||||
* @param[in] trans LP I2S transaction
|
* @param[in] trans LP I2S transaction
|
||||||
* @param[in] timeout_ms Timeout in ms, set to `LP_I2S_MAX_DELAY` to wait until read is done
|
* @param[in] timeout_ms Timeout in ms, set to `LP_I2S_MAX_DELAY` to wait until read is done
|
||||||
*
|
*
|
||||||
@ -95,7 +95,7 @@ esp_err_t lp_i2s_channel_read(lp_i2s_chan_handle_t chan, lp_i2s_trans_t *trans,
|
|||||||
/**
|
/**
|
||||||
* @brief Read LP I2S received data until certain bytes
|
* @brief Read LP I2S received data until certain bytes
|
||||||
*
|
*
|
||||||
* @param[in] handle LP I2S channel handle
|
* @param[in] chan LP I2S channel handle
|
||||||
* @param[in] trans LP I2S transaction
|
* @param[in] trans LP I2S transaction
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
@ -108,7 +108,7 @@ esp_err_t lp_i2s_channel_read_until_bytes(lp_i2s_chan_handle_t chan, lp_i2s_tran
|
|||||||
/**
|
/**
|
||||||
* @brief Disable LP I2S driver
|
* @brief Disable LP I2S driver
|
||||||
*
|
*
|
||||||
* @param[in] handle LP I2S channel handle
|
* @param[in] chan LP I2S channel handle
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: On success
|
* - ESP_OK: On success
|
||||||
@ -120,13 +120,13 @@ esp_err_t lp_i2s_channel_disable(lp_i2s_chan_handle_t chan);
|
|||||||
/**
|
/**
|
||||||
* @brief Delete the LP I2S channel
|
* @brief Delete the LP I2S channel
|
||||||
*
|
*
|
||||||
* @param[in] handle LP I2S channel handler
|
* @param[in] chan LP I2S channel handler
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK Delete successfully
|
* - ESP_OK Delete successfully
|
||||||
* - ESP_ERR_INVALID_ARG NULL pointer
|
* - ESP_ERR_INVALID_ARG NULL pointer
|
||||||
*/
|
*/
|
||||||
esp_err_t lp_i2s_del_channel(lp_i2s_chan_handle_t handle);
|
esp_err_t lp_i2s_del_channel(lp_i2s_chan_handle_t chan);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -78,8 +78,9 @@ typedef struct vad_unit_ctx_t *vad_unit_handle_t;
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
int init_frame_num; /**< Number of init frames that are used for VAD to denoise, this helps the VAD to decrease the accidental trigger ratio.
|
int init_frame_num; /**< Number of init frames that are used for VAD to denoise, this helps the VAD to decrease the accidental trigger ratio.
|
||||||
Note too big values may lead to voice activity miss */
|
Note too big values may lead to voice activity miss */
|
||||||
int min_energy_thresh; ///< Min energy threshold.
|
int min_energy_thresh; ///< Minimum energy threshold, voice activities with energy higher than this value will be detected.
|
||||||
bool skip_band_energy_thresh; ///< Skip band energy threshold or not
|
bool skip_band_energy_thresh; /**< Skip band energy threshold or not, the passband energy check determines whether the proportion of passband energy within the total frequency domain meets the required threshold.
|
||||||
|
Note in different environments, enabling the passband energy check may reduce false trigger rates but could also increase the rate of missed detections. */
|
||||||
|
|
||||||
int speak_activity_thresh; /**< When in speak-activity-listening-state, if number of the detected speak activity is higher than this value, VAD runs into speak-activity-detected-state */
|
int speak_activity_thresh; /**< When in speak-activity-listening-state, if number of the detected speak activity is higher than this value, VAD runs into speak-activity-detected-state */
|
||||||
|
|
||||||
@ -93,6 +94,9 @@ typedef struct {
|
|||||||
int max_speak_activity_thresh; /**< When in speak-activity-detected-state, if the number of the detected speak activity is higher than this value, VAD runs into speak-activity-listening-state */
|
int max_speak_activity_thresh; /**< When in speak-activity-detected-state, if the number of the detected speak activity is higher than this value, VAD runs into speak-activity-listening-state */
|
||||||
} lp_vad_config_t;
|
} lp_vad_config_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief LP VAD Init Configurations
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
lp_i2s_chan_handle_t lp_i2s_chan; ///< LP I2S channel handle
|
lp_i2s_chan_handle_t lp_i2s_chan; ///< LP I2S channel handle
|
||||||
lp_vad_config_t vad_config; ///< LP VAD config
|
lp_vad_config_t vad_config; ///< LP VAD config
|
||||||
@ -115,7 +119,6 @@ esp_err_t lp_i2s_vad_new_unit(lp_vad_t vad_id, const lp_vad_init_config_t *init_
|
|||||||
* @brief Enable LP VAD
|
* @brief Enable LP VAD
|
||||||
*
|
*
|
||||||
* @param[in] unit VAD handle
|
* @param[in] unit VAD handle
|
||||||
* @param[in] init_config Initial configurations
|
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: On success
|
* - ESP_OK: On success
|
||||||
@ -128,7 +131,6 @@ esp_err_t lp_i2s_vad_enable(vad_unit_handle_t unit);
|
|||||||
* @brief Disable LP VAD
|
* @brief Disable LP VAD
|
||||||
*
|
*
|
||||||
* @param[in] unit VAD handle
|
* @param[in] unit VAD handle
|
||||||
* @param[in] init_config Initial configurations
|
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: On success
|
* - ESP_OK: On success
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/semphr.h"
|
#include "freertos/semphr.h"
|
||||||
#include "esp_clk_tree.h"
|
#include "esp_clk_tree.h"
|
||||||
|
#include "esp_memory_utils.h"
|
||||||
#include "hal/hal_utils.h"
|
#include "hal/hal_utils.h"
|
||||||
#include "hal/lp_i2s_hal.h"
|
#include "hal/lp_i2s_hal.h"
|
||||||
#include "hal/lp_i2s_ll.h"
|
#include "hal/lp_i2s_ll.h"
|
||||||
@ -134,8 +135,8 @@ err1:
|
|||||||
esp_err_t lp_i2s_channel_enable(lp_i2s_chan_handle_t chan)
|
esp_err_t lp_i2s_channel_enable(lp_i2s_chan_handle_t chan)
|
||||||
{
|
{
|
||||||
ESP_RETURN_ON_FALSE(chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
ESP_RETURN_ON_FALSE(chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||||
ESP_RETURN_ON_FALSE(chan->state < I2S_CHAN_STATE_RUNNING, ESP_ERR_INVALID_STATE, TAG, "the channel is in enabled state already");
|
i2s_state_t expected_state = I2S_CHAN_STATE_READY;
|
||||||
|
ESP_RETURN_ON_FALSE(atomic_compare_exchange_strong(&(chan->state), &expected_state, I2S_CHAN_STATE_RUNNING), ESP_ERR_INVALID_STATE, TAG, "the channel isn't enabled");
|
||||||
lp_i2s_evt_data_t evt_data = {};
|
lp_i2s_evt_data_t evt_data = {};
|
||||||
if (chan->cbs.on_request_new_trans) {
|
if (chan->cbs.on_request_new_trans) {
|
||||||
chan->cbs.on_request_new_trans(chan, &evt_data, chan->user_data);
|
chan->cbs.on_request_new_trans(chan, &evt_data, chan->user_data);
|
||||||
@ -145,7 +146,6 @@ esp_err_t lp_i2s_channel_enable(lp_i2s_chan_handle_t chan)
|
|||||||
chan->trans = evt_data.trans;
|
chan->trans = evt_data.trans;
|
||||||
}
|
}
|
||||||
|
|
||||||
chan->state = I2S_CHAN_STATE_RUNNING;
|
|
||||||
portENTER_CRITICAL(&g_i2s.spinlock);
|
portENTER_CRITICAL(&g_i2s.spinlock);
|
||||||
lp_i2s_ll_rx_enable_interrupt(chan->ctlr->hal.dev, LP_I2S_LL_EVENT_RX_MEM_THRESHOLD_INT, true);
|
lp_i2s_ll_rx_enable_interrupt(chan->ctlr->hal.dev, LP_I2S_LL_EVENT_RX_MEM_THRESHOLD_INT, true);
|
||||||
lp_i2s_ll_rx_start(chan->ctlr->hal.dev);
|
lp_i2s_ll_rx_start(chan->ctlr->hal.dev);
|
||||||
@ -157,7 +157,7 @@ esp_err_t lp_i2s_channel_enable(lp_i2s_chan_handle_t chan)
|
|||||||
esp_err_t lp_i2s_channel_read(lp_i2s_chan_handle_t chan, lp_i2s_trans_t *trans, uint32_t timeout_ms)
|
esp_err_t lp_i2s_channel_read(lp_i2s_chan_handle_t chan, lp_i2s_trans_t *trans, uint32_t timeout_ms)
|
||||||
{
|
{
|
||||||
ESP_RETURN_ON_FALSE(chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
ESP_RETURN_ON_FALSE(chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||||
ESP_RETURN_ON_FALSE(chan->state == I2S_CHAN_STATE_RUNNING, ESP_ERR_INVALID_STATE, TAG, "the channel isn't enabled");
|
ESP_RETURN_ON_FALSE(atomic_load(&(chan->state)) == I2S_CHAN_STATE_RUNNING, ESP_ERR_INVALID_STATE, TAG, "the channel can't be deleted unless it is disabled");
|
||||||
ESP_RETURN_ON_FALSE(!chan->cbs.on_request_new_trans, ESP_ERR_INVALID_STATE, TAG, "on_request_new_trans registered, no use of this read API");
|
ESP_RETURN_ON_FALSE(!chan->cbs.on_request_new_trans, ESP_ERR_INVALID_STATE, TAG, "on_request_new_trans registered, no use of this read API");
|
||||||
|
|
||||||
TickType_t ticks_to_wait = timeout_ms / portTICK_PERIOD_MS;
|
TickType_t ticks_to_wait = timeout_ms / portTICK_PERIOD_MS;
|
||||||
@ -206,8 +206,8 @@ esp_err_t lp_i2s_channel_read_until_bytes(lp_i2s_chan_handle_t chan, lp_i2s_tran
|
|||||||
esp_err_t lp_i2s_channel_disable(lp_i2s_chan_handle_t chan)
|
esp_err_t lp_i2s_channel_disable(lp_i2s_chan_handle_t chan)
|
||||||
{
|
{
|
||||||
ESP_RETURN_ON_FALSE(chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
ESP_RETURN_ON_FALSE(chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||||
ESP_RETURN_ON_FALSE(chan->state > I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, TAG, "the channel is disabled already");
|
i2s_state_t expected_state = I2S_CHAN_STATE_RUNNING;
|
||||||
chan->state = I2S_CHAN_STATE_READY;
|
ESP_RETURN_ON_FALSE(atomic_compare_exchange_strong(&(chan->state), &expected_state, I2S_CHAN_STATE_READY), ESP_ERR_INVALID_STATE, TAG, "the channel isn't enabled");
|
||||||
|
|
||||||
portENTER_CRITICAL(&g_i2s.spinlock);
|
portENTER_CRITICAL(&g_i2s.spinlock);
|
||||||
lp_i2s_ll_rx_enable_interrupt(chan->ctlr->hal.dev, LP_I2S_LL_EVENT_RX_MEM_THRESHOLD_INT, false);
|
lp_i2s_ll_rx_enable_interrupt(chan->ctlr->hal.dev, LP_I2S_LL_EVENT_RX_MEM_THRESHOLD_INT, false);
|
||||||
@ -220,7 +220,7 @@ esp_err_t lp_i2s_channel_disable(lp_i2s_chan_handle_t chan)
|
|||||||
esp_err_t lp_i2s_del_channel(lp_i2s_chan_handle_t chan)
|
esp_err_t lp_i2s_del_channel(lp_i2s_chan_handle_t chan)
|
||||||
{
|
{
|
||||||
ESP_RETURN_ON_FALSE(chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
ESP_RETURN_ON_FALSE(chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null pointer");
|
||||||
ESP_RETURN_ON_FALSE(chan->state < I2S_CHAN_STATE_RUNNING, ESP_ERR_INVALID_STATE, TAG, "the channel can't be deleted unless it is disabled");
|
ESP_RETURN_ON_FALSE(atomic_load(&(chan->state)) == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, TAG, "the channel can't be deleted unless it is disabled");
|
||||||
|
|
||||||
int id = chan->ctlr->id;
|
int id = chan->ctlr->id;
|
||||||
portENTER_CRITICAL(&g_i2s.spinlock);
|
portENTER_CRITICAL(&g_i2s.spinlock);
|
||||||
@ -245,14 +245,21 @@ esp_err_t lp_i2s_del_channel(lp_i2s_chan_handle_t chan)
|
|||||||
_Static_assert(sizeof(lp_i2s_evt_cbs_t) == sizeof(lp_i2s_evt_cbs_internal_t), "Invalid size of lp_i2s_evt_cbs_t structure");
|
_Static_assert(sizeof(lp_i2s_evt_cbs_t) == sizeof(lp_i2s_evt_cbs_internal_t), "Invalid size of lp_i2s_evt_cbs_t structure");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
esp_err_t lp_i2s_register_event_callbacks(lp_i2s_chan_handle_t handle, const lp_i2s_evt_cbs_t *cbs, void *user_data)
|
esp_err_t lp_i2s_register_event_callbacks(lp_i2s_chan_handle_t chan, const lp_i2s_evt_cbs_t *cbs, void *user_data)
|
||||||
{
|
{
|
||||||
ESP_RETURN_ON_FALSE(handle && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
ESP_RETURN_ON_FALSE(chan && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||||
ESP_RETURN_ON_FALSE(handle->state < I2S_CHAN_STATE_RUNNING, ESP_ERR_INVALID_STATE, TAG, "the channel is in enabled state already");
|
ESP_RETURN_ON_FALSE(atomic_load(&(chan->state)) == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, TAG, "the channel is in enabled state already");
|
||||||
|
|
||||||
handle->cbs.on_thresh_met = cbs->on_thresh_met;
|
if (cbs->on_thresh_met) {
|
||||||
handle->cbs.on_request_new_trans = cbs->on_request_new_trans;
|
ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_thresh_met), ESP_ERR_INVALID_ARG, TAG, "on_thresh_met callback not in IRAM");
|
||||||
handle->user_data = user_data;
|
}
|
||||||
|
if (cbs->on_request_new_trans) {
|
||||||
|
ESP_RETURN_ON_FALSE(esp_ptr_in_iram(cbs->on_request_new_trans), ESP_ERR_INVALID_ARG, TAG, "on_request_new_trans callback not in IRAM");
|
||||||
|
}
|
||||||
|
|
||||||
|
chan->cbs.on_thresh_met = cbs->on_thresh_met;
|
||||||
|
chan->cbs.on_request_new_trans = cbs->on_request_new_trans;
|
||||||
|
chan->user_data = user_data;
|
||||||
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
@ -279,7 +286,7 @@ static esp_err_t s_i2s_register_channel(lp_i2s_controller_t *ctlr, i2s_dir_t dir
|
|||||||
new_chan->mode = I2S_COMM_MODE_NONE;
|
new_chan->mode = I2S_COMM_MODE_NONE;
|
||||||
new_chan->role = I2S_ROLE_MASTER;
|
new_chan->role = I2S_ROLE_MASTER;
|
||||||
new_chan->dir = dir;
|
new_chan->dir = dir;
|
||||||
new_chan->state = I2S_CHAN_STATE_REGISTER;
|
atomic_init(&(new_chan->state), I2S_CHAN_STATE_READY);
|
||||||
new_chan->ctlr = ctlr;
|
new_chan->ctlr = ctlr;
|
||||||
|
|
||||||
if (dir == I2S_DIR_RX) {
|
if (dir == I2S_DIR_RX) {
|
||||||
|
@ -222,7 +222,7 @@ TEST_CASE("test LP I2S read for STD", "[lp_i2s]")
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool s_lp_i2s_on_thresh_met(lp_i2s_chan_handle_t handle, lp_i2s_evt_data_t *edata, void *user_data)
|
static bool IRAM_ATTR s_lp_i2s_on_thresh_met(lp_i2s_chan_handle_t handle, lp_i2s_evt_data_t *edata, void *user_data)
|
||||||
{
|
{
|
||||||
ESP_DRAM_LOGD(TAG, "edata->trans.received_size: %d", edata->trans.received_size);
|
ESP_DRAM_LOGD(TAG, "edata->trans.received_size: %d", edata->trans.received_size);
|
||||||
s_data_check(edata->trans.buffer, edata->trans.received_size);
|
s_data_check(edata->trans.buffer, edata->trans.received_size);
|
||||||
@ -230,7 +230,7 @@ static bool s_lp_i2s_on_thresh_met(lp_i2s_chan_handle_t handle, lp_i2s_evt_data_
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool s_lp_i2s_on_request_new_trans(lp_i2s_chan_handle_t handle, lp_i2s_evt_data_t *edata, void *user_data)
|
static bool IRAM_ATTR s_lp_i2s_on_request_new_trans(lp_i2s_chan_handle_t handle, lp_i2s_evt_data_t *edata, void *user_data)
|
||||||
{
|
{
|
||||||
lp_i2s_trans_t trans = *(lp_i2s_trans_t *)user_data;
|
lp_i2s_trans_t trans = *(lp_i2s_trans_t *)user_data;
|
||||||
edata->trans.buffer = trans.buffer;
|
edata->trans.buffer = trans.buffer;
|
||||||
|
@ -1669,8 +1669,27 @@ esp_err_t esp_sleep_enable_timer_wakeup(uint64_t time_in_us)
|
|||||||
#if SOC_LP_VAD_SUPPORTED
|
#if SOC_LP_VAD_SUPPORTED
|
||||||
esp_err_t esp_sleep_enable_vad_wakeup(void)
|
esp_err_t esp_sleep_enable_vad_wakeup(void)
|
||||||
{
|
{
|
||||||
|
esp_err_t ret = ESP_FAIL;
|
||||||
|
|
||||||
|
ret = esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "fail to keep rtc periph power on");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_ON);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "fail to keep xtal power on");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
ret = esp_sleep_sub_mode_config(ESP_SLEEP_LP_USE_XTAL_MODE, true);
|
||||||
|
if (ret != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "fail to set to ESP_SLEEP_LP_USE_XTAL_MODE mode");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
s_config.wakeup_triggers |= RTC_LP_VAD_TRIG_EN;
|
s_config.wakeup_triggers |= RTC_LP_VAD_TRIG_EN;
|
||||||
return esp_sleep_sub_mode_config(ESP_SLEEP_LP_USE_XTAL_MODE, true);
|
|
||||||
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
| Supported Targets | ESP32-P4 |
|
| Supported Targets | ESP32-P4 |
|
||||||
| ----------------- | -------- |
|
| ----------------- | -------- |
|
||||||
|
|
||||||
|
Slave side (LP I2S) should use default (UART0) console, as the USJ isn't working well under sleep modes.
|
@ -98,8 +98,6 @@ static void s_hp_i2s_config(void)
|
|||||||
static void s_lp_vad_config(void)
|
static void s_lp_vad_config(void)
|
||||||
{
|
{
|
||||||
ESP_ERROR_CHECK(esp_sleep_enable_vad_wakeup());
|
ESP_ERROR_CHECK(esp_sleep_enable_vad_wakeup());
|
||||||
ESP_ERROR_CHECK(esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON));
|
|
||||||
ESP_ERROR_CHECK(esp_sleep_pd_config(ESP_PD_DOMAIN_XTAL, ESP_PD_OPTION_ON));
|
|
||||||
|
|
||||||
lp_i2s_chan_handle_t rx_handle = NULL;
|
lp_i2s_chan_handle_t rx_handle = NULL;
|
||||||
lp_i2s_chan_config_t config = {
|
lp_i2s_chan_config_t config = {
|
||||||
|
@ -82,7 +82,6 @@ esp_err_t lp_core_lp_vad_init(lp_vad_t vad_id, const lp_core_lp_vad_cfg_t *init_
|
|||||||
* @brief Enable LP VAD
|
* @brief Enable LP VAD
|
||||||
*
|
*
|
||||||
* @param[in] vad_id VAD ID
|
* @param[in] vad_id VAD ID
|
||||||
* @param[in] init_config Initial configurations
|
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: On success
|
* - ESP_OK: On success
|
||||||
@ -95,7 +94,6 @@ esp_err_t lp_core_lp_vad_enable(lp_vad_t vad_id);
|
|||||||
* @brief Disable LP VAD
|
* @brief Disable LP VAD
|
||||||
*
|
*
|
||||||
* @param[in] vad_id VAD ID
|
* @param[in] vad_id VAD ID
|
||||||
* @param[in] init_config Initial configurations
|
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK: On success
|
* - ESP_OK: On success
|
||||||
|
@ -174,6 +174,10 @@ SPI_DOCS = ['api-reference/peripherals/spi_master.rst',
|
|||||||
|
|
||||||
I2S_DOCS = ['api-reference/peripherals/i2s.rst']
|
I2S_DOCS = ['api-reference/peripherals/i2s.rst']
|
||||||
|
|
||||||
|
VAD_DOCS = ['api-reference/peripherals/vad.rst']
|
||||||
|
|
||||||
|
LP_I2S_DOCS = ['api-reference/peripherals/lp_i2s.rst']
|
||||||
|
|
||||||
ISP_DOCS = ['api-reference/peripherals/isp.rst']
|
ISP_DOCS = ['api-reference/peripherals/isp.rst']
|
||||||
|
|
||||||
DSLP_STUB_DOCS = ['api-guides/deep-sleep-stub.rst']
|
DSLP_STUB_DOCS = ['api-guides/deep-sleep-stub.rst']
|
||||||
@ -286,6 +290,8 @@ conditional_include_dict = {'SOC_BT_SUPPORTED':BT_DOCS,
|
|||||||
'SOC_I2C_SUPPORTED':I2C_DOCS,
|
'SOC_I2C_SUPPORTED':I2C_DOCS,
|
||||||
'SOC_GPSPI_SUPPORTED':SPI_DOCS,
|
'SOC_GPSPI_SUPPORTED':SPI_DOCS,
|
||||||
'SOC_I2S_SUPPORTED':I2S_DOCS,
|
'SOC_I2S_SUPPORTED':I2S_DOCS,
|
||||||
|
'SOC_LP_I2S_SUPPORTED':LP_I2S_DOCS,
|
||||||
|
'SOC_LP_VAD_SUPPORTED':VAD_DOCS,
|
||||||
'SOC_ISP_SUPPORTED':ISP_DOCS,
|
'SOC_ISP_SUPPORTED':ISP_DOCS,
|
||||||
'ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB': DSLP_STUB_DOCS,
|
'ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB': DSLP_STUB_DOCS,
|
||||||
'SOC_ADC_SUPPORTED':ADC_DOCS,
|
'SOC_ADC_SUPPORTED':ADC_DOCS,
|
||||||
|
@ -11,6 +11,7 @@ INPUT += \
|
|||||||
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_utils.h \
|
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_utils.h \
|
||||||
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_interrupts.h \
|
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_interrupts.h \
|
||||||
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_spi.h \
|
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_spi.h \
|
||||||
|
$(PROJECT_PATH)/components/ulp/lp_core/shared/include/ulp_lp_core_lp_vad_shared.h \
|
||||||
$(PROJECT_PATH)/components/ulp/ulp_common/include/ulp_common.h \
|
$(PROJECT_PATH)/components/ulp/ulp_common/include/ulp_common.h \
|
||||||
$(PROJECT_PATH)/components/usb/include/usb/usb_helpers.h \
|
$(PROJECT_PATH)/components/usb/include/usb/usb_helpers.h \
|
||||||
$(PROJECT_PATH)/components/usb/include/usb/usb_host.h \
|
$(PROJECT_PATH)/components/usb/include/usb/usb_host.h \
|
||||||
@ -41,6 +42,10 @@ INPUT += \
|
|||||||
$(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_gamma.h \
|
$(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_gamma.h \
|
||||||
$(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_hist.h \
|
$(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_hist.h \
|
||||||
$(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_color.h \
|
$(PROJECT_PATH)/components/esp_driver_isp/include/driver/isp_color.h \
|
||||||
|
$(PROJECT_PATH)/components/esp_driver_i2s/include/driver/lp_i2s.h \
|
||||||
|
$(PROJECT_PATH)/components/esp_driver_i2s/include/driver/lp_i2s_std.h \
|
||||||
|
$(PROJECT_PATH)/components/esp_driver_i2s/include/driver/lp_i2s_pdm.h \
|
||||||
|
$(PROJECT_PATH)/components/esp_driver_i2s/include/driver/lp_i2s_vad.h \
|
||||||
$(PROJECT_PATH)/components/esp_driver_jpeg/include/driver/jpeg_decode.h \
|
$(PROJECT_PATH)/components/esp_driver_jpeg/include/driver/jpeg_decode.h \
|
||||||
$(PROJECT_PATH)/components/esp_driver_jpeg/include/driver/jpeg_encode.h \
|
$(PROJECT_PATH)/components/esp_driver_jpeg/include/driver/jpeg_encode.h \
|
||||||
$(PROJECT_PATH)/components/esp_driver_ppa/include/driver/ppa.h \
|
$(PROJECT_PATH)/components/esp_driver_ppa/include/driver/ppa.h \
|
||||||
|
@ -10,6 +10,12 @@ Introduction
|
|||||||
|
|
||||||
I2S (Inter-IC Sound) is a synchronous serial communication protocol usually used for transmitting audio data between two digital audio devices.
|
I2S (Inter-IC Sound) is a synchronous serial communication protocol usually used for transmitting audio data between two digital audio devices.
|
||||||
|
|
||||||
|
.. only:: SOC_LP_I2S_SUPPORTED
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
For LP I2S documentation, see :doc:`Low Power Inter-IC Sound <./lp_i2s>`.
|
||||||
|
|
||||||
{IDF_TARGET_NAME} contains {IDF_TARGET_I2S_NUM} I2S peripheral(s). These peripherals can be configured to input and output sample data via the I2S driver.
|
{IDF_TARGET_NAME} contains {IDF_TARGET_I2S_NUM} I2S peripheral(s). These peripherals can be configured to input and output sample data via the I2S driver.
|
||||||
|
|
||||||
An I2S bus that communicates in standard or TDM mode consists of the following lines:
|
An I2S bus that communicates in standard or TDM mode consists of the following lines:
|
||||||
|
@ -41,6 +41,8 @@ Peripherals API
|
|||||||
:SOC_GPSPI_SUPPORTED: spi_master
|
:SOC_GPSPI_SUPPORTED: spi_master
|
||||||
:SOC_GPSPI_SUPPORTED: spi_slave
|
:SOC_GPSPI_SUPPORTED: spi_slave
|
||||||
:SOC_SPI_SUPPORT_SLAVE_HD_VER2: spi_slave_hd
|
:SOC_SPI_SUPPORT_SLAVE_HD_VER2: spi_slave_hd
|
||||||
|
:SOC_LP_I2S_SUPPORTED: lp_i2s
|
||||||
|
:SOC_LP_VAD_SUPPORTED: vad
|
||||||
:SOC_TEMP_SENSOR_SUPPORTED: temp_sensor
|
:SOC_TEMP_SENSOR_SUPPORTED: temp_sensor
|
||||||
:SOC_TOUCH_SENSOR_SUPPORTED and not esp32p4: touch_pad
|
:SOC_TOUCH_SENSOR_SUPPORTED and not esp32p4: touch_pad
|
||||||
:esp32p4: cap_touch_sens
|
:esp32p4: cap_touch_sens
|
||||||
|
134
docs/en/api-reference/peripherals/lp_i2s.rst
Normal file
134
docs/en/api-reference/peripherals/lp_i2s.rst
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
Low Power Inter-IC Sound (LP I2S)
|
||||||
|
=================================
|
||||||
|
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
------------
|
||||||
|
|
||||||
|
LP I2S (Low Power Inter-IC Sound) is a synchronous protocol which can be used for audio data transmission. It also provides a data reception communication interface for Voice Activity Detection (VAD) and some digital audio applications in low power mode. For more details about VAD, see :doc:`Voice Activity Detection <./vad>`.
|
||||||
|
|
||||||
|
.. only:: SOC_I2S_SUPPORTED
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
For I2S documentation, see :doc:`Inter-IC Sound <./i2s>`.
|
||||||
|
|
||||||
|
The I2S standard bus defines three signals,
|
||||||
|
- BCK: bit clock
|
||||||
|
- WS: word select
|
||||||
|
- SD: serial data
|
||||||
|
|
||||||
|
A basic I2S data bus has one master and one slave. The roles remain unchanged throughout the communication.
|
||||||
|
|
||||||
|
.. only:: esp32p4
|
||||||
|
|
||||||
|
LP I2S on {IDF_TARGET_NAME} only supports working as an I2S Slave.
|
||||||
|
|
||||||
|
The LP I2S module on {IDF_TARGET_NAME} provides an independent RX unit, which supports receiving data when the chip is running under sleep modes. Compared to HP I2S, LP I2S does not support DMA access. Instead, it uses a piece of separate internal memory to store data.
|
||||||
|
|
||||||
|
|
||||||
|
I2S Communication Mode
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
Standard Mode
|
||||||
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
In standard mode, there are always two sound channels, i.e., the left and right channels, which are called "slots". These slots support 16-bit-width sample data. The communication format for the slots can be found in this :ref:`i2s-communication-mode` section.
|
||||||
|
|
||||||
|
PDM Mode (RX)
|
||||||
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
PDM (Pulse-density Modulation) mode for RX channel can receive PDM-format data. Only 16-bit-width sample data are supported. The communication format for the slots can be found in this :ref:`i2s-communication-mode` section.
|
||||||
|
|
||||||
|
|
||||||
|
Functional Overview
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Resource Allocation
|
||||||
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
To create a LP I2S channel handle, you should set up the LP I2S channel configuration structure :cpp:type:`lp_i2s_chan_config_t`, and call :cpp:func:`lp_i2s_new_channel` with the prepared configuration structure.
|
||||||
|
|
||||||
|
If the LP I2S channel is no longer used, you should recycle the allocated resource by calling :cpp:func:`lp_i2s_del_channel`.
|
||||||
|
|
||||||
|
.. code:: c
|
||||||
|
|
||||||
|
//initialization
|
||||||
|
lp_i2s_chan_handle_t rx_handle = NULL;
|
||||||
|
lp_i2s_chan_config_t config = {
|
||||||
|
.id = 0,
|
||||||
|
.role = I2S_ROLE_SLAVE,
|
||||||
|
.threshold = 512,
|
||||||
|
};
|
||||||
|
ESP_ERROR_CHECK(lp_i2s_new_channel(&config, NULL, &rx_handle));
|
||||||
|
|
||||||
|
//deinitialization
|
||||||
|
ESP_ERROR_CHECK(lp_i2s_del_channel(rx_chan));
|
||||||
|
|
||||||
|
|
||||||
|
Register Event Callbacks
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
By calling :cpp:func:`lp_i2s_register_event_callbacks`, you can hook your own function to the driver ISR. Supported event callbacks are listed in :cpp:type:`lp_i2s_evt_cbs_t`.
|
||||||
|
|
||||||
|
As the above callbacks are called in an ISR context, you should always ensure the callback function is suitable for an ISR context. Blocking logic should not appear in these callbacks. The callback function prototype is declared in :cpp:type:`lp_i2s_callback_t`.
|
||||||
|
|
||||||
|
You can also register your own context when calling :cpp:func:`lp_i2s_register_event_callbacks` by the parameter ``user_data``. This user data will be passed to the callback functions directly.
|
||||||
|
|
||||||
|
This function may fail due to reasons like :c:macro:`ESP_ERR_INVALID_ARG`, especially, this error may indicate that the callback functions are not in the internal RAM. Callbacks should be placed in IRAM since the default ISR handler is allocated with the `ESP_INTR_FLAG_IRAM` flag.
|
||||||
|
|
||||||
|
Please check the error log for more details. If it fails due to :c:macro:`ESP_ERR_INVALID_STATE`, it indicates that the LP I2S channel is enabled, and you cannot add a callback at this moment.
|
||||||
|
|
||||||
|
.. code:: c
|
||||||
|
|
||||||
|
lp_i2s_evt_cbs_t cbs = {
|
||||||
|
.on_thresh_met = s_lp_i2s_on_thresh_met,
|
||||||
|
.on_request_new_trans = s_lp_i2s_on_request_new_trans,
|
||||||
|
};
|
||||||
|
ESP_ERROR_CHECK(lp_i2s_register_event_callbacks(rx_chan, &cbs, &trans));
|
||||||
|
|
||||||
|
Enable and Disable LP I2S
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Before using LP I2S to receive data, you need to enable the LP I2S channel by calling :cpp:func:`lp_i2s_channel_enable`, this function switches the driver state from **init** to **enable**. Calling :cpp:func:`lp_i2s_channel_disable` does the opposite, that is, puts the driver back to the **init** state.
|
||||||
|
|
||||||
|
Communication Mode
|
||||||
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
.. list::
|
||||||
|
|
||||||
|
- Calling :cpp:func:`lp_i2s_channel_init_std_mode` can help you initialize the LP I2S channel to STD mode. Some initialization helpers are listed below:
|
||||||
|
- :c:macro:`LP_I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG`
|
||||||
|
- :c:macro:`LP_I2S_STD_MSB_SLOT_DEFAULT_CONFIG`
|
||||||
|
- :c:macro:`LP_I2S_STD_PCM_SHORT_SLOT_DEFAULT_CONFIG`
|
||||||
|
|
||||||
|
- Calling :cpp:func:`lp_i2s_channel_init_pdm_rx_mode` can help you initialize the LP I2S channel to PDM mode. :c:macro:`LP_I2S_PDM_RX_SLOT_DEFAULT_CONFIG` is an initialization helper.
|
||||||
|
|
||||||
|
Read Data via LP I2S
|
||||||
|
^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
After the LP I2S channel is enabled, :cpp:func:`lp_i2s_channel_read` and :cpp:func:`lp_i2s_channel_read_until_bytes` will be available.
|
||||||
|
|
||||||
|
.. list::
|
||||||
|
|
||||||
|
- For :cpp:func:`lp_i2s_channel_read`, if there are new data received by the LP I2S channel, this API will move the received data to the ``buffer`` you specified in :cpp:type:`lp_i2s_trans_t`. The API will try to receive the data as the ``buflen`` you specified. Check the ``received_size`` to know how many bytes you received, in case there are no enough received data. If no new received data, the API will block until ``timeout_ms``.
|
||||||
|
|
||||||
|
- For :cpp:func:`lp_i2s_channel_read_until_bytes`, this API is a wrapper of the :cpp:func:`lp_i2s_channel_read`. The difference is, the :cpp:func:`lp_i2s_channel_read_until_bytes` will block until ``buflen`` bytes are received.
|
||||||
|
|
||||||
|
- For both of the two APIs, if :cpp:member:`lp_i2s_evt_cbs_t::on_request_new_trans` is set, the driver will each time requesting a new LP I2S transaction descriptor (:cpp:type:`lp_i2s_trans_t`) from the callback event data structure (:cpp:type:`lp_i2s_evt_data_t`). This also means, the ``buffer`` in the (:cpp:type:`lp_i2s_trans_t`) needs to be ready for receiving data.
|
||||||
|
|
||||||
|
|
||||||
|
Thread Safety
|
||||||
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
All the APIs are guaranteed to be thread safe by the driver, which means, you can call them from different RTOS tasks without protection by extra locks.
|
||||||
|
|
||||||
|
All the APIs are not allowed to be used in ISR context.
|
||||||
|
|
||||||
|
|
||||||
|
API Reference
|
||||||
|
-------------
|
||||||
|
|
||||||
|
.. include-build-file:: inc/lp_i2s.inc
|
||||||
|
.. include-build-file:: inc/lp_i2s_std.inc
|
||||||
|
.. include-build-file:: inc/lp_i2s_pdm.inc
|
181
docs/en/api-reference/peripherals/vad.rst
Normal file
181
docs/en/api-reference/peripherals/vad.rst
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
Voice Activity Detection (VAD)
|
||||||
|
==============================
|
||||||
|
|
||||||
|
:link_to_translation:`zh_CN:[中文]`
|
||||||
|
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
------------
|
||||||
|
|
||||||
|
Voice Activity Detection (VAD) module facilitates the hardware implementation of the first-stage algorithm for voice wake-up and other multimedia functions.
|
||||||
|
|
||||||
|
Additionally, it provides hardware support for low-power voice wake-up solutions.
|
||||||
|
|
||||||
|
.. only:: SOC_LP_I2S_SUPPORTED
|
||||||
|
|
||||||
|
For LP I2S documentation, see :doc:`Low Power Inter-IC Sound <./lp_i2s>`.
|
||||||
|
|
||||||
|
|
||||||
|
Hardware State Machine
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
LP VAD driver provides a structure :cpp:type:`lp_vad_config_t` to configure the LP VAD module:
|
||||||
|
|
||||||
|
- :cpp:member:`lp_vad_config_t::init_frame_num`, number of init frames that are used for VAD to denoise, this helps the VAD to decrease the accidental trigger ratio. Note too big values may lead to voice activity miss.
|
||||||
|
- :cpp:member:`lp_vad_config_t::min_energy_thresh`, minimum energy threshold, voice activities with energy higher than this value will be detected.
|
||||||
|
- :cpp:member:`lp_vad_config_t::skip_band_energy_thresh`, skip band energy threshold or not, the passband energy check determines whether the proportion of passband energy within the total frequency domain meets the required threshold. Note in different environments, enabling the passband energy check may reduce false trigger rates but could also increase the rate of missed detections.
|
||||||
|
- :cpp:member:`lp_vad_config_t::speak_activity_thresh`, when in speak-activity-listening-state, if number of the detected speak activity is higher than this value, VAD runs into speak-activity-detected-state.
|
||||||
|
- :cpp:member:`lp_vad_config_t::non_speak_activity_thresh`, when in speak-activity-detected-state, if the number of the detected speak activity is higher than this value, but lower than :cpp:member:`lp_vad_config_t::max_speak_activity_thresh`,
|
||||||
|
* if the number of the detected non-speak activity is higher than this value, VAD runs into speak-activity-listening-state
|
||||||
|
* if the number of the detected non-speak activity is lower than this value, VAD keeps in speak-activity-detected-state
|
||||||
|
- :cpp:member:`lp_vad_config_t::min_speak_activity_thresh`, when in speak-activity-detected-state, if the number of the detected speak activity is higher than this value, but lower than :cpp:member:`lp_vad_config_t::max_speak_activity_thresh`, then the VAD state machine will depends on the value of :cpp:member:`lp_vad_config_t::non_speak_activity_thresh`
|
||||||
|
- :cpp:member:`lp_vad_config_t::max_speak_activity_thresh`, when in speak-activity-detected-state, if the number of the detected speak activity is higher than this value, VAD runs into speak-activity-listening-state
|
||||||
|
|
||||||
|
Above configurations can change the VAD state machine shown below:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
┌──────────────────────────────────┐
|
||||||
|
│ │
|
||||||
|
┌─────────────┤ speak-activity-listening-state │ ◄───────────────┐
|
||||||
|
│ │ │ │
|
||||||
|
│ └──────────────────────────────────┘ │
|
||||||
|
│ ▲ │
|
||||||
|
│ │ │
|
||||||
|
│ │ │
|
||||||
|
│ │ │
|
||||||
|
│ │ │
|
||||||
|
detected speak activity │ │ detected speak activity │ detected speak activity
|
||||||
|
>= │ │ >= │ >=
|
||||||
|
'speak_activity_thresh' │ │ 'min_speak_activity_thresh' │ 'max_speak_activity_thresh'
|
||||||
|
│ │ │
|
||||||
|
│ │ && │
|
||||||
|
│ │ │
|
||||||
|
│ │ detected non-speak activity │
|
||||||
|
│ │ < │
|
||||||
|
│ │ 'non_speak_activity_thresh' │
|
||||||
|
│ │ │
|
||||||
|
│ │ │
|
||||||
|
│ │ │
|
||||||
|
│ │ │
|
||||||
|
│ │ │
|
||||||
|
│ ┌───────────┴─────────────────────┐ │
|
||||||
|
│ │ │ │
|
||||||
|
└───────────► │ speak-activity-detected-state ├─────────────────┘
|
||||||
|
│ │
|
||||||
|
└─┬───────────────────────────────┘
|
||||||
|
│
|
||||||
|
│ ▲
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │ detected speak activity
|
||||||
|
│ │ >=
|
||||||
|
│ │ 'min_speak_activity_thresh'
|
||||||
|
│ │
|
||||||
|
│ │ &&
|
||||||
|
│ │
|
||||||
|
│ │ detected non-speak activity
|
||||||
|
│ │ <
|
||||||
|
└─────────────────────┘ 'non_speak_activity_thresh'
|
||||||
|
|
||||||
|
|
||||||
|
HP Driver Functional Overview
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
The VAD HP driver is used for configure the LP VAD to be working under the control of the HP core. The HP core can also be woken up by the VAD when voice activity is detected.
|
||||||
|
|
||||||
|
Resource Allocation
|
||||||
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
.. only:: SOC_LP_I2S_SUPPORT_VAD
|
||||||
|
|
||||||
|
:cpp:type:`lp_vad_init_config_t` is the configuration structure that is needed to create a LP I2S VAD unit handle. To create a LP I2S VAD unit handle, you will need to first create a LP I2S channel handle. see :doc:`Low Power Inter-IC Sound <./lp_i2s>`.
|
||||||
|
|
||||||
|
You can call :cpp:func:`lp_i2s_vad_new_unit` to create the handle. If the VAD unit is no longer used, you should recycle the allocated resource by calling :cpp:func:`lp_i2s_vad_del_unit`.
|
||||||
|
|
||||||
|
.. code:: c
|
||||||
|
|
||||||
|
vad_unit_handle_t vad_handle = NULL;
|
||||||
|
lp_vad_init_config_t init_config = {
|
||||||
|
.lp_i2s_chan = rx_handle,
|
||||||
|
.vad_config = {
|
||||||
|
.init_frame_num = 100,
|
||||||
|
.min_energy_thresh = 100,
|
||||||
|
.speak_activity_thresh = 10,
|
||||||
|
.non_speak_activity_thresh = 30,
|
||||||
|
.min_speak_activity_thresh = 3,
|
||||||
|
.max_speak_activity_thresh = 100,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
ESP_ERROR_CHECK(lp_i2s_vad_new_unit(vad_id, init_config, &vad_handle));
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(lp_i2s_vad_del_unit(vad_handle));
|
||||||
|
|
||||||
|
Enable and Disable the VAD
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
.. only:: SOC_LP_I2S_SUPPORT_VAD
|
||||||
|
|
||||||
|
Before using a VAD unit to detect voice activity, you need to enable the VAD unit by calling :cpp:func:`lp_i2s_vad_enable`, this function switches the driver state from **init** to **enable**, and also enables the VAD hardware. Calling :cpp:func:`lp_i2s_vad_disable` does the opposite, that is, put the driver back to the **init** state, the hardware will stop as well.
|
||||||
|
|
||||||
|
HP Core Wake-up
|
||||||
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
.. only:: SOC_LP_I2S_SUPPORT_VAD
|
||||||
|
|
||||||
|
:cpp:func:`esp_sleep_enable_vad_wakeup` can help you to set the VAD to be working as the HP core wake-up source. To make VAD work during sleep, you should let the system maintain the RTC domain and XTAL power. See code example below:
|
||||||
|
|
||||||
|
.. code:: c
|
||||||
|
|
||||||
|
ESP_ERROR_CHECK(esp_sleep_enable_vad_wakeup());
|
||||||
|
|
||||||
|
|
||||||
|
LP Driver Functional Overview
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
The VAD LP driver is mainly for LP core wake-up. The VAD can be configured under HP core control, then it can wakeup the LP core when voice activities are detected.
|
||||||
|
|
||||||
|
Resource Allocation
|
||||||
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
.. only:: SOC_LP_I2S_SUPPORT_VAD
|
||||||
|
|
||||||
|
:cpp:type:`lp_core_lp_vad_cfg_t` and :cpp:func:`lp_core_lp_vad_init` are used to initialize the VAD LP driver.
|
||||||
|
|
||||||
|
:cpp:func:`lp_core_lp_vad_deinit` is used to recycle the allocated resources.
|
||||||
|
|
||||||
|
Enable and Disable the VAD
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
.. only:: SOC_LP_I2S_SUPPORT_VAD
|
||||||
|
|
||||||
|
:cpp:func:`lp_core_lp_vad_enable` and :cpp:func:`lp_core_lp_vad_disable` are used for enabling / disabling the hardware.
|
||||||
|
|
||||||
|
LP Core Wake-up
|
||||||
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
.. only:: SOC_LP_I2S_SUPPORT_VAD
|
||||||
|
|
||||||
|
Set :c:macro:`ULP_LP_CORE_WAKEUP_SOURCE_LP_VAD` in :cpp:type:`ulp_lp_core_cfg_t` to enable the VAD to be working as the LP core wake-up source.
|
||||||
|
|
||||||
|
.. code:: c
|
||||||
|
|
||||||
|
static void load_and_start_lp_core_firmware(ulp_lp_core_cfg_t* cfg, const uint8_t* firmware_start, const uint8_t* firmware_end)
|
||||||
|
{
|
||||||
|
TEST_ASSERT(ulp_lp_core_load_binary(firmware_start,
|
||||||
|
(firmware_end - firmware_start)) == ESP_OK);
|
||||||
|
|
||||||
|
TEST_ASSERT(ulp_lp_core_run(cfg) == ESP_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
ulp_lp_core_cfg_t cfg = {
|
||||||
|
.wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_LP_VAD,
|
||||||
|
};
|
||||||
|
load_and_start_lp_core_firmware(&cfg, lp_core_main_vad_bin_start, lp_core_main_vad_bin_end);
|
||||||
|
|
||||||
|
|
||||||
|
API Reference
|
||||||
|
-------------
|
||||||
|
|
||||||
|
.. include-build-file:: inc/lp_i2s_vad.inc
|
||||||
|
.. include-build-file:: inc/ulp_lp_core_lp_vad_shared.inc
|
@ -40,6 +40,8 @@
|
|||||||
:SOC_GPSPI_SUPPORTED: spi_master
|
:SOC_GPSPI_SUPPORTED: spi_master
|
||||||
:SOC_GPSPI_SUPPORTED: spi_slave
|
:SOC_GPSPI_SUPPORTED: spi_slave
|
||||||
:SOC_SPI_SUPPORT_SLAVE_HD_VER2: spi_slave_hd
|
:SOC_SPI_SUPPORT_SLAVE_HD_VER2: spi_slave_hd
|
||||||
|
:SOC_LP_I2S_SUPPORTED: lp_i2s
|
||||||
|
:SOC_LP_VAD_SUPPORTED: vad
|
||||||
:SOC_JPEG_CODEC_SUPPORTED: jpeg
|
:SOC_JPEG_CODEC_SUPPORTED: jpeg
|
||||||
:SOC_TEMP_SENSOR_SUPPORTED: temp_sensor
|
:SOC_TEMP_SENSOR_SUPPORTED: temp_sensor
|
||||||
:SOC_TOUCH_SENSOR_SUPPORTED and not esp32p4: touch_pad
|
:SOC_TOUCH_SENSOR_SUPPORTED and not esp32p4: touch_pad
|
||||||
|
1
docs/zh_CN/api-reference/peripherals/lp_i2s.rst
Normal file
1
docs/zh_CN/api-reference/peripherals/lp_i2s.rst
Normal file
@ -0,0 +1 @@
|
|||||||
|
.. include:: ../../../en/api-reference/peripherals/lp_i2s.rst
|
1
docs/zh_CN/api-reference/peripherals/vad.rst
Normal file
1
docs/zh_CN/api-reference/peripherals/vad.rst
Normal file
@ -0,0 +1 @@
|
|||||||
|
.. include:: ../../../en/api-reference/peripherals/vad.rst
|
Loading…
x
Reference in New Issue
Block a user