// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include #include "esp_attr.h" #include "esp_err.h" #include "rom/ets_sys.h" #include "rom/uart.h" #include "rom/rtc.h" #include "rom/cache.h" #include "soc/cpu.h" #include "soc/dport_reg.h" #include "soc/io_mux_reg.h" #include "soc/rtc_cntl_reg.h" #include "soc/timer_group_reg.h" #include "driver/rtc_io.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" #include "freertos/queue.h" #include "freertos/portmacro.h" #include "tcpip_adapter.h" #include "esp_heap_alloc_caps.h" #include "sdkconfig.h" #include "esp_system.h" #include "esp_spi_flash.h" #include "nvs_flash.h" #include "esp_event.h" #include "esp_spi_flash.h" #include "esp_ipc.h" #include "esp_crosscore_int.h" #include "esp_log.h" #include "esp_vfs_dev.h" #include "esp_newlib.h" #include "esp_brownout.h" #include "esp_int_wdt.h" #include "esp_task_wdt.h" #include "esp_phy_init.h" #include "esp_cache_err_int.h" #include "esp_coexist.h" #include "esp_core_dump.h" #include "trax.h" #include "esp_psram.h" #define STRINGIFY(s) STRINGIFY2(s) #define STRINGIFY2(s) #s void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default"))); void start_cpu0_default(void) IRAM_ATTR; #if !CONFIG_FREERTOS_UNICORE static void IRAM_ATTR call_start_cpu1(); void start_cpu1(void) __attribute__((weak, alias("start_cpu1_default"))); void start_cpu1_default(void) IRAM_ATTR; static bool app_cpu_started = false; #endif //!CONFIG_FREERTOS_UNICORE static void do_global_ctors(void); static void main_task(void* args); extern void app_main(void); extern int _bss_start; extern int _bss_end; extern int _rtc_bss_start; extern int _rtc_bss_end; extern int _init_start; extern void (*__init_array_start)(void); extern void (*__init_array_end)(void); extern volatile int port_xSchedulerRunning[2]; static const char* TAG = "cpu_start"; #if CONFIG_FREERTOS_UNICORE #define PSRAM_MODE PSRAM_VADDR_MODE_NORMAL #else #define PSRAM_MODE PSRAM_VADDR_MODE_LOWHIGH #endif /* * We arrive here after the bootloader finished loading the program from flash. The hardware is mostly uninitialized, * and the app CPU is in reset. We do have a stack, so we can do the initialization in C. */ void IRAM_ATTR call_start_cpu0() { cpu_configure_region_protection(); //Move exception vectors to IRAM asm volatile (\ "wsr %0, vecbase\n" \ ::"r"(&_init_start)); memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start)); /* Unless waking from deep sleep (implying RTC memory is intact), clear RTC bss */ if (rtc_get_reset_reason(0) != DEEPSLEEP_RESET) { memset(&_rtc_bss_start, 0, (&_rtc_bss_end - &_rtc_bss_start) * sizeof(_rtc_bss_start)); } #if CONFIG_MEMMAP_SPIRAM_ENABLE if ( psram_enable(PSRAM_CACHE_F40M_S40M, PSRAM_MODE) != ESP_OK) { ESP_EARLY_LOGE(TAG, "PSRAM enabled but initialization failed. Bailing out."); abort(); } else { ESP_EARLY_LOGI(TAG, "PSRAM initialized, cache is in %s mode.", (PSRAM_MODE==PSRAM_VADDR_MODE_EVENODD)?"even/odd (2-core)":"normal (1-core"); } #endif ESP_EARLY_LOGI(TAG, "Pro cpu up."); #if !CONFIG_FREERTOS_UNICORE ESP_EARLY_LOGI(TAG, "Starting app cpu, entry point is %p", call_start_cpu1); //Flush and enable icache for APP CPU CLEAR_PERI_REG_MASK(DPORT_APP_CACHE_CTRL1_REG, DPORT_APP_CACHE_MASK_DRAM1); cache_sram_mmu_set( 1, 0, 0x3f800000, 0, 32, 128 ); Cache_Flush(1); Cache_Read_Enable(1); esp_cpu_unstall(1); //Enable clock gating and reset the app cpu. SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN); CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_C_REG, DPORT_APPCPU_RUNSTALL); SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING); CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING); ets_set_appcpu_boot_addr((uint32_t)call_start_cpu1); while (!app_cpu_started) { ets_delay_us(100); } #else ESP_EARLY_LOGI(TAG, "Single core mode"); CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN); #endif /* Initialize heap allocator. WARNING: This *needs* to happen *after* the app cpu has booted. If the heap allocator is initialized first, it will put free memory linked list items into memory also used by the ROM. Starting the app cpu will let its ROM initialize that memory, corrupting those linked lists. Initializing the allocator *after* the app cpu has booted works around this problem. */ heap_alloc_caps_init(); ESP_EARLY_LOGI(TAG, "Pro cpu start user code"); start_cpu0(); } #if !CONFIG_FREERTOS_UNICORE void IRAM_ATTR call_start_cpu1() { asm volatile (\ "wsr %0, vecbase\n" \ ::"r"(&_init_start)); cpu_configure_region_protection(); #if CONFIG_CONSOLE_UART_NONE ets_install_putc1(NULL); ets_install_putc2(NULL); #else // CONFIG_CONSOLE_UART_NONE uartAttach(); ets_install_uart_printf(); uart_tx_switch(CONFIG_CONSOLE_UART_NUM); #endif ESP_EARLY_LOGI(TAG, "App cpu up."); app_cpu_started = 1; start_cpu1(); } #endif //!CONFIG_FREERTOS_UNICORE void start_cpu0_default(void) { esp_setup_syscall_table(); //Enable trace memory and immediately start trace. #if CONFIG_MEMMAP_TRACEMEM #if CONFIG_MEMMAP_TRACEMEM_TWOBANKS trax_enable(TRAX_ENA_PRO_APP); #else trax_enable(TRAX_ENA_PRO); #endif trax_start_trace(TRAX_DOWNCOUNT_WORDS); #endif esp_set_cpu_freq(); // set CPU frequency configured in menuconfig #ifndef CONFIG_CONSOLE_UART_NONE uart_div_modify(CONFIG_CONSOLE_UART_NUM, (APB_CLK_FREQ << 4) / CONFIG_CONSOLE_UART_BAUDRATE); #endif #if CONFIG_BROWNOUT_DET esp_brownout_init(); #endif rtc_gpio_force_hold_dis_all(); esp_setup_time_syscalls(); esp_vfs_dev_uart_register(); esp_reent_init(_GLOBAL_REENT); #ifndef CONFIG_CONSOLE_UART_NONE const char* default_uart_dev = "/dev/uart/" STRINGIFY(CONFIG_CONSOLE_UART_NUM); _GLOBAL_REENT->_stdin = fopen(default_uart_dev, "r"); _GLOBAL_REENT->_stdout = fopen(default_uart_dev, "w"); _GLOBAL_REENT->_stderr = fopen(default_uart_dev, "w"); #else _GLOBAL_REENT->_stdin = (FILE*) &__sf_fake_stdin; _GLOBAL_REENT->_stdout = (FILE*) &__sf_fake_stdout; _GLOBAL_REENT->_stderr = (FILE*) &__sf_fake_stderr; #endif do_global_ctors(); #if CONFIG_INT_WDT esp_int_wdt_init(); #endif #if CONFIG_TASK_WDT esp_task_wdt_init(); #endif esp_cache_err_int_init(); #if !CONFIG_FREERTOS_UNICORE esp_crosscore_int_init(); #endif esp_ipc_init(); spi_flash_init(); /* init default OS-aware flash access critical section */ spi_flash_guard_set(&g_flash_guard_default_ops); #if CONFIG_ESP32_ENABLE_COREDUMP esp_core_dump_init(); #endif xTaskCreatePinnedToCore(&main_task, "main", ESP_TASK_MAIN_STACK, NULL, ESP_TASK_MAIN_PRIO, NULL, 0); ESP_LOGI(TAG, "Starting scheduler on PRO CPU."); vTaskStartScheduler(); } #if !CONFIG_FREERTOS_UNICORE void start_cpu1_default(void) { #if CONFIG_MEMMAP_TRACEMEM_TWOBANKS trax_start_trace(TRAX_DOWNCOUNT_WORDS); #endif // Wait for FreeRTOS initialization to finish on PRO CPU while (port_xSchedulerRunning[0] == 0) { ; } //Take care putting stuff here: if asked, FreeRTOS will happily tell you the scheduler //has started, but it isn't active *on this CPU* yet. esp_crosscore_int_init(); ESP_EARLY_LOGI(TAG, "Starting scheduler on APP CPU."); xPortStartScheduler(); } #endif //!CONFIG_FREERTOS_UNICORE static void do_global_ctors(void) { void (**p)(void); for (p = &__init_array_end - 1; p >= &__init_array_start; --p) { (*p)(); } } static void main_task(void* args) { // Now that the application is about to start, disable boot watchdogs REG_CLR_BIT(TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN_S); REG_CLR_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN); //Enable allocation in region where the startup stacks were located. heap_alloc_enable_nonos_stack_tag(); app_main(); vTaskDelete(NULL); }