mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-01 10:40:47 +03:00
Merge branch 'feat/sys_event_in_freertos' into 'master'
feat(system_init): Introduce pre-scheduler and pre-app main handler registrations Closes IDF-16133 See merge request espressif/esp-idf!52296
This commit is contained in:
@@ -19,8 +19,8 @@ idf_component_optional_requires(PRIVATE mbedtls)
|
||||
|
||||
if(CONFIG_BOOTLOADER_APP_ROLLBACK_CONFIRM_ON_STARTUP)
|
||||
# ota_auto_confirm.c has no other externally referenced symbol, so force the linker to pull
|
||||
# it in from the archive to override the weak esp_ota_confirm_rollback_hook() in freertos.
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u esp_ota_confirm_rollback_hook")
|
||||
# its static PRE_APP_MAIN event registration from the archive.
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u esp_ota_auto_confirm_include")
|
||||
endif()
|
||||
|
||||
idf_define_esp_err_codes(HEADERS include/esp_ota_ops.h)
|
||||
|
||||
@@ -10,17 +10,20 @@
|
||||
|
||||
#include "esp_ota_ops.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_private/esp_sys_event_app_init.h"
|
||||
|
||||
ESP_LOG_ATTR_TAG(TAG, "ota_auto_confirm");
|
||||
|
||||
// Strong override of the weak hook declared in components/freertos/app_startup.c
|
||||
void esp_ota_confirm_rollback_hook(void)
|
||||
ESP_PRE_APP_MAIN_HANDLER_REGISTER(esp_ota_auto_confirm, 200)
|
||||
{
|
||||
(void)user_arg;
|
||||
(void)ctx;
|
||||
|
||||
esp_ota_img_states_t ota_state;
|
||||
const esp_partition_t *running = esp_ota_get_running_partition();
|
||||
|
||||
if (esp_ota_get_state_partition(running, &ota_state) != ESP_OK) {
|
||||
return;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) {
|
||||
@@ -33,13 +36,16 @@ void esp_ota_confirm_rollback_hook(void)
|
||||
ESP_LOGW(TAG, "Bootloader is not capable of rollback");
|
||||
|
||||
} else {
|
||||
return;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t err = esp_ota_mark_app_valid_cancel_rollback();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to mark app valid: %s", esp_err_to_name(err));
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void esp_ota_auto_confirm_include(void) {}
|
||||
|
||||
#endif /* CONFIG_BOOTLOADER_APP_ROLLBACK_CONFIRM_ON_STARTUP */
|
||||
|
||||
@@ -34,3 +34,12 @@ if(CONFIG_ESP_SYSTEM_PANIC_GDBSTUB)
|
||||
# Make sure the panic event registration in gdbstub.c is considered by the linker
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u esp_gdbstub_panic_handler")
|
||||
endif()
|
||||
|
||||
if(CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME)
|
||||
# Pull in the PRE_SCHEDULER registration from gdbstub.c.
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u esp_gdbstub_init")
|
||||
if(CONFIG_IDF_TARGET_ARCH_XTENSA)
|
||||
# Pull in the Xtensa debug exception handler from its separate object file.
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u _xt_panic_gdbstub")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#endif
|
||||
|
||||
#include "esp_private/esp_sys_event_panic.h"
|
||||
#include "esp_private/esp_sys_event_app_init.h"
|
||||
#include "esp_private/panic_internal.h"
|
||||
#include "esp_private/crosscore_int.h"
|
||||
|
||||
@@ -451,6 +452,14 @@ void esp_gdbstub_init(void)
|
||||
esp_intr_alloc(ETS_UART0_INTR_SOURCE, 0, esp_gdbstub_int, NULL, NULL);
|
||||
esp_gdbstub_init_dports();
|
||||
}
|
||||
|
||||
ESP_PRE_SCHEDULER_HANDLER_REGISTER(init_gdbstub, 130)
|
||||
{
|
||||
(void)user_arg;
|
||||
(void)ctx;
|
||||
esp_gdbstub_init();
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif /* CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME */
|
||||
|
||||
#ifdef CONFIG_ESP_GDBSTUB_SUPPORT_TASKS
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "esp_private/esp_psram_mspi.h"
|
||||
#include "esp_private/mspi_mem_barrier.h"
|
||||
#include "esp_private/startup_internal.h"
|
||||
#include "esp_private/esp_sys_event_app_init.h"
|
||||
#if SOC_SPIRAM_XIP_SUPPORTED
|
||||
#include "esp_private/mmu_psram_flash.h"
|
||||
#endif
|
||||
@@ -675,6 +676,23 @@ esp_err_t esp_psram_extram_reserve_dma_pool(size_t size)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL
|
||||
ESP_PRE_APP_MAIN_HANDLER_REGISTER(reserve_dma_pool, 110)
|
||||
{
|
||||
(void)user_arg;
|
||||
(void)ctx;
|
||||
if (!esp_psram_is_initialized()) {
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t err = esp_psram_extram_reserve_dma_pool(CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Could not reserve internal/DMA pool (error 0x%x)", err);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool IRAM_ATTR __attribute__((pure)) esp_psram_is_initialized(void)
|
||||
{
|
||||
return s_psram_ctx.is_initialised;
|
||||
|
||||
@@ -198,6 +198,11 @@ endif()
|
||||
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u esp_system_include_startup_funcs")
|
||||
|
||||
if(CONFIG_ESP_INT_WDT)
|
||||
# Pull in the PRE_SCHEDULER registrations from int_wdt.c.
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u esp_int_wdt_init")
|
||||
endif()
|
||||
|
||||
# [refactor-todo] requirements due to init code, should be removable
|
||||
# once link-time registration of component init functions is used.
|
||||
if(NOT CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# This file is used to check the order of execution of ESP_SYSTEM_INIT_FN functions.
|
||||
# This file checks the order of execution of system startup handlers.
|
||||
# It compares the priorities found in .c source files to the contents of system_init_fn.txt
|
||||
# In case of an inconsistency, the script prints the differences found and returns with a
|
||||
# non-zero exit code.
|
||||
@@ -15,12 +15,47 @@ import re
|
||||
import sys
|
||||
|
||||
COMMENT_REGEX = re.compile(r'//.*?$|/\*.*?\*/', re.DOTALL | re.MULTILINE)
|
||||
ESP_SYSTEM_INIT_FN_REGEX_SIMPLE = re.compile(r'\bESP_SYSTEM_INIT_FN\s*\(')
|
||||
ESP_SYSTEM_INIT_FN_REGEX = re.compile(
|
||||
r'ESP_SYSTEM_INIT_FN\(([a-zA-Z0-9_]+)\s*,\s*([a-zA-Z\ _0-9\(\)|]+)\s*,\s*([a-zA-Z\ _0-9\(\)|]+)\s*,\s*([0-9]+)\)'
|
||||
ESP_SYSTEM_INIT_FN_REGEX = (
|
||||
r'{macro}\((?P<func>[a-zA-Z0-9_]+)\s*,\s*'
|
||||
r'(?P<stage>[a-zA-Z\ _0-9\(\)|]+)\s*,\s*'
|
||||
r'(?P<affinity>[a-zA-Z\ _0-9\(\)|]+)\s*,\s*'
|
||||
r'(?P<priority>[0-9]+)\)'
|
||||
)
|
||||
APP_INIT_FN_REGEX = r'{macro}\s*\(\s*(?P<func>[a-zA-Z0-9_]+)\s*,\s*(?P<priority>[0-9]+)\s*\)'
|
||||
STARTUP_REGISTRATIONS = (
|
||||
(
|
||||
'ESP_SYSTEM_INIT_FN',
|
||||
re.compile(ESP_SYSTEM_INIT_FN_REGEX.format(macro='ESP_SYSTEM_INIT_FN')),
|
||||
'',
|
||||
'',
|
||||
),
|
||||
(
|
||||
'ESP_PRE_SCHEDULER_HANDLER_REGISTER',
|
||||
re.compile(APP_INIT_FN_REGEX.format(macro='ESP_PRE_SCHEDULER_HANDLER_REGISTER')),
|
||||
'PRE_SCHEDULER',
|
||||
'BIT(0)',
|
||||
),
|
||||
(
|
||||
'ESP_PRE_SCHEDULER_HANDLER_REGISTER_PER_CPU',
|
||||
re.compile(APP_INIT_FN_REGEX.format(macro='ESP_PRE_SCHEDULER_HANDLER_REGISTER_PER_CPU')),
|
||||
'PRE_SCHEDULER',
|
||||
'ESP_SYSTEM_INIT_ALL_CORES',
|
||||
),
|
||||
(
|
||||
'ESP_PRE_APP_MAIN_HANDLER_REGISTER',
|
||||
re.compile(APP_INIT_FN_REGEX.format(macro='ESP_PRE_APP_MAIN_HANDLER_REGISTER')),
|
||||
'PRE_APP_MAIN',
|
||||
'MAIN_TASK',
|
||||
),
|
||||
)
|
||||
STARTUP_ENTRIES_FILE = 'components/esp_system/system_init_fn.txt'
|
||||
EXCLUDED_SOURCE_DIRS = {'test_apps', 'host_test', 'host_tests'}
|
||||
STAGE_ORDER = {
|
||||
'CORE': 0,
|
||||
'SECONDARY': 1,
|
||||
'PRE_SCHEDULER': 2,
|
||||
'PRE_APP_MAIN': 3,
|
||||
}
|
||||
|
||||
|
||||
class StartupEntry:
|
||||
@@ -69,36 +104,36 @@ def main() -> None:
|
||||
file_contents = f_obj.read()
|
||||
|
||||
file_contents_no_comments = strip_comments(file_contents)
|
||||
if not ESP_SYSTEM_INIT_FN_REGEX_SIMPLE.search(file_contents_no_comments):
|
||||
continue
|
||||
for macro, pattern, default_stage, default_affinity in STARTUP_REGISTRATIONS:
|
||||
count_expected = len(re.findall(rf'\b{macro}\s*\(', file_contents_no_comments))
|
||||
found = list(pattern.finditer(file_contents_no_comments))
|
||||
if len(found) != count_expected:
|
||||
print(
|
||||
f'error: In {filename}, found {macro} {count_expected} time(s), '
|
||||
f'but regular expression matched {len(found)} time(s)',
|
||||
file=sys.stderr,
|
||||
)
|
||||
has_errors = True
|
||||
|
||||
count_expected = len(ESP_SYSTEM_INIT_FN_REGEX_SIMPLE.findall(file_contents_no_comments))
|
||||
found = ESP_SYSTEM_INIT_FN_REGEX.findall(file_contents_no_comments)
|
||||
if len(found) != count_expected:
|
||||
print(
|
||||
(
|
||||
f'error: In {filename}, found ESP_SYSTEM_INIT_FN {count_expected} time(s), '
|
||||
f'but regular expression matched {len(found)} time(s)'
|
||||
),
|
||||
file=sys.stderr,
|
||||
)
|
||||
has_errors = True
|
||||
|
||||
for match in found:
|
||||
entry = StartupEntry(
|
||||
filename=relpath, func=match[0], stage=match[1], affinity=match[2], priority=int(match[3])
|
||||
)
|
||||
startup_entries.append(entry)
|
||||
for match in found:
|
||||
startup_entries.append(
|
||||
StartupEntry(
|
||||
relpath,
|
||||
match.group('func'),
|
||||
match.groupdict().get('stage') or default_stage,
|
||||
match.groupdict().get('affinity') or default_affinity,
|
||||
int(match.group('priority')),
|
||||
)
|
||||
)
|
||||
|
||||
#
|
||||
# 2. Sort the ESP_SYSTEM_INIT_FN functions in C source files.
|
||||
# 2. Sort the startup handlers in C source files.
|
||||
# In addition to the stage and priority, we also add filename to the sort key,
|
||||
# to have a stable sorting order in case when the same startup function is defined in multiple files,
|
||||
# for example for different targets.
|
||||
#
|
||||
def sort_key(entry: StartupEntry) -> tuple[str, int, str]:
|
||||
# luckily 'core' and 'secondary' are in alphabetical order, so we can return the string
|
||||
return (entry.stage, entry.priority, entry.filename)
|
||||
def sort_key(entry: StartupEntry) -> tuple[int, int, str]:
|
||||
return (STAGE_ORDER[entry.stage], entry.priority, entry.filename)
|
||||
|
||||
startup_entries = list(sorted(startup_entries, key=sort_key))
|
||||
startup_entries_lines = [str(entry) for entry in startup_entries]
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_debug_helpers.h"
|
||||
#include "esp_private/crosscore_int.h"
|
||||
#include "esp_private/esp_sys_event_app_init.h"
|
||||
#include "soc/periph_defs.h"
|
||||
#include "soc/system_intr.h"
|
||||
#include "hal/crosscore_int_ll.h"
|
||||
@@ -113,6 +114,14 @@ void esp_crosscore_int_init(void)
|
||||
ESP_ERROR_CHECK(err);
|
||||
}
|
||||
|
||||
ESP_PRE_SCHEDULER_HANDLER_REGISTER_PER_CPU(init_crosscore_interrupt, 120)
|
||||
{
|
||||
(void)user_arg;
|
||||
(void)ctx;
|
||||
esp_crosscore_int_init();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void ESP_SYSTEM_IRAM_ATTR esp_crosscore_int_send(int core_id, uint32_t reason_mask)
|
||||
{
|
||||
assert(core_id < CONFIG_FREERTOS_NUMBER_OF_CORES);
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "esp_cpu.h"
|
||||
#include "esp_private/esp_sys_event.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Register a handler to run on core 0 immediately before the scheduler starts
|
||||
*/
|
||||
#define ESP_PRE_SCHEDULER_HANDLER_REGISTER(fn, priority) \
|
||||
static esp_err_t fn(void *user_arg, void *ctx); \
|
||||
_ESP_SYS_EVENT_REGISTER(PRE_SCHEDULER, priority, __esp_pre_scheduler_##fn) \
|
||||
{ \
|
||||
if (esp_cpu_get_core_id() != 0) { \
|
||||
return ESP_OK; \
|
||||
} \
|
||||
return fn(user_arg, ctx); \
|
||||
} \
|
||||
static esp_err_t fn(void *user_arg, void *ctx)
|
||||
|
||||
/**
|
||||
* @brief Register a handler to run on every core immediately before its scheduler starts
|
||||
*/
|
||||
#define ESP_PRE_SCHEDULER_HANDLER_REGISTER_PER_CPU(fn, priority) \
|
||||
_ESP_SYS_EVENT_REGISTER(PRE_SCHEDULER, priority, fn)
|
||||
|
||||
/**
|
||||
* @brief Register a handler to run in the main task immediately before app_main
|
||||
*
|
||||
* Handlers run in ascending priority order after all CPUs have completed
|
||||
* FreeRTOS initialization. The scheduler and heap allocator are available.
|
||||
*/
|
||||
#define ESP_PRE_APP_MAIN_HANDLER_REGISTER(fn, priority) \
|
||||
_ESP_SYS_EVENT_REGISTER(PRE_APP_MAIN, priority, fn)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -34,6 +34,8 @@
|
||||
#define _ESP_SYS_EVENT_SECTION_SHUTDOWN esysev_shdn
|
||||
#define _ESP_SYS_EVENT_SECTION_SYSTEM_INIT_CORE esysev_initc
|
||||
#define _ESP_SYS_EVENT_SECTION_SYSTEM_INIT_SECONDARY esysev_inits
|
||||
#define _ESP_SYS_EVENT_SECTION_PRE_SCHEDULER esysev_presc
|
||||
#define _ESP_SYS_EVENT_SECTION_PRE_APP_MAIN esysev_pream
|
||||
#define _ESP_SYS_EVENT_SECTION_PANIC esysev_panic
|
||||
#define _ESP_SYS_EVENT_SECTION_PANIC_EARLY_BREAK esysev_paneb
|
||||
#endif
|
||||
@@ -42,5 +44,7 @@
|
||||
ESP_SYS_EVENT_DEF(SHUTDOWN)
|
||||
ESP_SYS_EVENT_DEF(SYSTEM_INIT_CORE)
|
||||
ESP_SYS_EVENT_DEF(SYSTEM_INIT_SECONDARY)
|
||||
ESP_SYS_EVENT_DEF(PRE_SCHEDULER)
|
||||
ESP_SYS_EVENT_DEF(PRE_APP_MAIN)
|
||||
ESP_SYS_EVENT_DEF(PANIC)
|
||||
ESP_SYS_EVENT_DEF(PANIC_EARLY_BREAK)
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "esp_freertos_hooks.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "esp_private/esp_int_wdt.h"
|
||||
#include "esp_private/esp_sys_event_app_init.h"
|
||||
#include "mwdt_priv.h"
|
||||
|
||||
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_MWDT_SUPPORT_SLEEP_RETENTION
|
||||
@@ -194,6 +195,22 @@ void esp_int_wdt_cpu_init(void)
|
||||
esp_intr_enable_source(ETS_INT_WDT_INUM);
|
||||
}
|
||||
|
||||
ESP_PRE_SCHEDULER_HANDLER_REGISTER(init_int_wdt, 100)
|
||||
{
|
||||
(void)user_arg;
|
||||
(void)ctx;
|
||||
esp_int_wdt_init();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
ESP_PRE_SCHEDULER_HANDLER_REGISTER_PER_CPU(init_int_wdt_cpu, 110)
|
||||
{
|
||||
(void)user_arg;
|
||||
(void)ctx;
|
||||
esp_int_wdt_cpu_init();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void ESP_SYSTEM_IRAM_ATTR esp_int_wdt_pause(void)
|
||||
{
|
||||
wdt_hal_write_protect_disable(&iwdt_context);
|
||||
|
||||
@@ -22,6 +22,16 @@ SECTIONS
|
||||
KEEP(*(SORT_BY_INIT_PRIORITY(.esysev_inits.*)))
|
||||
PROVIDE(_esysev_inits_end = .);
|
||||
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_esysev_presc_start = .);
|
||||
KEEP(*(SORT_BY_INIT_PRIORITY(.esysev_presc.*)))
|
||||
PROVIDE(_esysev_presc_end = .);
|
||||
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_esysev_pream_start = .);
|
||||
KEEP(*(SORT_BY_INIT_PRIORITY(.esysev_pream.*)))
|
||||
PROVIDE(_esysev_pream_end = .);
|
||||
|
||||
. = ALIGN(4);
|
||||
PROVIDE(_esysev_panic_start = .);
|
||||
KEEP(*(SORT_BY_INIT_PRIORITY(.esysev_panic.*)))
|
||||
|
||||
@@ -12,6 +12,14 @@ entries:
|
||||
entries:
|
||||
.esysev_inits+
|
||||
|
||||
[sections:esysev_presc]
|
||||
entries:
|
||||
.esysev_presc+
|
||||
|
||||
[sections:esysev_pream]
|
||||
entries:
|
||||
.esysev_pream+
|
||||
|
||||
[sections:esysev_panic]
|
||||
entries:
|
||||
.esysev_panic+
|
||||
@@ -26,6 +34,8 @@ entries:
|
||||
esysev_shdn -> flash_rodata
|
||||
esysev_initc -> flash_rodata
|
||||
esysev_inits -> flash_rodata
|
||||
esysev_presc -> flash_rodata
|
||||
esysev_pream -> flash_rodata
|
||||
esysev_panic -> flash_rodata
|
||||
esysev_paneb -> flash_rodata
|
||||
|
||||
@@ -36,6 +46,8 @@ entries:
|
||||
esysev_shdn -> flash_rodata ALIGN(4, pre) KEEP() SORT(init_priority) SURROUND(esysev_shdn),
|
||||
esysev_initc -> flash_rodata ALIGN(4, pre) KEEP() SORT(init_priority) SURROUND(esysev_initc),
|
||||
esysev_inits -> flash_rodata ALIGN(4, pre) KEEP() SORT(init_priority) SURROUND(esysev_inits),
|
||||
esysev_presc -> flash_rodata ALIGN(4, pre) KEEP() SORT(init_priority) SURROUND(esysev_presc),
|
||||
esysev_pream -> flash_rodata ALIGN(4, pre) KEEP() SORT(init_priority) SURROUND(esysev_pream),
|
||||
esysev_panic -> flash_rodata ALIGN(4, pre) KEEP() SORT(init_priority) SURROUND(esysev_panic),
|
||||
esysev_paneb -> flash_rodata ALIGN(4, pre) KEEP() SORT(init_priority) SURROUND(esysev_paneb)
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_attr.h"
|
||||
@@ -13,8 +14,10 @@
|
||||
#include "esp_check.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_chip_info.h"
|
||||
#include "esp_xt_wdt.h"
|
||||
#include "esp_cpu.h"
|
||||
#include "esp_private/esp_sys_event_app_init.h"
|
||||
#include "esp_private/startup_internal.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "soc/soc_caps.h"
|
||||
@@ -50,6 +53,16 @@ void esp_system_include_startup_funcs(void)
|
||||
|
||||
// [refactor-todo] Most of these init functions should be moved to the respective components.
|
||||
|
||||
#if !CONFIG_ESP_INT_WDT && CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
|
||||
ESP_PRE_SCHEDULER_HANDLER_REGISTER(check_cache_lock_bug, 90)
|
||||
{
|
||||
(void)user_arg;
|
||||
(void)ctx;
|
||||
assert(!soc_has_cache_lock_bug() && "ESP32 Rev 3 + Dual Core + PSRAM requires INT WDT enabled in project config!");
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
ESP_SYSTEM_INIT_FN(init_show_cpu_freq, CORE, BIT(0), 10)
|
||||
{
|
||||
ESP_EARLY_LOGI(TAG, "Pro cpu start user code");
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# This file documents the expected order of execution of ESP_SYSTEM_INIT_FN functions.
|
||||
# This file documents the expected order of execution of system startup handlers.
|
||||
#
|
||||
# When adding new ESP_SYSTEM_INIT_FN functions or changing init priorities of existing functions,
|
||||
# keep this file up to date. This is checked in CI.
|
||||
# When adding startup handlers or changing their priorities, keep this file up to date.
|
||||
# This is checked in CI.
|
||||
# When adding new functions or changing the priorities, please read the comments and see if
|
||||
# they need to be updated to be consistent with the changes you are making.
|
||||
#
|
||||
@@ -9,7 +9,7 @@
|
||||
# Each line has the following format:
|
||||
# stage: prio: function_name in path/to/source_file on affinity_expression
|
||||
# Where:
|
||||
# stage: which startup stage the function is executed in (CORE or SECONDARY)
|
||||
# stage: which startup stage the function is executed in (CORE, SECONDARY, PRE_SCHEDULER, or PRE_APP_MAIN)
|
||||
# prio: priority value (higher value means function is executed later)
|
||||
# affinity_expression: bit map of cores the function is executed on
|
||||
|
||||
@@ -148,4 +148,35 @@ SECONDARY: 240: psram_adjust_timing_point_via_temperature in components/esp_hw_s
|
||||
# Now that the application is about to start, disable boot watchdog
|
||||
SECONDARY: 999: init_disable_rtc_wdt in components/esp_system/startup_funcs.c on BIT(0)
|
||||
|
||||
# DO NOT add new init functions here. Add them to the correct stage above.
|
||||
# DO NOT add new init functions at the end of a stage. Add them at the correct priority.
|
||||
|
||||
|
||||
########### PRE_SCHEDULER startup stage ###########
|
||||
|
||||
# If the interrupt watchdog is disabled, validate the ESP32 ECO3 cache lock configuration instead.
|
||||
PRE_SCHEDULER: 90: check_cache_lock_bug in components/esp_system/startup_funcs.c on BIT(0)
|
||||
|
||||
# Initialize the interrupt watchdog globally, then enable it on each core.
|
||||
PRE_SCHEDULER: 100: init_int_wdt in components/esp_system/int_wdt.c on BIT(0)
|
||||
PRE_SCHEDULER: 110: init_int_wdt_cpu in components/esp_system/int_wdt.c on ESP_SYSTEM_INIT_ALL_CORES
|
||||
|
||||
# Cross-core interrupts must be available before each core starts its scheduler.
|
||||
PRE_SCHEDULER: 120: init_crosscore_interrupt in components/esp_system/crosscore_int.c on ESP_SYSTEM_INIT_ALL_CORES
|
||||
|
||||
# Runtime GDB stub initialization requires cross-core interrupts.
|
||||
PRE_SCHEDULER: 130: init_gdbstub in components/esp_gdbstub/src/gdbstub.c on BIT(0)
|
||||
|
||||
|
||||
########### PRE_APP_MAIN startup stage ###########
|
||||
|
||||
# Reclaim startup stacks only after every core has completed FreeRTOS initialization.
|
||||
PRE_APP_MAIN: 100: enable_nonos_stack_heaps in components/heap/heap_caps_init.c on MAIN_TASK
|
||||
|
||||
# Reserve the internal DMA pool after startup stack memory has been reclaimed.
|
||||
PRE_APP_MAIN: 110: reserve_dma_pool in components/esp_psram/system_layer/esp_psram.c on MAIN_TASK
|
||||
|
||||
# Initialize the task watchdog after the scheduler is available.
|
||||
PRE_APP_MAIN: 120: init_task_wdt in components/esp_system/task_wdt/task_wdt.c on MAIN_TASK
|
||||
|
||||
# Confirm the running OTA image immediately before calling app_main.
|
||||
PRE_APP_MAIN: 200: esp_ota_auto_confirm in components/app_update/ota_auto_confirm.c on MAIN_TASK
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "esp_task_wdt.h"
|
||||
#include "esp_private/system_internal.h"
|
||||
#include "esp_private/crosscore_int.h"
|
||||
#include "esp_private/esp_sys_event_app_init.h"
|
||||
#include "esp_private/esp_task_wdt.h"
|
||||
#include "esp_private/esp_task_wdt_impl.h"
|
||||
|
||||
@@ -58,6 +59,28 @@ extern bool g_panic_abort;
|
||||
/* Global flag marking whether the current ISR is a Task Watchdog ISR. */
|
||||
bool g_twdt_isr = false;
|
||||
|
||||
#if CONFIG_ESP_TASK_WDT_INIT
|
||||
ESP_PRE_APP_MAIN_HANDLER_REGISTER(init_task_wdt, 120)
|
||||
{
|
||||
(void)user_arg;
|
||||
(void)ctx;
|
||||
esp_task_wdt_config_t config = {
|
||||
.timeout_ms = CONFIG_ESP_TASK_WDT_TIMEOUT_S * 1000,
|
||||
.idle_core_mask = 0,
|
||||
#if CONFIG_ESP_TASK_WDT_PANIC
|
||||
.trigger_panic = true,
|
||||
#endif
|
||||
};
|
||||
#if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0
|
||||
config.idle_core_mask |= BIT(0);
|
||||
#endif
|
||||
#if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1
|
||||
config.idle_core_mask |= BIT(1);
|
||||
#endif
|
||||
return esp_task_wdt_init(&config);
|
||||
}
|
||||
#endif
|
||||
|
||||
// --------------------------------------------------- Definitions -----------------------------------------------------
|
||||
|
||||
// ---------------------- Typedefs -------------------------
|
||||
|
||||
@@ -223,22 +223,12 @@ else()
|
||||
idf_component_optional_requires(PUBLIC esp_trace)
|
||||
endif()
|
||||
|
||||
if(CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME)
|
||||
# [refactor-todo]: app_startup.c esp_startup_start_app_other_cores() calls esp_gdbstub_init() (called on CPU0).
|
||||
# This should be resolved when link-time registration of startup functions is added.
|
||||
idf_component_optional_requires(PRIVATE esp_gdbstub)
|
||||
endif()
|
||||
|
||||
if(CONFIG_FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER)
|
||||
# [refactor-todo]: esp_timer is required by FreeRTOS when we use esp_timer_get_time() to do profiling
|
||||
# Introduce a port wrapper function to avoid including esp_timer.h into the public header
|
||||
idf_component_optional_requires(PUBLIC esp_timer)
|
||||
endif()
|
||||
|
||||
if(CONFIG_SPIRAM)
|
||||
idf_component_optional_requires(PRIVATE esp_psram)
|
||||
endif()
|
||||
|
||||
if(CONFIG_PM_TRACE)
|
||||
# esp_pm is required by port_systick.c for tracing
|
||||
idf_component_optional_requires(PRIVATE esp_pm)
|
||||
|
||||
@@ -12,20 +12,7 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/portmacro.h"
|
||||
#include "esp_private/esp_int_wdt.h"
|
||||
#include "esp_private/crosscore_int.h"
|
||||
#include "esp_task_wdt.h"
|
||||
#include "esp_freertos_hooks.h"
|
||||
#include "esp_heap_caps_init.h"
|
||||
#include "esp_chip_info.h"
|
||||
#if CONFIG_SPIRAM
|
||||
/* Required by esp_psram_extram_reserve_dma_pool() */
|
||||
#include "esp_psram.h"
|
||||
#include "esp_private/esp_psram_extram.h"
|
||||
#endif
|
||||
#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
|
||||
#include "esp_gdbstub.h" /* Required by esp_gdbstub_init() */
|
||||
#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
|
||||
#include "esp_private/esp_sys_event_internal.h"
|
||||
|
||||
/* ------------------------------------------------- App/OS Startup ----------------------------------------------------
|
||||
* - Functions related to application and FreeRTOS startup
|
||||
@@ -56,26 +43,18 @@ CONFIG_FREERTOS_UNICORE and CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE should be identic
|
||||
static void main_task(void* args);
|
||||
ESP_LOG_ATTR_TAG(APP_START_TAG, "app_start");
|
||||
|
||||
static void run_app_startup_event(esp_sys_event_id_t id)
|
||||
{
|
||||
ESP_SYS_EVENT_FOREACH(handler, id) {
|
||||
ESP_ERROR_CHECK(handler->handler(NULL, NULL));
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------ CPU0 App Startup ---------------------
|
||||
|
||||
void esp_startup_start_app(void)
|
||||
{
|
||||
#if CONFIG_ESP_INT_WDT
|
||||
esp_int_wdt_init();
|
||||
// Initialize the interrupt watch dog for CPU0.
|
||||
esp_int_wdt_cpu_init();
|
||||
#elif CONFIG_ESP32_ECO3_CACHE_LOCK_FIX
|
||||
// If the INT WDT isn't enabled on ESP32 ECO3, issue an error regarding the cache lock bug
|
||||
assert(!soc_has_cache_lock_bug() && "ESP32 Rev 3 + Dual Core + PSRAM requires INT WDT enabled in project config!");
|
||||
#endif
|
||||
|
||||
// Initialize the cross-core interrupt on CPU0
|
||||
esp_crosscore_int_init();
|
||||
|
||||
#if CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
|
||||
void esp_gdbstub_init(void);
|
||||
esp_gdbstub_init();
|
||||
#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME
|
||||
run_app_startup_event(ESP_SYS_EVENT_PRE_SCHEDULER);
|
||||
|
||||
BaseType_t res = xTaskCreatePinnedToCore(main_task, "main",
|
||||
ESP_TASK_MAIN_STACK, NULL,
|
||||
@@ -87,11 +66,21 @@ void esp_startup_start_app(void)
|
||||
If a particular FreeRTOS port has port/arch specific OS startup behavior, they can implement a function of type
|
||||
"void port_start_app_hook(void)" in their `port.c` files. This function will be called below, thus allowing each
|
||||
FreeRTOS port to implement port specific app startup behavior.
|
||||
|
||||
Deprecated: Register a PRE_SCHEDULER handler with priority 999 to preserve this ordering.
|
||||
*/
|
||||
void __attribute__((weak)) port_start_app_hook(void);
|
||||
// TODO: IDF-16135
|
||||
void __attribute__((weak, deprecated("port_start_app_hook is deprecated and will be removed in IDF 7.0. Use ESP_PRE_SCHEDULER_HANDLER_REGISTER instead.")))
|
||||
port_start_app_hook(void);
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
if (port_start_app_hook != NULL) {
|
||||
ESP_EARLY_LOGW(APP_START_TAG,
|
||||
"port_start_app_hook is deprecated and will be removed in IDF 7.0. "
|
||||
"Use ESP_PRE_SCHEDULER_HANDLER_REGISTER instead.");
|
||||
port_start_app_hook();
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
ESP_EARLY_LOGD(APP_START_TAG, "Starting scheduler on CPU0");
|
||||
vTaskStartScheduler();
|
||||
@@ -113,13 +102,7 @@ void esp_startup_start_app_other_cores(void)
|
||||
;
|
||||
}
|
||||
|
||||
#if CONFIG_ESP_INT_WDT
|
||||
// Initialize the interrupt watch dog for CPU1.
|
||||
esp_int_wdt_cpu_init();
|
||||
#endif
|
||||
|
||||
// Initialize the cross-core interrupt on CPU1
|
||||
esp_crosscore_int_init();
|
||||
run_app_startup_event(ESP_SYS_EVENT_PRE_SCHEDULER);
|
||||
|
||||
ESP_EARLY_LOGD(APP_START_TAG, "Starting scheduler on CPU%d", xPortGetCoreID());
|
||||
xPortStartScheduler();
|
||||
@@ -154,54 +137,13 @@ static void wait_for_all_cores_ready(void)
|
||||
#endif // !CONFIG_FREERTOS_UNICORE
|
||||
}
|
||||
|
||||
// Reinitialize the startup stack heaps, so it can be used for heap allocation.
|
||||
static void reclaim_startup_stack_memory_for_heap(void)
|
||||
{
|
||||
wait_for_all_cores_ready();
|
||||
// [refactor-todo] check if there is a way to move the following block to esp_system startup
|
||||
heap_caps_enable_nonos_stack_heaps();
|
||||
|
||||
// Now we have startup stack RAM available for heap, enable any DMA pool memory
|
||||
#if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL
|
||||
if (esp_psram_is_initialized()) {
|
||||
esp_err_t r = esp_psram_extram_reserve_dma_pool(CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL);
|
||||
if (r != ESP_OK) {
|
||||
ESP_LOGE(MAIN_TAG, "Could not reserve internal/DMA pool (error 0x%x)", r);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void main_task(void* args)
|
||||
{
|
||||
ESP_LOGI(MAIN_TAG, "Started on CPU%d", (int)xPortGetCoreID());
|
||||
|
||||
reclaim_startup_stack_memory_for_heap();
|
||||
wait_for_all_cores_ready();
|
||||
|
||||
// Initialize TWDT if configured to do so
|
||||
#if CONFIG_ESP_TASK_WDT_INIT
|
||||
esp_task_wdt_config_t twdt_config = {
|
||||
.timeout_ms = CONFIG_ESP_TASK_WDT_TIMEOUT_S * 1000,
|
||||
.idle_core_mask = 0,
|
||||
#if CONFIG_ESP_TASK_WDT_PANIC
|
||||
.trigger_panic = true,
|
||||
#endif
|
||||
};
|
||||
#if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0
|
||||
twdt_config.idle_core_mask |= (1 << 0);
|
||||
#endif
|
||||
#if CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1
|
||||
twdt_config.idle_core_mask |= (1 << 1);
|
||||
#endif
|
||||
ESP_ERROR_CHECK(esp_task_wdt_init(&twdt_config));
|
||||
#endif // CONFIG_ESP_TASK_WDT
|
||||
|
||||
// app_update overrides it to auto-confirm an OTA rollback right before app_main.
|
||||
void __attribute__((weak)) esp_ota_confirm_rollback_hook(void);
|
||||
if (esp_ota_confirm_rollback_hook != NULL) {
|
||||
esp_ota_confirm_rollback_hook();
|
||||
}
|
||||
run_app_startup_event(ESP_SYS_EVENT_PRE_APP_MAIN);
|
||||
|
||||
/*
|
||||
Note: Be careful when changing the "Calling app_main()" log below as multiple pytest scripts expect this log as a
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "esp_heap_task_info_internal.h"
|
||||
#include "heap_memory_layout.h"
|
||||
|
||||
#include "esp_private/esp_sys_event_app_init.h"
|
||||
#include "esp_private/startup_internal.h"
|
||||
|
||||
static const char *TAG = "heap_init";
|
||||
@@ -98,6 +99,14 @@ void heap_caps_enable_nonos_stack_heaps(void)
|
||||
s_in_startup = false;
|
||||
}
|
||||
|
||||
ESP_PRE_APP_MAIN_HANDLER_REGISTER(enable_nonos_stack_heaps, 100)
|
||||
{
|
||||
(void)user_arg;
|
||||
(void)ctx;
|
||||
heap_caps_enable_nonos_stack_heaps();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/* Initialize the heap allocator to use all of the memory not
|
||||
used by static data or reserved for other purposes
|
||||
*/
|
||||
|
||||
@@ -3,6 +3,21 @@ System
|
||||
|
||||
:link_to_translation:`zh_CN:[中文]`
|
||||
|
||||
FreeRTOS
|
||||
---------
|
||||
|
||||
The legacy ``port_start_app_hook`` is deprecated and will be removed in ESP-IDF v7.0. To preserve the previous execution order, replace it with an ``ESP_PRE_SCHEDULER_HANDLER_REGISTER`` handler at priority ``999``.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include "esp_private/esp_sys_event_app_init.h"
|
||||
|
||||
ESP_PRE_SCHEDULER_HANDLER_REGISTER(port_start_app_hook, 999)
|
||||
{
|
||||
// Port-specific startup behavior
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
OTA Updates
|
||||
-----------
|
||||
|
||||
|
||||
@@ -3,6 +3,21 @@
|
||||
|
||||
:link_to_translation:`en:[English]`
|
||||
|
||||
FreeRTOS
|
||||
--------
|
||||
|
||||
旧版 ``port_start_app_hook`` 已弃用,并将在 ESP-IDF v7.0 中移除。为保持原有执行顺序,请使用优先级为 ``999`` 的 ``ESP_PRE_SCHEDULER_HANDLER_REGISTER`` 处理函数替代。
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include "esp_private/esp_sys_event_app_init.h"
|
||||
|
||||
ESP_PRE_SCHEDULER_HANDLER_REGISTER(port_start_app_hook, 999)
|
||||
{
|
||||
// 特定于端口的启动行为
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
OTA 更新
|
||||
--------
|
||||
|
||||
|
||||
Reference in New Issue
Block a user