mirror of
https://github.com/espressif/esp-idf.git
synced 2025-07-31 19:24:33 +02:00
Merge branch 'feat/lp_i2s_vad' into 'master'
lp_i2s: vad lp driver and lp/hp core wakeup feature Closes IDF-10211 and IDF-6517 See merge request espressif/esp-idf!33804
This commit is contained in:
@@ -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
|
||||
|
153
components/esp_driver_i2s/include/driver/lp_i2s_vad.h
Normal file
153
components/esp_driver_i2s/include/driver/lp_i2s_vad.h
Normal 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
|
@@ -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
|
@@ -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;
|
||||
}
|
||||
|
112
components/esp_driver_i2s/lp_i2s_vad.c
Normal file
112
components/esp_driver_i2s/lp_i2s_vad.c
Normal 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 */
|
@@ -1 +0,0 @@
|
||||
CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y
|
||||
|
@@ -50,6 +50,7 @@ typedef enum {
|
||||
#define RTC_SLEEP_USE_ADC_TESEN_MONITOR BIT(17)
|
||||
#define RTC_SLEEP_NO_ULTRA_LOW BIT(18) //!< Avoid using ultra low power in deep sleep, in which RTCIO cannot be used as input, and RTCMEM can't work under high temperature
|
||||
#define RTC_SLEEP_XTAL_AS_RTC_FAST BIT(19)
|
||||
#define RTC_SLEEP_LP_PERIPH_USE_XTAL BIT(20)
|
||||
|
||||
#if SOC_PM_SUPPORT_EXT0_WAKEUP
|
||||
#define RTC_EXT0_TRIG_EN PMU_EXT0_WAKEUP_EN //!< EXT0 wakeup
|
||||
@@ -109,6 +110,12 @@ typedef enum {
|
||||
#define RTC_LP_CORE_TRIG_EN 0
|
||||
#endif //SOC_LP_CORE_SUPPORTED
|
||||
|
||||
#if SOC_LP_VAD_SUPPORTED
|
||||
#define RTC_LP_VAD_TRIG_EN PMU_LP_I2S_WAKEUP_EN //!< LP VAD wakeup
|
||||
#else
|
||||
#define RTC_LP_VAD_TRIG_EN 0
|
||||
#endif //SOC_LP_VAD_SUPPORTED
|
||||
|
||||
#define RTC_XTAL32K_DEAD_TRIG_EN 0 // TODO
|
||||
#define RTC_BROWNOUT_DET_TRIG_EN 0 // TODO
|
||||
|
||||
@@ -127,6 +134,7 @@ typedef enum {
|
||||
RTC_TOUCH_TRIG_EN | \
|
||||
RTC_XTAL32K_DEAD_TRIG_EN | \
|
||||
RTC_USB_TRIG_EN | \
|
||||
RTC_LP_VAD_TRIG_EN | \
|
||||
RTC_BROWNOUT_DET_TRIG_EN)
|
||||
|
||||
|
||||
|
@@ -38,6 +38,7 @@ typedef enum {
|
||||
ESP_SLEEP_ULTRA_LOW_MODE, //!< In ultra low mode, 2uA is saved, but RTC memory can't use at high temperature, and RTCIO can't be used as INPUT.
|
||||
ESP_SLEEP_RTC_FAST_USE_XTAL_MODE, //!< The mode in which the crystal is used as the RTC_FAST clock source, need keep XTAL on in HP_SLEEP mode when ULP is working.
|
||||
ESP_SLEEP_DIG_USE_XTAL_MODE, //!< The mode requested by digital peripherals to keep XTAL clock on during sleep (both HP_SLEEP and LP_SLEEP mode). (!!! Only valid for lightsleep, will override the XTAL domain config by esp_sleep_pd_config)
|
||||
ESP_SLEEP_LP_USE_XTAL_MODE, //!< The mode requested by lp peripherals to keep XTAL clock on during sleep. Only valid for lightsleep.
|
||||
ESP_SLEEP_MODE_MAX,
|
||||
} esp_sleep_sub_mode_t;
|
||||
|
||||
|
@@ -118,6 +118,7 @@ typedef enum {
|
||||
ESP_SLEEP_WAKEUP_COCPU, //!< Wakeup caused by COCPU int
|
||||
ESP_SLEEP_WAKEUP_COCPU_TRAP_TRIG, //!< Wakeup caused by COCPU crash
|
||||
ESP_SLEEP_WAKEUP_BT, //!< Wakeup caused by BT (light sleep only)
|
||||
ESP_SLEEP_WAKEUP_VAD, //!< Wakeup caused by VAD
|
||||
} esp_sleep_source_t;
|
||||
|
||||
/**
|
||||
@@ -179,6 +180,16 @@ esp_err_t esp_sleep_enable_ulp_wakeup(void);
|
||||
*/
|
||||
esp_err_t esp_sleep_enable_timer_wakeup(uint64_t time_in_us);
|
||||
|
||||
#if SOC_LP_VAD_SUPPORTED
|
||||
/**
|
||||
* @brief Enable wakeup by VAD
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
*/
|
||||
esp_err_t esp_sleep_enable_vad_wakeup(void);
|
||||
#endif
|
||||
|
||||
#if SOC_TOUCH_SENSOR_SUPPORTED
|
||||
/**
|
||||
* @brief Enable wakeup by touch sensor
|
||||
|
@@ -29,6 +29,7 @@
|
||||
#include "hal/pmu_hal.h"
|
||||
#include "hal/psram_ctrlr_ll.h"
|
||||
#include "hal/lp_sys_ll.h"
|
||||
#include "hal/clk_gate_ll.h"
|
||||
#include "esp_private/esp_pmu.h"
|
||||
#include "pmu_param.h"
|
||||
#include "esp_rom_sys.h"
|
||||
@@ -202,6 +203,10 @@ const pmu_sleep_config_t* pmu_sleep_config_default(
|
||||
config->analog.hp_sys.analog.dbias = HP_CALI_ACTIVE_DBIAS_DEFAULT;
|
||||
}
|
||||
|
||||
if (sleep_flags & RTC_SLEEP_LP_PERIPH_USE_XTAL) {
|
||||
_clk_gate_ll_xtal_to_lp_periph_en(true);
|
||||
}
|
||||
|
||||
config->power = power_default;
|
||||
pmu_sleep_param_config_t param_default = PMU_SLEEP_PARAM_CONFIG_DEFAULT(sleep_flags);
|
||||
config->param = *pmu_sleep_param_config_default(¶m_default, &power_default, sleep_flags, adjustment, slowclk_period, fastclk_period);
|
||||
|
@@ -223,7 +223,7 @@ typedef struct {
|
||||
} domain[ESP_PD_DOMAIN_MAX];
|
||||
portMUX_TYPE lock;
|
||||
uint64_t sleep_duration;
|
||||
uint32_t wakeup_triggers : 15;
|
||||
uint32_t wakeup_triggers : 20;
|
||||
#if SOC_PM_SUPPORT_EXT1_WAKEUP
|
||||
uint32_t ext1_trigger_mode : 22; // 22 is the maximum RTCIO number in all chips
|
||||
uint32_t ext1_rtc_gpio_mask : 22;
|
||||
@@ -924,6 +924,12 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m
|
||||
sleep_flags |= RTC_SLEEP_XTAL_AS_RTC_FAST;
|
||||
}
|
||||
|
||||
#if SOC_LP_VAD_SUPPORTED
|
||||
if (s_sleep_sub_mode_ref_cnt[ESP_SLEEP_LP_USE_XTAL_MODE] && !deep_sleep) {
|
||||
sleep_flags |= RTC_SLEEP_LP_PERIPH_USE_XTAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_ESP_SLEEP_DEBUG
|
||||
if (s_sleep_ctx != NULL) {
|
||||
s_sleep_ctx->sleep_flags = sleep_flags;
|
||||
@@ -1650,6 +1656,14 @@ esp_err_t esp_sleep_enable_timer_wakeup(uint64_t time_in_us)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#if SOC_LP_VAD_SUPPORTED
|
||||
esp_err_t esp_sleep_enable_vad_wakeup(void)
|
||||
{
|
||||
s_config.wakeup_triggers |= RTC_LP_VAD_TRIG_EN;
|
||||
return esp_sleep_sub_mode_config(ESP_SLEEP_LP_USE_XTAL_MODE, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
static esp_err_t timer_wakeup_prepare(int64_t sleep_duration)
|
||||
{
|
||||
if (sleep_duration < 0) {
|
||||
@@ -2170,6 +2184,10 @@ esp_sleep_wakeup_cause_t esp_sleep_get_wakeup_cause(void)
|
||||
#if SOC_LP_CORE_SUPPORTED
|
||||
} else if (wakeup_cause & RTC_LP_CORE_TRIG_EN) {
|
||||
return ESP_SLEEP_WAKEUP_ULP;
|
||||
#endif
|
||||
#if SOC_LP_VAD_SUPPORTED
|
||||
} else if (wakeup_cause & RTC_LP_VAD_TRIG_EN) {
|
||||
return ESP_SLEEP_WAKEUP_VAD;
|
||||
#endif
|
||||
} else {
|
||||
return ESP_SLEEP_WAKEUP_UNDEFINED;
|
||||
@@ -2234,6 +2252,7 @@ int32_t* esp_sleep_sub_mode_dump_config(FILE *stream) {
|
||||
[ESP_SLEEP_ULTRA_LOW_MODE] = "ESP_SLEEP_ULTRA_LOW_MODE",
|
||||
[ESP_SLEEP_RTC_FAST_USE_XTAL_MODE] = "ESP_SLEEP_RTC_FAST_USE_XTAL_MODE",
|
||||
[ESP_SLEEP_DIG_USE_XTAL_MODE] = "ESP_SLEEP_DIG_USE_XTAL_MODE",
|
||||
[ESP_SLEEP_LP_USE_XTAL_MODE] = "ESP_SLEEP_LP_USE_XTAL_MODE",
|
||||
}[mode],
|
||||
s_sleep_sub_mode_ref_cnt[mode] ? "ENABLED" : "DISABLED",
|
||||
s_sleep_sub_mode_ref_cnt[mode]);
|
||||
|
@@ -42,6 +42,10 @@ components/esp_hw_support/test_apps/rtc_power_modes:
|
||||
temporary: true
|
||||
reason: the other targets are not tested yet
|
||||
|
||||
components/esp_hw_support/test_apps/vad_wakeup:
|
||||
disable:
|
||||
- if: SOC_LP_VAD_SUPPORTED != 1
|
||||
|
||||
components/esp_hw_support/test_apps/wakeup_tests:
|
||||
disable:
|
||||
- if: IDF_TARGET in ["esp32c5", "esp32p4", "linux", "esp32c61"]
|
||||
|
@@ -0,0 +1,8 @@
|
||||
# This is the project CMakeLists.txt file for the test subproject
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
set(COMPONENTS main)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(vad_wakeup)
|
3
components/esp_hw_support/test_apps/vad_wakeup/README.md
Normal file
3
components/esp_hw_support/test_apps/vad_wakeup/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
| Supported Targets | ESP32-P4 |
|
||||
| ----------------- | -------- |
|
||||
|
@@ -0,0 +1,7 @@
|
||||
set(srcs "test_app_main.c"
|
||||
"test_vad_wakeup.c")
|
||||
|
||||
idf_component_register(SRCS ${srcs}
|
||||
REQUIRES unity esp_driver_i2s esp_driver_uart ulp esp_timer
|
||||
WHOLE_ARCHIVE
|
||||
EMBED_FILES "test_vad_8k.pcm")
|
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "unity.h"
|
||||
#include "unity_test_runner.h"
|
||||
#include "unity_test_utils.h"
|
||||
|
||||
#define LEAKS (400)
|
||||
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
unity_utils_record_free_mem();
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
unity_utils_evaluate_leaks_direct(LEAKS);
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
unity_run_menu();
|
||||
}
|
Binary file not shown.
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/uart.h"
|
||||
#include "driver/lp_i2s.h"
|
||||
#include "driver/lp_i2s_std.h"
|
||||
#include "driver/i2s_std.h"
|
||||
#include "ulp_lp_core_lp_vad_shared.h"
|
||||
#include "unity.h"
|
||||
#include "esp_timer.h"
|
||||
|
||||
#define TEST_I2S_FRAME_SIZE (128) // Frame numbers in every writing / reading
|
||||
#define TEST_I2S_TRANS_SIZE (4096) // Trans size
|
||||
#define TEST_LP_I2S_PIN_BCK 4
|
||||
#define TEST_LP_I2S_PIN_WS 5
|
||||
#define TEST_LP_I2S_PIN_DIN 6
|
||||
|
||||
|
||||
extern const uint8_t test_vad_pcm_start[] asm("_binary_test_vad_8k_pcm_start");
|
||||
extern const uint8_t test_vad_pcm_end[] asm("_binary_test_vad_8k_pcm_end");
|
||||
static const char *TAG = "TEST_VAD";
|
||||
|
||||
static void s_hp_i2s_config(void)
|
||||
{
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
int pcm_size = test_vad_pcm_end - test_vad_pcm_start;
|
||||
printf("pcm_size: %d\n", pcm_size);
|
||||
|
||||
i2s_chan_handle_t tx_handle = NULL;
|
||||
i2s_chan_config_t i2s_channel_config = {
|
||||
.id = I2S_NUM_0,
|
||||
.role = I2S_ROLE_MASTER,
|
||||
.dma_desc_num = 16,
|
||||
.dma_frame_num = TEST_I2S_FRAME_SIZE,
|
||||
.auto_clear = false,
|
||||
};
|
||||
TEST_ESP_OK(i2s_new_channel(&i2s_channel_config, &tx_handle, NULL));
|
||||
|
||||
|
||||
i2s_std_config_t i2s_std_config = {
|
||||
.gpio_cfg = {
|
||||
.mclk = I2S_GPIO_UNUSED,
|
||||
.bclk = GPIO_NUM_7,
|
||||
.ws = GPIO_NUM_8,
|
||||
.dout = GPIO_NUM_21,
|
||||
.din = -1,
|
||||
.invert_flags = {
|
||||
.mclk_inv = false,
|
||||
.bclk_inv = false,
|
||||
.ws_inv = false,
|
||||
},
|
||||
},
|
||||
};
|
||||
i2s_std_config.clk_cfg = (i2s_std_clk_config_t)I2S_STD_CLK_DEFAULT_CONFIG(16000);
|
||||
i2s_std_config.slot_cfg = (i2s_std_slot_config_t)I2S_STD_PCM_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO);
|
||||
TEST_ESP_OK(i2s_channel_init_std_mode(tx_handle, &i2s_std_config));
|
||||
|
||||
|
||||
uint8_t *txbuf = (uint8_t *)heap_caps_calloc(1, TEST_I2S_TRANS_SIZE, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
|
||||
TEST_ASSERT(txbuf);
|
||||
|
||||
uint8_t *prebuf = (uint8_t *)heap_caps_calloc(1, TEST_I2S_TRANS_SIZE, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
|
||||
TEST_ASSERT(prebuf);
|
||||
|
||||
memcpy(prebuf, test_vad_pcm_start, TEST_I2S_TRANS_SIZE);
|
||||
memcpy(txbuf, test_vad_pcm_start, TEST_I2S_TRANS_SIZE);
|
||||
|
||||
for (int i = 0; i < TEST_I2S_TRANS_SIZE; i++) {
|
||||
ESP_LOGD(TAG, "prebuf[%d]: %d", i, prebuf[i]);
|
||||
ESP_LOGD(TAG, "txbuf[%d]: %d", i, txbuf[i]);
|
||||
}
|
||||
|
||||
size_t bytes_written = 0;
|
||||
TEST_ESP_OK(i2s_channel_preload_data(tx_handle, prebuf, TEST_I2S_TRANS_SIZE, &bytes_written));
|
||||
|
||||
TEST_ESP_OK(i2s_channel_enable(tx_handle));
|
||||
|
||||
while (1) {
|
||||
ret = i2s_channel_write(tx_handle, txbuf, TEST_I2S_TRANS_SIZE, &bytes_written, 0);
|
||||
if (ret != ESP_OK && ret != ESP_ERR_TIMEOUT) {
|
||||
TEST_ESP_OK(ret);
|
||||
}
|
||||
ESP_LOGD(TAG, "bytes_written: %d", bytes_written);
|
||||
vTaskDelay(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void s_lp_vad_config(void)
|
||||
{
|
||||
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_config_t config = {
|
||||
.id = 0,
|
||||
.role = I2S_ROLE_SLAVE,
|
||||
.threshold = 512,
|
||||
};
|
||||
TEST_ESP_OK(lp_i2s_new_channel(&config, NULL, &rx_handle));
|
||||
|
||||
lp_i2s_std_config_t lp_std_cfg = {
|
||||
.pin_cfg = {
|
||||
.bck = TEST_LP_I2S_PIN_BCK,
|
||||
.ws = TEST_LP_I2S_PIN_WS,
|
||||
.din = TEST_LP_I2S_PIN_DIN,
|
||||
},
|
||||
};
|
||||
lp_std_cfg.slot_cfg = (lp_i2s_std_slot_config_t)LP_I2S_STD_PCM_SHORT_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO);
|
||||
TEST_ESP_OK(lp_i2s_channel_init_std_mode(rx_handle, &lp_std_cfg));
|
||||
|
||||
// LP VAD Init
|
||||
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,
|
||||
},
|
||||
};
|
||||
TEST_ESP_OK(lp_core_lp_vad_init(0, &init_config));
|
||||
TEST_ESP_OK(lp_i2s_channel_enable(rx_handle));
|
||||
TEST_ESP_OK(lp_core_lp_vad_enable(0));
|
||||
|
||||
printf("Entering light sleep\n");
|
||||
/* To make sure the complete line is printed before entering sleep mode,
|
||||
* need to wait until UART TX FIFO is empty:
|
||||
*/
|
||||
uart_wait_tx_idle_polling(CONFIG_ESP_CONSOLE_UART_NUM);
|
||||
|
||||
/* Enter sleep mode */
|
||||
esp_light_sleep_start();
|
||||
|
||||
/* Determine wake up reason */
|
||||
const char* wakeup_reason;
|
||||
switch (esp_sleep_get_wakeup_cause()) {
|
||||
case ESP_SLEEP_WAKEUP_VAD:
|
||||
wakeup_reason = "vad";
|
||||
break;
|
||||
default:
|
||||
wakeup_reason = "other";
|
||||
TEST_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "wakeup, reason: %s", wakeup_reason);
|
||||
}
|
||||
|
||||
TEST_CASE_MULTIPLE_DEVICES("test LP VAD wakeup", "[vad][ignore][manual]", s_hp_i2s_config, s_lp_vad_config);
|
@@ -0,0 +1,11 @@
|
||||
# SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
|
||||
|
||||
@pytest.mark.esp32p4
|
||||
@pytest.mark.temp_skip_ci(targets=['esp32p4'], reason='lack of runners for now')
|
||||
@pytest.mark.lp_i2s
|
||||
def test_efuse(dut: Dut) -> None:
|
||||
dut.run_all_single_board_cases()
|
@@ -0,0 +1,8 @@
|
||||
CONFIG_ESP_TASK_WDT_INIT=n
|
||||
|
||||
CONFIG_ULP_COPROC_ENABLED=y
|
||||
CONFIG_ULP_COPROC_TYPE_LP_CORE=y
|
||||
CONFIG_ULP_COPROC_RESERVE_MEM=12000
|
||||
CONFIG_ULP_PANIC_OUTPUT_ENABLE=y
|
||||
|
||||
CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y
|
@@ -14,6 +14,7 @@ extern "C" {
|
||||
#include <stdbool.h>
|
||||
#include "esp_attr.h"
|
||||
#include "soc/hp_sys_clkrst_struct.h"
|
||||
#include "soc/lp_clkrst_struct.h"
|
||||
|
||||
/**
|
||||
* Enable or disable the clock gate for ref_20m.
|
||||
@@ -75,6 +76,18 @@ FORCE_INLINE_ATTR void _clk_gate_ll_ref_240m_clk_en(bool enable)
|
||||
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
|
||||
#define clk_gate_ll_ref_240m_clk_en(...) (void)__DECLARE_RCC_ATOMIC_ENV; _clk_gate_ll_ref_240m_clk_en(__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Enable or disable the clock gate for xtal to lp periph
|
||||
* @param enable Enable / disable
|
||||
*/
|
||||
FORCE_INLINE_ATTR void _clk_gate_ll_xtal_to_lp_periph_en(bool enable)
|
||||
{
|
||||
LP_AON_CLKRST.lp_clk_en.xtal_clk_force_on = enable;
|
||||
}
|
||||
/// use a macro to wrap the function, force the caller to use it in a critical section
|
||||
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
|
||||
#define clk_gate_ll_xtal_to_lp_periph_en(...) (void)__DECLARE_RCC_ATOMIC_ENV; _clk_gate_ll_xtal_to_lp_periph_en(__VA_ARGS__)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@@ -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 */
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
@@ -1851,6 +1859,14 @@ config SOC_PM_PAU_REGDMA_UPDATE_CACHE_BEFORE_WAIT_COMPARE
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_SLEEP_SYSTIMER_STALL_WORKAROUND
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_SLEEP_TGWDT_STOP_WORKAROUND
|
||||
bool
|
||||
default y
|
||||
|
||||
config SOC_PSRAM_VDD_POWER_MPLL
|
||||
bool
|
||||
default y
|
||||
@@ -1966,3 +1982,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
|
||||
|
@@ -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)
|
||||
@@ -698,6 +702,8 @@
|
||||
#define SOC_CPU_IN_TOP_DOMAIN (1)
|
||||
|
||||
#define SOC_PM_PAU_REGDMA_UPDATE_CACHE_BEFORE_WAIT_COMPARE (1)
|
||||
#define SOC_SLEEP_SYSTIMER_STALL_WORKAROUND 1 //TODO IDF-11381: replace with all xtal field clk gate control
|
||||
#define SOC_SLEEP_TGWDT_STOP_WORKAROUND 1 //TODO IDF-11381: replace with all xtal field clk gate control
|
||||
|
||||
/*-------------------------- PSRAM CAPS ----------------------------*/
|
||||
#define SOC_PSRAM_VDD_POWER_MPLL (1)
|
||||
@@ -747,3 +753,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 */
|
||||
|
@@ -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}
|
||||
|
@@ -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})
|
||||
|
@@ -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
|
||||
|
@@ -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 */
|
||||
|
@@ -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()) {
|
||||
|
@@ -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
|
65
components/ulp/lp_core/shared/ulp_lp_core_lp_vad_shared.c
Normal file
65
components/ulp/lp_core/shared/ulp_lp_core_lp_vad_shared.c
Normal 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 */
|
@@ -20,6 +20,10 @@ if(CONFIG_SOC_LP_ADC_SUPPORTED)
|
||||
list(APPEND app_sources "test_lp_core_adc.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_LP_VAD_SUPPORTED)
|
||||
list(APPEND app_sources "test_lp_core_vad.c")
|
||||
endif()
|
||||
|
||||
set(lp_core_sources "lp_core/test_main.c")
|
||||
set(lp_core_sources_counter "lp_core/test_main_counter.c")
|
||||
|
||||
@@ -46,10 +50,15 @@ if(CONFIG_SOC_LP_ADC_SUPPORTED)
|
||||
set(lp_core_sources_adc "lp_core/test_main_adc.c")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_LP_VAD_SUPPORTED)
|
||||
set(lp_core_sources_vad "lp_core/test_main_vad.c")
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS ${app_sources}
|
||||
INCLUDE_DIRS "lp_core"
|
||||
REQUIRES ulp unity esp_timer test_utils
|
||||
WHOLE_ARCHIVE)
|
||||
WHOLE_ARCHIVE
|
||||
EMBED_FILES "test_vad_8k.pcm")
|
||||
|
||||
set(lp_core_exp_dep_srcs ${app_sources})
|
||||
|
||||
@@ -79,3 +88,7 @@ endif()
|
||||
if(CONFIG_SOC_LP_ADC_SUPPORTED)
|
||||
ulp_embed_binary(lp_core_test_app_adc "${lp_core_sources_adc}" "${lp_core_exp_dep_srcs}")
|
||||
endif()
|
||||
|
||||
if(CONFIG_SOC_LP_VAD_SUPPORTED)
|
||||
ulp_embed_binary(lp_core_test_app_vad "${lp_core_sources_vad}" "${lp_core_exp_dep_srcs}")
|
||||
endif()
|
||||
|
@@ -0,0 +1,9 @@
|
||||
menu "Test Configurations"
|
||||
|
||||
config TEST_LP_CORE_VAD_ENABLE
|
||||
bool "Enable LP VAD test"
|
||||
default n
|
||||
help
|
||||
Enable this to trigger LP VAD test
|
||||
|
||||
endmenu
|
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
volatile bool vad_wakup;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
vad_wakup = true;
|
||||
|
||||
return 0;
|
||||
}
|
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "unity.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "driver/lp_i2s.h"
|
||||
#include "driver/lp_i2s_std.h"
|
||||
#include "driver/i2s_std.h"
|
||||
#include "ulp_lp_core.h"
|
||||
#include "ulp_lp_core_lp_vad_shared.h"
|
||||
#include "lp_core_test_app_vad.h"
|
||||
|
||||
#if CONFIG_TEST_LP_CORE_VAD_ENABLE
|
||||
|
||||
#define TEST_I2S_FRAME_SIZE (128) // Frame numbers in every writing / reading
|
||||
#define TEST_I2S_TRANS_SIZE (4096) // Trans size
|
||||
|
||||
extern const uint8_t test_vad_pcm_start[] asm("_binary_test_vad_8k_pcm_start");
|
||||
extern const uint8_t test_vad_pcm_end[] asm("_binary_test_vad_8k_pcm_end");
|
||||
extern const uint8_t lp_core_main_vad_bin_start[] asm("_binary_lp_core_test_app_vad_bin_start");
|
||||
extern const uint8_t lp_core_main_vad_bin_end[] asm("_binary_lp_core_test_app_vad_bin_end");
|
||||
static const char *TAG = "TEST_VAD";
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void test_lp_vad(lp_vad_t vad_id)
|
||||
{
|
||||
esp_err_t ret = ESP_FAIL;
|
||||
int pcm_size = test_vad_pcm_end - test_vad_pcm_start;
|
||||
printf("pcm_size: %d\n", pcm_size);
|
||||
|
||||
lp_i2s_chan_handle_t rx_handle = NULL;
|
||||
lp_i2s_chan_config_t config = {
|
||||
.id = 0,
|
||||
.role = I2S_ROLE_SLAVE,
|
||||
.threshold = 512,
|
||||
};
|
||||
TEST_ESP_OK(lp_i2s_new_channel(&config, NULL, &rx_handle));
|
||||
|
||||
i2s_chan_handle_t tx_handle = NULL;
|
||||
i2s_chan_config_t i2s_channel_config = {
|
||||
.id = I2S_NUM_0,
|
||||
.role = I2S_ROLE_MASTER,
|
||||
.dma_desc_num = 4,
|
||||
.dma_frame_num = TEST_I2S_FRAME_SIZE,
|
||||
.auto_clear = false,
|
||||
};
|
||||
TEST_ESP_OK(i2s_new_channel(&i2s_channel_config, &tx_handle, NULL));
|
||||
|
||||
lp_i2s_std_config_t lp_std_cfg = {
|
||||
.pin_cfg = {
|
||||
.bck = 4,
|
||||
.ws = 5,
|
||||
.din = 6,
|
||||
},
|
||||
};
|
||||
lp_std_cfg.slot_cfg = (lp_i2s_std_slot_config_t)LP_I2S_STD_PCM_SHORT_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO);
|
||||
TEST_ESP_OK(lp_i2s_channel_init_std_mode(rx_handle, &lp_std_cfg));
|
||||
|
||||
i2s_std_config_t i2s_std_config = {
|
||||
.gpio_cfg = {
|
||||
.mclk = I2S_GPIO_UNUSED,
|
||||
.bclk = GPIO_NUM_7,
|
||||
.ws = GPIO_NUM_8,
|
||||
.dout = GPIO_NUM_21,
|
||||
.din = -1,
|
||||
.invert_flags = {
|
||||
.mclk_inv = false,
|
||||
.bclk_inv = false,
|
||||
.ws_inv = false,
|
||||
},
|
||||
},
|
||||
};
|
||||
i2s_std_config.clk_cfg = (i2s_std_clk_config_t)I2S_STD_CLK_DEFAULT_CONFIG(16000);
|
||||
i2s_std_config.slot_cfg = (i2s_std_slot_config_t)I2S_STD_PCM_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO);
|
||||
TEST_ESP_OK(i2s_channel_init_std_mode(tx_handle, &i2s_std_config));
|
||||
|
||||
// LP VAD Init
|
||||
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,
|
||||
},
|
||||
};
|
||||
TEST_ESP_OK(lp_core_lp_vad_init(0, &init_config));
|
||||
|
||||
/* Load ULP firmware and start the coprocessor */
|
||||
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);
|
||||
|
||||
uint8_t *txbuf = (uint8_t *)heap_caps_calloc(1, TEST_I2S_TRANS_SIZE, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
|
||||
TEST_ASSERT(txbuf);
|
||||
|
||||
uint8_t *prebuf = (uint8_t *)heap_caps_calloc(1, TEST_I2S_TRANS_SIZE, MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
|
||||
TEST_ASSERT(prebuf);
|
||||
|
||||
memcpy(prebuf, test_vad_pcm_start, TEST_I2S_TRANS_SIZE);
|
||||
memcpy(txbuf, test_vad_pcm_start, TEST_I2S_TRANS_SIZE);
|
||||
|
||||
for (int i = 0; i < TEST_I2S_TRANS_SIZE; i++) {
|
||||
ESP_LOGD(TAG, "prebuf[%d]: %d", i, prebuf[i]);
|
||||
ESP_LOGD(TAG, "txbuf[%d]: %d", i, txbuf[i]);
|
||||
}
|
||||
|
||||
size_t bytes_written = 0;
|
||||
TEST_ESP_OK(i2s_channel_preload_data(tx_handle, prebuf, TEST_I2S_TRANS_SIZE, &bytes_written));
|
||||
TEST_ESP_OK(lp_i2s_channel_enable(rx_handle));
|
||||
TEST_ESP_OK(lp_core_lp_vad_enable(0));
|
||||
TEST_ESP_OK(i2s_channel_enable(tx_handle));
|
||||
|
||||
ret = i2s_channel_write(tx_handle, txbuf, TEST_I2S_TRANS_SIZE, &bytes_written, 0);
|
||||
if (ret != ESP_OK && ret != ESP_ERR_TIMEOUT) {
|
||||
TEST_ESP_OK(ret);
|
||||
}
|
||||
ESP_LOGD(TAG, "bytes_written: %d", bytes_written);
|
||||
|
||||
while (!ulp_vad_wakup) {
|
||||
;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "wakeup");
|
||||
|
||||
TEST_ESP_OK(lp_i2s_channel_disable(rx_handle));
|
||||
TEST_ESP_OK(lp_i2s_del_channel(rx_handle));
|
||||
TEST_ESP_OK(i2s_channel_disable(tx_handle));
|
||||
TEST_ESP_OK(i2s_del_channel(tx_handle));
|
||||
free(txbuf);
|
||||
free(prebuf);
|
||||
}
|
||||
|
||||
TEST_CASE("LP VAD wakeup test", "[lp_core][lp_vad]")
|
||||
{
|
||||
test_lp_vad(0);
|
||||
}
|
||||
#endif //CONFIG_TEST_LP_CORE_VAD_ENABLE
|
Binary file not shown.
@@ -33,6 +33,19 @@ def test_lp_core_xtal(dut: Dut) -> None:
|
||||
dut.run_all_single_board_cases()
|
||||
|
||||
|
||||
@pytest.mark.esp32p4
|
||||
@pytest.mark.lp_i2s
|
||||
@pytest.mark.parametrize(
|
||||
'config',
|
||||
[
|
||||
'lp_vad',
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
def test_lp_vad(dut: Dut) -> None:
|
||||
dut.run_all_single_board_cases(group='lp_vad')
|
||||
|
||||
|
||||
@pytest.mark.esp32c6
|
||||
# TODO: Enable LP I2C test for esp32p4 (IDF-9407)
|
||||
@pytest.mark.generic_multi_device
|
||||
|
@@ -0,0 +1 @@
|
||||
CONFIG_TEST_LP_CORE_VAD_ENABLE=y
|
Reference in New Issue
Block a user