diff --git a/components/freertos/CMakeLists.txt b/components/freertos/CMakeLists.txt index b02442da6c..a3c902a146 100644 --- a/components/freertos/CMakeLists.txt +++ b/components/freertos/CMakeLists.txt @@ -51,6 +51,7 @@ if(${target} STREQUAL "linux") "${kernel_dir}/portable/${arch}/utils/wait_for_event.c") else() list(APPEND srcs + "app_startup.c" "FreeRTOS-openocd.c" "${kernel_dir}/portable/${arch}/portasm.S") @@ -130,13 +131,14 @@ else() # FreeRTOS headers have a dependency on app_trace when SystemView tracing is enabled idf_component_optional_requires(PUBLIC app_trace) elseif(CONFIG_APPTRACE_ENABLE) - # [refactor-todo]: port.c has a dependency on esp_apptrace_init, for running it on APP CPU. - # this should be resolved when link-time registration of startup functions is added. + # [refactor-todo]: app_startup.c esp_startup_start_app_other_cores() has a dependency on esp_apptrace_init() + # (called on CPU1). This should be resolved when link-time registration of startup functions is added. idf_component_optional_requires(PRIVATE app_trace) endif() if(CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME) - # [refactor-todo]: port.c esp_startup_start_app_common() calls esp_gdbstub_init() + # [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() diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c index cb4a8bc8bd..47c4abb41a 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/riscv/port.c @@ -35,24 +35,17 @@ #include "hal/systimer_hal.h" #include "hal/systimer_ll.h" #endif - #ifdef CONFIG_PM_TRACE #include "esp_private/pm_trace.h" #endif //CONFIG_PM_TRACE -#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME -#include "esp_gdbstub.h" -#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME - _Static_assert(portBYTE_ALIGNMENT == 16, "portBYTE_ALIGNMENT must be set to 16"); /* ---------------------------------------------------- Variables ------------------------------------------------------ * * ------------------------------------------------------------------------------------------------------------------ */ -static const char *TAG = "cpu_start"; // [refactor-todo]: might be appropriate to change in the future, but - -BaseType_t uxSchedulerRunning = 0; +BaseType_t uxSchedulerRunning = 0; // Duplicate of xSchedulerRunning, accessible to port files volatile UBaseType_t uxInterruptNesting = 0; portMUX_TYPE port_xTaskLock = portMUX_INITIALIZER_UNLOCKED; portMUX_TYPE port_xISRLock = portMUX_INITIALIZER_UNLOCKED; @@ -226,83 +219,7 @@ IRAM_ATTR void SysTickIsrHandler(void *arg) #endif // CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER -// --------------------- App Start-up ---------------------- -extern void app_main(void); - -static void main_task(void *args) -{ -#if !CONFIG_FREERTOS_UNICORE - // Wait for FreeRTOS initialization to finish on APP CPU, before replacing its startup stack - while (uxSchedulerRunning == 0) { - ; - } -#endif - - // [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 (g_spiram_ok) { - esp_err_t r = esp_spiram_reserve_dma_pool(CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL); - if (r != ESP_OK) { - ESP_EARLY_LOGE(TAG, "Could not reserve internal/DMA pool (error 0x%x)", r); - abort(); - } - } -#endif - - //Initialize task wdt 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_INIT - - app_main(); - vTaskDelete(NULL); -} - -void esp_startup_start_app_common(void) -{ -#if CONFIG_ESP_INT_WDT_INIT - esp_int_wdt_init(); - //Initialize the interrupt watch dog for CPU0. - esp_int_wdt_cpu_init(); -#endif - - esp_crosscore_int_init(); - -#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME - esp_gdbstub_init(); -#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME - - portBASE_TYPE res = xTaskCreatePinnedToCore(main_task, "main", - ESP_TASK_MAIN_STACK, NULL, - ESP_TASK_MAIN_PRIO, NULL, ESP_TASK_MAIN_CORE); - assert(res == pdTRUE); - (void)res; -} - -void esp_startup_start_app(void) -{ - esp_startup_start_app_common(); - - ESP_LOGI(TAG, "Starting scheduler."); - vTaskStartScheduler(); -} /* ---------------------------------------------- Port Implementations ------------------------------------------------- * Implementations of Porting Interface functions diff --git a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c index 8d05f19c18..a4fb7ebc9f 100644 --- a/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c +++ b/components/freertos/FreeRTOS-Kernel-SMP/portable/xtensa/port.c @@ -32,18 +32,6 @@ #include "esp_freertos_hooks.h" #include "esp_intr_alloc.h" #include "esp_memory_utils.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_APPTRACE_ENABLE -#include "esp_app_trace.h" -#endif -#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME -#include "esp_gdbstub.h" /* Required by esp_gdbstub_init() */ -#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME #ifdef CONFIG_FREERTOS_SYSTICK_USES_SYSTIMER #include "soc/periph_defs.h" #include "soc/system_reg.h" @@ -56,7 +44,7 @@ _Static_assert(portBYTE_ALIGNMENT == 16, "portBYTE_ALIGNMENT must be set to 16") /* OS state variables */ -volatile unsigned port_xSchedulerRunning[portNUM_PROCESSORS] = {0}; +volatile unsigned port_xSchedulerRunning[portNUM_PROCESSORS] = {0}; // Indicates whether scheduler is running on a per-core basis unsigned int port_interruptNesting[portNUM_PROCESSORS] = {0}; // Interrupt nesting level. Increased/decreased in portasm.c, _frxt_int_enter/_frxt_int_exit //FreeRTOS SMP Locks portMUX_TYPE port_xTaskLock = portMUX_INITIALIZER_UNLOCKED; @@ -305,121 +293,6 @@ IRAM_ATTR void SysTickIsrHandler(void *arg) #endif // CONFIG_FREERTOS_SYSTICK_USES_CCOUNT -// --------------------- App Start-up ---------------------- - -static const char *TAG = "cpu_start"; - -extern void app_main(void); - -static void main_task(void *args) -{ -#if !CONFIG_FREERTOS_UNICORE - // Wait for FreeRTOS initialization to finish on APP CPU, before replacing its startup stack - while (port_xSchedulerRunning[1] == 0) { - ; - } -#endif - - // [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_EARLY_LOGE(TAG, "Could not reserve internal/DMA pool (error 0x%x)", r); - abort(); - } - } -#endif - - //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_main(); - vTaskDelete(NULL); -} - -void esp_startup_start_app_common(void) -{ -#if CONFIG_ESP_INT_WDT - esp_int_wdt_init(); - //Initialize the interrupt watch dog for CPU0. - esp_int_wdt_cpu_init(); -#endif - - esp_crosscore_int_init(); - -#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME - esp_gdbstub_init(); -#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME - - portBASE_TYPE res = xTaskCreatePinnedToCore(main_task, "main", - ESP_TASK_MAIN_STACK, NULL, - ESP_TASK_MAIN_PRIO, NULL, ESP_TASK_MAIN_CORE); - assert(res == pdTRUE); - (void)res; -} - -void esp_startup_start_app_other_cores(void) -{ - // For now, we only support up to two core: 0 and 1. - if (xPortGetCoreID() >= 2) { - abort(); - } - - // Wait for FreeRTOS initialization to finish on PRO CPU - while (port_xSchedulerRunning[0] == 0) { - ; - } - -#if CONFIG_APPTRACE_ENABLE - // [refactor-todo] move to esp_system initialization - esp_err_t err = esp_apptrace_init(); - assert(err == ESP_OK && "Failed to init apptrace module on APP CPU!"); -#endif - -#if CONFIG_ESP_INT_WDT - //Initialize the interrupt watch dog for CPU1. - esp_int_wdt_cpu_init(); -#endif - - esp_crosscore_int_init(); - - ESP_EARLY_LOGI(TAG, "Starting scheduler on APP CPU."); - xPortStartScheduler(); - abort(); /* Only get to here if FreeRTOS somehow very broken */ -} - -void esp_startup_start_app(void) -{ -#if !CONFIG_ESP_INT_WDT -#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX - assert(!soc_has_cache_lock_bug() && "ESP32 Rev 3 + Dual Core + PSRAM requires INT WDT enabled in project config!"); -#endif -#endif - - esp_startup_start_app_common(); - - ESP_EARLY_LOGI(TAG, "Starting scheduler on PRO CPU."); - vTaskStartScheduler(); -} /* ---------------------------------------------- Port Implementations ------------------------------------------------- diff --git a/components/freertos/FreeRTOS-Kernel/portable/port_common.c b/components/freertos/FreeRTOS-Kernel/portable/port_common.c index b7270f30ff..b84103d6a3 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/port_common.c +++ b/components/freertos/FreeRTOS-Kernel/portable/port_common.c @@ -7,130 +7,9 @@ #include #include "FreeRTOS.h" #include "task.h" -#include "portmacro.h" -#include "esp_private/esp_int_wdt.h" #include "esp_system.h" -#include "esp_heap_caps_init.h" -#include "esp_task_wdt.h" -#include "esp_task.h" -#include "esp_private/crosscore_int.h" -#include "esp_log.h" #include "esp_memory_utils.h" -#include "esp_freertos_hooks.h" #include "sdkconfig.h" -#include "esp_freertos_hooks.h" - -#if CONFIG_SPIRAM -#include "esp_psram.h" -#include "esp_private/esp_psram_extram.h" -#endif - -#if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL -static const char* TAG = "cpu_start"; -#endif - -/* Architecture-agnostic parts of the FreeRTOS ESP-IDF port layer can go here. - * - * The actual call flow will be to call esp_startup_start_app() in /port.c, - * which will then call esp_startup_start_app_common() - */ - -// Duplicate of inaccessible xSchedulerRunning; needed at startup to avoid counting nesting -volatile unsigned port_xSchedulerRunning[portNUM_PROCESSORS] = {0}; - -// For now, running FreeRTOS on one core and a bare metal on the other (or other OSes) -// is not supported. For now CONFIG_FREERTOS_UNICORE and CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE -// should mirror each other's values. -// -// And since this should be true, we can just check for CONFIG_FREERTOS_UNICORE. -#if CONFIG_FREERTOS_UNICORE != CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE - #error "FreeRTOS and system configuration mismatch regarding the use of multiple cores." -#endif - -static void main_task(void* args); - -#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME -void esp_gdbstub_init(void); -#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME - -extern void app_main(void); - -void esp_startup_start_app_common(void) -{ -#if CONFIG_ESP_INT_WDT - esp_int_wdt_init(); - //Initialize the interrupt watch dog for CPU0. - esp_int_wdt_cpu_init(); -#endif - - esp_crosscore_int_init(); - -#if CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME && !CONFIG_IDF_TARGET_ESP32C2 - esp_gdbstub_init(); -#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME - - portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main", - ESP_TASK_MAIN_STACK, NULL, - ESP_TASK_MAIN_PRIO, NULL, ESP_TASK_MAIN_CORE); - assert(res == pdTRUE); - (void)res; -} - -#if !CONFIG_FREERTOS_UNICORE -static volatile bool s_other_cpu_startup_done = false; -static bool other_cpu_startup_idle_hook_cb(void) -{ - s_other_cpu_startup_done = true; - return true; -} -#endif - -static void main_task(void* args) -{ -#if !CONFIG_FREERTOS_UNICORE - // Wait for FreeRTOS initialization to finish on other core, before replacing its startup stack - esp_register_freertos_idle_hook_for_cpu(other_cpu_startup_idle_hook_cb, !xPortGetCoreID()); - while (!s_other_cpu_startup_done) { - ; - } - esp_deregister_freertos_idle_hook_for_cpu(other_cpu_startup_idle_hook_cb, !xPortGetCoreID()); -#endif - - // [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_EARLY_LOGE(TAG, "Could not reserve internal/DMA pool (error 0x%x)", r); - abort(); - } - } -#endif - - //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_main(); - vTaskDelete(NULL); -} // -------------------- Heap Related ----------------------- diff --git a/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c b/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c index 962fb140a2..e86466beed 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c +++ b/components/freertos/FreeRTOS-Kernel/portable/riscv/port.c @@ -63,8 +63,6 @@ _Static_assert(portBYTE_ALIGNMENT == 16, "portBYTE_ALIGNMENT must be set to 16") * * ------------------------------------------------------------------------------------------------------------------ */ -static const char *TAG = "cpu_start"; // [refactor-todo]: might be appropriate to change in the future, but - /** * @brief A variable is used to keep track of the critical section nesting. * @note This variable has to be stored as part of the task context and must be initialized to a non zero value @@ -73,7 +71,7 @@ static const char *TAG = "cpu_start"; // [refactor-todo]: might be appropriate t */ static UBaseType_t uxCriticalNesting = 0; static UBaseType_t uxSavedInterruptState = 0; -BaseType_t uxSchedulerRunning = 0; +BaseType_t uxSchedulerRunning = 0; // Duplicate of xSchedulerRunning, accessible to port files UBaseType_t uxInterruptNesting = 0; BaseType_t xPortSwitchFlag = 0; __attribute__((aligned(16))) static StackType_t xIsrStack[configISR_STACK_SIZE]; @@ -473,16 +471,3 @@ void vPortSetStackWatchpoint(void *pxStackStart) /* ---------------------------------------------- Misc Implementations ------------------------------------------------- * * ------------------------------------------------------------------------------------------------------------------ */ - -// --------------------- App Start-up ---------------------- - -/* [refactor-todo]: See if we can include this through a header */ -extern void esp_startup_start_app_common(void); - -void esp_startup_start_app(void) -{ - esp_startup_start_app_common(); - - ESP_LOGI(TAG, "Starting scheduler."); - vTaskStartScheduler(); -} diff --git a/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c b/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c index 68a9b62474..dad25e9ed2 100644 --- a/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c +++ b/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c @@ -69,15 +69,11 @@ #include "esp_private/esp_int_wdt.h" #include "esp_system.h" #include "esp_log.h" -#ifdef CONFIG_APPTRACE_ENABLE -#include "esp_app_trace.h" /* Required for esp_apptrace_init. [refactor-todo] */ -#endif #include "FreeRTOS.h" /* This pulls in portmacro.h */ #include "task.h" /* Required for TaskHandle_t, tskNO_AFFINITY, and vTaskStartScheduler */ #include "port_systick.h" #include "esp_cpu.h" #include "esp_memory_utils.h" -#include "esp_chip_info.h" _Static_assert(portBYTE_ALIGNMENT == 16, "portBYTE_ALIGNMENT must be set to 16"); @@ -88,8 +84,7 @@ _Static_assert(tskNO_AFFINITY == CONFIG_FREERTOS_NO_AFFINITY, "incorrect tskNO_A * * ------------------------------------------------------------------------------------------------------------------ */ -static const char *TAG = "cpu_start"; /* [refactor-todo]: might be appropriate to change in the future, but for now maintain the same log output */ -extern volatile int port_xSchedulerRunning[portNUM_PROCESSORS]; +volatile unsigned port_xSchedulerRunning[portNUM_PROCESSORS] = {0}; // Indicates whether scheduler is running on a per-core basis unsigned port_interruptNesting[portNUM_PROCESSORS] = {0}; // Interrupt nesting level. Increased/decreased in portasm.c, _frxt_int_enter/_frxt_int_exit BaseType_t port_uxCriticalNesting[portNUM_PROCESSORS] = {0}; BaseType_t port_uxOldInterruptState[portNUM_PROCESSORS] = {0}; @@ -618,53 +613,3 @@ void vPortReleaseTaskMPUSettings( xMPU_SETTINGS *xMPUSettings ) _xt_coproc_release( xMPUSettings->coproc_area ); } #endif /* portUSING_MPU_WRAPPERS */ - -// --------------------- App Start-up ---------------------- - -#if !CONFIG_FREERTOS_UNICORE -void esp_startup_start_app_other_cores(void) -{ - // For now, we only support up to two core: 0 and 1. - if (xPortGetCoreID() >= 2) { - abort(); - } - - // Wait for FreeRTOS initialization to finish on PRO CPU - while (port_xSchedulerRunning[0] == 0) { - ; - } - -#if CONFIG_APPTRACE_ENABLE - // [refactor-todo] move to esp_system initialization - esp_err_t err = esp_apptrace_init(); - assert(err == ESP_OK && "Failed to init apptrace module on APP CPU!"); -#endif - -#if CONFIG_ESP_INT_WDT - //Initialize the interrupt watch dog for CPU1. - esp_int_wdt_cpu_init(); -#endif - - esp_crosscore_int_init(); - - ESP_EARLY_LOGI(TAG, "Starting scheduler on APP CPU."); - xPortStartScheduler(); - abort(); /* Only get to here if FreeRTOS somehow very broken */ -} -#endif // !CONFIG_FREERTOS_UNICORE - -extern void esp_startup_start_app_common(void); - -void esp_startup_start_app(void) -{ -#if !CONFIG_ESP_INT_WDT -#if CONFIG_ESP32_ECO3_CACHE_LOCK_FIX - assert(!soc_has_cache_lock_bug() && "ESP32 Rev 3 + Dual Core + PSRAM requires INT WDT enabled in project config!"); -#endif -#endif - - esp_startup_start_app_common(); - - ESP_LOGI(TAG, "Starting scheduler on PRO CPU."); - vTaskStartScheduler(); -} diff --git a/components/freertos/app_startup.c b/components/freertos/app_startup.c new file mode 100644 index 0000000000..7789c6124e --- /dev/null +++ b/components/freertos/app_startup.c @@ -0,0 +1,207 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sdkconfig.h" +#include +#include +#include "esp_task.h" +#include "esp_log.h" +#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_APPTRACE_ENABLE +#include "esp_app_trace.h" /* Required for esp_apptrace_init. [refactor-todo] */ +#endif +#ifdef CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME +#include "esp_gdbstub.h" /* Required by esp_gdbstub_init() */ +#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME + +/* ------------------------------------------------- App/OS Startup ---------------------------------------------------- + * - Functions related to application and FreeRTOS startup + * - This startup is common to all architectures (e.g. RISC-V and Xtensa) and all FreeRTOS implementations (i.e., IDF + * FreeRTOS and Amazon SMP FreeRTOS). + * - Application startup flow as follows: + * - For CPU 0 + * - CPU0 completes CPU startup (in startup.c), then calls esp_startup_start_app() + * - esp_startup_start_app() registers some daemon services for CPU0 then starts FreeRTOS + * - For CPUx (1 to N-1) + * - CPUx completes CPU startup in startup.c, then calls esp_startup_start_app_other_cores() + * - esp_startup_start_app_other_cores(), registers some daemon services for CPUx, waits for CPU0 to start + * FreeRTOS, then yields (via xPortStartScheduler()) to schedule a task. + * ------------------------------------------------------------------------------------------------------------------ */ + +// ----------------------- Checks -------------------------- + +/* +For now, AMP is not supported (i.e., running FreeRTOS on one core and a bare metal/other OS on the other). Therefore, +CONFIG_FREERTOS_UNICORE and CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE should be identical. We add a check for this here. +*/ +#if CONFIG_FREERTOS_UNICORE != CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + #error "AMP not supported. FreeRTOS number of cores and system number of cores must be identical" +#endif + +// -------------------- Declarations ----------------------- + +static void main_task(void* args); +static const char* APP_START_TAG = "app_start"; + +// ------------------ 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 && !CONFIG_IDF_TARGET_ESP32C2 + void esp_gdbstub_init(void); + esp_gdbstub_init(); +#endif // CONFIG_ESP_SYSTEM_GDBSTUB_RUNTIME + + BaseType_t res = xTaskCreatePinnedToCore(main_task, "main", + ESP_TASK_MAIN_STACK, NULL, + ESP_TASK_MAIN_PRIO, NULL, ESP_TASK_MAIN_CORE); + assert(res == pdTRUE); + (void)res; + + /* + 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. + */ + void __attribute__((weak)) port_start_app_hook(void); + if (port_start_app_hook != NULL) { + port_start_app_hook(); + } + + ESP_EARLY_LOGI(APP_START_TAG, "Starting scheduler on CPU0"); + vTaskStartScheduler(); +} + +// --------------- CPU[1:N-1] App Startup ------------------ + +#if !CONFIG_FREERTOS_UNICORE +void esp_startup_start_app_other_cores(void) +{ + // For now, we only support up to two core: 0 and 1. + if (xPortGetCoreID() >= 2) { + abort(); + } + + // Wait for CPU0 to start FreeRTOS before progressing + extern volatile unsigned port_xSchedulerRunning[portNUM_PROCESSORS]; + while (port_xSchedulerRunning[0] == 0) { + ; + } + +#if CONFIG_APPTRACE_ENABLE + // [refactor-todo] move to esp_system initialization + esp_err_t err = esp_apptrace_init(); + assert(err == ESP_OK && "Failed to init apptrace module on APP CPU!"); +#endif + +#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(); + + ESP_EARLY_LOGI(APP_START_TAG, "Starting scheduler on CPU%d", xPortGetCoreID()); + xPortStartScheduler(); + abort(); // Only get to here if FreeRTOS somehow very broken +} +#endif // !CONFIG_FREERTOS_UNICORE + +/* ---------------------------------------------------- Main Task ------------------------------------------------------ + * - main_task is a daemon task created by CPU0 before it starts FreeRTOS + * - Pinned to CPU(ESP_TASK_MAIN_CORE) + * - Priority of ESP_TASK_MAIN_PRIO + * - Used to dispatch "void app_main(void)" provided by the application + * - main_task will self delete if app_main returns + * ------------------------------------------------------------------------------------------------------------------ */ + +static const char* MAIN_TAG = "main_task"; + +#if !CONFIG_FREERTOS_UNICORE +static volatile bool s_other_cpu_startup_done = false; +static bool other_cpu_startup_idle_hook_cb(void) +{ + s_other_cpu_startup_done = true; + return true; +} +#endif + +static void main_task(void* args) +{ + ESP_LOGI(MAIN_TAG, "Started on CPU%d", xPortGetCoreID()); +#if !CONFIG_FREERTOS_UNICORE + // Wait for FreeRTOS initialization to finish on other core, before replacing its startup stack + esp_register_freertos_idle_hook_for_cpu(other_cpu_startup_idle_hook_cb, !xPortGetCoreID()); + while (!s_other_cpu_startup_done) { + ; + } + esp_deregister_freertos_idle_hook_for_cpu(other_cpu_startup_idle_hook_cb, !xPortGetCoreID()); +#endif + + // [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 + + // 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 + + ESP_LOGI(MAIN_TAG, "Calling app_main()"); + extern void app_main(void); + app_main(); + ESP_LOGI(MAIN_TAG, "Returned from app_main()"); + vTaskDelete(NULL); +} diff --git a/components/freertos/linker.lf b/components/freertos/linker.lf index c8a2e6b66e..294e301f4c 100644 --- a/components/freertos/linker.lf +++ b/components/freertos/linker.lf @@ -130,14 +130,12 @@ entries: queue: uxQueueGetQueueNumber (default) queue: vQueueSetQueueNumber (default) queue: ucQueueGetQueueType (default) - # port.c Functions - port: esp_startup_start_app (default) - if ESP_SYSTEM_SINGLE_CORE_MODE = n: - port: esp_startup_start_app_other_cores (default) + # app_startup.c + app_startup: esp_startup_start_app (default) + if CONFIG_FREERTOS_UNICORE = n: + app_startup: esp_startup_start_app_other_cores (default) + app_startup: other_cpu_startup_idle_hook_cb (default) + app_startup: main_task (default) # port_common.c Functions - port_common:main_task (default) - port_common:esp_startup_start_app_common (default) port_common:vApplicationGetIdleTaskMemory (default) port_common:vApplicationGetTimerTaskMemory (default) - if FREERTOS_UNICORE = n: - port_common:other_cpu_startup_idle_hook_cb (default) diff --git a/components/freertos/linker_smp.lf b/components/freertos/linker_smp.lf index 01f7c5b211..523c25bf85 100644 --- a/components/freertos/linker_smp.lf +++ b/components/freertos/linker_smp.lf @@ -144,10 +144,12 @@ entries: # port port: pxPortInitialiseStack (default) port: xPortStartScheduler (default) - port: main_task (default) - port: esp_startup_start_app (default) - if ESP_SYSTEM_SINGLE_CORE_MODE = n: - port:esp_startup_start_app_other_cores (default) + # app_startup.c + app_startup: esp_startup_start_app (default) + if CONFIG_FREERTOS_UNICORE = n: + app_startup: esp_startup_start_app_other_cores (default) + app_startup: other_cpu_startup_idle_hook_cb (default) + app_startup: main_task (default) # timers.c timers: xTimerCreateTimerTask (default) timers: xTimerCreate (default) diff --git a/tools/unit-test-app/components/test_utils/test_runner.c b/tools/unit-test-app/components/test_utils/test_runner.c index 79e918544e..b010a50214 100644 --- a/tools/unit-test-app/components/test_utils/test_runner.c +++ b/tools/unit-test-app/components/test_utils/test_runner.c @@ -21,8 +21,10 @@ static void unity_task(void *pvParameters) { - vTaskDelay(2); /* Delay a bit to let the main task be deleted */ - unity_run_menu(); /* Doesn't return */ + // Delay a bit to let the main task and any other startup tasks be deleted + vTaskDelay(pdMS_TO_TICKS(50)); + // Start running unity (prints test menu and doesn't return) + unity_run_menu(); } void test_main(void)