Merge branch 'feature/p4_lp_core' into 'master'

feat(ulp/lp_core): Added basic support for building and running a LP-Core app on ESP32P4

Closes IDF-7534

See merge request espressif/esp-idf!26869
This commit is contained in:
Marius Vikhammer 2023-11-30 09:35:49 +08:00
commit ae4be8eb03
24 changed files with 563 additions and 181 deletions

View File

@ -46,3 +46,7 @@ config ESP_ROM_HAS_LAYOUT_TABLE
config ESP_ROM_WDT_INIT_PATCH
bool
default y
config ESP_ROM_HAS_LP_ROM
bool
default y

View File

@ -17,3 +17,4 @@
#define ESP_ROM_HAS_HAL_SYSTIMER (1) // ROM has the implementation of Systimer HAL driver
#define ESP_ROM_HAS_LAYOUT_TABLE (1) // ROM has the layout table
#define ESP_ROM_WDT_INIT_PATCH (1) // ROM version does not configure the clock
#define ESP_ROM_HAS_LP_ROM (1) // ROM also has a LP ROM placed in LP memory

View File

@ -0,0 +1,114 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use it in application code.
******************************************************************************/
#pragma once
#include <stdbool.h>
#include "soc/lpperi_struct.h"
#include "soc/pmu_struct.h"
#include "soc/lp_aon_struct.h"
#ifdef __cplusplus
extern "C" {
#endif
#define LP_CORE_LL_WAKEUP_SOURCE_HP_CPU BIT(0) // Started by HP core (1 single wakeup)
#define LP_CORE_LL_WAKEUP_SOURCE_LP_UART BIT(1) // Enable wake-up by a certain number of LP UART RX pulses
#define LP_CORE_LL_WAKEUP_SOURCE_LP_IO BIT(2) // Enable wake-up by LP IO interrupt
#define LP_CORE_LL_WAKEUP_SOURCE_ETM BIT(3) // Enable wake-up by ETM event
#define LP_CORE_LL_WAKEUP_SOURCE_LP_TIMER BIT(4) // Enable wake-up by LP timer
/**
* @brief Enable the bus clock for LP-core
*
* @param enable Enable if true, disable if false
*/
static inline void lp_core_ll_enable_bus_clock(bool enable)
{
/* ESP32C6 does not have clk/rst periph control for LP-core */
(void)enable;
}
/**
* @brief Reset the lp_core module
*
*/
static inline void lp_core_ll_reset_register(void)
{
/* ESP32C6 does not have clk/rst periph control for LP-core */
}
/**
* @brief Enable fast access of LP memory
*
* @note When fast access is activated, LP-core cannot access LP mem during deep sleep
*
* @param enable Enable if true, disable if false
*/
static inline void lp_core_ll_fast_lp_mem_enable(bool enable)
{
LP_AON.lpbus.fast_mem_mux_sel = enable;
LP_AON.lpbus.fast_mem_mux_sel_update = 1;
}
/**
* @brief Trigger a LP_CORE_LL_WAKEUP_SOURCE_HP_CPU wake-up on the LP-core
*
*/
static inline void lp_core_ll_hp_wake_lp(void)
{
PMU.hp_lp_cpu_comm.hp_trigger_lp = 1;
}
/**
* @brief Enable the debug module of LP-core, allowing JTAG to connect
*
* @param enable Enable if true, disable if false
*/
static inline void lp_core_ll_debug_module_enable(bool enable)
{
LPPERI.cpu.lpcore_dbgm_unavaliable = !enable;
}
/**
* @brief Enable CPU reset at sleep
*
* @param enable Enable if true, disable if false
*/
static inline void lp_core_ll_rst_at_sleep_enable(bool enable)
{
PMU.lp_ext.pwr0.slp_reset_en = enable;
}
/**
* @brief Stall LP-core at sleep requests
*
* @param enable Enable if true, disable if false
*/
static inline void lp_core_ll_stall_at_sleep_request(bool enable)
{
PMU.lp_ext.pwr0.slp_stall_en = enable;
}
/**
* @brief Set wake-up sources for the LP-core
*
* @param flags Wake-up sources
*/
static inline void lp_core_ll_set_wakeup_source(uint32_t flags)
{
PMU.lp_ext.pwr1.wakeup_en = flags;
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,138 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
/*******************************************************************************
* NOTICE
* The hal is not public api, don't use it in application code.
******************************************************************************/
#pragma once
#include <stdbool.h>
#include "soc/lpperi_struct.h"
#include "soc/pmu_struct.h"
#include "soc/lp_system_struct.h"
#ifdef __cplusplus
extern "C" {
#endif
#define LP_CORE_LL_WAKEUP_SOURCE_LP_IO BIT(9)
#define LP_CORE_LL_WAKEUP_SOURCE_LP_UART BIT(10)
#define LP_CORE_LL_WAKEUP_SOURCE_LP_TIMER_0 BIT(13)
#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_HP_CPU BIT(22)
/* Use lp timer 1 as the normal wakeup timer, timer 0 is used by deep sleep */
#define LP_CORE_LL_WAKEUP_SOURCE_LP_TIMER LP_CORE_LL_WAKEUP_SOURCE_LP_TIMER_1
/**
* @brief Enable the bus clock for LP-coree
*
* @param enable true to enable, false to disable
*/
static inline void lp_core_ll_enable_bus_clock(bool enable)
{
LPPERI.clk_en.ck_en_lp_core = 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 lp_core_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; lp_core_ll_enable_bus_clock(__VA_ARGS__)
/**
* @brief Reset the lp_core module
*
*/
static inline void lp_core_ll_reset_register(void)
{
LPPERI.reset_en.rst_en_lp_core = 1;
LPPERI.reset_en.rst_en_lp_core = 0;
}
/// 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 lp_core_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; lp_core_ll_reset_register(__VA_ARGS__)
/**
* @brief Trigger a LP_CORE_LL_WAKEUP_SOURCE_HP_CPU wake-up on the lp core
*
*/
static inline void lp_core_ll_hp_wake_lp(void)
{
PMU.hp_lp_cpu_comm.hp_trigger_lp = 1;
}
/**
* @brief Enables the LP core debug module, allowing JTAG to connect
*
* @param enable enable if true, disable if false
*/
static inline void lp_core_ll_debug_module_enable(bool enable)
{
LPPERI.cpu.lpcore_dbgm_unavailable = !enable;
}
/**
* @brief Enables CPU reset at sleep
*
* @param enable enable if true, disable if false
*/
static inline void lp_core_ll_rst_at_sleep_enable(bool enable)
{
PMU.lp_cpu_pwr0.lp_cpu_slp_reset_en = enable;
}
/**
* @brief Stall lp core cpu at sleep request
*
* @param enable enable if true, disable if false
*/
static inline void lp_core_ll_stall_at_sleep_request(bool enable)
{
PMU.lp_cpu_pwr0.lp_cpu_slp_stall_en = enable;
}
/**
* @brief Set the wake-up source for the lp-core
*
* @param flags wake-up sources
*/
static inline void lp_core_ll_set_wakeup_source(uint32_t flags)
{
PMU.lp_cpu_pwr2.lp_cpu_wakeup_en = flags;
}
/**
* @brief Set boot address for lp core
*
* @param boot_address address which the lp core will start booting from
*/
static inline void lp_core_ll_set_boot_address(intptr_t boot_address)
{
LP_SYS.lp_core_boot_addr.lp_cpu_boot_addr = boot_address;
}
/**
* @brief Set address LP-ROM bootloader will jump to after initialization
*
* @param boot_address address which the LP-ROM bootloader will jump to
*/
static inline void lp_core_ll_set_app_boot_address(intptr_t boot_address)
{
LP_SYS.boot_addr_hp_lp_reg.boot_addr_hp_lp = boot_address;
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,72 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
// The LL layer for ESP32-P4 LP_Timer register operations
#pragma once
#include <stdlib.h>
#include "soc/soc.h"
#include "soc/rtc.h"
#include "soc/lp_timer_struct.h"
#include "soc/lp_system_reg.h"
#include "hal/lp_timer_types.h"
#include "esp_attr.h"
#ifdef __cplusplus
extern "C" {
#endif
FORCE_INLINE_ATTR void lp_timer_ll_set_alarm_target(lp_timer_dev_t *dev, uint8_t timer_id, uint64_t value)
{
dev->target[timer_id].hi.target_hi = (value >> 32) & 0xFFFF;
dev->target[timer_id].lo.target_lo = value & 0xFFFFFFFF;
}
FORCE_INLINE_ATTR void lp_timer_ll_set_target_enable(lp_timer_dev_t *dev, uint8_t timer_id, bool en)
{
dev->target[timer_id].hi.enable = en;
}
FORCE_INLINE_ATTR uint32_t lp_timer_ll_get_counter_value_low(lp_timer_dev_t *dev, uint8_t timer_id)
{
return dev->counter[timer_id].lo.counter_lo;
}
FORCE_INLINE_ATTR uint32_t lp_timer_ll_get_counter_value_high(lp_timer_dev_t *dev, uint8_t timer_id)
{
return dev->counter[timer_id].hi.counter_hi;
}
FORCE_INLINE_ATTR void lp_timer_ll_counter_snapshot(lp_timer_dev_t *dev)
{
dev->update.main_timer_update = 1;
}
FORCE_INLINE_ATTR void lp_timer_ll_clear_alarm_intr_status(lp_timer_dev_t *dev)
{
dev->int_clr.soc_wakeup_int_clr = 1;
}
FORCE_INLINE_ATTR void lp_timer_ll_clear_overflow_intr_status(lp_timer_dev_t *dev)
{
dev->int_clr.overflow_clr = 1;
}
FORCE_INLINE_ATTR void lp_timer_ll_clear_lp_alarm_intr_status(lp_timer_dev_t *dev)
{
dev->lp_int_clr.main_timer_lp_int_clr = 1;
}
FORCE_INLINE_ATTR uint64_t lp_timer_ll_time_to_count(uint64_t time_in_us)
{
uint32_t slow_clk_value = REG_READ(LP_SYSTEM_REG_LP_STORE1_REG);
return ((time_in_us * (1 << RTC_CLK_CAL_FRACT)) / slow_clk_value);
}
#ifdef __cplusplus
}
#endif

View File

@ -55,6 +55,14 @@ config SOC_SUPPORTS_SECURE_DL_MODE
bool
default y
config SOC_ULP_SUPPORTED
bool
default y
config SOC_LP_CORE_SUPPORTED
bool
default y
config SOC_EFUSE_KEY_PURPOSE_FIELD
bool
default y
@ -127,6 +135,10 @@ config SOC_SECURE_BOOT_SUPPORTED
bool
default y
config SOC_LP_TIMER_SUPPORTED
bool
default y
config SOC_LP_GPIO_MATRIX_SUPPORTED
bool
default y

View File

@ -10,68 +10,22 @@
extern "C" {
#endif
/** Group: configure_register */
/** Type of tar0_low register
* need_des
*/
typedef union {
struct {
/** main_timer_tar_low0 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t main_timer_tar_low0:32;
};
uint32_t val;
} lp_timer_tar0_low_reg_t;
/** Type of tar0_high register
* need_des
*/
typedef union {
struct {
/** main_timer_tar_high0 : R/W; bitpos: [15:0]; default: 0;
* need_des
*/
uint32_t main_timer_tar_high0:16;
uint32_t reserved_16:15;
/** main_timer_tar_en0 : WT; bitpos: [31]; default: 0;
* need_des
*/
uint32_t main_timer_tar_en0:1;
};
uint32_t val;
} lp_timer_tar0_high_reg_t;
/** Type of tar1_low register
* need_des
*/
typedef union {
struct {
/** main_timer_tar_low1 : R/W; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t main_timer_tar_low1:32;
};
uint32_t val;
} lp_timer_tar1_low_reg_t;
/** Type of tar1_high register
* need_des
*/
typedef union {
struct {
/** main_timer_tar_high1 : R/W; bitpos: [15:0]; default: 0;
* need_des
*/
uint32_t main_timer_tar_high1:16;
uint32_t reserved_16:15;
/** main_timer_tar_en1 : WT; bitpos: [31]; default: 0;
* need_des
*/
uint32_t main_timer_tar_en1:1;
};
uint32_t val;
} lp_timer_tar1_high_reg_t;
typedef struct {
union {
struct {
uint32_t target_lo: 32;
};
uint32_t val;
} lo;
union {
struct {
uint32_t target_hi: 16;
uint32_t reserved0: 15;
uint32_t enable : 1;
};
uint32_t val;
} hi;
} lp_timer_target_reg_t;
/** Type of update register
* need_des
@ -99,59 +53,22 @@ typedef union {
uint32_t val;
} lp_timer_update_reg_t;
/** Type of main_buf0_low register
* need_des
*/
typedef union {
struct {
/** main_timer_buf0_low : RO; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t main_timer_buf0_low:32;
};
uint32_t val;
} lp_timer_main_buf0_low_reg_t;
typedef struct {
union {
struct {
uint32_t counter_lo: 32;
};
uint32_t val;
} lo;
union {
struct {
uint32_t counter_hi: 16;
uint32_t reserved0 : 16;
};
uint32_t val;
} hi;
} lp_timer_counter_reg_t;
/** Type of main_buf0_high register
* need_des
*/
typedef union {
struct {
/** main_timer_buf0_high : RO; bitpos: [15:0]; default: 0;
* need_des
*/
uint32_t main_timer_buf0_high:16;
uint32_t reserved_16:16;
};
uint32_t val;
} lp_timer_main_buf0_high_reg_t;
/** Type of main_buf1_low register
* need_des
*/
typedef union {
struct {
/** main_timer_buf1_low : RO; bitpos: [31:0]; default: 0;
* need_des
*/
uint32_t main_timer_buf1_low:32;
};
uint32_t val;
} lp_timer_main_buf1_low_reg_t;
/** Type of main_buf1_high register
* need_des
*/
typedef union {
struct {
/** main_timer_buf1_high : RO; bitpos: [15:0]; default: 0;
* need_des
*/
uint32_t main_timer_buf1_high:16;
uint32_t reserved_16:16;
};
uint32_t val;
} lp_timer_main_buf1_high_reg_t;
/** Type of main_overflow register
* need_des
@ -330,15 +247,9 @@ typedef union {
typedef struct {
volatile lp_timer_tar0_low_reg_t tar0_low;
volatile lp_timer_tar0_high_reg_t tar0_high;
volatile lp_timer_tar1_low_reg_t tar1_low;
volatile lp_timer_tar1_high_reg_t tar1_high;
volatile lp_timer_update_reg_t update;
volatile lp_timer_main_buf0_low_reg_t main_buf0_low;
volatile lp_timer_main_buf0_high_reg_t main_buf0_high;
volatile lp_timer_main_buf1_low_reg_t main_buf1_low;
volatile lp_timer_main_buf1_high_reg_t main_buf1_high;
volatile lp_timer_target_reg_t target[2];
volatile lp_timer_update_reg_t update;
volatile lp_timer_counter_reg_t counter[2];
volatile lp_timer_main_overflow_reg_t main_overflow;
volatile lp_timer_int_raw_reg_t int_raw;
volatile lp_timer_int_st_reg_t int_st;
@ -352,6 +263,7 @@ typedef struct {
volatile lp_timer_date_reg_t date;
} lp_timer_dev_t;
extern lp_timer_dev_t LP_TIMER;
#ifndef __cplusplus
_Static_assert(sizeof(lp_timer_dev_t) == 0x400, "Invalid size of lp_timer_dev_t structure");

View File

@ -41,7 +41,8 @@
// #define SOC_USB_SERIAL_JTAG_SUPPORTED 1 //TODO: IDF-7496
// #define SOC_TEMP_SENSOR_SUPPORTED 1 //TODO: IDF-7482
#define SOC_SUPPORTS_SECURE_DL_MODE 1
// #define SOC_RISCV_COPROC_SUPPORTED 1
#define SOC_ULP_SUPPORTED 1
#define SOC_LP_CORE_SUPPORTED 1
#define SOC_EFUSE_KEY_PURPOSE_FIELD 1
#define SOC_EFUSE_SUPPORTED 1
#define SOC_RTC_FAST_MEM_SUPPORTED 1
@ -68,7 +69,7 @@
// #define SOC_APM_SUPPORTED 1 //TODO: IDF-7542
// #define SOC_PMU_SUPPORTED 1 //TODO: IDF-7531
// #define SOC_PAU_SUPPORTED 1 //TODO: IDF-7531
// #define SOC_LP_TIMER_SUPPORTED 1 //TODO: IDF-7532
#define SOC_LP_TIMER_SUPPORTED 1
// #define SOC_ULP_LP_UART_SUPPORTED 1 //TODO: IDF-7533
#define SOC_LP_GPIO_MATRIX_SUPPORTED 1
#define SOC_LP_PERIPHERALS_SUPPORTED 1

View File

@ -55,8 +55,12 @@ if(CONFIG_ULP_COPROC_TYPE_LP_CORE)
"lp_core/lp_core.c"
"lp_core/shared/ulp_lp_core_memory_shared.c"
"lp_core/shared/ulp_lp_core_lp_timer_shared.c"
"lp_core/lp_core_i2c.c"
"lp_core/lp_core_uart.c")
if(CONFIG_IDF_TARGET_ESP32C6)
# Add to P4 TODO IDF-7540
list(APPEND srcs "lp_core/lp_core_i2c.c")
endif()
endif()
idf_component_register(SRCS ${srcs}

View File

@ -34,6 +34,7 @@ menu "Ultra Low Power (ULP) Co-processor"
default 4096 if !IDF_TARGET_ESP32
range 32 8176 if !IDF_TARGET_ESP32C6
range 32 16352 if IDF_TARGET_ESP32C6
range 32 32768 if IDF_TARGET_ESP32P4
help
Bytes of memory to reserve for ULP Co-processor firmware & data.
Data is reserved at the beginning of RTC slow memory.

View File

@ -86,11 +86,12 @@ elseif(ULP_COCPU_IS_LP_CORE)
"${IDF_PATH}/components/ulp/lp_core/shared/ulp_lp_core_lp_timer_shared.c"
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_startup.c"
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_utils.c"
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_i2c.c"
"${IDF_PATH}/components/hal/uart_hal_iram.c"
"${IDF_PATH}/components/hal/uart_hal.c"
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_uart.c"
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_print.c")
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_print.c"
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_i2c.c")
target_link_options(${ULP_APP_NAME} PRIVATE "-nostartfiles")
target_link_options(${ULP_APP_NAME} PRIVATE "-Wl,--no-warn-rwx-segments")
@ -98,6 +99,16 @@ elseif(ULP_COCPU_IS_LP_CORE)
target_link_options(${ULP_APP_NAME} PRIVATE -Wl,-Map=${CMAKE_CURRENT_BINARY_DIR}/${ULP_APP_NAME}.map)
target_link_options(${ULP_APP_NAME}
PRIVATE SHELL:-T ${IDF_PATH}/components/soc/${IDF_TARGET}/ld/${IDF_TARGET}.peripherals.ld)
if(CONFIG_ESP_ROM_HAS_LP_ROM)
target_link_options(${ULP_APP_NAME}
PRIVATE SHELL:-T ${IDF_PATH}/components/esp_rom/${IDF_TARGET}/ld/${IDF_TARGET}lp.rom.ld)
target_link_options(${ULP_APP_NAME}
PRIVATE SHELL:-T ${IDF_PATH}/components/esp_rom/${IDF_TARGET}/ld/${IDF_TARGET}lp.rom.newlib.ld)
target_link_options(${ULP_APP_NAME}
PRIVATE SHELL:-T ${IDF_PATH}/components/esp_rom/${IDF_TARGET}/ld/${IDF_TARGET}lp.rom.version.ld)
endif()
target_sources(${ULP_APP_NAME} PRIVATE ${ULP_S_SOURCES})
target_include_directories(${ULP_APP_NAME} PRIVATE "${IDF_PATH}/components/ulp/lp_core/lp_core/include"
"${IDF_PATH}/components/ulp/lp_core/shared/include")

View File

@ -4,14 +4,15 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "sdkconfig.h"
#include "soc/soc.h"
ENTRY(reset_vector)
MEMORY
{
/*first 128byte for exception/interrupt vectors*/
vector_table(RX) : ORIGIN = 0x50000000, LENGTH = 0x80
ram(RWX) : ORIGIN = 0x50000080, LENGTH = CONFIG_ULP_COPROC_RESERVE_MEM - 0x80 - CONFIG_ULP_SHARED_MEM
vector_table(RX) : ORIGIN = SOC_RTC_DRAM_LOW, LENGTH = 0x80
ram(RWX) : ORIGIN = SOC_RTC_DRAM_LOW + 0x80, LENGTH = CONFIG_ULP_COPROC_RESERVE_MEM - 0x80 - CONFIG_ULP_SHARED_MEM
}
SECTIONS

View File

@ -5,18 +5,49 @@
*/
#include "sdkconfig.h"
#include "esp_rom_caps.h"
#include "esp_log.h"
#include "esp_assert.h"
#include "soc/pmu_reg.h"
#include "soc/lp_aon_reg.h"
#include "soc/lpperi_reg.h"
#include "hal/misc.h"
#include "esp_private/periph_ctrl.h"
#include "ulp_common.h"
#include "ulp_lp_core.h"
#include "ulp_lp_core_memory_shared.h"
#include "ulp_lp_core_lp_timer_shared.h"
#include "hal/lp_core_ll.h"
#if CONFIG_IDF_TARGET_ESP32P4
#define LP_CORE_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
#else
#define LP_CORE_RCC_ATOMIC()
#endif
const static char* TAG = "ulp-lp-core";
#define WAKEUP_SOURCE_MAX_NUMBER 5
/* Maps the flags defined in ulp_lp_core.h e.g. ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU to their actual HW values */
static uint32_t wakeup_src_sw_to_hw_flag_lookup[WAKEUP_SOURCE_MAX_NUMBER] = {
LP_CORE_LL_WAKEUP_SOURCE_HP_CPU,
LP_CORE_LL_WAKEUP_SOURCE_LP_UART,
LP_CORE_LL_WAKEUP_SOURCE_LP_IO,
LP_CORE_LL_WAKEUP_SOURCE_ETM,
LP_CORE_LL_WAKEUP_SOURCE_LP_TIMER,
};
/* Convert the wake-up sources defined in ulp_lp_core.h to the actual HW wake-up source values */
static uint32_t lp_core_get_wakeup_source_hw_flags(uint32_t flags)
{
uint32_t hw_flags = 0;
for(int i = 0; i < WAKEUP_SOURCE_MAX_NUMBER; i++) {
if (flags & (1 << i)) {
hw_flags |= wakeup_src_sw_to_hw_flag_lookup[i];
}
}
return hw_flags;
}
esp_err_t ulp_lp_core_run(ulp_lp_core_cfg_t* cfg)
{
if (!cfg->wakeup_source) {
@ -26,27 +57,36 @@ esp_err_t ulp_lp_core_run(ulp_lp_core_cfg_t* cfg)
ulp_lp_core_memory_shared_cfg_t* shared_mem = ulp_lp_core_memory_shared_cfg_get();
/* Enable LP-Core */
REG_CLR_BIT(LP_AON_LPCORE_REG, LP_AON_LPCORE_DISABLE);
#if ESP_ROM_HAS_LP_ROM
/* If we have a LP ROM we boot from it, before jumping to the app code */
lp_core_ll_set_boot_address(SOC_LP_ROM_LOW);
lp_core_ll_set_app_boot_address(RTC_SLOW_MEM);
#endif //ESP_ROM_HAS_LP_ROM
/* Allow LP core to access LP memory during sleep */
REG_CLR_BIT(LP_AON_LPBUS_REG, LP_AON_FAST_MEM_MUX_SEL);
REG_SET_BIT(LP_AON_LPBUS_REG, LP_AON_FAST_MEM_MUX_SEL_UPDATE);
LP_CORE_RCC_ATOMIC() {
lp_core_ll_reset_register();
lp_core_ll_enable_bus_clock(true);
}
#if CONFIG_IDF_TARGET_ESP32C6
/* Disable fast LP mem access to allow LP core to access LP memory during sleep */
lp_core_ll_fast_lp_mem_enable(false);
#endif //CONFIG_IDF_TARGET_ESP32C6
/* Enable stall at sleep request*/
REG_SET_FIELD(PMU_LP_CPU_PWR0_REG, PMU_LP_CPU_SLP_STALL_EN, 1);
lp_core_ll_stall_at_sleep_request(true);
/* Enable reset after wake-up */
REG_SET_BIT(PMU_LP_CPU_PWR0_REG, PMU_LP_CPU_SLP_RESET_EN);
/* Enable reset CPU when going to sleep */
lp_core_ll_rst_at_sleep_enable(true);
/* Set wake-up sources */
REG_SET_FIELD(PMU_LP_CPU_PWR1_REG, PMU_LP_CPU_WAKEUP_EN, cfg->wakeup_source);
lp_core_ll_set_wakeup_source(lp_core_get_wakeup_source_hw_flags(cfg->wakeup_source));
/* Enable JTAG debugging */
REG_CLR_BIT(LPPERI_CPU_REG, LPPERI_LPCORE_DBGM_UNAVALIABLE);
lp_core_ll_debug_module_enable(true);
if (cfg->wakeup_source & ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU) {
REG_SET_FIELD(PMU_HP_LP_CPU_COMM_REG, PMU_HP_TRIGGER_LP, 1);
lp_core_ll_hp_wake_lp();
}
if (cfg->wakeup_source & ULP_LP_CORE_WAKEUP_SOURCE_LP_TIMER) {

View File

@ -4,6 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "sdkconfig.h"
#include "ulp_lp_core_i2c.h"
#include "ulp_lp_core_utils.h"
#include "soc/lp_i2c_reg.h"
@ -18,6 +19,8 @@
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#if !CONFIG_IDF_TARGET_ESP32P4 // # Add to P4 TODO IDF-7540
/* I2C LL context */
i2c_dev_t *dev = I2C_LL_GET_HW(LP_I2C_NUM_0);
@ -475,3 +478,5 @@ esp_err_t lp_core_i2c_master_write_read_device(i2c_port_t lp_i2c_num, uint16_t d
return ret;
}
#endif //!CONFIG_IDF_TARGET_ESP32P4

View File

@ -11,7 +11,11 @@
#include "soc/pmu_reg.h"
/* LP_FAST_CLK is not very accurate, for now use a rough estimate */
#if CONFIG_IDF_TARGET_ESP32C6
#define LP_CORE_CPU_FREQUENCY_HZ 16000000
#elif CONFIG_IDF_TARGET_ESP32P4
#define LP_CORE_CPU_FREQUENCY_HZ 20000000
#endif
/**
* @brief Wakeup main CPU from sleep or deep sleep.

View File

@ -1,3 +1,3 @@
| Supported Targets | ESP32-C6 |
| ----------------- | -------- |
| Supported Targets | ESP32-C6 | ESP32-P4 |
| ----------------- | -------- | -------- |

View File

@ -1,10 +1,19 @@
set(app_sources "test_app_main.c" "test_lp_core.c" "test_lp_core_i2c.c")
set(app_sources "test_app_main.c" "test_lp_core.c")
# Add to P4 TODO IDF-7540
if(CONFIG_IDF_TARGET_ESP32C6)
list(APPEND app_sources "test_lp_core_i2c.c")
endif()
set(lp_core_sources "lp_core/test_main.c")
set(lp_core_sources_counter "lp_core/test_main_counter.c")
set(lp_core_sources_set_timer_wakeup "lp_core/test_main_set_timer_wakeup.c")
set(lp_core_sources_gpio "lp_core/test_main_gpio.c")
set(lp_core_sources_i2c "lp_core/test_main_i2c.c")
# Add to P4 TODO IDF-7540
if(CONFIG_IDF_TARGET_ESP32C6)
set(lp_core_sources_i2c "lp_core/test_main_i2c.c")
endif()
idf_component_register(SRCS ${app_sources}
INCLUDE_DIRS "lp_core"
@ -17,4 +26,8 @@ ulp_embed_binary(lp_core_test_app "${lp_core_sources}" "${lp_core_exp_dep_srcs}"
ulp_embed_binary(lp_core_test_app_counter "${lp_core_sources_counter}" "${lp_core_exp_dep_srcs}")
ulp_embed_binary(lp_core_test_app_set_timer_wakeup "${lp_core_sources_set_timer_wakeup}" "${lp_core_exp_dep_srcs}")
ulp_embed_binary(lp_core_test_app_gpio "${lp_core_sources_gpio}" "${lp_core_exp_dep_srcs}")
ulp_embed_binary(lp_core_test_app_i2c "${lp_core_sources_i2c}" "${lp_core_exp_dep_srcs}")
# Add to P4 TODO IDF-7540
if(CONFIG_IDF_TARGET_ESP32C6)
ulp_embed_binary(lp_core_test_app_i2c "${lp_core_sources_i2c}" "${lp_core_exp_dep_srcs}")
endif()

View File

@ -112,6 +112,10 @@ TEST_CASE("Test LP core delay", "[lp_core]")
ulp_command_resp = LP_CORE_NO_COMMAND;
}
#define LP_TIMER_TEST_DURATION_S (5)
#define LP_TIMER_TEST_SLEEP_DURATION_US (20000)
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32P4)
static void do_ulp_wakeup_deepsleep(lp_core_test_commands_t ulp_cmd)
{
@ -158,31 +162,6 @@ TEST_CASE_MULTIPLE_STAGES("LP-core is able to wakeup main CPU from deep sleep af
do_ulp_wakeup_after_long_delay_deepsleep,
check_reset_reason_ulp_wakeup);
#define LP_TIMER_TEST_DURATION_S (5)
#define LP_TIMER_TEST_SLEEP_DURATION_US (20000)
TEST_CASE("LP Timer can wakeup lp core periodically", "[lp_core]")
{
int64_t start, test_duration;
/* Load ULP firmware and start the coprocessor */
ulp_lp_core_cfg_t cfg = {
.wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_LP_TIMER,
.lp_timer_sleep_duration_us = LP_TIMER_TEST_SLEEP_DURATION_US,
};
load_and_start_lp_core_firmware(&cfg, lp_core_main_counter_bin_start, lp_core_main_counter_bin_end);
start = esp_timer_get_time();
vTaskDelay(pdMS_TO_TICKS(LP_TIMER_TEST_DURATION_S*1000));
test_duration = esp_timer_get_time() - start;
uint32_t expected_run_count = test_duration / LP_TIMER_TEST_SLEEP_DURATION_US;
printf("LP core ran %"PRIu32" times in %"PRIi64" ms, expected it to run approx %"PRIu32" times\n", ulp_counter, test_duration/1000, expected_run_count);
TEST_ASSERT_INT_WITHIN_MESSAGE(5, expected_run_count, ulp_counter, "LP Core did not wake up the expected number of times");
}
RTC_FAST_ATTR static struct timeval tv_start;
#define ULP_COUNTER_WAKEUP_LIMIT_CNT 50
@ -229,6 +208,31 @@ TEST_CASE_MULTIPLE_STAGES("LP Timer can wakeup lp core periodically during deep
do_ulp_wakeup_with_lp_timer_deepsleep,
check_reset_reason_and_sleep_duration);
#endif //#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32P4)
TEST_CASE("LP Timer can wakeup lp core periodically", "[lp_core]")
{
int64_t start, test_duration;
/* Load ULP firmware and start the coprocessor */
ulp_lp_core_cfg_t cfg = {
.wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_LP_TIMER,
.lp_timer_sleep_duration_us = LP_TIMER_TEST_SLEEP_DURATION_US,
};
load_and_start_lp_core_firmware(&cfg, lp_core_main_counter_bin_start, lp_core_main_counter_bin_end);
start = esp_timer_get_time();
vTaskDelay(pdMS_TO_TICKS(LP_TIMER_TEST_DURATION_S*1000));
test_duration = esp_timer_get_time() - start;
uint32_t expected_run_count = test_duration / LP_TIMER_TEST_SLEEP_DURATION_US;
printf("LP core ran %"PRIu32" times in %"PRIi64" ms, expected it to run approx %"PRIu32" times\n", ulp_counter, test_duration/1000, expected_run_count);
TEST_ASSERT_INT_WITHIN_MESSAGE(5, expected_run_count, ulp_counter, "LP Core did not wake up the expected number of times");
}
static bool ulp_is_running(uint32_t *counter_variable)
{
uint32_t start_cnt = *counter_variable;

View File

@ -0,0 +1,19 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __ULP_COMMON_DEFS_H__
#define __ULP_COMMON_DEFS_H__
#ifdef __cplusplus
extern "C" {
#endif
#define RTC_SLOW_MEM (0x50108000) /*!< LP memory, 32k size */
#ifdef __cplusplus
}
#endif
#endif // __ULP_COMMON_DEFS_H__

View File

@ -1 +1,10 @@
INPUT += \
$(PROJECT_PATH)/components/ulp/lp_core/include/lp_core_i2c.h \
$(PROJECT_PATH)/components/ulp/lp_core/include/lp_core_uart.h \
$(PROJECT_PATH)/components/ulp/lp_core/include/ulp_lp_core.h \
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_gpio.h \
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_i2c.h \
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_print.h \
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_uart.h \
$(PROJECT_PATH)/components/ulp/lp_core/lp_core/include/ulp_lp_core_utils.h \
$(PROJECT_PATH)/components/ulp/ulp_common/include/ulp_common.h \

View File

@ -21,7 +21,7 @@ GPIO driver offers a dump function :cpp:func:`gpio_dump_io_configuration` to sho
FuncSel: 1 (GPIO)
GPIO Matrix SigIn ID: (simple GPIO input)
SleepSelEn: 1
IO[18] -
Pullup: 0, Pulldown: 0, DriveCap: 2
InputEn: 0, OutputEn: 1, OpenDrain: 0
@ -34,7 +34,7 @@ GPIO driver offers a dump function :cpp:func:`gpio_dump_io_configuration` to sho
InputEn: 1, OutputEn: 0, OpenDrain: 0
FuncSel: 0 (IOMUX)
SleepSelEn: 1
=================IO DUMP End==================
If an IO pin is routed to a peripheral signal through the GPIO matrix, the signal ID printed in the dump information is defined in the ``soc/gpio_sig_map.h`` file. The word ``**RESERVED**`` indicates the IO is occupied by either FLASH or PSRAM. It is strongly not recommended to reconfigure them for other application purposes.
@ -44,7 +44,7 @@ If an IO pin is routed to a peripheral signal through the GPIO matrix, the signa
.. only:: not SOC_LP_PERIPHERALS_SUPPORTED
There is also separate "RTC GPIO" support, which functions when GPIOs are routed to the "RTC" low-power and analog subsystem. These pin functions can be used when:
.. only:: SOC_LP_PERIPHERALS_SUPPORTED
There is also separate "RTC GPIO" support, which functions when GPIOs are routed to the "RTC" low-power, analog subsystem, and Low-Power(LP) peripherals. These pin functions can be used when:
@ -52,7 +52,9 @@ If an IO pin is routed to a peripheral signal through the GPIO matrix, the signa
.. list::
- In Deep-sleep mode
:SOC_ULP_SUPPORTED and not esp32c6: - The :doc:`Ultra Low Power co-processor <../../api-reference/system/ulp>` is running
:SOC_ULP_FSM_SUPPORTED: - The :doc:`Ultra Low Power FSM co-processor <../../api-reference/system/ulp>` is running
:SOC_RISCV_COPROC_SUPPORTED: - The :doc:`Ultra Low Power RISC-V co-processor <../../api-reference/system/ulp-risc-v>` is running
:SOC_LP_CORE_SUPPORTED: - The :doc:`Ultra Low Power LP-Core co-processor <../../api-reference/system/ulp-lp-core>` is running
- Analog functions such as ADC/DAC/etc are in use
:SOC_LP_PERIPHERALS_SUPPORTED: - LP peripherals, such as LP_UART, LP_I2C, are in use

View File

@ -21,7 +21,7 @@ GPIO 驱动提供了一个函数 :cpp:func:`gpio_dump_io_configuration` 用来
FuncSel: 1 (GPIO)
GPIO Matrix SigIn ID: (simple GPIO input)
SleepSelEn: 1
IO[18] -
Pullup: 0, Pulldown: 0, DriveCap: 2
InputEn: 0, OutputEn: 1, OpenDrain: 0
@ -34,7 +34,7 @@ GPIO 驱动提供了一个函数 :cpp:func:`gpio_dump_io_configuration` 用来
InputEn: 1, OutputEn: 0, OpenDrain: 0
FuncSel: 0 (IOMUX)
SleepSelEn: 1
=================IO DUMP End==================
当 IO 管脚是通过 GPIO 交换矩阵连接到内部外设信号,输出信息打印中的外设信号 ID 定义可以在 ``soc/gpio_sig_map.h`` 文件中查看。``**RESERVED**`` 字样则表示此 IO 被用于连接 FLASH 或 PSRAM因此该引脚不应该被其他任何应用场景所征用并进行重新配置。
@ -52,7 +52,9 @@ GPIO 驱动提供了一个函数 :cpp:func:`gpio_dump_io_configuration` 用来
.. list::
- 处于 Deep-sleep 模式时
:SOC_ULP_SUPPORTED and not esp32c6: - :doc:`超低功耗协处理器 (ULP) <../../api-reference/system/ulp>` 运行时
:SOC_ULP_FSM_SUPPORTED: - :doc:`超低功耗协处理器 (ULP-FSM) <../../api-reference/system/ulp>` 运行时
:SOC_RISCV_COPROC_SUPPORTED: - :doc:`超低功耗协处理器 (ULP-RISC-V) <../../api-reference/system/ulp-risc-v>` 运行时
:SOC_LP_CORE_SUPPORTED: - :doc:`超低功耗协处理器 (ULP-LP-Core) <../../api-reference/system/ulp-lp-core>` 运行时
- 使用 ADC/DAC 等模拟功能时
:SOC_LP_PERIPHERALS_SUPPORTED: - 使用低功耗外设时,例如: LP_UART LP_I2C 等

View File

@ -244,24 +244,38 @@ examples/system/task_watchdog:
examples/system/ulp/lp_core/gpio:
enable:
- if: SOC_LP_CORE_SUPPORTED == 1
disable:
- if: IDF_TARGET == "esp32p4"
temporary: true
reason: target esp32p4 is not supported yet, TODO IDF-7536
depends_components:
- ulp
examples/system/ulp/lp_core/lp_i2c:
enable:
- if: SOC_LP_I2C_SUPPORTED == 1
disable:
- if: IDF_TARGET == "esp32p4"
temporary: true
reason: target esp32p4 is not supported yet, TODO IDF-7540
depends_components:
- ulp
examples/system/ulp/lp_core/lp_uart/lp_uart_echo:
disable:
- if: SOC_ULP_LP_UART_SUPPORTED != 1
- if: IDF_TARGET == "esp32p4"
temporary: true
reason: target esp32p4 is not supported yet TODO IDF-7533
depends_components:
- ulp
examples/system/ulp/lp_core/lp_uart/lp_uart_print:
disable:
- if: SOC_ULP_LP_UART_SUPPORTED != 1
- if: IDF_TARGET == "esp32p4"
temporary: true
reason: target esp32p4 is not supported yet TODO IDF-7533
depends_components:
- ulp

View File

@ -1252,7 +1252,6 @@ examples/system/ota/otatool/main/otatool_main.c
examples/system/ota/otatool/otatool_example.py
examples/system/ota/simple_ota_example/main/simple_ota_example.c
examples/system/perfmon/main/perfmon_example_main.c
examples/system/pthread/main/pthread_example.c
examples/system/select/main/select_example.c
examples/system/startup_time/main/hello_world_main.c
examples/system/sysview_tracing/main/sysview_tracing.c