feat(vad): lp vad driver and wakeup feature

This commit is contained in:
Armando 2024-09-26 16:18:30 +08:00 committed by Armando (Dou Yiwen)
parent 39430c1404
commit 1792aba1dc
16 changed files with 635 additions and 7 deletions

View File

@ -30,6 +30,10 @@ if(CONFIG_SOC_LP_I2S_SUPPORTED)
list(APPEND srcs "lp_i2s.c" "lp_i2s_std.c" "lp_i2s_pdm.c")
endif()
if(CONFIG_SOC_LP_I2S_SUPPORT_VAD)
list(APPEND srcs "lp_i2s_vad.c")
endif()
idf_component_register(SRCS ${srcs}
INCLUDE_DIRS ${include}
PRIV_REQUIRES esp_driver_gpio esp_pm esp_mm

View File

@ -0,0 +1,153 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "soc/soc_caps.h"
#include "esp_err.h"
#include "driver/i2s_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief State Machine
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'
*/
/**
* @brief LP VAD peripheral
*/
typedef uint32_t lp_vad_t;
/**
* @brief Type of VAD unit handle
*/
typedef struct vad_unit_ctx_t *vad_unit_handle_t;
/**
* @brief LP VAD configurations
*/
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.
Note too big values may lead to voice activity miss */
int min_energy_thresh; ///< Min energy threshold.
bool skip_band_energy_thresh; ///< Skip band energy threshold or not
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 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 `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 */
int 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 `max_speak_activity_thresh`,
then the VAD state machine will depends on the value of `non_speak_activity_thresh` */
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;
typedef struct {
lp_i2s_chan_handle_t lp_i2s_chan; ///< LP I2S channel handle
lp_vad_config_t vad_config; ///< LP VAD config
} lp_vad_init_config_t;
/**
* @brief New LP VAD unit
* @param[in] vad_id VAD id
* @param[in] init_config Initial configurations
* @param[out] ret_unit Unit handle
*
* @return
* - ESP_OK: On success
* - ESP_ERR_INVALID_ARG: Invalid argument
* - ESP_ERR_INVALID_STATE: Driver state is invalid, you shouldn't call this API at this moment
*/
esp_err_t lp_i2s_vad_new_unit(lp_vad_t vad_id, const lp_vad_init_config_t *init_config, vad_unit_handle_t *ret_unit);
/**
* @brief Enable LP VAD
*
* @param[in] unit VAD handle
* @param[in] init_config Initial configurations
*
* @return
* - ESP_OK: On success
* - ESP_ERR_INVALID_ARG: Invalid argument
* - ESP_ERR_INVALID_STATE: Driver state is invalid, you shouldn't call this API at this moment
*/
esp_err_t lp_i2s_vad_enable(vad_unit_handle_t unit);
/**
* @brief Disable LP VAD
*
* @param[in] unit VAD handle
* @param[in] init_config Initial configurations
*
* @return
* - ESP_OK: On success
* - ESP_ERR_INVALID_ARG: Invalid argument
* - ESP_ERR_INVALID_STATE: Driver state is invalid, you shouldn't call this API at this moment
*/
esp_err_t lp_i2s_vad_disable(vad_unit_handle_t unit);
/**
* @brief Delete LP VAD unit
* @param[in] unit VAD handle
*
* @return
* - ESP_OK: On success
* - ESP_ERR_INVALID_ARG: Invalid argument
* - ESP_ERR_INVALID_STATE: Driver state is invalid, you shouldn't call this API at this moment
*/
esp_err_t lp_i2s_vad_del_unit(vad_unit_handle_t unit);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "hal/lp_i2s_hal.h"
#include "driver/i2s_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Get LP I2S soc handle
*
* @param[in] chan LP I2S channel handle
*
* @return LP I2S soc handle
*/
lp_i2s_soc_handle_t lp_i2s_get_soc_handle(lp_i2s_chan_handle_t chan);
#ifdef __cplusplus
}
#endif

View File

@ -25,6 +25,7 @@
#include "driver/lp_i2s.h"
#include "esp_private/periph_ctrl.h"
#include "esp_private/i2s_platform.h"
#include "esp_private/lp_i2s_private.h"
#include "i2s_private.h"
#include "soc/i2s_periph.h"
@ -329,3 +330,15 @@ static void IRAM_ATTR s_i2s_default_isr(void *arg)
portYIELD_FROM_ISR();
}
}
/*---------------------------------------------------------------
HELPERS
---------------------------------------------------------------*/
lp_i2s_soc_handle_t lp_i2s_get_soc_handle(lp_i2s_chan_handle_t chan)
{
if (!chan) {
return NULL;
}
return chan->ctlr->hal.dev;
}

View File

@ -0,0 +1,112 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <inttypes.h>
#include "soc/soc_caps.h"
#include "stdatomic.h"
#if SOC_LP_VAD_SUPPORTED
#include "esp_check.h"
#include "esp_err.h"
#include "driver/lp_i2s_vad.h"
#include "esp_heap_caps.h"
#include "hal/lp_i2s_ll.h"
#include "hal/lp_i2s_hal.h"
#include "esp_private/lp_i2s_private.h"
#define LP_VAD_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)
static const char *LP_VAD_TAG = "LP_VAD";
typedef enum {
VAD_FSM_INIT,
VAD_FSM_ENABLE,
} vad_fsm_t;
typedef struct vad_unit_ctx_t {
lp_i2s_soc_handle_t hw;
lp_vad_t vad_id;
vad_fsm_t fsm;
} vad_unit_ctx_t;
static atomic_bool s_vad_id_claimed[SOC_ADC_PERIPH_NUM] = {ATOMIC_VAR_INIT(false)};
static bool s_vad_claim(lp_vad_t vad_id)
{
bool false_var = false;
return atomic_compare_exchange_strong(&s_vad_id_claimed[vad_id], &false_var, true);
}
static bool s_vad_free(lp_vad_t vad_id)
{
bool true_var = true;
return atomic_compare_exchange_strong(&s_vad_id_claimed[vad_id], &true_var, false);
}
esp_err_t lp_i2s_vad_new_unit(lp_vad_t vad_id, const lp_vad_init_config_t *init_config, vad_unit_handle_t *ret_unit)
{
esp_err_t ret = ESP_OK;
ESP_RETURN_ON_FALSE(init_config, ESP_ERR_INVALID_ARG, LP_VAD_TAG, "invalid arg");
ESP_RETURN_ON_FALSE(init_config->lp_i2s_chan, ESP_ERR_INVALID_ARG, LP_VAD_TAG, "LP I2S not initialised");
ESP_RETURN_ON_FALSE(init_config->vad_config.init_frame_num >= LP_VAD_LL_INIT_FRAME_MIN && init_config->vad_config.init_frame_num <= LP_VAD_LL_INIT_FRAME_MAX, ESP_ERR_INVALID_ARG, LP_VAD_TAG, "invalid init frame num");
bool success_claim = s_vad_claim(vad_id);
ESP_RETURN_ON_FALSE(success_claim, ESP_ERR_NOT_FOUND, LP_VAD_TAG, "vad%"PRId32" is already in use", vad_id);
vad_unit_ctx_t *unit = heap_caps_calloc(1, sizeof(vad_unit_ctx_t), LP_VAD_MEM_ALLOC_CAPS);
ESP_GOTO_ON_FALSE(unit, ESP_ERR_NO_MEM, err, LP_VAD_TAG, "no mem for unit");
unit->hw = lp_i2s_get_soc_handle(init_config->lp_i2s_chan);
ESP_LOGD(LP_VAD_TAG, "unit->hw: %p", unit->hw);
lp_vad_ll_set_init_frame_num(unit->hw, init_config->vad_config.init_frame_num);
lp_vad_ll_set_init_min_energy(unit->hw, init_config->vad_config.min_energy_thresh);
lp_vad_ll_set_speak_activity_thresh(unit->hw, init_config->vad_config.speak_activity_thresh);
lp_vad_ll_set_non_speak_activity_thresh(unit->hw, init_config->vad_config.non_speak_activity_thresh);
lp_vad_ll_set_min_speak_activity_thresh(unit->hw, init_config->vad_config.min_speak_activity_thresh);
lp_vad_ll_set_max_speak_activity_thresh(unit->hw, init_config->vad_config.max_speak_activity_thresh);
lp_vad_ll_skip_band_energy(unit->hw, init_config->vad_config.skip_band_energy_thresh);
unit->fsm = VAD_FSM_INIT;
*ret_unit = unit;
return ESP_OK;
err:
bool success_free = s_vad_free(vad_id);
assert(success_free);
return ret;
}
esp_err_t lp_i2s_vad_enable(vad_unit_handle_t unit)
{
ESP_RETURN_ON_FALSE(unit, ESP_ERR_INVALID_ARG, LP_VAD_TAG, "invalid arg");
ESP_RETURN_ON_FALSE(unit->fsm == VAD_FSM_INIT, ESP_ERR_INVALID_STATE, LP_VAD_TAG, "The driver is enabled already");
lp_vad_ll_enable(unit->hw, true);
unit->fsm = VAD_FSM_ENABLE;
return ESP_OK;
}
esp_err_t lp_i2s_vad_disable(vad_unit_handle_t unit)
{
ESP_RETURN_ON_FALSE(unit, ESP_ERR_INVALID_ARG, LP_VAD_TAG, "invalid arg");
ESP_RETURN_ON_FALSE(unit->fsm == VAD_FSM_ENABLE, ESP_ERR_INVALID_STATE, LP_VAD_TAG, "The driver is not enabled yet");
lp_vad_ll_enable(unit->hw, false);
unit->fsm = VAD_FSM_INIT;
return ESP_OK;
}
esp_err_t lp_i2s_vad_del_unit(vad_unit_handle_t unit)
{
ESP_RETURN_ON_FALSE(unit, ESP_ERR_INVALID_ARG, LP_VAD_TAG, "invalid arg");
ESP_RETURN_ON_FALSE(unit->fsm == VAD_FSM_INIT, ESP_ERR_INVALID_STATE, LP_VAD_TAG, "The driver is still in enabled state");
bool success_free = s_vad_free(unit->vad_id);
ESP_RETURN_ON_FALSE(success_free, ESP_ERR_NOT_FOUND, LP_VAD_TAG, "vad%"PRId32" isn't in use", unit->vad_id);
free(unit);
return ESP_OK;
}
#endif /* SOC_LP_VAD_SUPPORTED */

View File

@ -28,7 +28,7 @@ extern "C" {
#define LP_CORE_LL_WAKEUP_SOURCE_LP_BOD BIT(14)
#define LP_CORE_LL_WAKEUP_SOURCE_ETM BIT(17)
#define LP_CORE_LL_WAKEUP_SOURCE_LP_TIMER_1 BIT(18)
#define LP_CORE_LL_WAKEUP_SOURCE_LP_I2S BIT(19)
#define LP_CORE_LL_WAKEUP_SOURCE_LP_VAD BIT(19)
#define LP_CORE_LL_WAKEUP_SOURCE_HP_CPU BIT(22)
/* Use lp timer 1 as the normal wakeup timer, timer 0 is used by deep sleep */

View File

@ -32,6 +32,8 @@ extern "C" {
#define LP_I2S_LL_EVENT_RX_DONE_INT (1<<0)
#define LP_I2S_LL_EVENT_RX_HUNG_INT_INT (1<<1)
#define LP_I2S_LL_EVENT_RX_FIFOMEM_UDF_INT (1<<2)
#define LP_I2S_LL_EVENT_VAD_DONE_INT (1<<3)
#define LP_I2S_LL_EVENT_VAD_RESET_DONE_INT (1<<4)
#define LP_I2S_LL_EVENT_RX_MEM_THRESHOLD_INT (1<<5)
#define LP_I2S_LL_TDM_CH_MASK (0x03UL)
@ -709,9 +711,9 @@ static inline uint32_t lp_i2s_ll_get_intr_status_reg_addr(lp_i2s_dev_t *hw)
/**
* @brief Enable LP I2S RX channel interrupt
*
* @param hw LP I2S hardware instance
* @param mask mask
* @param enable enable or disable
* @param[in] hw LP I2S hardware instance
* @param[in] mask mask
* @param[in] enable enable or disable
*/
static inline void lp_i2s_ll_rx_enable_interrupt(lp_i2s_dev_t *hw, uint32_t mask, bool enable)
{
@ -727,8 +729,8 @@ static inline void lp_i2s_ll_rx_enable_interrupt(lp_i2s_dev_t *hw, uint32_t mask
/**
* @brief Clear LP I2S RX channel interrupt
*
* @param hw LP I2S hardware instance
* @param mask mask
* @param[in] hw LP I2S hardware instance
* @param[in] mask mask
*/
__attribute__((always_inline))
static inline void lp_i2s_ll_rx_clear_interrupt_status(lp_i2s_dev_t *hw, uint32_t mask)
@ -736,6 +738,100 @@ static inline void lp_i2s_ll_rx_clear_interrupt_status(lp_i2s_dev_t *hw, uint32_
hw->int_clr.val = mask;
}
/*---------------------------------------------------------------
VAD
---------------------------------------------------------------*/
#define LP_VAD_LL_INIT_FRAME_MIN 100
#define LP_VAD_LL_INIT_FRAME_MAX 200
/**
* @brief Set VAD init frame number
*
* @param[in] hw LP I2S hardware instance
* @param[in] frame_num Frame number
*/
static inline void lp_vad_ll_set_init_frame_num(lp_i2s_dev_t *hw, int frame_num)
{
hw->vad_param0.param_init_frame_num = frame_num;
}
/**
* @brief Set VAD min energy
*
* @param[in] hw LP I2S hardware instance
* @param[in] min_energy Min energy
*/
static inline void lp_vad_ll_set_init_min_energy(lp_i2s_dev_t *hw, int min_energy)
{
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->vad_param0, param_min_energy, min_energy);
}
/**
* @brief Set VAD speak activity thresh
*
* @param[in] hw LP I2S hardware instance
* @param[in] thresh Threshold
*/
static inline void lp_vad_ll_set_speak_activity_thresh(lp_i2s_dev_t *hw, int thresh)
{
hw->vad_param1.param_hangover_speech = thresh;
}
/**
* @brief Set VAD non speak activity thresh
*
* @param[in] hw LP I2S hardware instance
* @param[in] thresh Threshold
*/
static inline void lp_vad_ll_set_non_speak_activity_thresh(lp_i2s_dev_t *hw, int thresh)
{
hw->vad_param1.param_hangover_silent = thresh;
}
/**
* @brief Set VAD min speak activity thresh
*
* @param[in] hw LP I2S hardware instance
* @param[in] thresh Threshold
*/
static inline void lp_vad_ll_set_min_speak_activity_thresh(lp_i2s_dev_t *hw, int thresh)
{
hw->vad_param1.param_min_speech_count = thresh;
}
/**
* @brief Set VAD max speak activity thresh
*
* @param[in] hw LP I2S hardware instance
* @param[in] thresh Threshold
*/
static inline void lp_vad_ll_set_max_speak_activity_thresh(lp_i2s_dev_t *hw, int thresh)
{
hw->vad_param1.param_max_speech_count = thresh;
}
/**
* @brief Skip band energy check
*
* @param[in] hw LP I2S hardware instance
* @param[in] skip 1: skip; 0: not skip
*/
static inline void lp_vad_ll_skip_band_energy(lp_i2s_dev_t *hw, bool skip)
{
hw->vad_param1.param_skip_band_energy = skip;
}
/**
* @brief Enable LP I2S 24 fill
*
* @param[in] hw LP I2S hardware instance
* @param[in] en enable or disable
*/
static inline void lp_vad_ll_enable(lp_i2s_dev_t *hw, bool en)
{
hw->vad_conf.vad_en = en;
}
#ifdef __cplusplus
}
#endif

View File

@ -263,6 +263,10 @@ config SOC_LP_ADC_SUPPORTED
bool
default y
config SOC_LP_VAD_SUPPORTED
bool
default y
config SOC_SPIRAM_SUPPORTED
bool
default y
@ -1763,6 +1767,10 @@ config SOC_UART_SUPPORT_FSM_TX_WAIT_SEND
bool
default y
config SOC_LP_I2S_SUPPORT_VAD
bool
default y
config SOC_COEX_HW_PTI
bool
default y
@ -1962,3 +1970,7 @@ config SOC_LP_CORE_SUPPORT_ETM
config SOC_LP_CORE_SUPPORT_LP_ADC
bool
default y
config SOC_LP_CORE_SUPPORT_LP_VAD
bool
default y

View File

@ -83,6 +83,7 @@
#define SOC_LP_I2S_SUPPORTED 1
#define SOC_LP_SPI_SUPPORTED 1
#define SOC_LP_ADC_SUPPORTED 1
#define SOC_LP_VAD_SUPPORTED 1
#define SOC_SPIRAM_SUPPORTED 1
#define SOC_PSRAM_DMA_CAPABLE 1
#define SOC_SDMMC_HOST_SUPPORTED 1
@ -662,6 +663,9 @@
// UART has an extra TX_WAIT_SEND state when the FIFO is not empty and XOFF is enabled
#define SOC_UART_SUPPORT_FSM_TX_WAIT_SEND (1)
/*-------------------------- LP_VAD CAPS -------------------------------------*/
#define SOC_LP_I2S_SUPPORT_VAD (1)
// TODO: IDF-5679 (Copy from esp32c3, need check)
/*-------------------------- COEXISTENCE HARDWARE PTI CAPS -------------------------------*/
#define SOC_COEX_HW_PTI (1)
@ -745,3 +749,4 @@
/*------------------------------------- ULP CAPS -------------------------------------*/
#define SOC_LP_CORE_SUPPORT_ETM (1) /*!< LP Core supports ETM */
#define SOC_LP_CORE_SUPPORT_LP_ADC (1) /*!< LP ADC can be accessed from the LP-Core */
#define SOC_LP_CORE_SUPPORT_LP_VAD (1) /*!< LP VAD can be accessed from the LP-Core */

View File

@ -78,6 +78,10 @@ if(CONFIG_ULP_COPROC_TYPE_LP_CORE)
if(CONFIG_SOC_LP_ADC_SUPPORTED)
list(APPEND srcs "lp_core/shared/ulp_lp_core_lp_adc_shared.c")
endif()
if(CONFIG_SOC_LP_VAD_SUPPORTED)
list(APPEND srcs "lp_core/shared/ulp_lp_core_lp_vad_shared.c")
endif()
endif()
idf_component_register(SRCS ${srcs}

View File

@ -126,6 +126,7 @@ function(ulp_apply_default_sources ulp_app_name)
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_spi.c"
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_ubsan.c"
"${IDF_PATH}/components/ulp/lp_core/shared/ulp_lp_core_lp_adc_shared.c"
"${IDF_PATH}/components/ulp/lp_core/shared/ulp_lp_core_lp_vad_shared.c"
"${IDF_PATH}/components/ulp/lp_core/shared/ulp_lp_core_critical_section_shared.c")
set(target_folder ${IDF_TARGET})

View File

@ -22,6 +22,7 @@ extern "C" {
#define ULP_LP_CORE_WAKEUP_SOURCE_LP_IO BIT(2) // Enable wake-up by LP IO interrupt
#define ULP_LP_CORE_WAKEUP_SOURCE_ETM BIT(3) // Enable wake-up by ETM event
#define ULP_LP_CORE_WAKEUP_SOURCE_LP_TIMER BIT(4) // Enable wake-up by LP timer
#define ULP_LP_CORE_WAKEUP_SOURCE_LP_VAD BIT(5) // Enable wake-up by LP VAD
/**
* @brief ULP LP core init parameters

View File

@ -35,7 +35,7 @@ extern uint32_t _rtc_ulp_memory_start;
const static char* TAG = "ulp-lp-core";
#define WAKEUP_SOURCE_MAX_NUMBER 5
#define WAKEUP_SOURCE_MAX_NUMBER 6
#define RESET_HANDLER_ADDR (intptr_t)(&_rtc_ulp_memory_start + 0x80 / 4) // Placed after the 0x80 byte long vector table
@ -46,6 +46,9 @@ static uint32_t wakeup_src_sw_to_hw_flag_lookup[WAKEUP_SOURCE_MAX_NUMBER] = {
LP_CORE_LL_WAKEUP_SOURCE_LP_IO,
LP_CORE_LL_WAKEUP_SOURCE_ETM,
LP_CORE_LL_WAKEUP_SOURCE_LP_TIMER,
#if SOC_LP_VAD_SUPPORTED
LP_CORE_LL_WAKEUP_SOURCE_LP_VAD,
#endif
};
/* Convert the wake-up sources defined in ulp_lp_core.h to the actual HW wake-up source values */

View File

@ -14,6 +14,10 @@
#include "hal/pmu_ll.h"
#include "hal/uart_ll.h"
#include "hal/rtc_io_ll.h"
#if SOC_LP_I2S_SUPPORT_VAD
//For VAD
#include "hal/lp_i2s_ll.h"
#endif
#if SOC_LP_TIMER_SUPPORTED
#include "hal/lp_timer_ll.h"
@ -56,6 +60,13 @@ void ulp_lp_core_update_wakeup_cause(void)
rtcio_ll_clear_interrupt_status();
}
#if SOC_LP_VAD_SUPPORTED
if ((lp_core_ll_get_wakeup_source() & LP_CORE_LL_WAKEUP_SOURCE_LP_VAD)) {
lp_wakeup_cause |= LP_CORE_LL_WAKEUP_SOURCE_LP_VAD;
lp_i2s_ll_rx_clear_interrupt_status(&LP_I2S, LP_I2S_LL_EVENT_VAD_DONE_INT);
}
#endif
#if SOC_ETM_SUPPORTED
if ((lp_core_ll_get_wakeup_source() & LP_CORE_LL_WAKEUP_SOURCE_ETM) \
&& lp_core_ll_get_etm_wakeup_flag()) {

View File

@ -0,0 +1,121 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stdint.h>
#include "esp_err.h"
#include "driver/lp_i2s_vad.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief LP VAD configurations
*/
typedef lp_vad_init_config_t lp_core_lp_vad_cfg_t;
/**
* @brief State Machine
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'
*/
/**
* @brief LP VAD init
*
* @param[in] vad_id VAD ID
* @param[in] init_config Initial configurations
*
* @return
* - ESP_OK: On success
* - ESP_ERR_INVALID_ARG: Invalid argument
* - ESP_ERR_INVALID_STATE: Driver state is invalid, you shouldn't call this API at this moment
*/
esp_err_t lp_core_lp_vad_init(lp_vad_t vad_id, const lp_core_lp_vad_cfg_t *init_config);
/**
* @brief Enable LP VAD
*
* @param[in] vad_id VAD ID
* @param[in] init_config Initial configurations
*
* @return
* - ESP_OK: On success
* - ESP_ERR_INVALID_ARG: Invalid argument
* - ESP_ERR_INVALID_STATE: Driver state is invalid, you shouldn't call this API at this moment
*/
esp_err_t lp_core_lp_vad_enable(lp_vad_t vad_id);
/**
* @brief Disable LP VAD
*
* @param[in] vad_id VAD ID
* @param[in] init_config Initial configurations
*
* @return
* - ESP_OK: On success
* - ESP_ERR_INVALID_ARG: Invalid argument
* - ESP_ERR_INVALID_STATE: Driver state is invalid, you shouldn't call this API at this moment
*/
esp_err_t lp_core_lp_vad_disable(lp_vad_t vad_id);
/**
* @brief Deinit LP VAD
*
* @param[in] vad_id VAD ID
*
* @return
* - ESP_OK: On success
* - ESP_ERR_INVALID_ARG: Invalid argument
* - ESP_ERR_INVALID_STATE: Driver state is invalid, you shouldn't call this API at this moment
*/
esp_err_t lp_core_lp_vad_deinit(lp_vad_t vad_id);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,65 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "soc/soc_caps.h"
#if SOC_LP_VAD_SUPPORTED
#include "esp_check.h"
#include "esp_err.h"
#include "ulp_lp_core_lp_vad_shared.h"
#if SOC_LP_I2S_SUPPORT_VAD
//For VAD
#include "hal/lp_i2s_ll.h"
#include "hal/lp_i2s_hal.h"
#include "esp_private/lp_i2s_private.h"
#endif //SOC_LP_I2S_SUPPORT_VAD
//make this available for multi vad id in future
vad_unit_handle_t s_vad_handle;
esp_err_t lp_core_lp_vad_init(lp_vad_t vad_id, const lp_core_lp_vad_cfg_t *init_config)
{
#if IS_ULP_COCPU
// Not supported
return ESP_ERR_NOT_SUPPORTED;
#else
esp_err_t ret = lp_i2s_vad_new_unit(vad_id, init_config, &s_vad_handle);
return ret;
#endif
}
esp_err_t lp_core_lp_vad_enable(lp_vad_t vad_id)
{
#if IS_ULP_COCPU
// Not supported
return ESP_ERR_NOT_SUPPORTED;
#else
esp_err_t ret = lp_i2s_vad_enable(s_vad_handle);
return ret;
#endif
}
esp_err_t lp_core_lp_vad_disable(lp_vad_t vad_id)
{
#if IS_ULP_COCPU
// Not supported
return ESP_ERR_NOT_SUPPORTED;
#else
esp_err_t ret = lp_i2s_vad_disable(s_vad_handle);
return ret;
#endif
}
esp_err_t lp_core_lp_vad_deinit(lp_vad_t vad_id)
{
#if IS_ULP_COCPU
// Not supported
return ESP_ERR_NOT_SUPPORTED;
#else
esp_err_t ret = lp_i2s_vad_del_unit(s_vad_handle);
return ret;
#endif
}
#endif /* SOC_LP_VAD_SUPPORTED */