Merge branch 'feature/ulp_esp32s31' into 'master'

feat(ulp): add support for ulp on esp32s31

Closes IDF-14640

See merge request espressif/esp-idf!47268
This commit is contained in:
Marius Vikhammer
2026-04-20 19:19:35 +08:00
51 changed files with 536 additions and 101 deletions
@@ -13,6 +13,11 @@
#include "esp_cpu.h"
#include "hal/apm_hal.h"
#if CONFIG_IDF_TARGET_ESP32S31
#include "soc/hp_peri0_pms_reg.h"
#include "soc/hp_peri1_pms_reg.h"
#include "soc/lp_peri_pms_reg.h"
#endif
void bootloader_init_mem(void)
{
@@ -37,6 +42,22 @@ void bootloader_init_mem(void)
#endif // SOC_APM_CTRL_FILTER_SUPPORTED
#endif
#if CONFIG_IDF_TARGET_ESP32S31
/* TODO: [ESP32S31] IDF-14620
As a temp. fix to allow ULP access to all peripherals during bringup.
Open all LP/HP peripheral PMS control registers for all security modes.
*/
for (uint32_t reg = LP_PERI_PMS_LP_SYSREG_CTRL_REG; reg <= LP_PERI_PMS_LP_DAC_CTRL_REG; reg += 4) {
REG_WRITE(reg, 0xFF);
}
for (uint32_t reg = HP_PERI0_PMS_TRACE0_CTRL_REG; reg <= HP_PERI0_PMS_AXI_PERF_MON_CTRL_REG; reg += 4) {
REG_WRITE(reg, 0xFF);
}
for (uint32_t reg = HP_PERI1_PMS_HP_USBOTG_PHY_CTRL_REG; reg <= HP_PERI1_PMS_HP_PERI1_PMS_CTRL_REG; reg += 4) {
REG_WRITE(reg, 0xFF);
}
#endif
#if CONFIG_BOOTLOADER_REGION_PROTECTION_ENABLE
// protect memory region
esp_cpu_configure_region_protection();
@@ -20,6 +20,10 @@
extern "C" {
#endif
// Aliases used by LP core code (lp_core_utils.c) which references LP_TIMER naming convention
#define LP_TIMER RTC_TIMER
#define LP_TIMER_MAIN_TIMER_LP_INT_RAW RTC_TIMER_MAIN_TIMER_LP_INT_RAW
FORCE_INLINE_ATTR void rtc_timer_ll_set_alarm_target(rtc_timer_dev_t *dev, uint8_t timer_id, uint64_t value)
{
HAL_FORCE_MODIFY_U32_REG_FIELD(dev->target[timer_id].hi, target_hi, (value >> 32) & 0xFFFF);
@@ -32,3 +32,24 @@ config RTC_CLK_CAL_CYCLES
- 32768 Hz if the 32k crystal oscillator is used. For this use value 3000 or more.
In case more value will help improve the definition of the launch of the crystal.
If the crystal could not start, it will be switched to internal RC.
choice RTC_FAST_CLK_SRC
depends on SOC_CLK_LP_FAST_SUPPORT_XTAL
prompt "RTC fast clock source"
default RTC_FAST_CLK_SRC_RC_FAST
help
Choose which clock is used as RTC fast clock source.
Choosing the faster 40 MHz XTAL can allow modules which depend on RTC_FAST
to work at a higher clock frequency. With this the ULP LP-Core will run with a
CPU frequency of 40 Mhz instead of the default 20 Mhz.
The drawback is that the XTAL is usually powered down during sleep, as
it draw a lot of power. Choosing this option will cause the XTAL to stay
powered on, increasing sleep power consumption.
config RTC_FAST_CLK_SRC_RC_FAST
bool "20 Mhz RC Fast Clock"
config RTC_FAST_CLK_SRC_XTAL
bool "40 Mhz crystal (increased power consumption during sleep)"
endchoice
@@ -61,10 +61,14 @@ MEMORY
#endif // CONFIG_APP_BUILD_USE_FLASH_SECTIONS
/**
* lp ram memory (RWX). Persists over deep sleep. // TODO: IDF-5667
* lp ram memory (RWX). Persists over deep sleep.
*/
/* TODO: ["ESP32S31"] IDF-14640 */
lp_ram_seg(RW) : org = 0x2E000000, len = 0x8000 - RESERVE_RTC_MEM
#if CONFIG_ULP_COPROC_ENABLED
lp_ram_seg(RW) : org = 0x2E000000 + CONFIG_ULP_COPROC_RESERVE_MEM,
len = 0x8000 - CONFIG_ULP_COPROC_RESERVE_MEM - RESERVE_RTC_MEM
#else
lp_ram_seg(RW) : org = 0x2E000000, len = 0x8000 - RESERVE_RTC_MEM
#endif // CONFIG_ULP_COPROC_ENABLED
/* We reduced the size of lp_ram_seg by RESERVE_RTC_MEM value.
It reserves the amount of LP memory that we use for this memory segment.
@@ -72,10 +76,8 @@ MEMORY
- (lower addr) rtc timer data (s_rtc_timer_retain_mem, see esp_clk.c files).
- (higher addr) bootloader rtc data (s_bootloader_retain_mem, when a Kconfig option is on).
The aim of this is to keep data that will not be moved around and have a fixed address.
This segment is placed at the beginning of LP RAM, as the end of LP RAM is occupied by LP ROM stack/data
*/
/* TODO: ["ESP32S31"] IDF-14640 */
lp_reserved_seg(RW) : org = 0x2E000000 + 0x8000 - RESERVE_RTC_MEM, len = RESERVE_RTC_MEM
lp_reserved_seg(RW) : org = 0x2E000000 + 0x8000 - RESERVE_RTC_MEM, len = RESERVE_RTC_MEM
/* PSRAM seg */
extern_ram_seg(RWX) : org = 0x50000000, len = IDROM_SEG_SIZE
@@ -92,14 +94,12 @@ REGION_ALIAS("dram_seg", sram_seg);
* S31 has no distinguished LP(RTC) fast and slow memory sections, instead, there is a unified LP_RAM section
* Thus, the following region segments are not configurable like on other targets
*/
/* TODO: ["ESP32S31"] IDF-14640 */
REGION_ALIAS("rtc_text_seg", lp_ram_seg);
REGION_ALIAS("rtc_data_seg", lp_ram_seg);
REGION_ALIAS("rtc_slow_seg", lp_ram_seg);
REGION_ALIAS("rtc_force_fast_seg", lp_ram_seg);
REGION_ALIAS("rtc_force_slow_seg", lp_ram_seg);
REGION_ALIAS("rtc_reserved_seg", lp_reserved_seg );
REGION_ALIAS("rtc_reserved_seg", lp_reserved_seg);
#if CONFIG_APP_BUILD_USE_FLASH_SECTIONS
REGION_ALIAS("flash_text_seg", irom_seg);
@@ -9,9 +9,6 @@ ENTRY(call_start_cpu0);
SECTIONS
{
/**
* RTC memory should be implemented here TODO: [ESP32S31] IDF-14640
*/
#include "ld.rtc.sections"
#include "ld.iram.sections"
@@ -0,0 +1,190 @@
/*
* SPDX-FileCopyrightText: 2026 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 <stdint.h>
#include "soc/lp_peri_clkrst_struct.h"
#include "soc/lp_system_struct.h"
#include "soc/pmu_struct.h"
#ifdef __cplusplus
extern "C" {
#endif
#define LP_CORE_LL_WAKEUP_SOURCE_HP_CPU BIT(1) // SW_WAKEUP_HP
#define LP_CORE_LL_WAKEUP_SOURCE_LP_IO BIT(9) // LP_GPIO_WAKEUP
#define LP_CORE_LL_WAKEUP_SOURCE_LP_UART BIT(10) // LP_UART_WAKEUP
#define LP_CORE_LL_WAKEUP_SOURCE_LP_TIMER_0 BIT(13) // LP_TMR_WAKEUP[0]
#define LP_CORE_LL_WAKEUP_SOURCE_ETM BIT(17) // REG_ETM_LPCORE_WAKEUP
#define LP_CORE_LL_WAKEUP_SOURCE_LP_TIMER_1 BIT(18)
/* 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 Set the boot address of the LP-core
*
* @param boot_address Boot address
*/
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 Enable the bus clock for LP-core
*
* @param enable true to enable, false to disable
*/
static inline void _lp_core_ll_enable_bus_clock(bool enable)
{
LP_PERI_CLKRST.cpu_ctrl.lp_core_clk_force_on = enable;
LP_PERI_CLKRST.intr_ctrl.lp_intr_clk_en = 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(...) do { \
(void)__DECLARE_RCC_ATOMIC_ENV; \
_lp_core_ll_enable_bus_clock(__VA_ARGS__); \
} while(0)
/**
* @brief Reset the LP-core module
*/
static inline void lp_core_ll_reset_register(void)
{
LP_PERI_CLKRST.cpu_ctrl.lp_core_rst_en = 1;
LP_PERI_CLKRST.intr_ctrl.lp_intr_rst_en = 1;
LP_PERI_CLKRST.cpu_ctrl.lp_core_rst_en = 0;
LP_PERI_CLKRST.intr_ctrl.lp_intr_rst_en = 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(...) do { \
(void)__DECLARE_RCC_ATOMIC_ENV; \
lp_core_ll_reset_register(__VA_ARGS__); \
} while(0)
/**
* @brief Enable fast access of LP memory
*
* @note ESP32-S31 does not have a separate fast LP memory bus mux.
* This function is a no-op kept for API compatibility.
*
* @param enable Enable if true, disable if false
*/
static inline void lp_core_ll_fast_lp_mem_enable(bool enable)
{
/* ESP32-S31 does not have a fast_mem_mux_sel equivalent */
(void)enable;
}
/**
* @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)
{
LP_PERI_CLKRST.cpu.lpcore_dbgm_unavailable = !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 (see LP_CORE_LL_WAKEUP_SOURCE_* defines)
*/
static inline void lp_core_ll_set_wakeup_source(uint32_t flags)
{
PMU.lp_ext.pwr2.wakeup_en = flags;
}
/**
* @brief Get wake-up sources for the LP-core
*/
static inline uint32_t lp_core_ll_get_wakeup_source(void)
{
return PMU.lp_ext.pwr2.wakeup_en;
}
/**
* @brief Request PMU to put LP-core to sleep
*/
static inline void lp_core_ll_request_sleep(void)
{
PMU.lp_ext.pwr1.sleep_req = 1;
}
/**
* @brief Enable wakeup from LP UART
*
* @param enable enable if true, disable if false
*/
static inline void lp_core_ll_enable_lp_uart_wakeup(bool enable)
{
LP_PERI_CLKRST.uart_misc_ctrl.lp_uart_wakeup_en = enable;
}
/**
* @brief Get the flag that marks whether LP CPU is awakened by ETM
*
* @return Return true if lpcore is woken up by soc_etm
*/
static inline bool lp_core_ll_get_etm_wakeup_flag(void)
{
return LP_SYS.sys_ctrl.lp_core_etm_wakeup_flag;
}
/**
* @brief Clear the flag that marks whether LP CPU is awakened by ETM
*/
static inline void lp_core_ll_clear_etm_wakeup_flag(void)
{
LP_SYS.sys_ctrl.lp_core_etm_wakeup_flag_clr = 0x01;
}
#ifdef __cplusplus
}
#endif
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -103,6 +103,8 @@ SOC_RESERVE_MEMORY_REGION( SOC_EXTRAM_LOW, SOC_EXTRAM_HIGH, extram_region);
#ifdef CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP
SOC_RESERVE_MEMORY_REGION(SOC_RTC_DRAM_LOW, (intptr_t)&_rtc_force_slow_end, rtcram_data);
SOC_RESERVE_MEMORY_REGION((intptr_t)&_rtc_reserved_start, (intptr_t)&_rtc_reserved_end, rtc_reserved_data);
/* Reserve LP RAM from base up to end of .rtc.force_slow (includes ULP code/data area) */
SOC_RESERVE_MEMORY_REGION(SOC_LP_RAM_LOW, (intptr_t)&_rtc_force_slow_end, rtcram_data);
#endif
SOC_RESERVE_MEMORY_REGION((intptr_t)&_rtc_reserved_start, (intptr_t)&_rtc_reserved_end, rtc_reserved_data);
@@ -1610,3 +1610,7 @@ config SOC_LP_CORE_SUPPORT_ETM
config SOC_LP_CORE_SUPPORT_STORE_LOAD_EXCEPTIONS
bool
default y
config SOC_LP_CORE_SUPPORT_I2C
bool
default y
@@ -644,3 +644,4 @@
#define SOC_LP_CORE_SINGLE_INTERRUPT_VECTOR (1) /*!< LP Core interrupts all map to a single entry in vector table */
#define SOC_LP_CORE_SUPPORT_ETM (1) /*!< LP Core supports ETM */
#define SOC_LP_CORE_SUPPORT_STORE_LOAD_EXCEPTIONS (1) /*!< LP Core will raise exceptions if accessing invalid addresses */
#define SOC_LP_CORE_SUPPORT_I2C (1) /*!< LP Core supports I2C */
@@ -1363,6 +1363,10 @@ config SOC_LP_CORE_SUPPORT_ETM
bool
default y
config SOC_LP_CORE_SUPPORT_I2C
bool
default y
config SOC_DEBUG_HAVE_OCD_STUB_BINS
bool
default y
@@ -554,6 +554,7 @@
/*------------------------------------- ULP CAPS -------------------------------------*/
#define SOC_LP_CORE_SINGLE_INTERRUPT_VECTOR (1) /*!< LP Core interrupts all map to a single entry in vector table */
#define SOC_LP_CORE_SUPPORT_ETM (1) /*!< LP Core supports ETM */
#define SOC_LP_CORE_SUPPORT_I2C (1) /*!< LP Core supports I2C */
/*------------------------------------- DEBUG CAPS -------------------------------------*/
#define SOC_DEBUG_HAVE_OCD_STUB_BINS (1)
@@ -1918,3 +1918,7 @@ config SOC_LP_CORE_SUPPORT_LP_ADC
config SOC_LP_CORE_SUPPORT_STORE_LOAD_EXCEPTIONS
bool
default y
config SOC_LP_CORE_SUPPORT_I2C
bool
default y
@@ -735,3 +735,4 @@
#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_STORE_LOAD_EXCEPTIONS (1) /*!< LP Core will raise exceptions if accessing invalid addresses */
#define SOC_LP_CORE_SUPPORT_I2C (1) /*!< LP Core supports I2C */
@@ -59,6 +59,14 @@ config SOC_USB_OTG_SUPPORTED
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
@@ -1027,6 +1035,14 @@ config SOC_PM_RETENTION_MODULE_NUM
int
default 64
config SOC_LP_CORE_SUPPORT_ETM
bool
default y
config SOC_LP_CORE_CONFIGURABLE_BOOT_ADDR
bool
default y
config SOC_LP_TIMER_BIT_WIDTH_LO
int
default 32
@@ -190,6 +190,9 @@ typedef enum {
extern const char * const esp_isr_names[ETS_MAX_INTR_SOURCE];
// ESP32-S31 names the PMU interrupt source ETS_PMT_INTR_SOURCE; alias for cross-chip compatibility
#define ETS_PMU_INTR_SOURCE ETS_PMT_INTR_SOURCE
#ifdef __cplusplus
}
#endif
@@ -49,8 +49,8 @@
// #define SOC_USB_SERIAL_JTAG_SUPPORTED 1 // TODO: [ESP32S31] IDF-14788
// #define SOC_TEMP_SENSOR_SUPPORTED 1 // TODO: [ESP32S31] IDF-14799
// #define SOC_SUPPORTS_SECURE_DL_MODE 1 // TODO: [ESP32S31] IDF-14629
// #define SOC_ULP_SUPPORTED 1 // TODO: [ESP32S31] IDF-14640
// #define SOC_LP_CORE_SUPPORTED 1 // TODO: [ESP32S31] IDF-14640
#define SOC_ULP_SUPPORTED 1
#define SOC_LP_CORE_SUPPORTED 1
#define SOC_EFUSE_KEY_PURPOSE_FIELD 1 // TODO: [ESP32S31] IDF-14688
#define SOC_EFUSE_SUPPORTED 1 // TODO: [ESP32S31] IDF-14688
#define SOC_RTC_FAST_MEM_SUPPORTED 1
@@ -445,6 +445,12 @@
#define SOC_PM_RETENTION_MODULE_NUM (64)
/*-------------------------- LP_CORE CAPS ------------------------------------*/
// #define SOC_LP_MAILBOX_SUPPORTED (1) // TODO: [ESP32S31] IDF-14637
#define SOC_LP_CORE_SUPPORT_ETM (1) /*!< LP Core supports ETM wakeup */
#define SOC_LP_CORE_CONFIGURABLE_BOOT_ADDR (1) /*!< LP Core has no LP ROM; HP must write the reset_vector address (LP_RAM_BASE+0x80) to LP_SYS.lp_core_boot_addr before triggering LP wake */
//#define SOC_LP_CORE_SUPPORT_I2C (1) /*!< LP Core supports I2C */ TODO IDF-14635
/*-------------------------- LP_TIMER CAPS ----------------------------------*/
#define SOC_LP_TIMER_BIT_WIDTH_LO 32 // Bit width of lp_timer low part
#define SOC_LP_TIMER_BIT_WIDTH_HI 16 // Bit width of lp_timer high part
@@ -856,7 +856,6 @@ typedef struct {
volatile mb_reg_clk_en_reg_t reg_clk_en;
} mb_dev_t;
#ifndef __cplusplus
_Static_assert(sizeof(mb_dev_t) == 0x64, "Invalid size of mb_dev_t structure");
#endif
@@ -1019,6 +1019,8 @@ typedef struct {
} lp_pwr_dev_t;
extern lp_pwr_dev_t LP_PWR;
#ifndef __cplusplus
_Static_assert(sizeof(lp_pwr_dev_t) == 0xa8, "Invalid size of lp_pwr_dev_t structure");
#endif
@@ -137,6 +137,7 @@
#define DR_REG_INTERRUPT_CORE0_BASE DR_REG_INTR0_BASE
#define DR_REG_INTERRUPT_CORE1_BASE (DR_REG_INTR0_BASE + 0x800)
#define DR_REG_LPPERI_BASE DR_REG_LP_PERICLKRST_BASE
#define DR_REG_LP_PWR_BASE DR_REG_LP_PWR_REG_BASE /* alias used by lp_pwr_reg.h */
#define DR_REG_SDHOST_BASE DR_REG_SDMMC_BASE
#define DR_REG_TRACE_BASE DR_REG_TRACE0_BASE
#define DR_REG_MB_BASE DR_REG_LP_MAILBOX_BASE
+2 -2
View File
@@ -62,11 +62,11 @@ if(CONFIG_ULP_COPROC_TYPE_LP_CORE)
"lp_core/shared/ulp_lp_core_lp_uart_shared.c")
endif()
if(CONFIG_SOC_LP_I2C_SUPPORTED)
if(CONFIG_SOC_LP_CORE_SUPPORT_I2C)
list(APPEND srcs "lp_core/lp_core_i2c.c")
endif()
if(CONFIG_SOC_RTC_TIMER_V2)
if(CONFIG_SOC_RTC_TIMER_V2 OR CONFIG_SOC_RTC_TIMER_V3)
list(APPEND srcs "lp_core/shared/ulp_lp_core_lp_timer_shared.c")
endif()
+19 -8
View File
@@ -168,26 +168,37 @@ function(ulp_apply_default_sources ulp_app_name)
"${IDF_PATH}/components/ulp/lp_core/lp_core/vector.S"
"${IDF_PATH}/components/ulp/lp_core/lp_core/port/${IDF_TARGET}/vector_table.S"
"${IDF_PATH}/components/ulp/lp_core/shared/ulp_lp_core_memory_shared.c"
"${IDF_PATH}/components/ulp/lp_core/shared/ulp_lp_core_lp_uart_shared.c"
"${IDF_PATH}/components/esp_driver_uart/src/uart_wakeup.c"
"${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/esp_hal_uart/uart_hal_iram.c"
"${IDF_PATH}/components/esp_hal_uart/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_panic.c"
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_interrupt.c"
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_i2c.c"
"${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/lp_core/lp_core_mailbox.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")
if(CONFIG_SOC_LP_CORE_SUPPORT_I2C)
list(APPEND ULP_S_SOURCES
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_i2c.c")
endif()
if(CONFIG_SOC_LP_SPI_SUPPORTED)
list(APPEND ULP_S_SOURCES
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_spi.c")
endif()
if(CONFIG_SOC_ULP_LP_UART_SUPPORTED)
list(APPEND ULP_S_SOURCES
"${IDF_PATH}/components/ulp/lp_core/shared/ulp_lp_core_lp_uart_shared.c"
"${IDF_PATH}/components/esp_driver_uart/src/uart_wakeup.c"
"${IDF_PATH}/components/esp_hal_uart/uart_hal_iram.c"
"${IDF_PATH}/components/esp_hal_uart/uart_hal.c"
"${IDF_PATH}/components/ulp/lp_core/lp_core/lp_core_uart.c")
endif()
if(CONFIG_SOC_LP_MAILBOX_SUPPORTED)
list(APPEND ULP_S_SOURCES
"${IDF_PATH}/components/ulp/lp_core/lp_core/port/lp_core_mailbox_impl_hw.c")
+6 -1
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -15,6 +15,9 @@ extern "C" {
#include "hal/i2c_types.h"
#include "hal/gpio_types.h"
#include "esp_err.h"
#include "soc/soc_caps.h"
#if SOC_LP_CORE_SUPPORT_I2C
/**
* @brief LP Core I2C pin config parameters
@@ -95,6 +98,8 @@ typedef struct {
*/
esp_err_t lp_core_i2c_master_init(i2c_port_t lp_i2c_num, const lp_core_i2c_cfg_t *cfg);
#endif /* SOC_LP_CORE_SUPPORT_I2C */
#ifdef __cplusplus
}
#endif
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -14,6 +14,9 @@ extern "C" {
#include "esp_err.h"
#include "hal/uart_types.h"
#include "hal/gpio_types.h"
#include "soc/soc_caps.h"
#if SOC_ULP_LP_UART_SUPPORTED
/**
* Default LP_IO Mux pins for LP UART
@@ -101,6 +104,8 @@ typedef struct {
*/
esp_err_t lp_core_uart_init(const lp_core_uart_cfg_t *cfg);
#endif /* SOC_ULP_LP_UART_SUPPORTED */
#ifdef __cplusplus
}
#endif
+10 -1
View File
@@ -1,11 +1,12 @@
/*
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "sdkconfig.h"
#include "esp_rom_caps.h"
#include "soc/soc.h"
#include "soc/soc_caps.h"
#include "esp_log.h"
#include "esp_assert.h"
@@ -86,6 +87,14 @@ esp_err_t ulp_lp_core_run(ulp_lp_core_cfg_t* cfg)
#endif //ESP_ROM_HAS_LP_ROM
#if SOC_LP_CORE_CONFIGURABLE_BOOT_ADDR
/* Chips without LP ROM but with a SW-configurable boot address register
* (e.g. ESP32-S31) must set the boot address explicitly. The hardware
* default points to SOC_RTC_DRAM_LOW (the interrupt vector table base),
* not to reset_vector which is placed 0x80 bytes into LP RAM. */
lp_core_ll_set_boot_address((intptr_t)SOC_RTC_DRAM_LOW + 0x80);
#endif // SOC_LP_CORE_CONFIGURABLE_BOOT_ADDR
PERIPH_RCC_ATOMIC() {
#if CONFIG_ULP_NORESET_UNDER_DEBUG
/* lp_core module reset causes loss of configured HW breakpoints and dcsr.ebreak* */
@@ -100,7 +100,7 @@ esp_err_t lp_core_i2c_master_write_read_device(i2c_port_t lp_i2c_num, uint16_t d
*/
void lp_core_i2c_master_set_ack_check_en(i2c_port_t lp_i2c_num, bool ack_check_en);
#if SOC_LP_I2C_SUPPORTED
#if SOC_LP_CORE_SUPPORT_I2C
/**
* @brief Enable LP I2C master-related interrupts at the peripheral
*
@@ -126,7 +126,7 @@ static inline void ulp_lp_core_lp_i2c_intr_disable(i2c_port_t lp_i2c_num, uint32
HAL_ASSERT(lp_i2c_num == LP_I2C_NUM_0);
i2c_ll_disable_intr_mask(I2C_LL_GET_HW(lp_i2c_num), mask);
}
#endif /* SOC_LP_I2C_SUPPORTED */
#endif /* SOC_LP_CORE_SUPPORT_I2C */
#ifdef __cplusplus
}
+2 -2
View File
@@ -13,7 +13,7 @@
#include "soc/i2c_struct.h"
#include "hal/i2c_ll.h"
#if SOC_LP_I2C_SUPPORTED
#if SOC_LP_CORE_SUPPORT_I2C
#define LP_I2C_FIFO_LEN I2C_LL_GET(LP_FIFO_LEN)
#define LP_I2C_READ_MODE I2C_MASTER_READ
@@ -471,4 +471,4 @@ esp_err_t lp_core_i2c_master_write_read_device(i2c_port_t lp_i2c_num, uint16_t d
return ret;
}
#endif /* SOC_LP_I2C_SUPPORTED */
#endif /* SOC_LP_CORE_SUPPORT_I2C */
@@ -9,7 +9,6 @@
#include "hal/uart_hal.h"
#include "esp_rom_serial_output.h"
#define LP_UART_PORT_NUM LP_UART_NUM_0
#define BINARY_SUPPORT 1
#define is_digit(c) ((c >= '0') && (c <= '9'))
@@ -26,8 +25,9 @@ static void hp_uart_send_char(char t)
}
uart_ll_write_txfifo(uart, &t, 1);
}
#elif !CONFIG_ULP_ROM_PRINT_ENABLE
#elif !CONFIG_ULP_ROM_PRINT_ENABLE && CONFIG_SOC_ULP_LP_UART_SUPPORTED
void __attribute__((alias("lp_uart_send_char"))) lp_core_print_char(char c);
#define LP_UART_PORT_NUM LP_UART_NUM_0
static void lp_uart_send_char(char c)
{
int tx_len = 0;
@@ -0,0 +1,49 @@
/*
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
.section .init.vector,"ax"
.global _vector_table
.type _vector_table, @function
_vector_table:
.option push
.option norvc
j _panic_handler
j _panic_handler
j _panic_handler
j ulp_lp_core_sw_intr_handler
j _panic_handler
j _panic_handler
j _panic_handler
j ulp_lp_core_lp_uart_intr_handler
j _panic_handler
j _panic_handler
j _panic_handler
j ulp_lp_core_lp_spi_intr_handler
j _panic_handler
j _panic_handler
j _panic_handler
j _panic_handler
j ulp_lp_core_trng_intr_handler
j ulp_lp_core_lp_i2c_intr_handler
j ulp_lp_core_lp_io_intr_handler
j ulp_lp_core_lp_adc_intr_handler
j ulp_lp_core_lp_touch_intr_handler
j ulp_lp_core_tsens_intr_handler
j ulp_lp_core_efuse_intr_handler
j ulp_lp_core_lp_sysreg_intr_handler
j ulp_lp_core_lp_ana_peri_intr_handler
j ulp_lp_core_lp_pmu_intr_handler
j ulp_lp_core_mailbox_intr_handler
j ulp_lp_core_lp_timer_intr_handler
j ulp_lp_core_lp_wdt_intr_handler
j ulp_lp_core_lp_rtc_intr_handler
j _panic_handler
j _panic_handler
.option pop
.size _vector_table, .-_vector_table
@@ -4,6 +4,9 @@ components/ulp/test_apps/lp_core/lp_core_basic_tests:
disable:
- if: SOC_LP_CORE_SUPPORTED != 1
- if: CONFIG_NAME == "xtal" and SOC_CLK_LP_FAST_SUPPORT_XTAL != 1
- if: IDF_TARGET in ["esp32s31"] and CONFIG_NAME == "xtal"
temporary: true
reason: CONFIG_RTC_FAST_CLK_SRC_XTAL not supported yet # TODO: [ESP32S31] IDF-15576
- if: CONFIG_NAME == "lp_vad" and SOC_LP_VAD_SUPPORTED != 1
depends_components:
- ulp
@@ -1,3 +1,3 @@
| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-P4 |
| ----------------- | -------- | -------- | -------- |
| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-P4 | ESP32-S31 |
| ----------------- | -------- | -------- | -------- | --------- |
@@ -1,6 +1,6 @@
set(app_sources "test_app_main.c" "test_lp_core.c")
if(CONFIG_SOC_LP_I2C_SUPPORTED)
if(CONFIG_SOC_LP_CORE_SUPPORT_I2C)
list(APPEND app_sources "test_lp_core_i2c.c")
endif()
@@ -37,7 +37,7 @@ endif()
set(lp_core_sources_gpio "lp_core/test_main_gpio.c")
if(CONFIG_SOC_LP_I2C_SUPPORTED)
if(CONFIG_SOC_LP_CORE_SUPPORT_I2C)
set(lp_core_sources_i2c "lp_core/test_main_i2c.c")
endif()
@@ -79,7 +79,7 @@ endif()
ulp_embed_binary(lp_core_test_app_gpio "${lp_core_sources_gpio}" "${lp_core_exp_dep_srcs}")
if(CONFIG_SOC_LP_I2C_SUPPORTED)
if(CONFIG_SOC_LP_CORE_SUPPORT_I2C)
ulp_embed_binary(lp_core_test_app_i2c "${lp_core_sources_i2c}" "${lp_core_exp_dep_srcs}")
endif()
@@ -79,6 +79,24 @@ static void clear_test_cmds(void)
ulp_command_resp = LP_CORE_NO_COMMAND;
}
TEST_CASE("LP core boots and executes code", "[lp_core]")
{
ulp_lp_core_cfg_t cfg = {
.wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_HP_CPU,
};
ulp_counter = 0;
load_and_start_lp_core_firmware(&cfg, lp_core_main_counter_bin_start, lp_core_main_counter_bin_end);
int timeout_ms = 1000;
while (ulp_counter == 0 && timeout_ms-- > 0) {
vTaskDelay(pdMS_TO_TICKS(1));
}
TEST_ASSERT_MESSAGE(ulp_counter > 0, "LP core did not execute: counter stayed at 0");
}
TEST_CASE("LP core and main CPU are able to exchange data", "[lp_core]")
{
const uint32_t test_data = 0x12345678;
@@ -539,7 +557,7 @@ TEST_CASE("LP core can schedule next wake-up time by itself", "[ulp]")
TEST_ASSERT_INT_WITHIN_MESSAGE(5, expected_run_count, ulp_set_timer_wakeup_counter, "LP Core did not wake up the expected number of times");
}
#if SOC_RTCIO_PIN_COUNT > 0
#if SOC_RTCIO_PIN_COUNT > 0 && (SOC_RTCIO_INPUT_OUTPUT_SUPPORTED || SOC_LP_GPIO_MATRIX_SUPPORTED)
TEST_CASE("LP core gpio tests", "[ulp]")
{
/* Load ULP firmware and start the coprocessor */
@@ -583,7 +601,7 @@ TEST_CASE("LP core ISR tests", "[ulp]")
printf("ULP PMU ISR triggered %"PRIu32" times\n", ulp_pmu_isr_counter);
TEST_ASSERT_EQUAL(ISR_TEST_ITERATIONS, ulp_pmu_isr_counter);
#if SOC_RTCIO_PIN_COUNT > 0
#if SOC_RTCIO_PIN_COUNT > 0 && (SOC_RTCIO_INPUT_OUTPUT_SUPPORTED || SOC_LP_GPIO_MATRIX_SUPPORTED)
/* Test LP IO interrupt */
rtc_gpio_init(IO_TEST_PIN);
rtc_gpio_set_direction(IO_TEST_PIN, RTC_GPIO_MODE_INPUT_ONLY);
@@ -52,6 +52,7 @@ def test_lp_vad(dut: Dut) -> None:
# TODO: Support LP I2C test for esp32p4 (IDF-9581)
@pytest.mark.generic_multi_device
@pytest.mark.temp_skip_ci(targets=['esp32s31'], reason='TODO IDF-15572 Enable ULP multi device tests for ESP32-S31')
@pytest.mark.parametrize('count', [2], indirect=True)
@pytest.mark.parametrize(
'config',
@@ -66,6 +67,7 @@ def test_lp_core_multi_device(case_tester) -> None: # type: ignore
@pytest.mark.generic_multi_device
@pytest.mark.temp_skip_ci(targets=['esp32s31'], reason='TODO IDF-15572 Enable ULP multi device tests for ESP32-S31')
@pytest.mark.parametrize(
'target',
soc_filtered_targets('SOC_LP_CORE_SUPPORTED == 1'),
@@ -1,3 +1,3 @@
| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-P4 |
| ----------------- | -------- | -------- | -------- |
| Supported Targets | ESP32-C5 | ESP32-C6 | ESP32-P4 | ESP32-S31 |
| ----------------- | -------- | -------- | -------- | --------- |
@@ -17,6 +17,9 @@ def test_lp_core_hp_uart_print(dut: Dut) -> None:
@pytest.mark.generic
@pytest.mark.temp_skip_ci(
targets=['esp32s31'], reason='TODO IDF-15567 investigate esp32s31.default.test_lp_core_panic failure'
)
@idf_parametrize('target', soc_filtered_targets('SOC_LP_CORE_SUPPORTED == 1'), indirect=['target'])
def test_lp_core_panic(dut: Dut) -> None:
dut.expect_exact('Press ENTER to see the list of tests')