|
|
@@ -0,0 +1,207 @@
|
|
|
+/*
|
|
|
+ * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
|
|
+ *
|
|
|
+ * SPDX-License-Identifier: Apache-2.0
|
|
|
+ */
|
|
|
+
|
|
|
+#include "sdkconfig.h"
|
|
|
+#include <stddef.h>
|
|
|
+#include <assert.h>
|
|
|
+#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);
|
|
|
+}
|