From 39ef904fba764e8cc4d894d70a8f59f0922fcf0c Mon Sep 17 00:00:00 2001 From: Renz Bagaporo Date: Tue, 3 Mar 2020 12:10:38 +0800 Subject: [PATCH 01/17] soc: introduce hal function for cpu delay --- components/soc/include/hal/cpu_hal.h | 7 +++++++ components/soc/src/hal/cpu_hal.c | 13 +++++++++++++ 2 files changed, 20 insertions(+) diff --git a/components/soc/include/hal/cpu_hal.h b/components/soc/include/hal/cpu_hal.h index 7584aa4078..d5c81f4b63 100644 --- a/components/soc/include/hal/cpu_hal.h +++ b/components/soc/include/hal/cpu_hal.h @@ -107,6 +107,13 @@ void cpu_hal_set_watchpoint(int id, const void* addr, size_t size, watchpoint_tr */ void cpu_hal_clear_watchpoint(int id); +/* + * Insert a delay. + * + * @param delay_us length of delay in microseconds + */ +void cpu_hal_delay_us(uint32_t delay_us); + #endif // SOC_CPU_WATCHPOINTS_NUM > 0 /** diff --git a/components/soc/src/hal/cpu_hal.c b/components/soc/src/hal/cpu_hal.c index 1da4ff29ae..98f918f7cb 100644 --- a/components/soc/src/hal/cpu_hal.c +++ b/components/soc/src/hal/cpu_hal.c @@ -22,6 +22,14 @@ #include "soc/cpu_caps.h" +#include "sdkconfig.h" + +#if CONFIG_IDF_TARGET_ESP32 +#include "esp32/rom/ets_sys.h" +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/rom/ets_sys.h" +#endif + #if SOC_CPU_BREAKPOINTS_NUM > 0 void cpu_hal_set_breakpoint(int id, const void* addr) { @@ -60,3 +68,8 @@ void cpu_hal_set_vecbase(const void* base) { cpu_ll_set_vecbase(base); } + +void cpu_hal_delay_us(uint32_t delay_us) +{ + ets_delay_us(delay_us); +} \ No newline at end of file From 62ef63e83519c3e2dd7c4500318ef6f87e7f5909 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Fri, 31 Jan 2020 18:21:18 +0800 Subject: [PATCH 02/17] esp32, esp32s2: move clk init functions to esp_system --- components/esp32/clk.c | 305 +---------------- components/esp32s2/CMakeLists.txt | 1 - components/esp32s2/clk.c | 306 +---------------- components/esp32s2/esp_clk_internal.h | 44 --- .../esp_system/port/esp32/CMakeLists.txt | 6 +- components/esp_system/port/esp32/clk.c | 315 +++++++++++++++++ .../esp_system/port/esp32s2/CMakeLists.txt | 6 +- components/esp_system/port/esp32s2/clk.c | 318 ++++++++++++++++++ .../port/include}/esp_clk_internal.h | 0 components/soc/test/test_rtc_clk.c | 3 +- 10 files changed, 656 insertions(+), 648 deletions(-) delete mode 100644 components/esp32s2/esp_clk_internal.h create mode 100644 components/esp_system/port/esp32/clk.c create mode 100644 components/esp_system/port/esp32s2/clk.c rename components/{esp32 => esp_system/port/include}/esp_clk_internal.h (100%) diff --git a/components/esp32/clk.c b/components/esp32/clk.c index d12abd3ab7..6f2d0b7627 100644 --- a/components/esp32/clk.c +++ b/components/esp32/clk.c @@ -13,148 +13,20 @@ // limitations under the License. #include -#include -#include #include -#include "sdkconfig.h" + #include "esp_attr.h" -#include "esp_log.h" -#include "esp32/clk.h" -#include "esp_clk_internal.h" -#include "esp32/rom/ets_sys.h" -#include "esp32/rom/uart.h" -#include "esp32/rom/rtc.h" -#include "soc/soc.h" -#include "soc/dport_reg.h" #include "soc/rtc.h" -#include "soc/rtc_periph.h" -#include "soc/i2s_periph.h" -#include "hal/wdt_hal.h" -#include "driver/periph_ctrl.h" -#include "xtensa/core-macros.h" -#include "bootloader_clock.h" -#include "driver/spi_common_internal.h" - -/* Number of cycles to wait from the 32k XTAL oscillator to consider it running. - * Larger values increase startup delay. Smaller values may cause false positive - * detection (i.e. oscillator runs for a few cycles and then stops). - */ -#define SLOW_CLK_CAL_CYCLES CONFIG_ESP32_RTC_CLK_CAL_CYCLES - -#ifdef CONFIG_ESP32_RTC_XTAL_CAL_RETRY -#define RTC_XTAL_CAL_RETRY CONFIG_ESP32_RTC_XTAL_CAL_RETRY -#else -#define RTC_XTAL_CAL_RETRY 1 -#endif +#include "esp32/clk.h" #define MHZ (1000000) -/* Lower threshold for a reasonably-looking calibration value for a 32k XTAL. - * The ideal value (assuming 32768 Hz frequency) is 1000000/32768*(2**19) = 16*10^6. - */ -#define MIN_32K_XTAL_CAL_VAL 15000000L - -/* Indicates that this 32k oscillator gets input from external oscillator, rather - * than a crystal. - */ -#define EXT_OSC_FLAG BIT(3) - -/* This is almost the same as rtc_slow_freq_t, except that we define - * an extra enum member for the external 32k oscillator. - * For convenience, lower 2 bits should correspond to rtc_slow_freq_t values. - */ -typedef enum { - SLOW_CLK_150K = RTC_SLOW_FREQ_RTC, //!< Internal 150 kHz RC oscillator - SLOW_CLK_32K_XTAL = RTC_SLOW_FREQ_32K_XTAL, //!< External 32 kHz XTAL - SLOW_CLK_8MD256 = RTC_SLOW_FREQ_8MD256, //!< Internal 8 MHz RC oscillator, divided by 256 - SLOW_CLK_32K_EXT_OSC = RTC_SLOW_FREQ_32K_XTAL | EXT_OSC_FLAG //!< External 32k oscillator connected to 32K_XP pin -} slow_clk_sel_t; - -static void select_rtc_slow_clk(slow_clk_sel_t slow_clk); - // g_ticks_us defined in ROMs for PRO and APP CPU extern uint32_t g_ticks_per_us_pro; #ifndef CONFIG_FREERTOS_UNICORE extern uint32_t g_ticks_per_us_app; #endif -static const char* TAG = "clk"; - - -void esp_clk_init(void) -{ - rtc_config_t cfg = RTC_CONFIG_DEFAULT(); - rtc_init(cfg); - -#if (CONFIG_ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS || CONFIG_ESP32_APP_INIT_CLK) - /* Check the bootloader set the XTAL frequency. - - Bootloaders pre-v2.1 don't do this. - */ - rtc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get(); - if (xtal_freq == RTC_XTAL_FREQ_AUTO) { - ESP_EARLY_LOGW(TAG, "RTC domain not initialised by bootloader"); - bootloader_clock_configure(); - } -#else - /* If this assertion fails, either upgrade the bootloader or enable CONFIG_ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS */ - assert(rtc_clk_xtal_freq_get() != RTC_XTAL_FREQ_AUTO); -#endif - - rtc_clk_fast_freq_set(RTC_FAST_FREQ_8M); - -#ifdef CONFIG_BOOTLOADER_WDT_ENABLE - // WDT uses a SLOW_CLK clock source. After a function select_rtc_slow_clk a frequency of this source can changed. - // If the frequency changes from 150kHz to 32kHz, then the timeout set for the WDT will increase 4.6 times. - // Therefore, for the time of frequency change, set a new lower timeout value (1.6 sec). - // This prevents excessive delay before resetting in case the supply voltage is drawdown. - // (If frequency is changed from 150kHz to 32kHz then WDT timeout will increased to 1.6sec * 150/32 = 7.5 sec). - wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; - uint32_t stage_timeout_ticks = (uint32_t)(1600ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); - wdt_hal_write_protect_disable(&rtc_wdt_ctx); - wdt_hal_feed(&rtc_wdt_ctx); - //Bootloader has enabled RTC WDT until now. We're only modifying timeout, so keep the stage and timeout action the same - wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); - wdt_hal_write_protect_enable(&rtc_wdt_ctx); -#endif - -#if defined(CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS) - select_rtc_slow_clk(SLOW_CLK_32K_XTAL); -#elif defined(CONFIG_ESP32_RTC_CLK_SRC_EXT_OSC) - select_rtc_slow_clk(SLOW_CLK_32K_EXT_OSC); -#elif defined(CONFIG_ESP32_RTC_CLK_SRC_INT_8MD256) - select_rtc_slow_clk(SLOW_CLK_8MD256); -#else - select_rtc_slow_clk(RTC_SLOW_FREQ_RTC); -#endif - -#ifdef CONFIG_BOOTLOADER_WDT_ENABLE - // After changing a frequency WDT timeout needs to be set for new frequency. - stage_timeout_ticks = (uint32_t)((uint64_t)CONFIG_BOOTLOADER_WDT_TIME_MS * rtc_clk_slow_freq_get_hz() / 1000); - wdt_hal_write_protect_disable(&rtc_wdt_ctx); - wdt_hal_feed(&rtc_wdt_ctx); - wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); - wdt_hal_write_protect_enable(&rtc_wdt_ctx); -#endif - - rtc_cpu_freq_config_t old_config, new_config; - rtc_clk_cpu_freq_get_config(&old_config); - const uint32_t old_freq_mhz = old_config.freq_mhz; - const uint32_t new_freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ; - - bool res = rtc_clk_cpu_freq_mhz_to_config(new_freq_mhz, &new_config); - assert(res); - - // Wait for UART TX to finish, otherwise some UART output will be lost - // when switching APB frequency - uart_tx_wait_idle(CONFIG_ESP_CONSOLE_UART_NUM); - - rtc_clk_cpu_freq_set_config(&new_config); - - // Re calculate the ccount to make time calculation correct. - XTHAL_SET_CCOUNT( (uint64_t)XTHAL_GET_CCOUNT() * new_freq_mhz / old_freq_mhz ); -} - int IRAM_ATTR esp_clk_cpu_freq(void) { return g_ticks_per_us_pro * MHZ; @@ -178,176 +50,3 @@ void IRAM_ATTR ets_update_cpu_frequency(uint32_t ticks_per_us) g_ticks_per_us_app = ticks_per_us; #endif } - -static void select_rtc_slow_clk(slow_clk_sel_t slow_clk) -{ - rtc_slow_freq_t rtc_slow_freq = slow_clk & RTC_CNTL_ANA_CLK_RTC_SEL_V; - uint32_t cal_val = 0; - /* number of times to repeat 32k XTAL calibration - * before giving up and switching to the internal RC - */ - int retry_32k_xtal = RTC_XTAL_CAL_RETRY; - - do { - if (rtc_slow_freq == RTC_SLOW_FREQ_32K_XTAL) { - /* 32k XTAL oscillator needs to be enabled and running before it can - * be used. Hardware doesn't have a direct way of checking if the - * oscillator is running. Here we use rtc_clk_cal function to count - * the number of main XTAL cycles in the given number of 32k XTAL - * oscillator cycles. If the 32k XTAL has not started up, calibration - * will time out, returning 0. - */ - ESP_EARLY_LOGD(TAG, "waiting for 32k oscillator to start up"); - if (slow_clk == SLOW_CLK_32K_XTAL) { - rtc_clk_32k_enable(true); - } else if (slow_clk == SLOW_CLK_32K_EXT_OSC) { - rtc_clk_32k_enable_external(); - } - // When SLOW_CLK_CAL_CYCLES is set to 0, clock calibration will not be performed at startup. - if (SLOW_CLK_CAL_CYCLES > 0) { - cal_val = rtc_clk_cal(RTC_CAL_32K_XTAL, SLOW_CLK_CAL_CYCLES); - if (cal_val == 0 || cal_val < MIN_32K_XTAL_CAL_VAL) { - if (retry_32k_xtal-- > 0) { - continue; - } - ESP_EARLY_LOGW(TAG, "32 kHz XTAL not found, switching to internal 150 kHz oscillator"); - rtc_slow_freq = RTC_SLOW_FREQ_RTC; - } - } - } else if (rtc_slow_freq == RTC_SLOW_FREQ_8MD256) { - rtc_clk_8m_enable(true, true); - } - rtc_clk_slow_freq_set(rtc_slow_freq); - - if (SLOW_CLK_CAL_CYCLES > 0) { - /* TODO: 32k XTAL oscillator has some frequency drift at startup. - * Improve calibration routine to wait until the frequency is stable. - */ - cal_val = rtc_clk_cal(RTC_CAL_RTC_MUX, SLOW_CLK_CAL_CYCLES); - } else { - const uint64_t cal_dividend = (1ULL << RTC_CLK_CAL_FRACT) * 1000000ULL; - cal_val = (uint32_t) (cal_dividend / rtc_clk_slow_freq_get_hz()); - } - } while (cal_val == 0); - ESP_EARLY_LOGD(TAG, "RTC_SLOW_CLK calibration value: %d", cal_val); - esp_clk_slowclk_cal_set(cal_val); -} - -void rtc_clk_select_rtc_slow_clk(void) -{ - select_rtc_slow_clk(RTC_SLOW_FREQ_32K_XTAL); -} - -/* This function is not exposed as an API at this point. - * All peripheral clocks are default enabled after chip is powered on. - * This function disables some peripheral clocks when cpu starts. - * These peripheral clocks are enabled when the peripherals are initialized - * and disabled when they are de-initialized. - */ -void esp_perip_clk_init(void) -{ - uint32_t common_perip_clk, hwcrypto_perip_clk, wifi_bt_sdio_clk = 0; - -#if CONFIG_FREERTOS_UNICORE - RESET_REASON rst_reas[1]; -#else - RESET_REASON rst_reas[2]; -#endif - - rst_reas[0] = rtc_get_reset_reason(0); - -#if !CONFIG_FREERTOS_UNICORE - rst_reas[1] = rtc_get_reset_reason(1); -#endif - - /* For reason that only reset CPU, do not disable the clocks - * that have been enabled before reset. - */ - if ((rst_reas[0] >= TGWDT_CPU_RESET && rst_reas[0] <= RTCWDT_CPU_RESET) -#if !CONFIG_FREERTOS_UNICORE - || (rst_reas[1] >= TGWDT_CPU_RESET && rst_reas[1] <= RTCWDT_CPU_RESET) -#endif - ) { - common_perip_clk = ~DPORT_READ_PERI_REG(DPORT_PERIP_CLK_EN_REG); - hwcrypto_perip_clk = ~DPORT_READ_PERI_REG(DPORT_PERI_CLK_EN_REG); - wifi_bt_sdio_clk = ~DPORT_READ_PERI_REG(DPORT_WIFI_CLK_EN_REG); - } - else { - common_perip_clk = DPORT_WDG_CLK_EN | - DPORT_PCNT_CLK_EN | - DPORT_LEDC_CLK_EN | - DPORT_TIMERGROUP1_CLK_EN | - DPORT_PWM0_CLK_EN | - DPORT_CAN_CLK_EN | - DPORT_PWM1_CLK_EN | - DPORT_PWM2_CLK_EN | - DPORT_PWM3_CLK_EN; - hwcrypto_perip_clk = DPORT_PERI_EN_AES | - DPORT_PERI_EN_SHA | - DPORT_PERI_EN_RSA | - DPORT_PERI_EN_SECUREBOOT; - wifi_bt_sdio_clk = DPORT_WIFI_CLK_WIFI_EN | - DPORT_WIFI_CLK_BT_EN_M | - DPORT_WIFI_CLK_UNUSED_BIT5 | - DPORT_WIFI_CLK_UNUSED_BIT12 | - DPORT_WIFI_CLK_SDIOSLAVE_EN | - DPORT_WIFI_CLK_SDIO_HOST_EN | - DPORT_WIFI_CLK_EMAC_EN; - } - - //Reset the communication peripherals like I2C, SPI, UART, I2S and bring them to known state. - common_perip_clk |= DPORT_I2S0_CLK_EN | -#if CONFIG_ESP_CONSOLE_UART_NUM != 0 - DPORT_UART_CLK_EN | -#endif -#if CONFIG_ESP_CONSOLE_UART_NUM != 1 - DPORT_UART1_CLK_EN | -#endif -#if CONFIG_ESP_CONSOLE_UART_NUM != 2 - DPORT_UART2_CLK_EN | -#endif - DPORT_SPI2_CLK_EN | - DPORT_I2C_EXT0_CLK_EN | - DPORT_UHCI0_CLK_EN | - DPORT_RMT_CLK_EN | - DPORT_UHCI1_CLK_EN | - DPORT_SPI3_CLK_EN | - DPORT_I2C_EXT1_CLK_EN | - DPORT_I2S1_CLK_EN | - DPORT_SPI_DMA_CLK_EN; - - common_perip_clk &= ~DPORT_SPI01_CLK_EN; - -#if CONFIG_SPIRAM_SPEED_80M -//80MHz SPIRAM uses SPI2/SPI3 as well; it's initialized before this is called. Because it is used in -//a weird mode where clock to the peripheral is disabled but reset is also disabled, it 'hangs' -//in a state where it outputs a continuous 80MHz signal. Mask its bit here because we should -//not modify that state, regardless of what we calculated earlier. - if (spicommon_periph_in_use(HSPI_HOST)) { - common_perip_clk &= ~DPORT_SPI2_CLK_EN; - } - if (spicommon_periph_in_use(VSPI_HOST)) { - common_perip_clk &= ~DPORT_SPI3_CLK_EN; - } -#endif - - /* Change I2S clock to audio PLL first. Because if I2S uses 160MHz clock, - * the current is not reduced when disable I2S clock. - */ - DPORT_SET_PERI_REG_MASK(I2S_CLKM_CONF_REG(0), I2S_CLKA_ENA); - DPORT_SET_PERI_REG_MASK(I2S_CLKM_CONF_REG(1), I2S_CLKA_ENA); - - /* Disable some peripheral clocks. */ - DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, common_perip_clk); - DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, common_perip_clk); - - /* Disable hardware crypto clocks. */ - DPORT_CLEAR_PERI_REG_MASK(DPORT_PERI_CLK_EN_REG, hwcrypto_perip_clk); - DPORT_SET_PERI_REG_MASK(DPORT_PERI_RST_EN_REG, hwcrypto_perip_clk); - - /* Disable WiFi/BT/SDIO clocks. */ - DPORT_CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, wifi_bt_sdio_clk); - - /* Enable RNG clock. */ - periph_module_enable(PERIPH_RNG_MODULE); -} diff --git a/components/esp32s2/CMakeLists.txt b/components/esp32s2/CMakeLists.txt index b4b4865a41..a1173e6a50 100644 --- a/components/esp32s2/CMakeLists.txt +++ b/components/esp32s2/CMakeLists.txt @@ -14,7 +14,6 @@ else() set(srcs "cache_err_int.c" "memprot.c" "clk.c" - "cpu_start.c" "crosscore_int.c" "dport_access.c" "hw_random.c" diff --git a/components/esp32s2/clk.c b/components/esp32s2/clk.c index 36ed52dd34..4bf0e1e85f 100644 --- a/components/esp32s2/clk.c +++ b/components/esp32s2/clk.c @@ -13,318 +13,34 @@ // limitations under the License. #include -#include -#include #include -#include "sdkconfig.h" + #include "esp_attr.h" -#include "esp_log.h" -#include "esp32s2/clk.h" -#include "esp_clk_internal.h" -#include "esp32s2/rom/ets_sys.h" -#include "esp32s2/rom/uart.h" -#include "esp32s2/rom/rtc.h" -#include "soc/system_reg.h" -#include "soc/dport_access.h" -#include "soc/soc.h" #include "soc/rtc.h" -#include "soc/rtc_periph.h" -#include "soc/i2s_reg.h" -#include "hal/wdt_hal.h" -#include "driver/periph_ctrl.h" -#include "xtensa/core-macros.h" -#include "bootloader_clock.h" -#include "soc/syscon_reg.h" - -/* Number of cycles to wait from the 32k XTAL oscillator to consider it running. - * Larger values increase startup delay. Smaller values may cause false positive - * detection (i.e. oscillator runs for a few cycles and then stops). - */ -#define SLOW_CLK_CAL_CYCLES CONFIG_ESP32S2_RTC_CLK_CAL_CYCLES - -#ifdef CONFIG_ESP32S2_RTC_XTAL_CAL_RETRY -#define RTC_XTAL_CAL_RETRY CONFIG_ESP32S2_RTC_XTAL_CAL_RETRY -#else -#define RTC_XTAL_CAL_RETRY 1 -#endif +#include "esp32s2/clk.h" #define MHZ (1000000) -/* Lower threshold for a reasonably-looking calibration value for a 32k XTAL. - * The ideal value (assuming 32768 Hz frequency) is 1000000/32768*(2**19) = 16*10^6. - */ -#define MIN_32K_XTAL_CAL_VAL 15000000L - -/* Indicates that this 32k oscillator gets input from external oscillator, rather - * than a crystal. - */ -#define EXT_OSC_FLAG BIT(3) - -/* This is almost the same as rtc_slow_freq_t, except that we define - * an extra enum member for the external 32k oscillator. - * For convenience, lower 2 bits should correspond to rtc_slow_freq_t values. - */ -typedef enum { - SLOW_CLK_RTC = RTC_SLOW_FREQ_RTC, //!< Internal 90 kHz RC oscillator - SLOW_CLK_32K_XTAL = RTC_SLOW_FREQ_32K_XTAL, //!< External 32 kHz XTAL - SLOW_CLK_8MD256 = RTC_SLOW_FREQ_8MD256, //!< Internal 8 MHz RC oscillator, divided by 256 - SLOW_CLK_32K_EXT_OSC = RTC_SLOW_FREQ_32K_XTAL | EXT_OSC_FLAG //!< External 32k oscillator connected to 32K_XP pin -} slow_clk_sel_t; - -static void select_rtc_slow_clk(slow_clk_sel_t slow_clk); - -static const char *TAG = "clk"; - - -void esp_clk_init(void) -{ - rtc_config_t cfg = RTC_CONFIG_DEFAULT(); - RESET_REASON rst_reas; - rst_reas = rtc_get_reset_reason(0); - if (rst_reas == POWERON_RESET) { - cfg.cali_ocode = 1; - } - rtc_init(cfg); - - assert(rtc_clk_xtal_freq_get() == RTC_XTAL_FREQ_40M); - - rtc_clk_fast_freq_set(RTC_FAST_FREQ_8M); - -#ifdef CONFIG_BOOTLOADER_WDT_ENABLE - // WDT uses a SLOW_CLK clock source. After a function select_rtc_slow_clk a frequency of this source can changed. - // If the frequency changes from 90kHz to 32kHz, then the timeout set for the WDT will increase 2.8 times. - // Therefore, for the time of frequency change, set a new lower timeout value (1.6 sec). - // This prevents excessive delay before resetting in case the supply voltage is drawdown. - // (If frequency is changed from 90kHz to 32kHz then WDT timeout will increased to 1.6sec * 90/32 = 4.5 sec). - wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; - uint32_t stage_timeout_ticks = (uint32_t)(1600ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); - wdt_hal_write_protect_disable(&rtc_wdt_ctx); - wdt_hal_feed(&rtc_wdt_ctx); - //Bootloader has enabled RTC WDT until now. We're only modifying timeout, so keep the stage and timeout action the same - wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); - wdt_hal_write_protect_enable(&rtc_wdt_ctx); -#endif - -#if defined(CONFIG_ESP32S2_RTC_CLK_SRC_EXT_CRYS) - select_rtc_slow_clk(SLOW_CLK_32K_XTAL); -#elif defined(CONFIG_ESP32S2_RTC_CLK_SRC_EXT_OSC) - select_rtc_slow_clk(SLOW_CLK_32K_EXT_OSC); -#elif defined(CONFIG_ESP32S2_RTC_CLK_SRC_INT_8MD256) - select_rtc_slow_clk(SLOW_CLK_8MD256); -#else - select_rtc_slow_clk(RTC_SLOW_FREQ_RTC); -#endif - -#ifdef CONFIG_BOOTLOADER_WDT_ENABLE - // After changing a frequency WDT timeout needs to be set for new frequency. - stage_timeout_ticks = (uint32_t)((uint64_t)CONFIG_BOOTLOADER_WDT_TIME_MS * rtc_clk_slow_freq_get_hz() / 1000ULL); - wdt_hal_write_protect_disable(&rtc_wdt_ctx); - wdt_hal_feed(&rtc_wdt_ctx); - wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); - wdt_hal_write_protect_enable(&rtc_wdt_ctx); -#endif - - rtc_cpu_freq_config_t old_config, new_config; - rtc_clk_cpu_freq_get_config(&old_config); - const uint32_t old_freq_mhz = old_config.freq_mhz; - const uint32_t new_freq_mhz = CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ; - - bool res = rtc_clk_cpu_freq_mhz_to_config(new_freq_mhz, &new_config); - assert(res); - - // Wait for UART TX to finish, otherwise some UART output will be lost - // when switching APB frequency - uart_tx_wait_idle(CONFIG_ESP_CONSOLE_UART_NUM); - - rtc_clk_cpu_freq_set_config(&new_config); - - // Re calculate the ccount to make time calculation correct. - XTHAL_SET_CCOUNT( (uint64_t)XTHAL_GET_CCOUNT() * new_freq_mhz / old_freq_mhz ); -} +// g_ticks_us defined in ROMs for PRO and APP CPU +extern uint32_t g_ticks_per_us_pro; int IRAM_ATTR esp_clk_cpu_freq(void) { - return ets_get_cpu_frequency() * 1000000; + return g_ticks_per_us_pro * MHZ; } int IRAM_ATTR esp_clk_apb_freq(void) { - return MIN(ets_get_cpu_frequency(), 80) * 1000000; + return MIN(g_ticks_per_us_pro, 80) * MHZ; } -static void select_rtc_slow_clk(slow_clk_sel_t slow_clk) +int IRAM_ATTR esp_clk_xtal_freq(void) { - rtc_slow_freq_t rtc_slow_freq = slow_clk & RTC_CNTL_ANA_CLK_RTC_SEL_V; - uint32_t cal_val = 0; - /* number of times to repeat 32k XTAL calibration - * before giving up and switching to the internal RC - */ - int retry_32k_xtal = RTC_XTAL_CAL_RETRY; - - do { - if (rtc_slow_freq == RTC_SLOW_FREQ_32K_XTAL) { - /* 32k XTAL oscillator needs to be enabled and running before it can - * be used. Hardware doesn't have a direct way of checking if the - * oscillator is running. Here we use rtc_clk_cal function to count - * the number of main XTAL cycles in the given number of 32k XTAL - * oscillator cycles. If the 32k XTAL has not started up, calibration - * will time out, returning 0. - */ - ESP_EARLY_LOGD(TAG, "waiting for 32k oscillator to start up"); - if (slow_clk == SLOW_CLK_32K_XTAL) { - rtc_clk_32k_enable(true); - } else if (slow_clk == SLOW_CLK_32K_EXT_OSC) { - rtc_clk_32k_enable_external(); - } - // When SLOW_CLK_CAL_CYCLES is set to 0, clock calibration will not be performed at startup. - if (SLOW_CLK_CAL_CYCLES > 0) { - cal_val = rtc_clk_cal(RTC_CAL_32K_XTAL, SLOW_CLK_CAL_CYCLES); - if (cal_val == 0 || cal_val < MIN_32K_XTAL_CAL_VAL) { - if (retry_32k_xtal-- > 0) { - continue; - } - ESP_EARLY_LOGW(TAG, "32 kHz XTAL not found, switching to internal 90 kHz oscillator"); - rtc_slow_freq = RTC_SLOW_FREQ_RTC; - } - } - } else if (rtc_slow_freq == RTC_SLOW_FREQ_8MD256) { - rtc_clk_8m_enable(true, true); - } - rtc_clk_slow_freq_set(rtc_slow_freq); - - if (SLOW_CLK_CAL_CYCLES > 0) { - /* TODO: 32k XTAL oscillator has some frequency drift at startup. - * Improve calibration routine to wait until the frequency is stable. - */ - cal_val = rtc_clk_cal(RTC_CAL_RTC_MUX, SLOW_CLK_CAL_CYCLES); - } else { - const uint64_t cal_dividend = (1ULL << RTC_CLK_CAL_FRACT) * 1000000ULL; - cal_val = (uint32_t) (cal_dividend / rtc_clk_slow_freq_get_hz()); - } - } while (cal_val == 0); - ESP_EARLY_LOGD(TAG, "RTC_SLOW_CLK calibration value: %d", cal_val); - esp_clk_slowclk_cal_set(cal_val); + return rtc_clk_xtal_freq_get() * MHZ; } -void rtc_clk_select_rtc_slow_clk(void) +void IRAM_ATTR ets_update_cpu_frequency(uint32_t ticks_per_us) { - select_rtc_slow_clk(RTC_SLOW_FREQ_32K_XTAL); -} - -/* This function is not exposed as an API at this point. - * All peripheral clocks are default enabled after chip is powered on. - * This function disables some peripheral clocks when cpu starts. - * These peripheral clocks are enabled when the peripherals are initialized - * and disabled when they are de-initialized. - */ -void esp_perip_clk_init(void) -{ - uint32_t common_perip_clk, hwcrypto_perip_clk, wifi_bt_sdio_clk = 0; - uint32_t common_perip_clk1 = 0; - - RESET_REASON rst_reas[1]; - - rst_reas[0] = rtc_get_reset_reason(0); - - /* For reason that only reset CPU, do not disable the clocks - * that have been enabled before reset. - */ - if (rst_reas[0] >= TG0WDT_CPU_RESET && - rst_reas[0] <= TG0WDT_CPU_RESET && - rst_reas[0] != RTCWDT_BROWN_OUT_RESET) { - common_perip_clk = ~DPORT_READ_PERI_REG(DPORT_PERIP_CLK_EN_REG); - hwcrypto_perip_clk = ~DPORT_READ_PERI_REG(DPORT_PERIP_CLK_EN1_REG); - wifi_bt_sdio_clk = ~DPORT_READ_PERI_REG(DPORT_WIFI_CLK_EN_REG); - } else { - common_perip_clk = DPORT_WDG_CLK_EN | - DPORT_I2S0_CLK_EN | -#if CONFIG_ESP_CONSOLE_UART_NUM != 0 - DPORT_UART_CLK_EN | -#endif -#if CONFIG_ESP_CONSOLE_UART_NUM != 1 - DPORT_UART1_CLK_EN | -#endif - DPORT_USB_CLK_EN | - DPORT_SPI2_CLK_EN | - DPORT_I2C_EXT0_CLK_EN | - DPORT_UHCI0_CLK_EN | - DPORT_RMT_CLK_EN | - DPORT_PCNT_CLK_EN | - DPORT_LEDC_CLK_EN | - DPORT_TIMERGROUP1_CLK_EN | - DPORT_SPI3_CLK_EN | - DPORT_SPI4_CLK_EN | - DPORT_PWM0_CLK_EN | - DPORT_CAN_CLK_EN | - DPORT_PWM1_CLK_EN | - DPORT_I2S1_CLK_EN | - DPORT_SPI2_DMA_CLK_EN | - DPORT_SPI3_DMA_CLK_EN | - DPORT_PWM2_CLK_EN | - DPORT_PWM3_CLK_EN; - common_perip_clk1 = 0; - hwcrypto_perip_clk = DPORT_CRYPTO_AES_CLK_EN | - DPORT_CRYPTO_SHA_CLK_EN | - DPORT_CRYPTO_RSA_CLK_EN; - wifi_bt_sdio_clk = DPORT_WIFI_CLK_WIFI_EN | - DPORT_WIFI_CLK_BT_EN_M | - DPORT_WIFI_CLK_UNUSED_BIT5 | - DPORT_WIFI_CLK_UNUSED_BIT12 | - DPORT_WIFI_CLK_SDIOSLAVE_EN | - DPORT_WIFI_CLK_SDIO_HOST_EN | - DPORT_WIFI_CLK_EMAC_EN; - } - - //Reset the communication peripherals like I2C, SPI, UART, I2S and bring them to known state. - common_perip_clk |= DPORT_I2S0_CLK_EN | -#if CONFIG_ESP_CONSOLE_UART_NUM != 0 - DPORT_UART_CLK_EN | -#endif -#if CONFIG_ESP_CONSOLE_UART_NUM != 1 - DPORT_UART1_CLK_EN | -#endif - DPORT_USB_CLK_EN | - DPORT_SPI2_CLK_EN | - DPORT_I2C_EXT0_CLK_EN | - DPORT_UHCI0_CLK_EN | - DPORT_RMT_CLK_EN | - DPORT_UHCI1_CLK_EN | - DPORT_SPI3_CLK_EN | - DPORT_SPI4_CLK_EN | - DPORT_I2C_EXT1_CLK_EN | - DPORT_I2S1_CLK_EN | - DPORT_SPI2_DMA_CLK_EN | - DPORT_SPI3_DMA_CLK_EN; - common_perip_clk1 = 0; - - /* Change I2S clock to audio PLL first. Because if I2S uses 160MHz clock, - * the current is not reduced when disable I2S clock. - */ - REG_SET_FIELD(I2S_CLKM_CONF_REG(0), I2S_CLK_SEL, I2S_CLK_AUDIO_PLL); - REG_SET_FIELD(I2S_CLKM_CONF_REG(1), I2S_CLK_SEL, I2S_CLK_AUDIO_PLL); - - /* Disable some peripheral clocks. */ - DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, common_perip_clk); - DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, common_perip_clk); - - DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN1_REG, common_perip_clk1); - DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN1_REG, common_perip_clk1); - - /* Disable hardware crypto clocks. */ - DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN1_REG, hwcrypto_perip_clk); - DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN1_REG, hwcrypto_perip_clk); - - /* Disable WiFi/BT/SDIO clocks. */ - DPORT_CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, wifi_bt_sdio_clk); - - /* Enable WiFi MAC and POWER clocks */ - DPORT_SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_WIFI_EN); - - /* Set WiFi light sleep clock source to RTC slow clock */ - DPORT_REG_SET_FIELD(DPORT_BT_LPCK_DIV_INT_REG, DPORT_BT_LPCK_DIV_NUM, 0); - DPORT_CLEAR_PERI_REG_MASK(DPORT_BT_LPCK_DIV_FRAC_REG, DPORT_LPCLK_SEL_8M); - DPORT_SET_PERI_REG_MASK(DPORT_BT_LPCK_DIV_FRAC_REG, DPORT_LPCLK_SEL_RTC_SLOW); - - /* Enable RNG clock. */ - periph_module_enable(PERIPH_RNG_MODULE); + /* Update scale factors used by ets_delay_us */ + g_ticks_per_us_pro = ticks_per_us; } diff --git a/components/esp32s2/esp_clk_internal.h b/components/esp32s2/esp_clk_internal.h deleted file mode 100644 index f1f8964573..0000000000 --- a/components/esp32s2/esp_clk_internal.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2015-2017 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. - -#pragma once - -/** - * @file esp_clk_internal.h - * - * Private clock-related functions - */ - -/** - * @brief Initialize clock-related settings - * - * Called from cpu_start.c, not intended to be called from other places. - * This function configures the CPU clock, RTC slow and fast clocks, and - * performs RTC slow clock calibration. - */ -void esp_clk_init(void); - - -/** - * @brief Disables clock of some peripherals - * - * Called from cpu_start.c, not intended to be called from other places. - * This function disables clock of useless peripherals when cpu starts. - */ -void esp_perip_clk_init(void); - -/* Selects an external clock source (32 kHz) for RTC. - * Only internal use in unit test. - */ -void rtc_clk_select_rtc_slow_clk(void); diff --git a/components/esp_system/port/esp32/CMakeLists.txt b/components/esp_system/port/esp32/CMakeLists.txt index ca83bcc618..e07df9ed2a 100644 --- a/components/esp_system/port/esp32/CMakeLists.txt +++ b/components/esp_system/port/esp32/CMakeLists.txt @@ -1,2 +1,4 @@ -target_sources(${COMPONENT_LIB} PRIVATE "${CMAKE_CURRENT_LIST_DIR}/dport_panic_highint_hdl.S" - "${CMAKE_CURRENT_LIST_DIR}/reset_reason.c") +set(srcs "dport_panic_highint_hdl.S" "clk.c" "reset_reason.c") +add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" ${srcs}) + +target_sources(${COMPONENT_LIB} PRIVATE ${srcs}) diff --git a/components/esp_system/port/esp32/clk.c b/components/esp_system/port/esp32/clk.c new file mode 100644 index 0000000000..247f4e0f0a --- /dev/null +++ b/components/esp_system/port/esp32/clk.c @@ -0,0 +1,315 @@ + +// Copyright 2015-2017 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 "soc/rtc.h" +#include "soc/dport_reg.h" +#include "soc/dport_access.h" +#include "xtensa/core-macros.h" +#include "soc/i2s_reg.h" +#include "driver/periph_ctrl.h" +#include "bootloader_clock.h" +#include "hal/wdt_hal.h" + +#include "driver/spi_common_internal.h" // [refactor-todo]: for spicommon_periph_in_use + +#include "esp_log.h" + +#include "esp32/clk.h" +#include "esp32/rom/uart.h" +#include "esp32/rom/rtc.h" + +#include "sdkconfig.h" + +static const char* TAG = "clk"; + +/* Number of cycles to wait from the 32k XTAL oscillator to consider it running. + * Larger values increase startup delay. Smaller values may cause false positive + * detection (i.e. oscillator runs for a few cycles and then stops). + */ +#define SLOW_CLK_CAL_CYCLES CONFIG_ESP32_RTC_CLK_CAL_CYCLES + +#ifdef CONFIG_ESP32_RTC_XTAL_CAL_RETRY +#define RTC_XTAL_CAL_RETRY CONFIG_ESP32_RTC_XTAL_CAL_RETRY +#else +#define RTC_XTAL_CAL_RETRY 1 +#endif + +/* Lower threshold for a reasonably-looking calibration value for a 32k XTAL. + * The ideal value (assuming 32768 Hz frequency) is 1000000/32768*(2**19) = 16*10^6. + */ +#define MIN_32K_XTAL_CAL_VAL 15000000L + +/* Indicates that this 32k oscillator gets input from external oscillator, rather + * than a crystal. + */ +#define EXT_OSC_FLAG BIT(3) + +/* This is almost the same as rtc_slow_freq_t, except that we define + * an extra enum member for the external 32k oscillator. + * For convenience, lower 2 bits should correspond to rtc_slow_freq_t values. + */ +typedef enum { + SLOW_CLK_150K = RTC_SLOW_FREQ_RTC, //!< Internal 150 kHz RC oscillator + SLOW_CLK_32K_XTAL = RTC_SLOW_FREQ_32K_XTAL, //!< External 32 kHz XTAL + SLOW_CLK_8MD256 = RTC_SLOW_FREQ_8MD256, //!< Internal 8 MHz RC oscillator, divided by 256 + SLOW_CLK_32K_EXT_OSC = RTC_SLOW_FREQ_32K_XTAL | EXT_OSC_FLAG //!< External 32k oscillator connected to 32K_XP pin +} slow_clk_sel_t; + +static void select_rtc_slow_clk(slow_clk_sel_t slow_clk) +{ + rtc_slow_freq_t rtc_slow_freq = slow_clk & RTC_CNTL_ANA_CLK_RTC_SEL_V; + uint32_t cal_val = 0; + /* number of times to repeat 32k XTAL calibration + * before giving up and switching to the internal RC + */ + int retry_32k_xtal = RTC_XTAL_CAL_RETRY; + + do { + if (rtc_slow_freq == RTC_SLOW_FREQ_32K_XTAL) { + /* 32k XTAL oscillator needs to be enabled and running before it can + * be used. Hardware doesn't have a direct way of checking if the + * oscillator is running. Here we use rtc_clk_cal function to count + * the number of main XTAL cycles in the given number of 32k XTAL + * oscillator cycles. If the 32k XTAL has not started up, calibration + * will time out, returning 0. + */ + ESP_EARLY_LOGD(TAG, "waiting for 32k oscillator to start up"); + if (slow_clk == SLOW_CLK_32K_XTAL) { + rtc_clk_32k_enable(true); + } else if (slow_clk == SLOW_CLK_32K_EXT_OSC) { + rtc_clk_32k_enable_external(); + } + // When SLOW_CLK_CAL_CYCLES is set to 0, clock calibration will not be performed at startup. + if (SLOW_CLK_CAL_CYCLES > 0) { + cal_val = rtc_clk_cal(RTC_CAL_32K_XTAL, SLOW_CLK_CAL_CYCLES); + if (cal_val == 0 || cal_val < MIN_32K_XTAL_CAL_VAL) { + if (retry_32k_xtal-- > 0) { + continue; + } + ESP_EARLY_LOGW(TAG, "32 kHz XTAL not found, switching to internal 150 kHz oscillator"); + rtc_slow_freq = RTC_SLOW_FREQ_RTC; + } + } + } else if (rtc_slow_freq == RTC_SLOW_FREQ_8MD256) { + rtc_clk_8m_enable(true, true); + } + rtc_clk_slow_freq_set(rtc_slow_freq); + + if (SLOW_CLK_CAL_CYCLES > 0) { + /* TODO: 32k XTAL oscillator has some frequency drift at startup. + * Improve calibration routine to wait until the frequency is stable. + */ + cal_val = rtc_clk_cal(RTC_CAL_RTC_MUX, SLOW_CLK_CAL_CYCLES); + } else { + const uint64_t cal_dividend = (1ULL << RTC_CLK_CAL_FRACT) * 1000000ULL; + cal_val = (uint32_t) (cal_dividend / rtc_clk_slow_freq_get_hz()); + } + } while (cal_val == 0); + ESP_EARLY_LOGD(TAG, "RTC_SLOW_CLK calibration value: %d", cal_val); + esp_clk_slowclk_cal_set(cal_val); +} + +void esp_clk_init(void) +{ + rtc_config_t cfg = RTC_CONFIG_DEFAULT(); + rtc_init(cfg); + +#if (CONFIG_ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS || CONFIG_ESP32_APP_INIT_CLK) + /* Check the bootloader set the XTAL frequency. + + Bootloaders pre-v2.1 don't do this. + */ + rtc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get(); + if (xtal_freq == RTC_XTAL_FREQ_AUTO) { + ESP_EARLY_LOGW(TAG, "RTC domain not initialised by bootloader"); + bootloader_clock_configure(); + } +#else + /* If this assertion fails, either upgrade the bootloader or enable CONFIG_ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS */ + assert(rtc_clk_xtal_freq_get() != RTC_XTAL_FREQ_AUTO); +#endif + + rtc_clk_fast_freq_set(RTC_FAST_FREQ_8M); + +#ifdef CONFIG_BOOTLOADER_WDT_ENABLE + // WDT uses a SLOW_CLK clock source. After a function select_rtc_slow_clk a frequency of this source can changed. + // If the frequency changes from 150kHz to 32kHz, then the timeout set for the WDT will increase 4.6 times. + // Therefore, for the time of frequency change, set a new lower timeout value (1.6 sec). + // This prevents excessive delay before resetting in case the supply voltage is drawdown. + // (If frequency is changed from 150kHz to 32kHz then WDT timeout will increased to 1.6sec * 150/32 = 7.5 sec). + wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; + uint32_t stage_timeout_ticks = (uint32_t)(1600ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_feed(&rtc_wdt_ctx); + //Bootloader has enabled RTC WDT until now. We're only modifying timeout, so keep the stage and timeout action the same + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); +#endif + +#if defined(CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS) + select_rtc_slow_clk(SLOW_CLK_32K_XTAL); +#elif defined(CONFIG_ESP32_RTC_CLK_SRC_EXT_OSC) + select_rtc_slow_clk(SLOW_CLK_32K_EXT_OSC); +#elif defined(CONFIG_ESP32_RTC_CLK_SRC_INT_8MD256) + select_rtc_slow_clk(SLOW_CLK_8MD256); +#else + select_rtc_slow_clk(RTC_SLOW_FREQ_RTC); +#endif + +#ifdef CONFIG_BOOTLOADER_WDT_ENABLE + // After changing a frequency WDT timeout needs to be set for new frequency. + stage_timeout_ticks = (uint32_t)((uint64_t)CONFIG_BOOTLOADER_WDT_TIME_MS * rtc_clk_slow_freq_get_hz() / 1000); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_feed(&rtc_wdt_ctx); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); +#endif + + rtc_cpu_freq_config_t old_config, new_config; + rtc_clk_cpu_freq_get_config(&old_config); + const uint32_t old_freq_mhz = old_config.freq_mhz; + const uint32_t new_freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ; + + bool res = rtc_clk_cpu_freq_mhz_to_config(new_freq_mhz, &new_config); + assert(res); + + // Wait for UART TX to finish, otherwise some UART output will be lost + // when switching APB frequency + uart_tx_wait_idle(CONFIG_ESP_CONSOLE_UART_NUM); + + rtc_clk_cpu_freq_set_config(&new_config); + + // Re calculate the ccount to make time calculation correct. + XTHAL_SET_CCOUNT( (uint64_t)XTHAL_GET_CCOUNT() * new_freq_mhz / old_freq_mhz ); +} + +/* This function is not exposed as an API at this point. + * All peripheral clocks are default enabled after chip is powered on. + * This function disables some peripheral clocks when cpu starts. + * These peripheral clocks are enabled when the peripherals are initialized + * and disabled when they are de-initialized. + */ +void esp_perip_clk_init(void) +{ + uint32_t common_perip_clk, hwcrypto_perip_clk, wifi_bt_sdio_clk = 0; + +#if CONFIG_FREERTOS_UNICORE + RESET_REASON rst_reas[1]; +#else + RESET_REASON rst_reas[2]; +#endif + + rst_reas[0] = rtc_get_reset_reason(0); + +#if !CONFIG_FREERTOS_UNICORE + rst_reas[1] = rtc_get_reset_reason(1); +#endif + + /* For reason that only reset CPU, do not disable the clocks + * that have been enabled before reset. + */ + if ((rst_reas[0] >= TGWDT_CPU_RESET && rst_reas[0] <= RTCWDT_CPU_RESET) +#if !CONFIG_FREERTOS_UNICORE + || (rst_reas[1] >= TGWDT_CPU_RESET && rst_reas[1] <= RTCWDT_CPU_RESET) +#endif + ) { + common_perip_clk = ~DPORT_READ_PERI_REG(DPORT_PERIP_CLK_EN_REG); + hwcrypto_perip_clk = ~DPORT_READ_PERI_REG(DPORT_PERI_CLK_EN_REG); + wifi_bt_sdio_clk = ~DPORT_READ_PERI_REG(DPORT_WIFI_CLK_EN_REG); + } + else { + common_perip_clk = DPORT_WDG_CLK_EN | + DPORT_PCNT_CLK_EN | + DPORT_LEDC_CLK_EN | + DPORT_TIMERGROUP1_CLK_EN | + DPORT_PWM0_CLK_EN | + DPORT_CAN_CLK_EN | + DPORT_PWM1_CLK_EN | + DPORT_PWM2_CLK_EN | + DPORT_PWM3_CLK_EN; + hwcrypto_perip_clk = DPORT_PERI_EN_AES | + DPORT_PERI_EN_SHA | + DPORT_PERI_EN_RSA | + DPORT_PERI_EN_SECUREBOOT; + wifi_bt_sdio_clk = DPORT_WIFI_CLK_WIFI_EN | + DPORT_WIFI_CLK_BT_EN_M | + DPORT_WIFI_CLK_UNUSED_BIT5 | + DPORT_WIFI_CLK_UNUSED_BIT12 | + DPORT_WIFI_CLK_SDIOSLAVE_EN | + DPORT_WIFI_CLK_SDIO_HOST_EN | + DPORT_WIFI_CLK_EMAC_EN; + } + + //Reset the communication peripherals like I2C, SPI, UART, I2S and bring them to known state. + common_perip_clk |= DPORT_I2S0_CLK_EN | +#if CONFIG_ESP_CONSOLE_UART_NUM != 0 + DPORT_UART_CLK_EN | +#endif +#if CONFIG_ESP_CONSOLE_UART_NUM != 1 + DPORT_UART1_CLK_EN | +#endif +#if CONFIG_ESP_CONSOLE_UART_NUM != 2 + DPORT_UART2_CLK_EN | +#endif + DPORT_SPI2_CLK_EN | + DPORT_I2C_EXT0_CLK_EN | + DPORT_UHCI0_CLK_EN | + DPORT_RMT_CLK_EN | + DPORT_UHCI1_CLK_EN | + DPORT_SPI3_CLK_EN | + DPORT_I2C_EXT1_CLK_EN | + DPORT_I2S1_CLK_EN | + DPORT_SPI_DMA_CLK_EN; + + common_perip_clk &= ~DPORT_SPI01_CLK_EN; + +#if CONFIG_SPIRAM_SPEED_80M +//80MHz SPIRAM uses SPI2/SPI3 as well; it's initialized before this is called. Because it is used in +//a weird mode where clock to the peripheral is disabled but reset is also disabled, it 'hangs' +//in a state where it outputs a continuous 80MHz signal. Mask its bit here because we should +//not modify that state, regardless of what we calculated earlier. + if (spicommon_periph_in_use(HSPI_HOST)) { + common_perip_clk &= ~DPORT_SPI2_CLK_EN; + } + if (spicommon_periph_in_use(VSPI_HOST)) { + common_perip_clk &= ~DPORT_SPI3_CLK_EN; + } +#endif + + /* Change I2S clock to audio PLL first. Because if I2S uses 160MHz clock, + * the current is not reduced when disable I2S clock. + */ + DPORT_SET_PERI_REG_MASK(I2S_CLKM_CONF_REG(0), I2S_CLKA_ENA); + DPORT_SET_PERI_REG_MASK(I2S_CLKM_CONF_REG(1), I2S_CLKA_ENA); + + /* Disable some peripheral clocks. */ + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, common_perip_clk); + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, common_perip_clk); + + /* Disable hardware crypto clocks. */ + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERI_CLK_EN_REG, hwcrypto_perip_clk); + DPORT_SET_PERI_REG_MASK(DPORT_PERI_RST_EN_REG, hwcrypto_perip_clk); + + /* Disable WiFi/BT/SDIO clocks. */ + DPORT_CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, wifi_bt_sdio_clk); + + /* Enable RNG clock. */ + periph_module_enable(PERIPH_RNG_MODULE); +} + +void rtc_clk_select_rtc_slow_clk(void) +{ + select_rtc_slow_clk(RTC_SLOW_FREQ_32K_XTAL); +} \ No newline at end of file diff --git a/components/esp_system/port/esp32s2/CMakeLists.txt b/components/esp_system/port/esp32s2/CMakeLists.txt index ca83bcc618..e07df9ed2a 100644 --- a/components/esp_system/port/esp32s2/CMakeLists.txt +++ b/components/esp_system/port/esp32s2/CMakeLists.txt @@ -1,2 +1,4 @@ -target_sources(${COMPONENT_LIB} PRIVATE "${CMAKE_CURRENT_LIST_DIR}/dport_panic_highint_hdl.S" - "${CMAKE_CURRENT_LIST_DIR}/reset_reason.c") +set(srcs "dport_panic_highint_hdl.S" "clk.c" "reset_reason.c") +add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" ${srcs}) + +target_sources(${COMPONENT_LIB} PRIVATE ${srcs}) diff --git a/components/esp_system/port/esp32s2/clk.c b/components/esp_system/port/esp32s2/clk.c new file mode 100644 index 0000000000..e516df44f1 --- /dev/null +++ b/components/esp_system/port/esp32s2/clk.c @@ -0,0 +1,318 @@ + +// Copyright 2015-2017 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 +#include +#include "sdkconfig.h" +#include "esp_attr.h" +#include "esp_log.h" +#include "esp32s2/clk.h" +#include "esp_clk_internal.h" +#include "esp32s2/rom/ets_sys.h" +#include "esp32s2/rom/uart.h" +#include "esp32s2/rom/rtc.h" +#include "soc/system_reg.h" +#include "soc/dport_access.h" +#include "soc/soc.h" +#include "soc/rtc.h" +#include "hal/wdt_hal.h" +#include "soc/rtc_periph.h" +#include "soc/i2s_reg.h" +#include "driver/periph_ctrl.h" +#include "xtensa/core-macros.h" +#include "bootloader_clock.h" +#include "soc/syscon_reg.h" + +static const char *TAG = "clk"; + +/* Number of cycles to wait from the 32k XTAL oscillator to consider it running. + * Larger values increase startup delay. Smaller values may cause false positive + * detection (i.e. oscillator runs for a few cycles and then stops). + */ +#define SLOW_CLK_CAL_CYCLES CONFIG_ESP32S2_RTC_CLK_CAL_CYCLES + +#ifdef CONFIG_ESP32S2_RTC_XTAL_CAL_RETRY +#define RTC_XTAL_CAL_RETRY CONFIG_ESP32S2_RTC_XTAL_CAL_RETRY +#else +#define RTC_XTAL_CAL_RETRY 1 +#endif + +/* Lower threshold for a reasonably-looking calibration value for a 32k XTAL. + * The ideal value (assuming 32768 Hz frequency) is 1000000/32768*(2**19) = 16*10^6. + */ +#define MIN_32K_XTAL_CAL_VAL 15000000L + +/* Indicates that this 32k oscillator gets input from external oscillator, rather + * than a crystal. + */ +#define EXT_OSC_FLAG BIT(3) + +/* This is almost the same as rtc_slow_freq_t, except that we define + * an extra enum member for the external 32k oscillator. + * For convenience, lower 2 bits should correspond to rtc_slow_freq_t values. + */ +typedef enum { + SLOW_CLK_RTC = RTC_SLOW_FREQ_RTC, //!< Internal 90 kHz RC oscillator + SLOW_CLK_32K_XTAL = RTC_SLOW_FREQ_32K_XTAL, //!< External 32 kHz XTAL + SLOW_CLK_8MD256 = RTC_SLOW_FREQ_8MD256, //!< Internal 8 MHz RC oscillator, divided by 256 + SLOW_CLK_32K_EXT_OSC = RTC_SLOW_FREQ_32K_XTAL | EXT_OSC_FLAG //!< External 32k oscillator connected to 32K_XP pin +} slow_clk_sel_t; + +static void select_rtc_slow_clk(slow_clk_sel_t slow_clk); + +void esp_clk_init(void) +{ + rtc_config_t cfg = RTC_CONFIG_DEFAULT(); + RESET_REASON rst_reas; + rst_reas = rtc_get_reset_reason(0); + if (rst_reas == POWERON_RESET) { + cfg.cali_ocode = 1; + } + rtc_init(cfg); + + assert(rtc_clk_xtal_freq_get() == RTC_XTAL_FREQ_40M); + + rtc_clk_fast_freq_set(RTC_FAST_FREQ_8M); + +#ifdef CONFIG_BOOTLOADER_WDT_ENABLE + // WDT uses a SLOW_CLK clock source. After a function select_rtc_slow_clk a frequency of this source can changed. + // If the frequency changes from 90kHz to 32kHz, then the timeout set for the WDT will increase 2.8 times. + // Therefore, for the time of frequency change, set a new lower timeout value (1.6 sec). + // This prevents excessive delay before resetting in case the supply voltage is drawdown. + // (If frequency is changed from 90kHz to 32kHz then WDT timeout will increased to 1.6sec * 90/32 = 4.5 sec). + wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; + uint32_t stage_timeout_ticks = (uint32_t)(1600ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_feed(&rtc_wdt_ctx); + //Bootloader has enabled RTC WDT until now. We're only modifying timeout, so keep the stage and timeout action the same + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); +#endif + +#if defined(CONFIG_ESP32S2_RTC_CLK_SRC_EXT_CRYS) + select_rtc_slow_clk(SLOW_CLK_32K_XTAL); +#elif defined(CONFIG_ESP32S2_RTC_CLK_SRC_EXT_OSC) + select_rtc_slow_clk(SLOW_CLK_32K_EXT_OSC); +#elif defined(CONFIG_ESP32S2_RTC_CLK_SRC_INT_8MD256) + select_rtc_slow_clk(SLOW_CLK_8MD256); +#else + select_rtc_slow_clk(RTC_SLOW_FREQ_RTC); +#endif + +#ifdef CONFIG_BOOTLOADER_WDT_ENABLE + // After changing a frequency WDT timeout needs to be set for new frequency. + stage_timeout_ticks = (uint32_t)((uint64_t)CONFIG_BOOTLOADER_WDT_TIME_MS * rtc_clk_slow_freq_get_hz() / 1000ULL); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_feed(&rtc_wdt_ctx); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); +#endif + + rtc_cpu_freq_config_t old_config, new_config; + rtc_clk_cpu_freq_get_config(&old_config); + const uint32_t old_freq_mhz = old_config.freq_mhz; + const uint32_t new_freq_mhz = CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ; + + bool res = rtc_clk_cpu_freq_mhz_to_config(new_freq_mhz, &new_config); + assert(res); + + // Wait for UART TX to finish, otherwise some UART output will be lost + // when switching APB frequency + uart_tx_wait_idle(CONFIG_ESP_CONSOLE_UART_NUM); + + rtc_clk_cpu_freq_set_config(&new_config); + + // Re calculate the ccount to make time calculation correct. + XTHAL_SET_CCOUNT( (uint64_t)XTHAL_GET_CCOUNT() * new_freq_mhz / old_freq_mhz ); +} + +static void select_rtc_slow_clk(slow_clk_sel_t slow_clk) +{ + rtc_slow_freq_t rtc_slow_freq = slow_clk & RTC_CNTL_ANA_CLK_RTC_SEL_V; + uint32_t cal_val = 0; + /* number of times to repeat 32k XTAL calibration + * before giving up and switching to the internal RC + */ + int retry_32k_xtal = RTC_XTAL_CAL_RETRY; + + do { + if (rtc_slow_freq == RTC_SLOW_FREQ_32K_XTAL) { + /* 32k XTAL oscillator needs to be enabled and running before it can + * be used. Hardware doesn't have a direct way of checking if the + * oscillator is running. Here we use rtc_clk_cal function to count + * the number of main XTAL cycles in the given number of 32k XTAL + * oscillator cycles. If the 32k XTAL has not started up, calibration + * will time out, returning 0. + */ + ESP_EARLY_LOGD(TAG, "waiting for 32k oscillator to start up"); + if (slow_clk == SLOW_CLK_32K_XTAL) { + rtc_clk_32k_enable(true); + } else if (slow_clk == SLOW_CLK_32K_EXT_OSC) { + rtc_clk_32k_enable_external(); + } + // When SLOW_CLK_CAL_CYCLES is set to 0, clock calibration will not be performed at startup. + if (SLOW_CLK_CAL_CYCLES > 0) { + cal_val = rtc_clk_cal(RTC_CAL_32K_XTAL, SLOW_CLK_CAL_CYCLES); + if (cal_val == 0 || cal_val < MIN_32K_XTAL_CAL_VAL) { + if (retry_32k_xtal-- > 0) { + continue; + } + ESP_EARLY_LOGW(TAG, "32 kHz XTAL not found, switching to internal 90 kHz oscillator"); + rtc_slow_freq = RTC_SLOW_FREQ_RTC; + } + } + } else if (rtc_slow_freq == RTC_SLOW_FREQ_8MD256) { + rtc_clk_8m_enable(true, true); + } + rtc_clk_slow_freq_set(rtc_slow_freq); + + if (SLOW_CLK_CAL_CYCLES > 0) { + /* TODO: 32k XTAL oscillator has some frequency drift at startup. + * Improve calibration routine to wait until the frequency is stable. + */ + cal_val = rtc_clk_cal(RTC_CAL_RTC_MUX, SLOW_CLK_CAL_CYCLES); + } else { + const uint64_t cal_dividend = (1ULL << RTC_CLK_CAL_FRACT) * 1000000ULL; + cal_val = (uint32_t) (cal_dividend / rtc_clk_slow_freq_get_hz()); + } + } while (cal_val == 0); + ESP_EARLY_LOGD(TAG, "RTC_SLOW_CLK calibration value: %d", cal_val); + esp_clk_slowclk_cal_set(cal_val); +} + +void rtc_clk_select_rtc_slow_clk(void) +{ + select_rtc_slow_clk(RTC_SLOW_FREQ_32K_XTAL); +} + +/* This function is not exposed as an API at this point. + * All peripheral clocks are default enabled after chip is powered on. + * This function disables some peripheral clocks when cpu starts. + * These peripheral clocks are enabled when the peripherals are initialized + * and disabled when they are de-initialized. + */ +void esp_perip_clk_init(void) +{ + uint32_t common_perip_clk, hwcrypto_perip_clk, wifi_bt_sdio_clk = 0; + uint32_t common_perip_clk1 = 0; + + RESET_REASON rst_reas[1]; + + rst_reas[0] = rtc_get_reset_reason(0); + + /* For reason that only reset CPU, do not disable the clocks + * that have been enabled before reset. + */ + if (rst_reas[0] >= TG0WDT_CPU_RESET && + rst_reas[0] <= TG0WDT_CPU_RESET && + rst_reas[0] != RTCWDT_BROWN_OUT_RESET) { + common_perip_clk = ~DPORT_READ_PERI_REG(DPORT_PERIP_CLK_EN_REG); + hwcrypto_perip_clk = ~DPORT_READ_PERI_REG(DPORT_PERIP_CLK_EN1_REG); + wifi_bt_sdio_clk = ~DPORT_READ_PERI_REG(DPORT_WIFI_CLK_EN_REG); + } else { + common_perip_clk = DPORT_WDG_CLK_EN | + DPORT_I2S0_CLK_EN | +#if CONFIG_ESP_CONSOLE_UART_NUM != 0 + DPORT_UART_CLK_EN | +#endif +#if CONFIG_ESP_CONSOLE_UART_NUM != 1 + DPORT_UART1_CLK_EN | +#endif + DPORT_USB_CLK_EN | + DPORT_SPI2_CLK_EN | + DPORT_I2C_EXT0_CLK_EN | + DPORT_UHCI0_CLK_EN | + DPORT_RMT_CLK_EN | + DPORT_PCNT_CLK_EN | + DPORT_LEDC_CLK_EN | + DPORT_TIMERGROUP1_CLK_EN | + DPORT_SPI3_CLK_EN | + DPORT_SPI4_CLK_EN | + DPORT_PWM0_CLK_EN | + DPORT_CAN_CLK_EN | + DPORT_PWM1_CLK_EN | + DPORT_I2S1_CLK_EN | + DPORT_SPI2_DMA_CLK_EN | + DPORT_SPI3_DMA_CLK_EN | + DPORT_PWM2_CLK_EN | + DPORT_PWM3_CLK_EN; + common_perip_clk1 = 0; + hwcrypto_perip_clk = DPORT_CRYPTO_AES_CLK_EN | + DPORT_CRYPTO_SHA_CLK_EN | + DPORT_CRYPTO_RSA_CLK_EN; + wifi_bt_sdio_clk = DPORT_WIFI_CLK_WIFI_EN | + DPORT_WIFI_CLK_BT_EN_M | + DPORT_WIFI_CLK_UNUSED_BIT5 | + DPORT_WIFI_CLK_UNUSED_BIT12 | + DPORT_WIFI_CLK_SDIOSLAVE_EN | + DPORT_WIFI_CLK_SDIO_HOST_EN | + DPORT_WIFI_CLK_EMAC_EN; + } + + //Reset the communication peripherals like I2C, SPI, UART, I2S and bring them to known state. + common_perip_clk |= DPORT_I2S0_CLK_EN | +#if CONFIG_ESP_CONSOLE_UART_NUM != 0 + DPORT_UART_CLK_EN | +#endif +#if CONFIG_ESP_CONSOLE_UART_NUM != 1 + DPORT_UART1_CLK_EN | +#endif + DPORT_USB_CLK_EN | + DPORT_SPI2_CLK_EN | + DPORT_I2C_EXT0_CLK_EN | + DPORT_UHCI0_CLK_EN | + DPORT_RMT_CLK_EN | + DPORT_UHCI1_CLK_EN | + DPORT_SPI3_CLK_EN | + DPORT_SPI4_CLK_EN | + DPORT_I2C_EXT1_CLK_EN | + DPORT_I2S1_CLK_EN | + DPORT_SPI2_DMA_CLK_EN | + DPORT_SPI3_DMA_CLK_EN; + common_perip_clk1 = 0; + + /* Change I2S clock to audio PLL first. Because if I2S uses 160MHz clock, + * the current is not reduced when disable I2S clock. + */ + REG_SET_FIELD(I2S_CLKM_CONF_REG(0), I2S_CLK_SEL, I2S_CLK_AUDIO_PLL); + REG_SET_FIELD(I2S_CLKM_CONF_REG(1), I2S_CLK_SEL, I2S_CLK_AUDIO_PLL); + + /* Disable some peripheral clocks. */ + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, common_perip_clk); + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, common_perip_clk); + + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN1_REG, common_perip_clk1); + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN1_REG, common_perip_clk1); + + /* Disable hardware crypto clocks. */ + DPORT_CLEAR_PERI_REG_MASK(DPORT_PERIP_CLK_EN1_REG, hwcrypto_perip_clk); + DPORT_SET_PERI_REG_MASK(DPORT_PERIP_RST_EN1_REG, hwcrypto_perip_clk); + + /* Disable WiFi/BT/SDIO clocks. */ + DPORT_CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, wifi_bt_sdio_clk); + + /* Enable WiFi MAC and POWER clocks */ + DPORT_SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_WIFI_EN); + + /* Set WiFi light sleep clock source to RTC slow clock */ + DPORT_REG_SET_FIELD(DPORT_BT_LPCK_DIV_INT_REG, DPORT_BT_LPCK_DIV_NUM, 0); + DPORT_CLEAR_PERI_REG_MASK(DPORT_BT_LPCK_DIV_FRAC_REG, DPORT_LPCLK_SEL_8M); + DPORT_SET_PERI_REG_MASK(DPORT_BT_LPCK_DIV_FRAC_REG, DPORT_LPCLK_SEL_RTC_SLOW); + + /* Enable RNG clock. */ + periph_module_enable(PERIPH_RNG_MODULE); +} \ No newline at end of file diff --git a/components/esp32/esp_clk_internal.h b/components/esp_system/port/include/esp_clk_internal.h similarity index 100% rename from components/esp32/esp_clk_internal.h rename to components/esp_system/port/include/esp_clk_internal.h diff --git a/components/soc/test/test_rtc_clk.c b/components/soc/test/test_rtc_clk.c index 36480d0381..717acb713c 100644 --- a/components/soc/test/test_rtc_clk.c +++ b/components/soc/test/test_rtc_clk.c @@ -10,7 +10,8 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" -#include "../esp_clk_internal.h" + +extern void rtc_clk_select_rtc_slow_clk(void); #if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2) From bb5535ca5d3bc37c5f63114bb41abea6cd5bbd0e Mon Sep 17 00:00:00 2001 From: Renz Bagaporo Date: Tue, 3 Mar 2020 12:22:41 +0800 Subject: [PATCH 03/17] esp32, esp32s2: move startup code into esp_system --- components/esp32/CMakeLists.txt | 3 - components/esp32/cpu_start.c | 592 ------------------ components/esp32s2/CMakeLists.txt | 3 - components/esp_common/src/brownout.c | 2 +- components/esp_system/CMakeLists.txt | 9 +- components/esp_system/port/CMakeLists.txt | 2 +- components/esp_system/port/cpu_start.c | 407 ++++++++++++ components/esp_system/port/esp32/intr.c | 15 + components/esp_system/port/include/intr.h | 0 .../esp_system/private_include/sys_funcs.h | 21 + .../cpu_start.c => esp_system/startup.c} | 399 +++++------- components/freertos/Kconfig | 4 +- 12 files changed, 610 insertions(+), 847 deletions(-) delete mode 100644 components/esp32/cpu_start.c create mode 100644 components/esp_system/port/cpu_start.c create mode 100644 components/esp_system/port/esp32/intr.c create mode 100644 components/esp_system/port/include/intr.h create mode 100644 components/esp_system/private_include/sys_funcs.h rename components/{esp32s2/cpu_start.c => esp_system/startup.c} (58%) diff --git a/components/esp32/CMakeLists.txt b/components/esp32/CMakeLists.txt index f94fd806ff..fffee5cc0e 100644 --- a/components/esp32/CMakeLists.txt +++ b/components/esp32/CMakeLists.txt @@ -15,7 +15,6 @@ else() "cache_err_int.c" "cache_sram_mmu.c" "clk.c" - "cpu_start.c" "crosscore_int.c" "dport_access.c" "esp_himem.c" @@ -48,8 +47,6 @@ else() target_linker_script(${COMPONENT_LIB} INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/esp32_out.ld") - # Rely on user code to define app_main - target_link_libraries(${COMPONENT_LIB} INTERFACE "-u app_main") if(CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY) # This has to be linked before esp32.project.ld diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c deleted file mode 100644 index 2aa6d9c462..0000000000 --- a/components/esp32/cpu_start.c +++ /dev/null @@ -1,592 +0,0 @@ -// Copyright 2015-2018 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 "esp32/rom/ets_sys.h" -#include "esp32/rom/uart.h" -#include "esp32/rom/rtc.h" -#include "esp32/rom/cache.h" - -#include "soc/cpu.h" -#include "soc/rtc.h" -#include "soc/dport_reg.h" -#include "soc/gpio_periph.h" -#include "soc/timer_periph.h" -#include "soc/efuse_periph.h" - -#include "hal/wdt_hal.h" - -#include "driver/rtc_io.h" - -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" -#include "freertos/queue.h" - -#include "esp_heap_caps_init.h" -#include "sdkconfig.h" -#include "esp_system.h" -#include "esp_spi_flash.h" -#include "esp_flash_internal.h" -#include "nvs_flash.h" -#include "esp_spi_flash.h" -#include "esp_private/crosscore_int.h" -#include "esp_log.h" -#include "esp_vfs_dev.h" -#include "esp_newlib.h" -#include "esp32/brownout.h" -#include "esp_int_wdt.h" -#include "esp_task.h" -#include "esp_task_wdt.h" -#include "esp_phy_init.h" -#include "esp32/cache_err_int.h" -#include "esp_coexist_internal.h" -#include "esp_core_dump.h" -#include "esp_app_trace.h" -#include "esp_private/dbg_stubs.h" -#include "esp_flash_encrypt.h" -#include "esp32/spiram.h" -#include "esp_clk_internal.h" -#include "esp_timer.h" -#include "esp_pm.h" -#include "esp_private/pm_impl.h" -#include "trax.h" -#include "esp_ota_ops.h" -#include "esp_efuse.h" -#include "bootloader_flash_config.h" -#include "bootloader_mem.h" - -#ifdef CONFIG_APP_BUILD_TYPE_ELF_RAM -#include "esp32/rom/efuse.h" -#include "esp32/rom/spi_flash.h" -#endif // CONFIG_APP_BUILD_TYPE_ELF_RAM - -#define STRINGIFY(s) STRINGIFY2(s) -#define STRINGIFY2(s) #s - -void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default"))) __attribute__((noreturn)); -void start_cpu0_default(void) IRAM_ATTR __attribute__((noreturn)); -#if !CONFIG_FREERTOS_UNICORE -static void IRAM_ATTR call_start_cpu1(void) __attribute__((noreturn)); -void start_cpu1(void) __attribute__((weak, alias("start_cpu1_default"))) __attribute__((noreturn)); -void start_cpu1_default(void) IRAM_ATTR __attribute__((noreturn)); -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 esp_err_t esp_pthread_init(void); - -extern int _bss_start; -extern int _bss_end; -extern int _rtc_bss_start; -extern int _rtc_bss_end; -#ifdef CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY -extern int _iram_bss_start; -extern int _iram_bss_end; -#endif -#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY -extern int _ext_ram_bss_start; -extern int _ext_ram_bss_end; -#endif -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"; - -struct object { long placeholder[ 10 ]; }; -void __register_frame_info (const void *begin, struct object *ob); -extern char __eh_frame[]; - -//If CONFIG_SPIRAM_IGNORE_NOTFOUND is set and external RAM is not found or errors out on testing, this is set to false. -static bool s_spiram_okay=true; - -/* - * 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(void) -{ -#if CONFIG_FREERTOS_UNICORE - RESET_REASON rst_reas[1]; -#else - RESET_REASON rst_reas[2]; -#endif - - bootloader_init_mem(); - - // Move exception vectors to IRAM - cpu_hal_set_vecbase(&_init_start); - - rst_reas[0] = rtc_get_reset_reason(0); - -#if !CONFIG_FREERTOS_UNICORE - rst_reas[1] = rtc_get_reset_reason(1); -#endif - - // from panic handler we can be reset by RWDT or TG0WDT - if (rst_reas[0] == RTCWDT_SYS_RESET || rst_reas[0] == TG0WDT_SYS_RESET -#if !CONFIG_FREERTOS_UNICORE - || rst_reas[1] == RTCWDT_SYS_RESET || rst_reas[1] == TG0WDT_SYS_RESET -#endif - ) { -#ifndef CONFIG_BOOTLOADER_WDT_ENABLE - wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; - wdt_hal_write_protect_disable(&rtc_wdt_ctx); - wdt_hal_disable(&rtc_wdt_ctx); - wdt_hal_write_protect_enable(&rtc_wdt_ctx); -#endif - } - - //Clear BSS. Please do not attempt to do any complex stuff (like early logging) before this. - memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start)); - -#ifdef CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY - // Clear IRAM BSS - memset(&_iram_bss_start, 0, (&_iram_bss_end - &_iram_bss_start) * sizeof(_iram_bss_start)); -#endif - - /* Unless waking from deep sleep (implying RTC memory is intact), clear RTC bss */ - if (rst_reas[0] != DEEPSLEEP_RESET) { - memset(&_rtc_bss_start, 0, (&_rtc_bss_end - &_rtc_bss_start) * sizeof(_rtc_bss_start)); - } - -#if CONFIG_SPIRAM_BOOT_INIT - esp_spiram_init_cache(); - if (esp_spiram_init() != ESP_OK) { -#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY - ESP_EARLY_LOGE(TAG, "Failed to init external RAM, needed for external .bss segment"); - abort(); -#endif - -#if CONFIG_SPIRAM_IGNORE_NOTFOUND - ESP_EARLY_LOGI(TAG, "Failed to init external RAM; continuing without it."); - s_spiram_okay = false; -#else - ESP_EARLY_LOGE(TAG, "Failed to init external RAM!"); - abort(); -#endif - } -#endif - - ESP_EARLY_LOGI(TAG, "Pro cpu up."); - if (LOG_LOCAL_LEVEL >= ESP_LOG_INFO) { - const esp_app_desc_t *app_desc = esp_ota_get_app_description(); - ESP_EARLY_LOGI(TAG, "Application information:"); -#ifndef CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR - ESP_EARLY_LOGI(TAG, "Project name: %s", app_desc->project_name); -#endif -#ifndef CONFIG_APP_EXCLUDE_PROJECT_VER_VAR - ESP_EARLY_LOGI(TAG, "App version: %s", app_desc->version); -#endif -#ifdef CONFIG_BOOTLOADER_APP_SECURE_VERSION - ESP_EARLY_LOGI(TAG, "Secure version: %d", app_desc->secure_version); -#endif -#ifdef CONFIG_APP_COMPILE_TIME_DATE - ESP_EARLY_LOGI(TAG, "Compile time: %s %s", app_desc->date, app_desc->time); -#endif - char buf[17]; - esp_ota_get_app_elf_sha256(buf, sizeof(buf)); - ESP_EARLY_LOGI(TAG, "ELF file SHA256: %s...", buf); - ESP_EARLY_LOGI(TAG, "ESP-IDF: %s", app_desc->idf_ver); - } - -#if !CONFIG_FREERTOS_UNICORE - if (REG_GET_BIT(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_DIS_APP_CPU)) { - ESP_EARLY_LOGE(TAG, "Running on single core chip, but application is built with dual core support."); - ESP_EARLY_LOGE(TAG, "Please enable CONFIG_FREERTOS_UNICORE option in menuconfig."); - abort(); - } - ESP_EARLY_LOGI(TAG, "Starting app cpu, entry point is %p", call_start_cpu1); - - //Flush and enable icache for APP CPU - Cache_Flush(1); - Cache_Read_Enable(1); - esp_cpu_unstall(1); - // Enable clock and reset APP CPU. Note that OpenOCD may have already - // enabled clock and taken APP CPU out of reset. In this case don't reset - // APP CPU again, as that will clear the breakpoints which may have already - // been set. - if (!DPORT_GET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN)) { - DPORT_SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN); - DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_C_REG, DPORT_APPCPU_RUNSTALL); - DPORT_SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING); - DPORT_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"); - DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN); -#endif - - -#if CONFIG_SPIRAM_MEMTEST - if (s_spiram_okay) { - bool ext_ram_ok=esp_spiram_test(); - if (!ext_ram_ok) { - ESP_EARLY_LOGE(TAG, "External RAM failed memory test!"); - abort(); - } - } -#endif -#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY - memset(&_ext_ram_bss_start, 0, (&_ext_ram_bss_end - &_ext_ram_bss_start) * sizeof(_ext_ram_bss_start)); -#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. - With SPI RAM enabled, there's a second reason: half of the SPI RAM will be managed by the - app CPU, and when that is not up yet, the memory will be inaccessible and heap_caps_init may - fail initializing it properly. */ - heap_caps_init(); - - ESP_EARLY_LOGI(TAG, "Pro cpu start user code"); - start_cpu0(); -} - -#if !CONFIG_FREERTOS_UNICORE - -static void wdt_reset_cpu1_info_enable(void) -{ - DPORT_REG_SET_BIT(DPORT_APP_CPU_RECORD_CTRL_REG, DPORT_APP_CPU_PDEBUG_ENABLE | DPORT_APP_CPU_RECORD_ENABLE); - DPORT_REG_CLR_BIT(DPORT_APP_CPU_RECORD_CTRL_REG, DPORT_APP_CPU_RECORD_ENABLE); -} - -void IRAM_ATTR call_start_cpu1(void) -{ - // Move exception vectors to IRAM - cpu_hal_set_vecbase(&_init_start); - - ets_set_appcpu_boot_addr(0); - - bootloader_init_mem(); - -#if CONFIG_ESP_CONSOLE_UART_NONE - ets_install_putc1(NULL); - ets_install_putc2(NULL); -#else // CONFIG_ESP_CONSOLE_UART_NONE - uartAttach(); - ets_install_uart_printf(); - uart_tx_switch(CONFIG_ESP_CONSOLE_UART_NUM); -#endif - - wdt_reset_cpu1_info_enable(); - ESP_EARLY_LOGI(TAG, "App cpu up."); - app_cpu_started = 1; - start_cpu1(); -} -#endif //!CONFIG_FREERTOS_UNICORE - -static void intr_matrix_clear(void) -{ - //Clear all the interrupt matrix register - for (int i = ETS_WIFI_MAC_INTR_SOURCE; i <= ETS_CACHE_IA_INTR_SOURCE; i++) { - intr_matrix_set(0, i, ETS_INVALID_INUM); -#if !CONFIG_FREERTOS_UNICORE - intr_matrix_set(1, i, ETS_INVALID_INUM); -#endif - } -} - -void start_cpu0_default(void) -{ - esp_err_t err; - esp_setup_syscall_table(); - - if (s_spiram_okay) { -#if CONFIG_SPIRAM_BOOT_INIT && (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC) - esp_err_t r=esp_spiram_add_to_heapalloc(); - if (r != ESP_OK) { - ESP_EARLY_LOGE(TAG, "External RAM could not be added to heap!"); - abort(); - } -#if CONFIG_SPIRAM_USE_MALLOC - heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL); -#endif -#endif - } - -//Enable trace memory and immediately start trace. -#if CONFIG_ESP32_TRAX -#if CONFIG_ESP32_TRAX_TWOBANKS - trax_enable(TRAX_ENA_PRO_APP); -#else - trax_enable(TRAX_ENA_PRO); -#endif - trax_start_trace(TRAX_DOWNCOUNT_WORDS); -#endif - esp_clk_init(); - esp_perip_clk_init(); - intr_matrix_clear(); - -#ifndef CONFIG_ESP_CONSOLE_UART_NONE -#ifdef CONFIG_PM_ENABLE - const int uart_clk_freq = REF_CLK_FREQ; - /* When DFS is enabled, use REFTICK as UART clock source */ - CLEAR_PERI_REG_MASK(UART_CONF0_REG(CONFIG_ESP_CONSOLE_UART_NUM), UART_TICK_REF_ALWAYS_ON); -#else - const int uart_clk_freq = APB_CLK_FREQ; -#endif // CONFIG_PM_DFS_ENABLE - uart_div_modify(CONFIG_ESP_CONSOLE_UART_NUM, (uart_clk_freq << 4) / CONFIG_ESP_CONSOLE_UART_BAUDRATE); -#endif // CONFIG_ESP_CONSOLE_UART_NONE - -#if CONFIG_ESP32_BROWNOUT_DET - esp_brownout_init(); -#endif - - rtc_gpio_force_hold_dis_all(); - -#ifdef CONFIG_VFS_SUPPORT_IO - esp_vfs_dev_uart_register(); -#endif // CONFIG_VFS_SUPPORT_IO - -#if defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_UART_NONE) - esp_reent_init(_GLOBAL_REENT); - const char* default_uart_dev = "/dev/uart/" STRINGIFY(CONFIG_ESP_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 // defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_UART_NONE) - _REENT_SMALL_CHECK_INIT(_GLOBAL_REENT); -#endif // defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_UART_NONE) - // After setting _GLOBAL_REENT, ESP_LOGIx can be used instead of ESP_EARLY_LOGx. - -#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED - esp_flash_encryption_init_checks(); -#endif -#if CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE - esp_efuse_disable_basic_rom_console(); -#endif -#if CONFIG_SECURE_DISABLE_ROM_DL_MODE - esp_efuse_disable_rom_download_mode(); -#endif - - esp_timer_init(); - esp_set_time_from_rtc(); -#if CONFIG_APPTRACE_ENABLE - err = esp_apptrace_init(); - assert(err == ESP_OK && "Failed to init apptrace module on PRO CPU!"); -#endif -#if CONFIG_SYSVIEW_ENABLE - SEGGER_SYSVIEW_Conf(); -#endif -#if CONFIG_ESP_DEBUG_STUBS_ENABLE - esp_dbg_stubs_init(); -#endif - err = esp_pthread_init(); - assert(err == ESP_OK && "Failed to init pthread module!"); - - do_global_ctors(); -#if CONFIG_ESP_INT_WDT - esp_int_wdt_init(); - //Initialize the interrupt watch dog for CPU0. - esp_int_wdt_cpu_init(); -#else -#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_cache_err_int_init(); - esp_crosscore_int_init(); -#ifndef CONFIG_FREERTOS_UNICORE - esp_dport_access_int_init(); -#endif - - bootloader_flash_update_id(); -#if !CONFIG_SPIRAM_BOOT_INIT - // Read the application binary image header. This will also decrypt the header if the image is encrypted. - esp_image_header_t fhdr = {0}; -#ifdef CONFIG_APP_BUILD_TYPE_ELF_RAM - fhdr.spi_mode = ESP_IMAGE_SPI_MODE_DIO; - fhdr.spi_speed = ESP_IMAGE_SPI_SPEED_40M; - fhdr.spi_size = ESP_IMAGE_FLASH_SIZE_4MB; - - extern void esp_rom_spiflash_attach(uint32_t, bool); - esp_rom_spiflash_attach(ets_efuse_get_spiconfig(), false); - esp_rom_spiflash_unlock(); -#else - // This assumes that DROM is the first segment in the application binary, i.e. that we can read - // the binary header through cache by accessing SOC_DROM_LOW address. - memcpy(&fhdr, (void*) SOC_DROM_LOW, sizeof(fhdr)); -#endif // CONFIG_APP_BUILD_TYPE_ELF_RAM - - // If psram is uninitialized, we need to improve some flash configuration. - bootloader_flash_clock_config(&fhdr); - bootloader_flash_gpio_config(&fhdr); - bootloader_flash_dummy_config(&fhdr); - bootloader_flash_cs_timing_config(); -#endif //!CONFIG_SPIRAM_BOOT_INIT - - spi_flash_init(); - /* init default OS-aware flash access critical section */ - spi_flash_guard_set(&g_flash_guard_default_ops); - - esp_flash_app_init(); - esp_err_t flash_ret = esp_flash_init_default_chip(); - assert(flash_ret == ESP_OK); - -#ifdef CONFIG_PM_ENABLE - esp_pm_impl_init(); -#ifdef CONFIG_PM_DFS_INIT_AUTO - int xtal_freq = (int) rtc_clk_xtal_freq_get(); - esp_pm_config_esp32_t cfg = { - .max_freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ, - .min_freq_mhz = xtal_freq, - }; - esp_pm_configure(&cfg); -#endif //CONFIG_PM_DFS_INIT_AUTO -#endif //CONFIG_PM_ENABLE - -#if CONFIG_ESP32_ENABLE_COREDUMP - esp_core_dump_init(); -#endif - -#if CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE - esp_coex_adapter_register(&g_coex_adapter_funcs); - coex_pre_init(); -#endif - - portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main", - ESP_TASK_MAIN_STACK, NULL, - ESP_TASK_MAIN_PRIO, NULL, 0); - assert(res == pdTRUE); - ESP_LOGI(TAG, "Starting scheduler on PRO CPU."); - vTaskStartScheduler(); - abort(); /* Only get to here if not enough free heap to start scheduler */ -} - -#if !CONFIG_FREERTOS_UNICORE -void start_cpu1_default(void) -{ - // Wait for FreeRTOS initialization to finish on PRO CPU - while (port_xSchedulerRunning[0] == 0) { - ; - } -#if CONFIG_ESP32_TRAX_TWOBANKS - trax_start_trace(TRAX_DOWNCOUNT_WORDS); -#endif -#if CONFIG_APPTRACE_ENABLE - 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 - //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_cache_err_int_init(); - esp_crosscore_int_init(); - esp_dport_access_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 - -#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS -size_t __cxx_eh_arena_size_get(void) -{ - return CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE; -} -#endif - -static void do_global_ctors(void) -{ -#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS - static struct object ob; - __register_frame_info( __eh_frame, &ob ); -#endif - - void (**p)(void); - for (p = &__init_array_end - 1; p >= &__init_array_start; --p) { - (*p)(); - } -} - -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 - //Enable allocation in region where the startup stacks were located. - 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 - 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 -#ifdef CONFIG_ESP_TASK_WDT_PANIC - ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, true)); -#elif CONFIG_ESP_TASK_WDT - ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, false)); -#endif - - //Add IDLE 0 to task wdt -#ifdef CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 - TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0); - if(idle_0 != NULL){ - ESP_ERROR_CHECK(esp_task_wdt_add(idle_0)); - } -#endif - //Add IDLE 1 to task wdt -#ifdef CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1 - TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCPU(1); - if(idle_1 != NULL){ - ESP_ERROR_CHECK(esp_task_wdt_add(idle_1)); - } -#endif - - // Now that the application is about to start, disable boot watchdog -#ifndef CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE - wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; - wdt_hal_write_protect_disable(&rtc_wdt_ctx); - wdt_hal_disable(&rtc_wdt_ctx); - wdt_hal_write_protect_enable(&rtc_wdt_ctx); -#endif -#ifdef CONFIG_BOOTLOADER_EFUSE_SECURE_VERSION_EMULATE - const esp_partition_t *efuse_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_EFUSE_EM, NULL); - if (efuse_partition) { - esp_efuse_init(efuse_partition->address, efuse_partition->size); - } -#endif - app_main(); - vTaskDelete(NULL); -} - diff --git a/components/esp32s2/CMakeLists.txt b/components/esp32s2/CMakeLists.txt index a1173e6a50..624a78e4e6 100644 --- a/components/esp32s2/CMakeLists.txt +++ b/components/esp32s2/CMakeLists.txt @@ -50,9 +50,6 @@ else() target_linker_script(${COMPONENT_LIB} INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/esp32s2_out.ld") - # Rely on user code to define app_main - target_link_libraries(${COMPONENT_LIB} INTERFACE "-u app_main") - # Process the template file through the linker script generation mechanism, and use the output for linking the # final binary target_linker_script(${COMPONENT_LIB} INTERFACE "${CMAKE_CURRENT_LIST_DIR}/ld/esp32s2.project.ld.in" PROCESS "${CMAKE_CURRENT_BINARY_DIR}/ld/esp32s2.project.ld") diff --git a/components/esp_common/src/brownout.c b/components/esp_common/src/brownout.c index 57f62cefac..5408d10e57 100644 --- a/components/esp_common/src/brownout.c +++ b/components/esp_common/src/brownout.c @@ -69,7 +69,7 @@ void esp_brownout_init(void) brownout_hal_config(&cfg); - ESP_ERROR_CHECK( rtc_isr_register(rtc_brownout_isr_handler, NULL, RTC_CNTL_BROWN_OUT_INT_ENA_M) ); + rtc_isr_register(rtc_brownout_isr_handler, NULL, RTC_CNTL_BROWN_OUT_INT_ENA_M); brownout_hal_intr_enable(true); } diff --git a/components/esp_system/CMakeLists.txt b/components/esp_system/CMakeLists.txt index 7e5b4d57c2..de162eadc0 100644 --- a/components/esp_system/CMakeLists.txt +++ b/components/esp_system/CMakeLists.txt @@ -1,7 +1,12 @@ -idf_component_register(SRCS "panic.c" "system_api.c" +idf_component_register(SRCS "panic.c" "system_api.c" "startup.c" INCLUDE_DIRS include PRIV_INCLUDE_DIRS private_include - PRIV_REQUIRES spi_flash app_update + PRIV_REQUIRES spi_flash app_update + # requirements due to startup code + nvs_flash pthread app_trace LDFRAGMENTS "linker.lf") add_subdirectory(port) + +# Rely on user code to define app_main +target_link_libraries(${COMPONENT_LIB} INTERFACE "-u app_main") \ No newline at end of file diff --git a/components/esp_system/port/CMakeLists.txt b/components/esp_system/port/CMakeLists.txt index 75def881d3..976b568b2f 100644 --- a/components/esp_system/port/CMakeLists.txt +++ b/components/esp_system/port/CMakeLists.txt @@ -1,6 +1,6 @@ target_include_directories(${COMPONENT_LIB} PRIVATE include) -set(srcs "panic_handler.c" "panic_handler_asm.S") +set(srcs "panic_handler.c" "panic_handler_asm.S" "cpu_start.c") add_prefix(srcs "${CMAKE_CURRENT_LIST_DIR}/" ${srcs}) target_sources(${COMPONENT_LIB} PRIVATE ${srcs}) diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c new file mode 100644 index 0000000000..1999096c7a --- /dev/null +++ b/components/esp_system/port/cpu_start.c @@ -0,0 +1,407 @@ +// Copyright 2015-2018 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 + +#include "esp_attr.h" +#include "esp_err.h" + +#include "esp_log.h" +#include "esp_system.h" + +#include "esp_clk_internal.h" + +#include "sdkconfig.h" + +#if CONFIG_IDF_TARGET_ESP32 +#include "esp32/cache_err_int.h" +#include "esp32/brownout.h" +#include "esp32/rom/cache.h" +#include "esp32/rom/rtc.h" +#include "esp32/rom/uart.h" +#include "esp32/spiram.h" +#include "esp32/rom/ets_sys.h" +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/brownout.h" +#include "esp32s2/cache_err_int.h" +#include "esp32s2/rom/cache.h" +#include "esp32s2/rom/ets_sys.h" +#include "esp32s2/rom/rtc.h" +#include "esp32s2/spiram.h" +#include "esp32s2/rom/uart.h" +#include "soc/periph_defs.h" +#include "esp32s2/dport_access.h" +#include "esp32s2/memprot.h" +#endif + +#include "bootloader_flash_config.h" +#include "esp_private/crosscore_int.h" +#include "esp_flash_encrypt.h" + +#include "hal/rtc_io_hal.h" +#include "soc/dport_reg.h" +#include "soc/efuse_reg.h" +#include "soc/cpu.h" + +#include "trax.h" + +#include "bootloader_mem.h" + +#if CONFIG_IDF_TARGET_ESP32 +#if CONFIG_APP_BUILD_TYPE_ELF_RAM +#include "esp32/rom/efuse.h" +#include "esp32/rom/spi_flash.h" +#endif // CONFIG_APP_BUILD_TYPE_ELF_RAM +#endif + +#if !CONFIG_FREERTOS_UNICORE +static bool app_cpu_started = false; +#endif //!CONFIG_FREERTOS_UNICORE + +extern int _bss_start; +extern int _bss_end; +extern int _rtc_bss_start; +extern int _rtc_bss_end; + +extern int _init_start; + +static const char *TAG = "cpu_start"; + +#if CONFIG_IDF_TARGET_ESP32 +#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY +extern int _ext_ram_bss_start; +extern int _ext_ram_bss_end; +#endif +#ifdef CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY +extern int _iram_bss_start; +extern int _iram_bss_end; +#endif +#endif // CONFIG_IDF_TARGET_ESP32 + +extern void start_cpu0(void); +#if !CONFIG_FREERTOS_UNICORE +extern void start_cpu1(void); +#endif //!CONFIG_FREERTOS_UNICORE + +extern int _init_start; + +static const char* TAG = "cpu_start"; + +//If CONFIG_SPIRAM_IGNORE_NOTFOUND is set and external RAM is not found or errors out on testing, this is set to false. +bool g_spiram_ok = true; + +static void intr_matrix_clear(void) +{ +#if CONFIG_IDF_TARGET_ESP32 + //Clear all the interrupt matrix register + for (int i = ETS_WIFI_MAC_INTR_SOURCE; i <= ETS_CACHE_IA_INTR_SOURCE; i++) { +#elif CONFIG_IDF_TARGET_ESP32S2 + for (int i = ETS_WIFI_MAC_INTR_SOURCE; i < ETS_MAX_INTR_SOURCE; i++) { +#endif + intr_matrix_set(0, i, ETS_INVALID_INUM); +#if !CONFIG_FREERTOS_UNICORE + intr_matrix_set(1, i, ETS_INVALID_INUM); +#endif + } +} + +#if !CONFIG_FREERTOS_UNICORE +static void wdt_reset_cpu1_info_enable(void) +{ + DPORT_REG_SET_BIT(DPORT_APP_CPU_RECORD_CTRL_REG, DPORT_APP_CPU_PDEBUG_ENABLE | DPORT_APP_CPU_RECORD_ENABLE); + DPORT_REG_CLR_BIT(DPORT_APP_CPU_RECORD_CTRL_REG, DPORT_APP_CPU_RECORD_ENABLE); +} + +void IRAM_ATTR call_start_cpu1(void) +{ + cpu_hal_set_vecbase(&_init_start); + + ets_set_appcpu_boot_addr(0); + + bootloader_init_mem(); + +#if CONFIG_ESP_CONSOLE_UART_NONE + ets_install_putc1(NULL); + ets_install_putc2(NULL); +#else // CONFIG_ESP_CONSOLE_UART_NONE + uartAttach(); + ets_install_uart_printf(); + uart_tx_switch(CONFIG_ESP_CONSOLE_UART_NUM); +#endif + + wdt_reset_cpu1_info_enable(); + ESP_EARLY_LOGI(TAG, "App cpu up."); + app_cpu_started = 1; + + //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_cache_err_int_init(); + +#if CONFIG_IDF_TARGET_ESP32 +#if CONFIG_ESP32_TRAX_TWOBANKS + trax_start_trace(TRAX_DOWNCOUNT_WORDS); +#endif +#endif + + start_cpu1(); +} +#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(void) +{ +#if CONFIG_FREERTOS_UNICORE + RESET_REASON rst_reas[1]; +#else + RESET_REASON rst_reas[2]; +#endif + + bootloader_init_mem(); + + // Move exception vectors to IRAM + cpu_hal_set_vecbase(&_init_start); + + rst_reas[0] = rtc_get_reset_reason(0); + +#if !CONFIG_FREERTOS_UNICORE + rst_reas[1] = rtc_get_reset_reason(1); +#endif + + // from panic handler we can be reset by RWDT or TG0WDT + if (rst_reas[0] == RTCWDT_SYS_RESET || rst_reas[0] == TG0WDT_SYS_RESET +#if !CONFIG_FREERTOS_UNICORE + || rst_reas[1] == RTCWDT_SYS_RESET || rst_reas[1] == TG0WDT_SYS_RESET +#endif + ) { +#ifndef CONFIG_BOOTLOADER_WDT_ENABLE + wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_disable(&rtc_wdt_ctx); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); +#endif + } + + //Clear BSS. Please do not attempt to do any complex stuff (like early logging) before this. + memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start)); + +#if defined(CONFIG_IDF_TARGET_ESP32) && defined(CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY) + // Clear IRAM BSS + memset(&_iram_bss_start, 0, (&_iram_bss_end - &_iram_bss_start) * sizeof(_iram_bss_start)); +#endif + + /* Unless waking from deep sleep (implying RTC memory is intact), clear RTC bss */ + if (rst_reas[0] != DEEPSLEEP_RESET) { + memset(&_rtc_bss_start, 0, (&_rtc_bss_end - &_rtc_bss_start) * sizeof(_rtc_bss_start)); + } + + +#if CONFIG_IDF_TARGET_ESP32S2 + /* Configure the mode of instruction cache : cache size, cache associated ways, cache line size. */ + extern void esp_config_instruction_cache_mode(void); + esp_config_instruction_cache_mode(); + + /* If we need use SPIRAM, we should use data cache, or if we want to access rodata, we also should use data cache. + Configure the mode of data : cache size, cache associated ways, cache line size. + Enable data cache, so if we don't use SPIRAM, it just works. */ +#if CONFIG_SPIRAM_BOOT_INIT + extern void esp_config_data_cache_mode(void); + esp_config_data_cache_mode(); + Cache_Enable_DCache(0); +#endif +#endif + +#if CONFIG_SPIRAM_BOOT_INIT + esp_spiram_init_cache(); + if (esp_spiram_init() != ESP_OK) { +#if CONFIG_IDF_TARGET_ESP32 +#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY + ESP_EARLY_LOGE(TAG, "Failed to init external RAM, needed for external .bss segment"); + abort(); +#endif +#endif + +#if CONFIG_SPIRAM_IGNORE_NOTFOUND + ESP_EARLY_LOGI(TAG, "Failed to init external RAM; continuing without it."); + g_spiram_ok = false; +#else + ESP_EARLY_LOGE(TAG, "Failed to init external RAM!"); + abort(); +#endif + } +#endif + + ESP_EARLY_LOGI(TAG, "Pro cpu up."); + +#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED + esp_flash_encryption_init_checks(); +#endif + +#if !CONFIG_FREERTOS_UNICORE + if (REG_GET_BIT(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_DIS_APP_CPU)) { + ESP_EARLY_LOGE(TAG, "Running on single core chip, but application is built with dual core support."); + ESP_EARLY_LOGE(TAG, "Please enable CONFIG_FREERTOS_UNICORE option in menuconfig."); + abort(); + } + // ESP_EARLY_LOGI(TAG, "Starting app cpu, entry point is %p", call_start_cpu1); + + //Flush and enable icache for APP CPU + Cache_Flush(1); + Cache_Read_Enable(1); + esp_cpu_unstall(1); + + // Enable clock and reset APP CPU. Note that OpenOCD may have already + // enabled clock and taken APP CPU out of reset. In this case don't reset + // APP CPU again, as that will clear the breakpoints which may have already + // been set. + if (!DPORT_GET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN)) { + DPORT_SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN); + DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_C_REG, DPORT_APPCPU_RUNSTALL); + DPORT_SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING); + DPORT_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 +#if CONFIG_IDF_TARGET_ESP32 // Single core chips have no 'single core mode' + ESP_EARLY_LOGI(TAG, "Single core mode"); + DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN); +#endif +#endif + +#if CONFIG_SPIRAM_MEMTEST + if (g_spiram_ok) { + bool ext_ram_ok = esp_spiram_test(); + if (!ext_ram_ok) { + ESP_EARLY_LOGE(TAG, "External RAM failed memory test!"); + abort(); + } + } +#endif + +#if CONFIG_IDF_TARGET_ESP32S2 +#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS + extern void instruction_flash_page_info_init(void); + instruction_flash_page_info_init(); +#endif +#if CONFIG_SPIRAM_RODATA + extern void rodata_flash_page_info_init(void); + rodata_flash_page_info_init(); +#endif + +#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS + extern void esp_spiram_enable_instruction_access(void); + esp_spiram_enable_instruction_access(); +#endif +#if CONFIG_SPIRAM_RODATA + extern void esp_spiram_enable_rodata_access(void); + esp_spiram_enable_rodata_access(); +#endif + +#if CONFIG_ESP32S2_INSTRUCTION_CACHE_WRAP || CONFIG_ESP32S2_DATA_CACHE_WRAP + uint32_t icache_wrap_enable = 0, dcache_wrap_enable = 0; +#if CONFIG_ESP32S2_INSTRUCTION_CACHE_WRAP + icache_wrap_enable = 1; +#endif +#if CONFIG_ESP32S2_DATA_CACHE_WRAP + dcache_wrap_enable = 1; +#endif + extern void esp_enable_cache_wrap(uint32_t icache_wrap_enable, uint32_t dcache_wrap_enable); + esp_enable_cache_wrap(icache_wrap_enable, dcache_wrap_enable); +#endif +#endif // CONFIG_IDF_TARGET_ESP32S2 + +#if CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY + memset(&_ext_ram_bss_start, 0, (&_ext_ram_bss_end - &_ext_ram_bss_start) * sizeof(_ext_ram_bss_start)); +#endif + + /////////////////////////////////////////////////////////////////// + +//Enable trace memory and immediately start trace. +#if CONFIG_ESP32_TRAX || CONFIG_ESP32S2_TRAX +#if CONFIG_IDF_TARGET_ESP32 + #if CONFIG_ESP32_TRAX_TWOBANKS + trax_enable(TRAX_ENA_PRO_APP); + #else + trax_enable(TRAX_ENA_PRO); + #endif +#elif CONFIG_IDF_TARGET_ESP32S2 + trax_enable(TRAX_ENA_PRO); +#endif + trax_start_trace(TRAX_DOWNCOUNT_WORDS); +#endif // CONFIG_ESP32_TRAX || CONFIG_ESP32S2_TRAX + + esp_clk_init(); + esp_perip_clk_init(); + intr_matrix_clear(); + +#if CONFIG_ESP32_BROWNOUT_DET || CONFIG_ESP32S2_BROWNOUT_DET + esp_brownout_init(); +#endif + +#if CONFIG_SECURE_DISABLE_ROM_DL_MODE + err = esp_efuse_disable_rom_download_mode(); + assert(err == ESP_OK && "Failed to disable ROM download mode"); +#endif +#if CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE + err = esp_efuse_enable_rom_secure_download_mode(); + assert(err == ESP_OK && "Failed to enable Secure Download mode"); +#endif + +#if CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE || CONFIG_ESP32S2_DISABLE_BASIC_ROM_CONSOLE + esp_efuse_disable_basic_rom_console(); +#endif + + rtc_gpio_force_hold_dis_all(); + + esp_cache_err_int_init(); + + bootloader_flash_update_id(); + +#if CONFIG_IDF_TARGET_ESP32 +#if !CONFIG_SPIRAM_BOOT_INIT + // Read the application binary image header. This will also decrypt the header if the image is encrypted. + esp_image_header_t fhdr = {0}; +#ifdef CONFIG_APP_BUILD_TYPE_ELF_RAM + fhdr.spi_mode = ESP_IMAGE_SPI_MODE_DIO; + fhdr.spi_speed = ESP_IMAGE_SPI_SPEED_40M; + fhdr.spi_size = ESP_IMAGE_FLASH_SIZE_4MB; + + extern void esp_rom_spiflash_attach(uint32_t, bool); + esp_rom_spiflash_attach(ets_efuse_get_spiconfig(), false); + esp_rom_spiflash_unlock(); +#else + // This assumes that DROM is the first segment in the application binary, i.e. that we can read + // the binary header through cache by accessing SOC_DROM_LOW address. + memcpy(&fhdr, (void*) SOC_DROM_LOW, sizeof(fhdr)); +#endif // CONFIG_APP_BUILD_TYPE_ELF_RAM + + // If psram is uninitialized, we need to improve some flash configuration. + bootloader_flash_clock_config(&fhdr); + bootloader_flash_gpio_config(&fhdr); + bootloader_flash_dummy_config(&fhdr); + bootloader_flash_cs_timing_config(); +#endif //!CONFIG_SPIRAM_BOOT_INIT +#endif + + start_cpu0(); +} \ No newline at end of file diff --git a/components/esp_system/port/esp32/intr.c b/components/esp_system/port/esp32/intr.c new file mode 100644 index 0000000000..59ca2756ec --- /dev/null +++ b/components/esp_system/port/esp32/intr.c @@ -0,0 +1,15 @@ +// Copyright 2015-2018 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. + + diff --git a/components/esp_system/port/include/intr.h b/components/esp_system/port/include/intr.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/components/esp_system/private_include/sys_funcs.h b/components/esp_system/private_include/sys_funcs.h new file mode 100644 index 0000000000..21fee3ed02 --- /dev/null +++ b/components/esp_system/private_include/sys_funcs.h @@ -0,0 +1,21 @@ +// Copyright 2020 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. + +#pragma once + +#include "sdkconfig.h" + +extern bool g_spiram_ok; + +void sys_startup(void); \ No newline at end of file diff --git a/components/esp32s2/cpu_start.c b/components/esp_system/startup.c similarity index 58% rename from components/esp32s2/cpu_start.c rename to components/esp_system/startup.c index 66f4b63e3a..517d86c481 100644 --- a/components/esp32s2/cpu_start.c +++ b/components/esp_system/startup.c @@ -14,29 +14,11 @@ #include #include -#include "sdkconfig.h" + #include "esp_attr.h" #include "esp_err.h" -#include "esp32s2/rom/ets_sys.h" -#include "esp32s2/rom/uart.h" -#include "esp32s2/rom/rtc.h" -#include "esp32s2/rom/cache.h" -#include "esp32s2/dport_access.h" -#include "esp32s2/brownout.h" -#include "esp32s2/cache_err_int.h" -#include "esp32s2/spiram.h" -#include "esp32s2/memprot.h" - -#include "soc/cpu.h" -#include "soc/rtc.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 "soc/periph_defs.h" -#include "hal/wdt_hal.h" -#include "driver/rtc_io.h" +#include "soc/rtc_wdt.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -45,10 +27,8 @@ #include "esp_heap_caps_init.h" #include "esp_system.h" -#include "esp_spi_flash.h" #include "esp_flash_internal.h" #include "nvs_flash.h" -#include "esp_event.h" #include "esp_spi_flash.h" #include "esp_private/crosscore_int.h" #include "esp_log.h" @@ -59,114 +39,153 @@ #include "esp_task_wdt.h" #include "esp_phy_init.h" #include "esp_coexist_internal.h" -#include "esp_debug_helpers.h" #include "esp_core_dump.h" #include "esp_app_trace.h" #include "esp_private/dbg_stubs.h" +#include "esp_flash_encrypt.h" #include "esp_clk_internal.h" #include "esp_timer.h" #include "esp_pm.h" #include "esp_private/pm_impl.h" -#include "trax.h" #include "esp_ota_ops.h" -#include "esp_efuse.h" -#include "bootloader_mem.h" + +#include "sdkconfig.h" + +#if CONFIG_IDF_TARGET_ESP32 +#include "esp32/rom/uart.h" +#include "esp32/dport_access.h" +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/rom/uart.h" +#include "esp32s2/dport_access.h" +#endif + +#include "sys_funcs.h" #define STRINGIFY(s) STRINGIFY2(s) #define STRINGIFY2(s) #s void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default"))) __attribute__((noreturn)); void start_cpu0_default(void) IRAM_ATTR __attribute__((noreturn)); +#if !CONFIG_FREERTOS_UNICORE +void start_cpu1(void) __attribute__((weak, alias("start_cpu1_default"))) __attribute__((noreturn)); +void start_cpu1_default(void) IRAM_ATTR __attribute__((noreturn)); +#endif //!CONFIG_FREERTOS_UNICORE -static void do_global_ctors(void); -static void main_task(void *args); extern void app_main(void); extern esp_err_t esp_pthread_init(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"; +static const char* TAG = "cpu_start"; -struct object { - long placeholder[ 10 ]; -}; +struct object { long placeholder[ 10 ]; }; void __register_frame_info (const void *begin, struct object *ob); extern char __eh_frame[]; -//If CONFIG_SPIRAM_IGNORE_NOTFOUND is set and external RAM is not found or errors out on testing, this is set to false. -static bool s_spiram_okay = true; +static void do_global_ctors(void) +{ +#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS + static struct object ob; + __register_frame_info( __eh_frame, &ob ); +#endif + + void (**p)(void); + for (p = &__init_array_end - 1; p >= &__init_array_start; --p) { + (*p)(); + } +} + +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 + + // 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 +#ifdef CONFIG_ESP_TASK_WDT_PANIC + ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, true)); +#elif CONFIG_ESP_TASK_WDT + ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, false)); +#endif + + //Add IDLE 0 to task wdt +#ifdef CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 + TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0); + if(idle_0 != NULL){ + ESP_ERROR_CHECK(esp_task_wdt_add(idle_0)); + } +#endif + //Add IDLE 1 to task wdt +#ifdef CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1 + TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCPU(1); + if(idle_1 != NULL){ + ESP_ERROR_CHECK(esp_task_wdt_add(idle_1)); + } + esp_spiram_init_cache(); +#endif + + // Now that the application is about to start, disable boot watchdog +#ifndef CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE + rtc_wdt_disable(); +#endif +#ifdef CONFIG_BOOTLOADER_EFUSE_SECURE_VERSION_EMULATE + const esp_partition_t *efuse_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_EFUSE_EM, NULL); + if (efuse_partition) { + esp_efuse_init(efuse_partition->address, efuse_partition->size); + } +#endif + app_main(); + vTaskDelete(NULL); +} + +#if !CONFIG_FREERTOS_UNICORE +void start_cpu1_default(void) +{ + // Wait for FreeRTOS initialization to finish on PRO CPU + while (port_xSchedulerRunning[0] == 0) { + ; + } + +#if CONFIG_APPTRACE_ENABLE + 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_dport_access_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 /* * 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(void) +void IRAM_ATTR start_cpu0_default(void) { - RESET_REASON rst_reas; - - bootloader_init_mem(); - - // Move exception vectors to IRAM - cpu_hal_set_vecbase(&_init_start); - - rst_reas = rtc_get_reset_reason(0); - - // from panic handler we can be reset by RWDT or TG0WDT - if (rst_reas == RTCWDT_SYS_RESET || rst_reas == TG0WDT_SYS_RESET) { -#ifndef CONFIG_BOOTLOADER_WDT_ENABLE - wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; - wdt_hal_write_protect_disable(&rtc_wdt_ctx); - wdt_hal_disable(&rtc_wdt_ctx); - wdt_hal_write_protect_enable(&rtc_wdt_ctx); -#endif - } - - //Clear BSS. Please do not attempt to do any complex stuff (like early logging) before this. - 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 (rst_reas != DEEPSLEEP_RESET) { - memset(&_rtc_bss_start, 0, (&_rtc_bss_end - &_rtc_bss_start) * sizeof(_rtc_bss_start)); - } - - /* Configure the mode of instruction cache : cache size, cache associated ways, cache line size. */ - extern void esp_config_instruction_cache_mode(void); - esp_config_instruction_cache_mode(); - - /* If we need use SPIRAM, we should use data cache, or if we want to access rodata, we also should use data cache. - Configure the mode of data : cache size, cache associated ways, cache line size. - Enable data cache, so if we don't use SPIRAM, it just works. */ -#if CONFIG_SPIRAM_BOOT_INIT - extern void esp_config_data_cache_mode(void); - esp_config_data_cache_mode(); - Cache_Enable_DCache(0); -#endif - - /* In SPIRAM code, we will reconfigure data cache, as well as instruction cache, so that we can: - 1. make data buses works with SPIRAM - 2. make instruction and rodata work with SPIRAM, still through instruction cache */ -#if CONFIG_SPIRAM_BOOT_INIT - if (esp_spiram_init() != ESP_OK) { -#if CONFIG_SPIRAM_IGNORE_NOTFOUND - ESP_EARLY_LOGI(TAG, "Failed to init external RAM; continuing without it."); - s_spiram_okay = false; -#else - ESP_EARLY_LOGE(TAG, "Failed to init external RAM!"); - abort(); -#endif - } - esp_spiram_init_cache(); -#endif - - ESP_EARLY_LOGI(TAG, "Pro cpu up."); if (LOG_LOCAL_LEVEL >= ESP_LOG_INFO) { const esp_app_desc_t *app_desc = esp_ota_get_app_description(); ESP_EARLY_LOGI(TAG, "Application information:"); @@ -187,97 +206,28 @@ void IRAM_ATTR call_start_cpu0(void) ESP_EARLY_LOGI(TAG, "ELF file SHA256: %s...", buf); ESP_EARLY_LOGI(TAG, "ESP-IDF: %s", app_desc->idf_ver); } - ESP_EARLY_LOGI(TAG, "Single core mode"); - -#if CONFIG_SPIRAM_MEMTEST - if (s_spiram_okay) { - bool ext_ram_ok = esp_spiram_test(); - if (!ext_ram_ok) { - ESP_EARLY_LOGE(TAG, "External RAM failed memory test!"); - abort(); - } - } -#endif - -#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS - extern void instruction_flash_page_info_init(void); - instruction_flash_page_info_init(); -#endif -#if CONFIG_SPIRAM_RODATA - extern void rodata_flash_page_info_init(void); - rodata_flash_page_info_init(); -#endif - -#if CONFIG_SPIRAM_FETCH_INSTRUCTIONS - extern void esp_spiram_enable_instruction_access(void); - esp_spiram_enable_instruction_access(); -#endif -#if CONFIG_SPIRAM_RODATA - extern void esp_spiram_enable_rodata_access(void); - esp_spiram_enable_rodata_access(); -#endif - -#if CONFIG_ESP32S2_INSTRUCTION_CACHE_WRAP || CONFIG_ESP32S2_DATA_CACHE_WRAP - uint32_t icache_wrap_enable = 0, dcache_wrap_enable = 0; -#if CONFIG_ESP32S2_INSTRUCTION_CACHE_WRAP - icache_wrap_enable = 1; -#endif -#if CONFIG_ESP32S2_DATA_CACHE_WRAP - dcache_wrap_enable = 1; -#endif - extern void esp_enable_cache_wrap(uint32_t icache_wrap_enable, uint32_t dcache_wrap_enable); - esp_enable_cache_wrap(icache_wrap_enable, dcache_wrap_enable); -#endif /* Initialize heap allocator */ heap_caps_init(); ESP_EARLY_LOGI(TAG, "Pro cpu start user code"); - start_cpu0(); -} -static void intr_matrix_clear(void) -{ - //Clear all the interrupt matrix register - for (int i = ETS_WIFI_MAC_INTR_SOURCE; i < ETS_MAX_INTR_SOURCE; i++) { - intr_matrix_set(0, i, ETS_INVALID_INUM); - } -} - -void start_cpu0_default(void) -{ esp_err_t err; esp_setup_syscall_table(); - if (s_spiram_okay) { + if (g_spiram_ok) { #if CONFIG_SPIRAM_BOOT_INIT && (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC) - esp_err_t r = esp_spiram_add_to_heapalloc(); + esp_err_t r=esp_spiram_add_to_heapalloc(); if (r != ESP_OK) { ESP_EARLY_LOGE(TAG, "External RAM could not be added to heap!"); abort(); } -#if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL - 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!"); - abort(); - } -#endif #if CONFIG_SPIRAM_USE_MALLOC heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL); #endif #endif } -//Enable trace memory and immediately start trace. -#if CONFIG_ESP32S2_TRAX - trax_enable(TRAX_ENA_PRO); - trax_start_trace(TRAX_DOWNCOUNT_WORDS); -#endif - esp_clk_init(); - esp_perip_clk_init(); - intr_matrix_clear(); - #ifndef CONFIG_ESP_CONSOLE_UART_NONE #ifdef CONFIG_PM_ENABLE const int uart_clk_freq = REF_CLK_FREQ; @@ -289,11 +239,6 @@ void start_cpu0_default(void) uart_div_modify(CONFIG_ESP_CONSOLE_UART_NUM, (uart_clk_freq << 4) / CONFIG_ESP_CONSOLE_UART_BAUDRATE); #endif // CONFIG_ESP_CONSOLE_UART_NONE -#if CONFIG_ESP32S2_BROWNOUT_DET - esp_brownout_init(); -#endif - - rtc_gpio_force_hold_dis_all(); #ifdef CONFIG_VFS_SUPPORT_IO esp_vfs_dev_uart_register(); @@ -310,10 +255,15 @@ void start_cpu0_default(void) #endif // defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_UART_NONE) // After setting _GLOBAL_REENT, ESP_LOGIx can be used instead of ESP_EARLY_LOGx. +#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED + esp_flash_encryption_init_checks(); +#endif + #if CONFIG_SECURE_DISABLE_ROM_DL_MODE err = esp_efuse_disable_rom_download_mode(); assert(err == ESP_OK && "Failed to disable ROM download mode"); #endif + #if CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE err = esp_efuse_enable_rom_secure_download_mode(); assert(err == ESP_OK && "Failed to enable Secure Download mode"); @@ -321,16 +271,19 @@ void start_cpu0_default(void) esp_timer_init(); esp_set_time_from_rtc(); + #if CONFIG_APPTRACE_ENABLE err = esp_apptrace_init(); assert(err == ESP_OK && "Failed to init apptrace module on PRO CPU!"); #endif + #if CONFIG_SYSVIEW_ENABLE SEGGER_SYSVIEW_Conf(); #endif -#if CONFIG_ESP32S2_DEBUG_STUBS_ENABLE +#if CONFIG_ESP_DEBUG_STUBS_ENABLE esp_dbg_stubs_init(); #endif + err = esp_pthread_init(); assert(err == ESP_OK && "Failed to init pthread module!"); @@ -345,11 +298,20 @@ void start_cpu0_default(void) do_global_ctors(); #if CONFIG_ESP_INT_WDT esp_int_wdt_init(); - //Initialize the interrupt watch dog + //Initialize the interrupt watch dog for CPU0. esp_int_wdt_cpu_init(); +#else +#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 - esp_cache_err_int_init(); +#endif + esp_crosscore_int_init(); + +#ifndef CONFIG_FREERTOS_UNICORE + esp_dport_access_int_init(); +#endif + spi_flash_init(); /* init default OS-aware flash access critical section */ spi_flash_guard_set(&g_flash_guard_default_ops); @@ -358,88 +320,37 @@ void start_cpu0_default(void) esp_err_t flash_ret = esp_flash_init_default_chip(); assert(flash_ret == ESP_OK); +#if CONFIG_IDF_TARGET_ESP32 +#if CONFIG_ESP32_ENABLE_COREDUMP + esp_core_dump_init(); +#endif +#endif + #ifdef CONFIG_PM_ENABLE esp_pm_impl_init(); #ifdef CONFIG_PM_DFS_INIT_AUTO int xtal_freq = (int) rtc_clk_xtal_freq_get(); - esp_pm_config_esp32s2_t cfg = { - .max_freq_mhz = CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ, + esp_pm_config_esp32_t cfg = { + .max_freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ, .min_freq_mhz = xtal_freq, }; esp_pm_configure(&cfg); #endif //CONFIG_PM_DFS_INIT_AUTO #endif //CONFIG_PM_ENABLE -#if CONFIG_ESP32_ENABLE_COREDUMP - esp_core_dump_init(); +#if CONFIG_IDF_TARGET_ESP32 +#if CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE + esp_coex_adapter_register(&g_coex_adapter_funcs); + coex_pre_init(); +#endif #endif portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main", - ESP_TASK_MAIN_STACK, NULL, - ESP_TASK_MAIN_PRIO, NULL, 0); + ESP_TASK_MAIN_STACK, NULL, + ESP_TASK_MAIN_PRIO, NULL, 0); assert(res == pdTRUE); ESP_LOGI(TAG, "Starting scheduler on PRO CPU."); vTaskStartScheduler(); abort(); /* Only get to here if not enough free heap to start scheduler */ -} - -#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS -size_t __cxx_eh_arena_size_get(void) -{ - return CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE; -} -#endif - -static void do_global_ctors(void) -{ -#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS - static struct object ob; - __register_frame_info( __eh_frame, &ob ); -#endif - - void (**p)(void); - for (p = &__init_array_end - 1; p >= &__init_array_start; --p) { - (*p)(); - } -} - -static void main_task(void *args) -{ - //Enable allocation in region where the startup stacks were located. - heap_caps_enable_nonos_stack_heaps(); - - //Initialize task wdt if configured to do so -#ifdef CONFIG_ESP_TASK_WDT_PANIC - ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, true)); -#elif CONFIG_ESP_TASK_WDT - ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, false)); -#endif - - //Add IDLE 0 to task wdt -#ifdef CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 - TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0); - if (idle_0 != NULL) { - ESP_ERROR_CHECK(esp_task_wdt_add(idle_0)); - } -#endif - - // Now that the application is about to start, disable boot watchdog -#ifndef CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE - wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; - wdt_hal_write_protect_disable(&rtc_wdt_ctx); - wdt_hal_disable(&rtc_wdt_ctx); - wdt_hal_write_protect_enable(&rtc_wdt_ctx); -#endif - -#ifdef CONFIG_BOOTLOADER_EFUSE_SECURE_VERSION_EMULATE - const esp_partition_t *efuse_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_EFUSE_EM, NULL); - if (efuse_partition) { - esp_efuse_init(efuse_partition->address, efuse_partition->size); - } -#endif - - app_main(); - vTaskDelete(NULL); -} - +} \ No newline at end of file diff --git a/components/freertos/Kconfig b/components/freertos/Kconfig index de7a368ff7..11ca559a55 100644 --- a/components/freertos/Kconfig +++ b/components/freertos/Kconfig @@ -1,8 +1,10 @@ menu "FreeRTOS" config FREERTOS_UNICORE - # This config variable is also checked in the ESP32 startup code, not only in FreeRTOS. + # This config variable is also checked in the target startup code, not only in FreeRTOS + # hence the dependency on what target the app is being built for. bool "Run FreeRTOS only on first core" + default y if IDF_TARGET_ESP32S2 default n help This version of FreeRTOS normally takes control of all cores of From 0f43a2620d0f9d89f906661441519312e34c9361 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Wed, 5 Feb 2020 19:57:40 +0800 Subject: [PATCH 04/17] esp_system: component init functions macro Allows components to declare initialization function, such that the startup code does not have direct dependency on the component. --- components/esp32/ld/esp32.project.ld.in | 6 +++ components/esp32s2/ld/esp32s2.project.ld.in | 4 ++ .../private_include/startup_internal.h | 37 +++++++++++++++++++ components/esp_system/startup.c | 17 +++++++++ 4 files changed, 64 insertions(+) create mode 100644 components/esp_system/private_include/startup_internal.h diff --git a/components/esp32/ld/esp32.project.ld.in b/components/esp32/ld/esp32.project.ld.in index 369ebb5d67..96557ed62e 100644 --- a/components/esp32/ld/esp32.project.ld.in +++ b/components/esp32/ld/esp32.project.ld.in @@ -208,6 +208,10 @@ SECTIONS _coredump_dram_end = ABSOLUTE(.); /* should be placed after coredump mapping */ + _esp_system_init_fn_array_start = ABSOLUTE(.); + KEEP (*(SORT(.esp_system_init_fn) SORT(.esp_system_init_fn.*))) + _esp_system_init_fn_array_end = ABSOLUTE(.); + mapping[dram0_data] _data_end = ABSOLUTE(.); @@ -278,6 +282,7 @@ SECTIONS mapping[flash_rodata] + *(.irom1.text) /* catch stray ICACHE_RODATA_ATTR */ *(.gnu.linkonce.r.*) *(.rodata1) @@ -297,6 +302,7 @@ SECTIONS __init_array_start = ABSOLUTE(.); KEEP (*(EXCLUDE_FILE (*crtend.* *crtbegin.*) .ctors SORT(.ctors.*))) __init_array_end = ABSOLUTE(.); + KEEP (*crtbegin.*(.dtors)) KEEP (*(EXCLUDE_FILE (*crtend.*) .dtors)) KEEP (*(SORT(.dtors.*))) diff --git a/components/esp32s2/ld/esp32s2.project.ld.in b/components/esp32s2/ld/esp32s2.project.ld.in index cffa42e9c4..71b24f7065 100644 --- a/components/esp32s2/ld/esp32s2.project.ld.in +++ b/components/esp32s2/ld/esp32s2.project.ld.in @@ -214,6 +214,10 @@ SECTIONS _coredump_dram_end = ABSOLUTE(.); /* should be placed after coredump mapping */ + _esp_system_init_fn_array_start = ABSOLUTE(.); + KEEP (*(SORT(.esp_system_init_fn) SORT(.esp_system_init_fn.*))) + _esp_system_init_fn_array_end = ABSOLUTE(.); + mapping[dram0_data] _data_end = ABSOLUTE(.); diff --git a/components/esp_system/private_include/startup_internal.h b/components/esp_system/private_include/startup_internal.h new file mode 100644 index 0000000000..4d18c950ea --- /dev/null +++ b/components/esp_system/private_include/startup_internal.h @@ -0,0 +1,37 @@ +// Copyright 2015-2018 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. + +#pragma once + +#include "esp_attr.h" +typedef struct { + void (*fn)(void); + uint32_t cores; +} esp_system_init_fn_t; + +/* + * Declare an component initialization function that will execute on the specified cores (ex. if BIT0 == 1, will execute + * on CORE0, CORE1 if BIT1 and so on). + * + * @note Initialization functions should be placed in a compilation unit where at least one other + * symbol is referenced 'meaningfully' in another compilation unit, otherwise this gets discarded during linking. (By + * 'meaningfully' we mean the reference should not itself get optimized out by the compiler/discarded by the linker). + */ +#define ESP_SYSTEM_INIT_FN(f, c, ...) \ +static void __attribute__((used)) __VA_ARGS__ __esp_system_init_fn_##f(void); \ +static __attribute__((used)) esp_system_init_fn_t _SECTION_ATTR_IMPL(".esp_system_init_fn", f) \ + esp_system_init_fn_##f = { .fn = ( __esp_system_init_fn_##f), .cores = (c) }; \ +static __attribute__((used)) __VA_ARGS__ void __esp_system_init_fn_##f(void) // [refactor-todo] this can be made public API if we allow components to declare init functions, + // instead of calling them explicitly + diff --git a/components/esp_system/startup.c b/components/esp_system/startup.c index 517d86c481..1eeda8d5d5 100644 --- a/components/esp_system/startup.c +++ b/components/esp_system/startup.c @@ -97,6 +97,20 @@ static void do_global_ctors(void) } } +static void do_system_init_fn(void) +{ + extern esp_system_init_fn_t _esp_system_init_fn_array_start; + extern esp_system_init_fn_t _esp_system_init_fn_array_end; + + esp_system_init_fn_t *p; + + for (p = &_esp_system_init_fn_array_end - 1; p >= &_esp_system_init_fn_array_start; --p) { + if (p->cores & BIT(cpu_hal_get_core_id())) { + (*(p->fn))(); + } + } +} + static void main_task(void* args) { #if !CONFIG_FREERTOS_UNICORE @@ -312,6 +326,7 @@ void IRAM_ATTR start_cpu0_default(void) esp_dport_access_int_init(); #endif + spi_flash_init(); /* init default OS-aware flash access critical section */ spi_flash_guard_set(&g_flash_guard_default_ops); @@ -345,6 +360,8 @@ void IRAM_ATTR start_cpu0_default(void) #endif #endif + do_system_init_fn(); + portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main", ESP_TASK_MAIN_STACK, NULL, ESP_TASK_MAIN_PRIO, NULL, 0); From c53ad56515c965fba0f85b189bc5f9c4873eb373 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Wed, 5 Feb 2020 22:40:15 +0800 Subject: [PATCH 05/17] esp_system: startup flow modifications Changes the startup flow to the ff: hardware -> core libraries init -> other libraries init -> os init (optional) -> app_main - hardware init resides in the port layer, and is the entry point - core libraries init executes init functions of core components - other libraries init executes init functions of other components (weak references) - after other lib is init, the app_main function is called, however, an OS can wrap the real call to app_main to init its own stuff, and *then* call the real app_main --- components/esp_system/CMakeLists.txt | 5 +- components/esp_system/port/cpu_start.c | 169 ++++---- .../private_include/startup_internal.h | 17 + .../esp_system/private_include/sys_funcs.h | 21 - components/esp_system/startup.c | 405 ++++++++---------- components/freertos/CMakeLists.txt | 2 + components/freertos/xtensa/port.c | 131 ++++++ components/pthread/include/esp_pthread.h | 5 + 8 files changed, 432 insertions(+), 323 deletions(-) delete mode 100644 components/esp_system/private_include/sys_funcs.h diff --git a/components/esp_system/CMakeLists.txt b/components/esp_system/CMakeLists.txt index de162eadc0..655d945bb1 100644 --- a/components/esp_system/CMakeLists.txt +++ b/components/esp_system/CMakeLists.txt @@ -1,7 +1,7 @@ idf_component_register(SRCS "panic.c" "system_api.c" "startup.c" INCLUDE_DIRS include PRIV_INCLUDE_DIRS private_include - PRIV_REQUIRES spi_flash app_update + PRIV_REQUIRES spi_flash app_update # requirements due to startup code nvs_flash pthread app_trace LDFRAGMENTS "linker.lf") @@ -9,4 +9,5 @@ idf_component_register(SRCS "panic.c" "system_api.c" "startup.c" add_subdirectory(port) # Rely on user code to define app_main -target_link_libraries(${COMPONENT_LIB} INTERFACE "-u app_main") \ No newline at end of file +target_link_libraries(${COMPONENT_LIB} INTERFACE "-u app_main") +target_link_libraries(${COMPONENT_LIB} INTERFACE "-u app_mainX") \ No newline at end of file diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index 1999096c7a..08239b4e86 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -67,10 +67,6 @@ #endif // CONFIG_APP_BUILD_TYPE_ELF_RAM #endif -#if !CONFIG_FREERTOS_UNICORE -static bool app_cpu_started = false; -#endif //!CONFIG_FREERTOS_UNICORE - extern int _bss_start; extern int _bss_end; extern int _rtc_bss_start; @@ -91,18 +87,20 @@ extern int _iram_bss_end; #endif #endif // CONFIG_IDF_TARGET_ESP32 -extern void start_cpu0(void); -#if !CONFIG_FREERTOS_UNICORE -extern void start_cpu1(void); -#endif //!CONFIG_FREERTOS_UNICORE +#include "startup_internal.h" -extern int _init_start; +static volatile bool s_cpu_up[SOC_CPU_CORES_NUM] = { false }; +static volatile bool s_cpu_inited[SOC_CPU_CORES_NUM] = { false }; +static volatile bool s_resume_cores; -static const char* TAG = "cpu_start"; - -//If CONFIG_SPIRAM_IGNORE_NOTFOUND is set and external RAM is not found or errors out on testing, this is set to false. +// If CONFIG_SPIRAM_IGNORE_NOTFOUND is set and external RAM is not found or errors out on testing, this is set to false. bool g_spiram_ok = true; +void startup_resume_other_cores(void) +{ + s_resume_cores = true; +} + static void intr_matrix_clear(void) { #if CONFIG_IDF_TARGET_ESP32 @@ -112,19 +110,11 @@ static void intr_matrix_clear(void) for (int i = ETS_WIFI_MAC_INTR_SOURCE; i < ETS_MAX_INTR_SOURCE; i++) { #endif intr_matrix_set(0, i, ETS_INVALID_INUM); -#if !CONFIG_FREERTOS_UNICORE intr_matrix_set(1, i, ETS_INVALID_INUM); -#endif } } -#if !CONFIG_FREERTOS_UNICORE -static void wdt_reset_cpu1_info_enable(void) -{ - DPORT_REG_SET_BIT(DPORT_APP_CPU_RECORD_CTRL_REG, DPORT_APP_CPU_PDEBUG_ENABLE | DPORT_APP_CPU_RECORD_ENABLE); - DPORT_REG_CLR_BIT(DPORT_APP_CPU_RECORD_CTRL_REG, DPORT_APP_CPU_RECORD_ENABLE); -} - +#if SOC_CPU_CORES_NUM > 1 void IRAM_ATTR call_start_cpu1(void) { cpu_hal_set_vecbase(&_init_start); @@ -142,9 +132,11 @@ void IRAM_ATTR call_start_cpu1(void) uart_tx_switch(CONFIG_ESP_CONSOLE_UART_NUM); #endif - wdt_reset_cpu1_info_enable(); + DPORT_REG_SET_BIT(DPORT_APP_CPU_RECORD_CTRL_REG, DPORT_APP_CPU_PDEBUG_ENABLE | DPORT_APP_CPU_RECORD_ENABLE); + DPORT_REG_CLR_BIT(DPORT_APP_CPU_RECORD_CTRL_REG, DPORT_APP_CPU_RECORD_ENABLE); + + s_cpu_up[1] = true; ESP_EARLY_LOGI(TAG, "App cpu up."); - app_cpu_started = 1; //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. @@ -156,7 +148,13 @@ void IRAM_ATTR call_start_cpu1(void) #endif #endif - start_cpu1(); + s_cpu_inited[1] = true; + + while(!s_resume_cores) { + cpu_hal_delay_us(100); + } + + SYS_STARTUP_FN(); } #endif @@ -164,14 +162,9 @@ void IRAM_ATTR call_start_cpu1(void) * 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(void) { -#if CONFIG_FREERTOS_UNICORE - RESET_REASON rst_reas[1]; -#else - RESET_REASON rst_reas[2]; -#endif + RESET_REASON rst_reas[SOC_CPU_CORES_NUM]; bootloader_init_mem(); @@ -179,14 +172,14 @@ void IRAM_ATTR call_start_cpu0(void) cpu_hal_set_vecbase(&_init_start); rst_reas[0] = rtc_get_reset_reason(0); - -#if !CONFIG_FREERTOS_UNICORE +#if SOC_CPU_CORES_NUM > 1 rst_reas[1] = rtc_get_reset_reason(1); #endif +#ifndef CONFIG_BOOTLOADER_WDT_ENABLE // from panic handler we can be reset by RWDT or TG0WDT if (rst_reas[0] == RTCWDT_SYS_RESET || rst_reas[0] == TG0WDT_SYS_RESET -#if !CONFIG_FREERTOS_UNICORE +#if SOC_CPU_CORES_NUM > 1 || rst_reas[1] == RTCWDT_SYS_RESET || rst_reas[1] == TG0WDT_SYS_RESET #endif ) { @@ -197,6 +190,7 @@ void IRAM_ATTR call_start_cpu0(void) wdt_hal_write_protect_enable(&rtc_wdt_ctx); #endif } +#endif //Clear BSS. Please do not attempt to do any complex stuff (like early logging) before this. memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start)); @@ -211,7 +205,6 @@ void IRAM_ATTR call_start_cpu0(void) memset(&_rtc_bss_start, 0, (&_rtc_bss_end - &_rtc_bss_start) * sizeof(_rtc_bss_start)); } - #if CONFIG_IDF_TARGET_ESP32S2 /* Configure the mode of instruction cache : cache size, cache associated ways, cache line size. */ extern void esp_config_instruction_cache_mode(void); @@ -247,45 +240,45 @@ void IRAM_ATTR call_start_cpu0(void) } #endif + s_cpu_up[0] = true; ESP_EARLY_LOGI(TAG, "Pro cpu up."); -#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED - esp_flash_encryption_init_checks(); -#endif +#if CONFIG_IDF_TARGET_ESP32 + // If not the single core variant of ESP32 - check this since there is + // no separate soc_caps.h for the single core variant. + if (!REG_GET_BIT(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_DIS_APP_CPU)) { + ESP_EARLY_LOGI(TAG, "Starting app cpu, entry point is %p", call_start_cpu1); -#if !CONFIG_FREERTOS_UNICORE - if (REG_GET_BIT(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_DIS_APP_CPU)) { - ESP_EARLY_LOGE(TAG, "Running on single core chip, but application is built with dual core support."); - ESP_EARLY_LOGE(TAG, "Please enable CONFIG_FREERTOS_UNICORE option in menuconfig."); - abort(); + Cache_Flush(1); + Cache_Read_Enable(1); + esp_cpu_unstall(1); + + // Enable clock and reset APP CPU. Note that OpenOCD may have already + // enabled clock and taken APP CPU out of reset. In this case don't reset + // APP CPU again, as that will clear the breakpoints which may have already + // been set. + if (!DPORT_GET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN)) { + DPORT_SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN); + DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_C_REG, DPORT_APPCPU_RUNSTALL); + DPORT_SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING); + DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING); + } + ets_set_appcpu_boot_addr((uint32_t)call_start_cpu1); + + volatile bool cpus_up = false; + + while(!cpus_up){ + cpus_up = true; + for (int i = 0; i < SOC_CPU_CORES_NUM; i++) { + cpus_up &= s_cpu_up[i]; + } + cpu_hal_delay_us(100); + } } - // ESP_EARLY_LOGI(TAG, "Starting app cpu, entry point is %p", call_start_cpu1); - - //Flush and enable icache for APP CPU - Cache_Flush(1); - Cache_Read_Enable(1); - esp_cpu_unstall(1); - - // Enable clock and reset APP CPU. Note that OpenOCD may have already - // enabled clock and taken APP CPU out of reset. In this case don't reset - // APP CPU again, as that will clear the breakpoints which may have already - // been set. - if (!DPORT_GET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN)) { - DPORT_SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN); - DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_C_REG, DPORT_APPCPU_RUNSTALL); - DPORT_SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING); - DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING); + else { + s_cpu_inited[1] = true; + DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN); } - ets_set_appcpu_boot_addr((uint32_t)call_start_cpu1); - - while (!app_cpu_started) { - ets_delay_us(100); - } -#else -#if CONFIG_IDF_TARGET_ESP32 // Single core chips have no 'single core mode' - ESP_EARLY_LOGI(TAG, "Single core mode"); - DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN); -#endif #endif #if CONFIG_SPIRAM_MEMTEST @@ -334,8 +327,6 @@ void IRAM_ATTR call_start_cpu0(void) memset(&_ext_ram_bss_start, 0, (&_ext_ram_bss_end - &_ext_ram_bss_start) * sizeof(_ext_ram_bss_start)); #endif - /////////////////////////////////////////////////////////////////// - //Enable trace memory and immediately start trace. #if CONFIG_ESP32_TRAX || CONFIG_ESP32S2_TRAX #if CONFIG_IDF_TARGET_ESP32 @@ -358,25 +349,21 @@ void IRAM_ATTR call_start_cpu0(void) esp_brownout_init(); #endif -#if CONFIG_SECURE_DISABLE_ROM_DL_MODE - err = esp_efuse_disable_rom_download_mode(); - assert(err == ESP_OK && "Failed to disable ROM download mode"); -#endif -#if CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE - err = esp_efuse_enable_rom_secure_download_mode(); - assert(err == ESP_OK && "Failed to enable Secure Download mode"); -#endif - -#if CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE || CONFIG_ESP32S2_DISABLE_BASIC_ROM_CONSOLE - esp_efuse_disable_basic_rom_console(); -#endif - rtc_gpio_force_hold_dis_all(); esp_cache_err_int_init(); - bootloader_flash_update_id(); +#if CONFIG_IDF_TARGET_ESP32S2 +#if CONFIG_ESP32S2_MEMPROT_FEATURE +#if CONFIG_ESP32S2_MEMPROT_FEATURE_LOCK + esp_memprot_set_prot(true, true); +#else + esp_memprot_set_prot(true, false); +#endif +#endif +#endif + bootloader_flash_update_id(); #if CONFIG_IDF_TARGET_ESP32 #if !CONFIG_SPIRAM_BOOT_INIT // Read the application binary image header. This will also decrypt the header if the image is encrypted. @@ -403,5 +390,17 @@ void IRAM_ATTR call_start_cpu0(void) #endif //!CONFIG_SPIRAM_BOOT_INIT #endif - start_cpu0(); + s_cpu_inited[0] = true; + + volatile bool cpus_inited = false; + + while(!cpus_inited) { + cpus_inited = true; + for (int i = 0; i < SOC_CPU_CORES_NUM; i++) { + cpus_inited &= s_cpu_inited[i]; + } + cpu_hal_delay_us(100); + } + + SYS_STARTUP_FN(); } \ No newline at end of file diff --git a/components/esp_system/private_include/startup_internal.h b/components/esp_system/private_include/startup_internal.h index 4d18c950ea..a7791fd2d9 100644 --- a/components/esp_system/private_include/startup_internal.h +++ b/components/esp_system/private_include/startup_internal.h @@ -15,6 +15,23 @@ #pragma once #include "esp_attr.h" + +#include "soc/soc_caps.h" +#include "hal/cpu_hal.h" + +extern bool g_spiram_ok; // [refactor-todo] better way to communicate this from port layer to common startup code + +// Port layer defines the entry point. It then transfer control to a `sys_startup_fn_t`, stored in this +// array, one per core. +typedef void (*sys_startup_fn_t)(void); +extern sys_startup_fn_t g_startup_fn[SOC_CPU_CORES_NUM]; + +// Utility to execute `sys_startup_fn_t` for the current core. +#define SYS_STARTUP_FN() ((*g_startup_fn[(cpu_hal_get_core_id())])()) + +void startup_resume_other_cores(void); +void startup_core_init(); + typedef struct { void (*fn)(void); uint32_t cores; diff --git a/components/esp_system/private_include/sys_funcs.h b/components/esp_system/private_include/sys_funcs.h deleted file mode 100644 index 21fee3ed02..0000000000 --- a/components/esp_system/private_include/sys_funcs.h +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2020 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. - -#pragma once - -#include "sdkconfig.h" - -extern bool g_spiram_ok; - -void sys_startup(void); \ No newline at end of file diff --git a/components/esp_system/startup.c b/components/esp_system/startup.c index 1eeda8d5d5..0dcb8076f3 100644 --- a/components/esp_system/startup.c +++ b/components/esp_system/startup.c @@ -18,75 +18,77 @@ #include "esp_attr.h" #include "esp_err.h" -#include "soc/rtc_wdt.h" - -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" -#include "freertos/queue.h" - -#include "esp_heap_caps_init.h" #include "esp_system.h" -#include "esp_flash_internal.h" -#include "nvs_flash.h" -#include "esp_spi_flash.h" -#include "esp_private/crosscore_int.h" #include "esp_log.h" -#include "esp_vfs_dev.h" +#include "esp_ota_ops.h" + +#include "sdkconfig.h" + +#include "soc/rtc_wdt.h" +#include "soc/soc_caps.h" + +#include "esp_system.h" +#include "esp_log.h" +#include "esp_heap_caps_init.h" +#include "esp_spi_flash.h" +#include "esp_flash_internal.h" #include "esp_newlib.h" -#include "esp_int_wdt.h" -#include "esp_task.h" -#include "esp_task_wdt.h" +#include "esp_vfs_dev.h" +#include "esp_timer.h" +#include "esp_efuse.h" +#include "esp_flash_encrypt.h" + +/* Headers for other components init functions */ +#include "nvs_flash.h" #include "esp_phy_init.h" #include "esp_coexist_internal.h" #include "esp_core_dump.h" #include "esp_app_trace.h" #include "esp_private/dbg_stubs.h" #include "esp_flash_encrypt.h" -#include "esp_clk_internal.h" -#include "esp_timer.h" #include "esp_pm.h" -#include "esp_private/pm_impl.h" -#include "esp_ota_ops.h" - -#include "sdkconfig.h" +#include "esp_pthread.h" +// [refactor-todo] make this file completely target-independent #if CONFIG_IDF_TARGET_ESP32 #include "esp32/rom/uart.h" -#include "esp32/dport_access.h" +#include "esp32/spiram.h" #elif CONFIG_IDF_TARGET_ESP32S2 #include "esp32s2/rom/uart.h" -#include "esp32s2/dport_access.h" +#include "esp32s2/spiram.h" #endif +/***********************************************/ -#include "sys_funcs.h" - -#define STRINGIFY(s) STRINGIFY2(s) -#define STRINGIFY2(s) #s +#include "startup_internal.h" void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default"))) __attribute__((noreturn)); -void start_cpu0_default(void) IRAM_ATTR __attribute__((noreturn)); -#if !CONFIG_FREERTOS_UNICORE -void start_cpu1(void) __attribute__((weak, alias("start_cpu1_default"))) __attribute__((noreturn)); -void start_cpu1_default(void) IRAM_ATTR __attribute__((noreturn)); -#endif //!CONFIG_FREERTOS_UNICORE +void start_cpuX(void) __attribute__((weak, alias("start_cpuX_default"))) __attribute__((noreturn)); + +void app_mainX(void) __attribute__((weak, alias("app_mainX_default"))) __attribute__((noreturn)); extern void app_main(void); -extern esp_err_t esp_pthread_init(void); -extern void (*__init_array_start)(void); -extern void (*__init_array_end)(void); -extern volatile int port_xSchedulerRunning[2]; +sys_startup_fn_t g_startup_fn[SOC_CPU_CORES_NUM] = { [0] = start_cpu0, +#if SOC_CPU_CORES_NUM > 1 + [1 ... SOC_CPU_CORES_NUM - 1] = start_cpuX +#endif +}; + +static volatile bool s_system_inited[SOC_CPU_CORES_NUM] = { false }; +static volatile bool s_system_full_inited = false; static const char* TAG = "cpu_start"; -struct object { long placeholder[ 10 ]; }; -void __register_frame_info (const void *begin, struct object *ob); -extern char __eh_frame[]; - -static void do_global_ctors(void) +static void IRAM_ATTR do_global_ctors(void) { + extern void (*__init_array_start)(void); + extern void (*__init_array_end)(void); + #ifdef CONFIG_COMPILER_CXX_EXCEPTIONS + struct object { long placeholder[ 10 ]; }; + void __register_frame_info (const void *begin, struct object *ob); + extern char __eh_frame[]; + static struct object ob; __register_frame_info( __eh_frame, &ob ); #endif @@ -97,7 +99,7 @@ static void do_global_ctors(void) } } -static void do_system_init_fn(void) +static void IRAM_ATTR do_system_init_fn(void) { extern esp_system_init_fn_t _esp_system_init_fn_array_start; extern esp_system_init_fn_t _esp_system_init_fn_array_end; @@ -109,16 +111,54 @@ static void do_system_init_fn(void) (*(p->fn))(); } } + + s_system_inited[cpu_hal_get_core_id()] = true; } -static void main_task(void* args) +static void IRAM_ATTR app_mainX_default(void) { -#if !CONFIG_FREERTOS_UNICORE - // Wait for FreeRTOS initialization to finish on APP CPU, before replacing its startup stack - while (port_xSchedulerRunning[1] == 0) { - ; + while(1) { + cpu_hal_delay_us(UINT32_MAX); } +} + +static void IRAM_ATTR start_cpuX_default(void) +{ + do_system_init_fn(); + + while(!s_system_full_inited) { + cpu_hal_delay_us(100); + } + + app_mainX(); +} + +static void IRAM_ATTR do_core_init(void) +{ + /* 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. + With SPI RAM enabled, there's a second reason: half of the SPI RAM will be managed by the + app CPU, and when that is not up yet, the memory will be inaccessible and heap_caps_init may + fail initializing it properly. */ + heap_caps_init(); + + esp_setup_syscall_table(); + + if (g_spiram_ok) { +#if CONFIG_SPIRAM_BOOT_INIT && (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC) + esp_err_t r=esp_spiram_add_to_heapalloc(); + if (r != ESP_OK) { + ESP_EARLY_LOGE(TAG, "External RAM could not be added to heap!"); + abort(); + } +#if CONFIG_SPIRAM_USE_MALLOC + heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL); #endif +#endif + } // Now we have startup stack RAM available for heap, enable any DMA pool memory #if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL @@ -131,75 +171,80 @@ static void main_task(void* args) } #endif - //Initialize task wdt if configured to do so -#ifdef CONFIG_ESP_TASK_WDT_PANIC - ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, true)); -#elif CONFIG_ESP_TASK_WDT - ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, false)); + esp_reent_init(_GLOBAL_REENT); + +#ifndef CONFIG_ESP_CONSOLE_UART_NONE + const int uart_clk_freq = APB_CLK_FREQ; + uart_div_modify(CONFIG_ESP_CONSOLE_UART_NUM, (uart_clk_freq << 4) / CONFIG_ESP_CONSOLE_UART_BAUDRATE); #endif - //Add IDLE 0 to task wdt -#ifdef CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 - TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0); - if(idle_0 != NULL){ - ESP_ERROR_CHECK(esp_task_wdt_add(idle_0)); - } -#endif - //Add IDLE 1 to task wdt -#ifdef CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1 - TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCPU(1); - if(idle_1 != NULL){ - ESP_ERROR_CHECK(esp_task_wdt_add(idle_1)); - } - esp_spiram_init_cache(); +#ifdef CONFIG_VFS_SUPPORT_IO + esp_vfs_dev_uart_register(); +#endif // CONFIG_VFS_SUPPORT_IO + +#if defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_UART_NONE) + esp_reent_init(_GLOBAL_REENT); + const char *default_uart_dev = "/dev/uart/" STRINGIFY(CONFIG_ESP_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 // defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_UART_NONE) + _REENT_SMALL_CHECK_INIT(_GLOBAL_REENT); +#endif // defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_UART_NONE) + +#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED + esp_flash_encryption_init_checks(); #endif - // Now that the application is about to start, disable boot watchdog -#ifndef CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE - rtc_wdt_disable(); +#if CONFIG_SECURE_DISABLE_ROM_DL_MODE + err = esp_efuse_disable_rom_download_mode(); + assert(err == ESP_OK && "Failed to disable ROM download mode"); #endif -#ifdef CONFIG_BOOTLOADER_EFUSE_SECURE_VERSION_EMULATE - const esp_partition_t *efuse_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_EFUSE_EM, NULL); - if (efuse_partition) { - esp_efuse_init(efuse_partition->address, efuse_partition->size); - } + +#if CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE + err = esp_efuse_enable_rom_secure_download_mode(); + assert(err == ESP_OK && "Failed to enable Secure Download mode"); #endif - app_main(); - vTaskDelete(NULL); + +#if CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE + esp_efuse_disable_basic_rom_console(); +#endif + + spi_flash_init(); + /* init default OS-aware flash access critical section */ + spi_flash_guard_set(&g_flash_guard_default_ops); + + esp_flash_app_init(); + esp_err_t flash_ret = esp_flash_init_default_chip(); + assert(flash_ret == ESP_OK); } -#if !CONFIG_FREERTOS_UNICORE -void start_cpu1_default(void) +static void IRAM_ATTR do_secondary_init(void) { - // Wait for FreeRTOS initialization to finish on PRO CPU - while (port_xSchedulerRunning[0] == 0) { - ; + // The port layer transferred control to this function with other cores 'paused', + // resume execution so that cores might execute component initialization functions. + startup_resume_other_cores(); + + // Execute initialization functions esp_system_init_fn_t assigned to the main core. While + // this is happening, all other cores are executing the initialization functions + // assigned to them since they have been resumed already. + do_system_init_fn(); + + // Wait for all cores to finish secondary init. + volatile bool system_inited = false; + + while(!system_inited) { + system_inited = true; + for (int i = 0; i < SOC_CPU_CORES_NUM; i++) { + system_inited &= s_system_inited[i]; + } + cpu_hal_delay_us(100); } - -#if CONFIG_APPTRACE_ENABLE - 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_dport_access_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 -/* - * 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 start_cpu0_default(void) { + // Display information about the current running image. if (LOG_LOCAL_LEVEL >= ESP_LOG_INFO) { const esp_app_desc_t *app_desc = esp_ota_get_app_description(); ESP_EARLY_LOGI(TAG, "Application information:"); @@ -221,126 +266,46 @@ void IRAM_ATTR start_cpu0_default(void) ESP_EARLY_LOGI(TAG, "ESP-IDF: %s", app_desc->idf_ver); } - /* Initialize heap allocator */ - heap_caps_init(); + // Initialize core components and services. + do_core_init(); + // Execute constructors. + do_global_ctors(); + + // Execute init functions of other components; blocks + // until all cores finish. + do_secondary_init(); + + // Now that the application is about to start, disable boot watchdog +#ifndef CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE + rtc_wdt_disable(); +#endif + + // Finally, we jump to user code. ESP_EARLY_LOGI(TAG, "Pro cpu start user code"); + s_system_full_inited = true; + + app_main(); + while(1); +} + +IRAM_ATTR ESP_SYSTEM_INIT_FN(init_components0, BIT(0)) +{ esp_err_t err; - esp_setup_syscall_table(); - if (g_spiram_ok) { -#if CONFIG_SPIRAM_BOOT_INIT && (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC) - esp_err_t r=esp_spiram_add_to_heapalloc(); - if (r != ESP_OK) { - ESP_EARLY_LOGE(TAG, "External RAM could not be added to heap!"); - abort(); - } -#if CONFIG_SPIRAM_USE_MALLOC - heap_caps_malloc_extmem_enable(CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL); -#endif -#endif - } - -#ifndef CONFIG_ESP_CONSOLE_UART_NONE #ifdef CONFIG_PM_ENABLE const int uart_clk_freq = REF_CLK_FREQ; /* When DFS is enabled, use REFTICK as UART clock source */ CLEAR_PERI_REG_MASK(UART_CONF0_REG(CONFIG_ESP_CONSOLE_UART_NUM), UART_TICK_REF_ALWAYS_ON); -#else - const int uart_clk_freq = APB_CLK_FREQ; -#endif // CONFIG_PM_DFS_ENABLE uart_div_modify(CONFIG_ESP_CONSOLE_UART_NUM, (uart_clk_freq << 4) / CONFIG_ESP_CONSOLE_UART_BAUDRATE); #endif // CONFIG_ESP_CONSOLE_UART_NONE - -#ifdef CONFIG_VFS_SUPPORT_IO - esp_vfs_dev_uart_register(); -#endif // CONFIG_VFS_SUPPORT_IO - -#if defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_UART_NONE) - esp_reent_init(_GLOBAL_REENT); - const char *default_uart_dev = "/dev/uart/" STRINGIFY(CONFIG_ESP_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 // defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_UART_NONE) - _REENT_SMALL_CHECK_INIT(_GLOBAL_REENT); -#endif // defined(CONFIG_VFS_SUPPORT_IO) && !defined(CONFIG_ESP_CONSOLE_UART_NONE) - // After setting _GLOBAL_REENT, ESP_LOGIx can be used instead of ESP_EARLY_LOGx. - -#ifdef CONFIG_SECURE_FLASH_ENC_ENABLED - esp_flash_encryption_init_checks(); -#endif - -#if CONFIG_SECURE_DISABLE_ROM_DL_MODE - err = esp_efuse_disable_rom_download_mode(); - assert(err == ESP_OK && "Failed to disable ROM download mode"); -#endif - -#if CONFIG_SECURE_ENABLE_SECURE_ROM_DL_MODE - err = esp_efuse_enable_rom_secure_download_mode(); - assert(err == ESP_OK && "Failed to enable Secure Download mode"); -#endif - - esp_timer_init(); - esp_set_time_from_rtc(); - -#if CONFIG_APPTRACE_ENABLE - err = esp_apptrace_init(); - assert(err == ESP_OK && "Failed to init apptrace module on PRO CPU!"); -#endif - -#if CONFIG_SYSVIEW_ENABLE - SEGGER_SYSVIEW_Conf(); -#endif -#if CONFIG_ESP_DEBUG_STUBS_ENABLE esp_dbg_stubs_init(); -#endif err = esp_pthread_init(); assert(err == ESP_OK && "Failed to init pthread module!"); -#if CONFIG_ESP32S2_MEMPROT_FEATURE -#if CONFIG_ESP32S2_MEMPROT_FEATURE_LOCK - esp_memprot_set_prot(true, true); -#else - esp_memprot_set_prot(true, false); -#endif -#endif - - do_global_ctors(); -#if CONFIG_ESP_INT_WDT - esp_int_wdt_init(); - //Initialize the interrupt watch dog for CPU0. - esp_int_wdt_cpu_init(); -#else -#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_crosscore_int_init(); - -#ifndef CONFIG_FREERTOS_UNICORE - esp_dport_access_int_init(); -#endif - - - spi_flash_init(); - /* init default OS-aware flash access critical section */ - spi_flash_guard_set(&g_flash_guard_default_ops); - - esp_flash_app_init(); - esp_err_t flash_ret = esp_flash_init_default_chip(); - assert(flash_ret == ESP_OK); - -#if CONFIG_IDF_TARGET_ESP32 -#if CONFIG_ESP32_ENABLE_COREDUMP - esp_core_dump_init(); -#endif -#endif - #ifdef CONFIG_PM_ENABLE esp_pm_impl_init(); #ifdef CONFIG_PM_DFS_INIT_AUTO @@ -353,6 +318,12 @@ void IRAM_ATTR start_cpu0_default(void) #endif //CONFIG_PM_DFS_INIT_AUTO #endif //CONFIG_PM_ENABLE +#if CONFIG_IDF_TARGET_ESP32 +#if CONFIG_ESP32_ENABLE_COREDUMP + esp_core_dump_init(); +#endif +#endif + #if CONFIG_IDF_TARGET_ESP32 #if CONFIG_ESP32_WIFI_SW_COEXIST_ENABLE esp_coex_adapter_register(&g_coex_adapter_funcs); @@ -360,14 +331,18 @@ void IRAM_ATTR start_cpu0_default(void) #endif #endif - do_system_init_fn(); +#ifdef CONFIG_BOOTLOADER_EFUSE_SECURE_VERSION_EMULATE + const esp_partition_t *efuse_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_EFUSE_EM, NULL); + if (efuse_partition) { + esp_efuse_init(efuse_partition->address, efuse_partition->size); + } +#endif +} - portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main", - ESP_TASK_MAIN_STACK, NULL, - ESP_TASK_MAIN_PRIO, NULL, 0); - assert(res == pdTRUE); - - ESP_LOGI(TAG, "Starting scheduler on PRO CPU."); - vTaskStartScheduler(); - abort(); /* Only get to here if not enough free heap to start scheduler */ +IRAM_ATTR ESP_SYSTEM_INIT_FN(init_components1, BIT(1)) +{ +#if CONFIG_APPTRACE_ENABLE + esp_err_t err = esp_apptrace_init(); + assert(err == ESP_OK && "Failed to init apptrace module on APP CPU!"); +#endif } \ No newline at end of file diff --git a/components/freertos/CMakeLists.txt b/components/freertos/CMakeLists.txt index 6471d32622..58bb3cbd15 100644 --- a/components/freertos/CMakeLists.txt +++ b/components/freertos/CMakeLists.txt @@ -62,3 +62,5 @@ set_source_files_properties( PROPERTIES COMPILE_DEFINITIONS _ESP_FREERTOS_INTERNAL ) + +target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=app_main") \ No newline at end of file diff --git a/components/freertos/xtensa/port.c b/components/freertos/xtensa/port.c index dbf0824bed..9188b2dff9 100644 --- a/components/freertos/xtensa/port.c +++ b/components/freertos/xtensa/port.c @@ -110,12 +110,23 @@ #include "sdkconfig.h" #include "esp_compiler.h" +#include "esp_task_wdt.h" +#include "esp_task.h" + +#include "soc/soc_caps.h" +#include "soc/efuse_reg.h" +#include "soc/dport_access.h" +#include "soc/dport_reg.h" +#include "esp_int_wdt.h" + /* Defined in portasm.h */ extern void _frxt_tick_timer_init(void); /* Defined in xtensa_context.S */ extern void _xt_coproc_init(void); +static const char* TAG = "cpu_start"; // [refactor-todo]: might be appropriate to change in the future, but + // for now maintain the same log output #if CONFIG_FREERTOS_CORETIMER_0 #define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER0_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF) @@ -124,6 +135,8 @@ extern void _xt_coproc_init(void); #define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER1_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF) #endif + + _Static_assert(tskNO_AFFINITY == CONFIG_FREERTOS_NO_AFFINITY, "incorrect tskNO_AFFINITY value"); /*-----------------------------------------------------------*/ @@ -434,4 +447,122 @@ void __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, c dest = strcat(dest, str[i]); } esp_system_abort(buf); +} + +// `esp_system` calls the app entry point app_main for core 0 and app_mainX for +// the rest of the cores which the app normally provides for non-os builds. +// If `freertos` is included in the build, wrap the call to app_main and provide +// our own definition of app_mainX so that we can do our own initializations for each +// core and start the scheduler. +// +// We now simply execute the real app_main in the context of the main task that +// we also start. +extern void __real_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 + + //Initialize task wdt if configured to do so +#ifdef CONFIG_ESP_TASK_WDT_PANIC + ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, true)); +#elif CONFIG_ESP_TASK_WDT + ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, false)); +#endif + + //Add IDLE 0 to task wdt +#ifdef CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 + TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0); + if(idle_0 != NULL){ + ESP_ERROR_CHECK(esp_task_wdt_add(idle_0)); + } +#endif + //Add IDLE 1 to task wdt +#ifdef CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1 + TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCPU(1); + if(idle_1 != NULL){ + ESP_ERROR_CHECK(esp_task_wdt_add(idle_1)); + } +#endif + + __real_app_main(); + vTaskDelete(NULL); +} + +#if !CONFIG_FREERTOS_UNICORE +void app_mainX(void) +{ + if (xPortGetCoreID() >= 2) { + // Explicitly support only up to two cores for now. + abort(); + } + + // Wait for FreeRTOS initialization to finish on PRO CPU + while (port_xSchedulerRunning[0] == 0) { + ; + } + +#if CONFIG_ESP_INT_WDT + //Initialize the interrupt watch dog for CPU1. + esp_int_wdt_cpu_init(); +#endif + + esp_crosscore_int_init(); + esp_dport_access_int_init(); + + ESP_EARLY_LOGI(TAG, "Starting scheduler on APP CPU."); + xPortStartScheduler(); + abort(); /* Only get to here if FreeRTOS somehow very broken */ +} +#endif + +void __wrap_app_main(void) +{ +#if CONFIG_ESP_INT_WDT + esp_int_wdt_init(); + //Initialize the interrupt watch dog for CPU0. + esp_int_wdt_cpu_init(); +#else +#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_crosscore_int_init(); + +#ifndef CONFIG_FREERTOS_UNICORE + esp_dport_access_int_init(); +#endif + + portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main", + ESP_TASK_MAIN_STACK, NULL, + ESP_TASK_MAIN_PRIO, NULL, 0); + assert(res == pdTRUE); + +#if !CONFIG_FREERTOS_UNICORE + // Check that FreeRTOS is configured properly for the number of cores the target + // has at compile and build time. +#if SOC_CPU_CORES_NUM < 2 + #error FreeRTOS configured to run on dual core, but target only has a single core. +#endif + if (REG_GET_BIT(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_DIS_APP_CPU)) { + ESP_EARLY_LOGE(TAG, "Running on single core chip, but application is built with dual core support."); + ESP_EARLY_LOGE(TAG, "Please enable CONFIG_FREERTOS_UNICORE option in menuconfig."); + abort(); + } + +#else + #if SOC_CPU_CORES_NUM > 1 // Single core chips have no 'single core mode' + ESP_EARLY_LOGI(TAG, "Single core mode"); + DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN); + #endif +#endif // !CONFIG_FREERTOS_UNICORE + + ESP_LOGI(TAG, "Starting scheduler on PRO CPU."); + vTaskStartScheduler(); } \ No newline at end of file diff --git a/components/pthread/include/esp_pthread.h b/components/pthread/include/esp_pthread.h index cdff0519e5..95e182c1f0 100644 --- a/components/pthread/include/esp_pthread.h +++ b/components/pthread/include/esp_pthread.h @@ -82,6 +82,11 @@ esp_err_t esp_pthread_set_cfg(const esp_pthread_cfg_t *cfg); */ esp_err_t esp_pthread_get_cfg(esp_pthread_cfg_t *p); +/** + * @brief Initialize pthread library + */ +esp_err_t esp_pthread_init(void); + #ifdef __cplusplus } #endif From ef2a44d251cd1bdb6ec51895759d9d774b468796 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Thu, 13 Feb 2020 17:43:23 +0500 Subject: [PATCH 06/17] esp_system: introduce single core mode proxy config --- components/esp_system/CMakeLists.txt | 5 +- components/esp_system/Kconfig | 6 + components/esp_system/port/cpu_start.c | 126 ++++++++++-------- .../private_include/startup_internal.h | 10 +- components/esp_system/startup.c | 39 +++++- components/freertos/Kconfig | 6 +- components/freertos/xtensa/port.c | 31 ++--- 7 files changed, 142 insertions(+), 81 deletions(-) diff --git a/components/esp_system/CMakeLists.txt b/components/esp_system/CMakeLists.txt index 655d945bb1..884b6ce3e2 100644 --- a/components/esp_system/CMakeLists.txt +++ b/components/esp_system/CMakeLists.txt @@ -10,4 +10,7 @@ add_subdirectory(port) # Rely on user code to define app_main target_link_libraries(${COMPONENT_LIB} INTERFACE "-u app_main") -target_link_libraries(${COMPONENT_LIB} INTERFACE "-u app_mainX") \ No newline at end of file + +if (NOT CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE) + target_link_libraries(${COMPONENT_LIB} INTERFACE "-u app_mainX") +endif() \ No newline at end of file diff --git a/components/esp_system/Kconfig b/components/esp_system/Kconfig index 73b54ad48d..58a2b90cb3 100644 --- a/components/esp_system/Kconfig +++ b/components/esp_system/Kconfig @@ -32,4 +32,10 @@ menu "ESP System Settings" of the crash. endchoice + config ESP_SYSTEM_SINGLE_CORE_MODE + bool + default n + help + Only initialize and use the main core. + endmenu # ESP System Settings diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index 08239b4e86..1efa5a6778 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -67,6 +67,8 @@ #endif // CONFIG_APP_BUILD_TYPE_ELF_RAM #endif +#include "startup_internal.h" + extern int _bss_start; extern int _bss_end; extern int _rtc_bss_start; @@ -87,34 +89,23 @@ extern int _iram_bss_end; #endif #endif // CONFIG_IDF_TARGET_ESP32 -#include "startup_internal.h" - +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE static volatile bool s_cpu_up[SOC_CPU_CORES_NUM] = { false }; static volatile bool s_cpu_inited[SOC_CPU_CORES_NUM] = { false }; + static volatile bool s_resume_cores; +#endif // If CONFIG_SPIRAM_IGNORE_NOTFOUND is set and external RAM is not found or errors out on testing, this is set to false. bool g_spiram_ok = true; +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE void startup_resume_other_cores(void) { s_resume_cores = true; } -static void intr_matrix_clear(void) -{ -#if CONFIG_IDF_TARGET_ESP32 - //Clear all the interrupt matrix register - for (int i = ETS_WIFI_MAC_INTR_SOURCE; i <= ETS_CACHE_IA_INTR_SOURCE; i++) { -#elif CONFIG_IDF_TARGET_ESP32S2 - for (int i = ETS_WIFI_MAC_INTR_SOURCE; i < ETS_MAX_INTR_SOURCE; i++) { -#endif - intr_matrix_set(0, i, ETS_INVALID_INUM); - intr_matrix_set(1, i, ETS_INVALID_INUM); - } -} -#if SOC_CPU_CORES_NUM > 1 void IRAM_ATTR call_start_cpu1(void) { cpu_hal_set_vecbase(&_init_start); @@ -156,7 +147,62 @@ void IRAM_ATTR call_start_cpu1(void) SYS_STARTUP_FN(); } + +static void start_other_core(void) +{ + // If not the single core variant of ESP32 - check this since there is + // no separate soc_caps.h for the single core variant. + if (!REG_GET_BIT(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_DIS_APP_CPU)) { + ESP_EARLY_LOGI(TAG, "Starting app cpu, entry point is %p", call_start_cpu1); + + Cache_Flush(1); + Cache_Read_Enable(1); + esp_cpu_unstall(1); + + // Enable clock and reset APP CPU. Note that OpenOCD may have already + // enabled clock and taken APP CPU out of reset. In this case don't reset + // APP CPU again, as that will clear the breakpoints which may have already + // been set. + if (!DPORT_GET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN)) { + DPORT_SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN); + DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_C_REG, DPORT_APPCPU_RUNSTALL); + DPORT_SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING); + DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING); + } + ets_set_appcpu_boot_addr((uint32_t)call_start_cpu1); + + volatile bool cpus_up = false; + + while(!cpus_up){ + cpus_up = true; + for (int i = 0; i < SOC_CPU_CORES_NUM; i++) { + cpus_up &= s_cpu_up[i]; + } + cpu_hal_delay_us(100); + } + } + else { + s_cpu_inited[1] = true; + ESP_EARLY_LOGI(TAG, "Single core mode"); + DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN); + } +} +#endif // !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + +static void intr_matrix_clear(void) +{ +#if CONFIG_IDF_TARGET_ESP32 + //Clear all the interrupt matrix register + for (int i = ETS_WIFI_MAC_INTR_SOURCE; i <= ETS_CACHE_IA_INTR_SOURCE; i++) { +#elif CONFIG_IDF_TARGET_ESP32S2 + for (int i = ETS_WIFI_MAC_INTR_SOURCE; i < ETS_MAX_INTR_SOURCE; i++) { #endif + intr_matrix_set(0, i, ETS_INVALID_INUM); +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + intr_matrix_set(1, i, ETS_INVALID_INUM); +#endif + } +} /* * We arrive here after the bootloader finished loading the program from flash. The hardware is mostly uninitialized, @@ -164,7 +210,11 @@ void IRAM_ATTR call_start_cpu1(void) */ void IRAM_ATTR call_start_cpu0(void) { +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE RESET_REASON rst_reas[SOC_CPU_CORES_NUM]; +#else + RESET_REASON rst_reas[1]; +#endif bootloader_init_mem(); @@ -172,14 +222,14 @@ void IRAM_ATTR call_start_cpu0(void) cpu_hal_set_vecbase(&_init_start); rst_reas[0] = rtc_get_reset_reason(0); -#if SOC_CPU_CORES_NUM > 1 +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE rst_reas[1] = rtc_get_reset_reason(1); #endif #ifndef CONFIG_BOOTLOADER_WDT_ENABLE // from panic handler we can be reset by RWDT or TG0WDT if (rst_reas[0] == RTCWDT_SYS_RESET || rst_reas[0] == TG0WDT_SYS_RESET -#if SOC_CPU_CORES_NUM > 1 +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE || rst_reas[1] == RTCWDT_SYS_RESET || rst_reas[1] == TG0WDT_SYS_RESET #endif ) { @@ -240,45 +290,13 @@ void IRAM_ATTR call_start_cpu0(void) } #endif +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE s_cpu_up[0] = true; +#endif ESP_EARLY_LOGI(TAG, "Pro cpu up."); -#if CONFIG_IDF_TARGET_ESP32 - // If not the single core variant of ESP32 - check this since there is - // no separate soc_caps.h for the single core variant. - if (!REG_GET_BIT(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_DIS_APP_CPU)) { - ESP_EARLY_LOGI(TAG, "Starting app cpu, entry point is %p", call_start_cpu1); - - Cache_Flush(1); - Cache_Read_Enable(1); - esp_cpu_unstall(1); - - // Enable clock and reset APP CPU. Note that OpenOCD may have already - // enabled clock and taken APP CPU out of reset. In this case don't reset - // APP CPU again, as that will clear the breakpoints which may have already - // been set. - if (!DPORT_GET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN)) { - DPORT_SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN); - DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_C_REG, DPORT_APPCPU_RUNSTALL); - DPORT_SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING); - DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_A_REG, DPORT_APPCPU_RESETTING); - } - ets_set_appcpu_boot_addr((uint32_t)call_start_cpu1); - - volatile bool cpus_up = false; - - while(!cpus_up){ - cpus_up = true; - for (int i = 0; i < SOC_CPU_CORES_NUM; i++) { - cpus_up &= s_cpu_up[i]; - } - cpu_hal_delay_us(100); - } - } - else { - s_cpu_inited[1] = true; - DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN); - } +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + start_other_core(); #endif #if CONFIG_SPIRAM_MEMTEST @@ -390,6 +408,7 @@ void IRAM_ATTR call_start_cpu0(void) #endif //!CONFIG_SPIRAM_BOOT_INIT #endif +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE s_cpu_inited[0] = true; volatile bool cpus_inited = false; @@ -401,6 +420,7 @@ void IRAM_ATTR call_start_cpu0(void) } cpu_hal_delay_us(100); } +#endif SYS_STARTUP_FN(); } \ No newline at end of file diff --git a/components/esp_system/private_include/startup_internal.h b/components/esp_system/private_include/startup_internal.h index a7791fd2d9..9976b189e5 100644 --- a/components/esp_system/private_include/startup_internal.h +++ b/components/esp_system/private_include/startup_internal.h @@ -19,18 +19,26 @@ #include "soc/soc_caps.h" #include "hal/cpu_hal.h" +#include "sdkconfig.h" + extern bool g_spiram_ok; // [refactor-todo] better way to communicate this from port layer to common startup code // Port layer defines the entry point. It then transfer control to a `sys_startup_fn_t`, stored in this // array, one per core. typedef void (*sys_startup_fn_t)(void); + +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE extern sys_startup_fn_t g_startup_fn[SOC_CPU_CORES_NUM]; +#else +extern sys_startup_fn_t g_startup_fn[1]; +#endif // Utility to execute `sys_startup_fn_t` for the current core. #define SYS_STARTUP_FN() ((*g_startup_fn[(cpu_hal_get_core_id())])()) +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE void startup_resume_other_cores(void); -void startup_core_init(); +#endif typedef struct { void (*fn)(void); diff --git a/components/esp_system/startup.c b/components/esp_system/startup.c index 0dcb8076f3..0d7bed96c0 100644 --- a/components/esp_system/startup.c +++ b/components/esp_system/startup.c @@ -38,7 +38,8 @@ #include "esp_efuse.h" #include "esp_flash_encrypt.h" -/* Headers for other components init functions */ +/***********************************************/ +// Headers for other components init functions #include "nvs_flash.h" #include "esp_phy_init.h" #include "esp_coexist_internal.h" @@ -61,12 +62,26 @@ #include "startup_internal.h" +// Ensure that system configuration matches the underlying number of cores. +// This should enable us to avoid checking for both everytime. +#if !(SOC_CPU_CORES_NUM > 1) && !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE + #error "System has been configured to run on multiple cores, but target SoC only has a single core." +#endif + +// App entry point for core 0 +extern void app_main(void); + +// Entry point for core 0 from hardware init (port layer) void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default"))) __attribute__((noreturn)); + +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE +// Entry point for core [1..X] from hardware init (port layer) void start_cpuX(void) __attribute__((weak, alias("start_cpuX_default"))) __attribute__((noreturn)); +// App entry point for core [1..X] void app_mainX(void) __attribute__((weak, alias("app_mainX_default"))) __attribute__((noreturn)); -extern void app_main(void); +static volatile bool s_system_inited[SOC_CPU_CORES_NUM] = { false }; sys_startup_fn_t g_startup_fn[SOC_CPU_CORES_NUM] = { [0] = start_cpu0, #if SOC_CPU_CORES_NUM > 1 @@ -74,8 +89,10 @@ sys_startup_fn_t g_startup_fn[SOC_CPU_CORES_NUM] = { [0] = start_cpu0, #endif }; -static volatile bool s_system_inited[SOC_CPU_CORES_NUM] = { false }; static volatile bool s_system_full_inited = false; +#else +sys_startup_fn_t g_startup_fn[1] = { start_cpu0 }; +#endif static const char* TAG = "cpu_start"; @@ -112,9 +129,12 @@ static void IRAM_ATTR do_system_init_fn(void) } } +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE s_system_inited[cpu_hal_get_core_id()] = true; +#endif } +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE static void IRAM_ATTR app_mainX_default(void) { while(1) { @@ -132,6 +152,7 @@ static void IRAM_ATTR start_cpuX_default(void) app_mainX(); } +#endif static void IRAM_ATTR do_core_init(void) { @@ -221,15 +242,18 @@ static void IRAM_ATTR do_core_init(void) static void IRAM_ATTR do_secondary_init(void) { +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE // The port layer transferred control to this function with other cores 'paused', // resume execution so that cores might execute component initialization functions. startup_resume_other_cores(); +#endif // Execute initialization functions esp_system_init_fn_t assigned to the main core. While // this is happening, all other cores are executing the initialization functions // assigned to them since they have been resumed already. do_system_init_fn(); +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE // Wait for all cores to finish secondary init. volatile bool system_inited = false; @@ -240,6 +264,7 @@ static void IRAM_ATTR do_secondary_init(void) } cpu_hal_delay_us(100); } +#endif } void IRAM_ATTR start_cpu0_default(void) @@ -273,7 +298,7 @@ void IRAM_ATTR start_cpu0_default(void) do_global_ctors(); // Execute init functions of other components; blocks - // until all cores finish. + // until all cores finish (when !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE). do_secondary_init(); // Now that the application is about to start, disable boot watchdog @@ -284,7 +309,9 @@ void IRAM_ATTR start_cpu0_default(void) // Finally, we jump to user code. ESP_EARLY_LOGI(TAG, "Pro cpu start user code"); +#if SOC_CPU_CORES_NUM > 1 && !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE s_system_full_inited = true; +#endif app_main(); while(1); @@ -339,10 +366,12 @@ IRAM_ATTR ESP_SYSTEM_INIT_FN(init_components0, BIT(0)) #endif } +#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE IRAM_ATTR ESP_SYSTEM_INIT_FN(init_components1, BIT(1)) { #if CONFIG_APPTRACE_ENABLE esp_err_t err = esp_apptrace_init(); assert(err == ESP_OK && "Failed to init apptrace module on APP CPU!"); #endif -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/components/freertos/Kconfig b/components/freertos/Kconfig index 11ca559a55..834067280c 100644 --- a/components/freertos/Kconfig +++ b/components/freertos/Kconfig @@ -1,11 +1,9 @@ menu "FreeRTOS" config FREERTOS_UNICORE - # This config variable is also checked in the target startup code, not only in FreeRTOS - # hence the dependency on what target the app is being built for. bool "Run FreeRTOS only on first core" - default y if IDF_TARGET_ESP32S2 - default n + default "y" if IDF_TARGET_ESP32S2 + select ESP_SYSTEM_SINGLE_CORE_MODE help This version of FreeRTOS normally takes control of all cores of the CPU. Select this if you only want to start it on the first core. diff --git a/components/freertos/xtensa/port.c b/components/freertos/xtensa/port.c index 9188b2dff9..8f8db730fa 100644 --- a/components/freertos/xtensa/port.c +++ b/components/freertos/xtensa/port.c @@ -135,8 +135,6 @@ static const char* TAG = "cpu_start"; // [refactor-todo]: might be appropriate t #define SYSTICK_INTR_ID (ETS_INTERNAL_TIMER1_INTR_SOURCE+ETS_INTERNAL_INTR_SOURCE_OFF) #endif - - _Static_assert(tskNO_AFFINITY == CONFIG_FREERTOS_NO_AFFINITY, "incorrect tskNO_AFFINITY value"); /*-----------------------------------------------------------*/ @@ -494,11 +492,20 @@ static void main_task(void* args) vTaskDelete(NULL); } +// 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 + #if !CONFIG_FREERTOS_UNICORE void app_mainX(void) { + // For now, we only support up to two core: 0 and 1. if (xPortGetCoreID() >= 2) { - // Explicitly support only up to two cores for now. abort(); } @@ -544,24 +551,14 @@ void __wrap_app_main(void) ESP_TASK_MAIN_PRIO, NULL, 0); assert(res == pdTRUE); -#if !CONFIG_FREERTOS_UNICORE - // Check that FreeRTOS is configured properly for the number of cores the target - // has at compile and build time. -#if SOC_CPU_CORES_NUM < 2 - #error FreeRTOS configured to run on dual core, but target only has a single core. -#endif + // ESP32 has single core variants. Check that FreeRTOS has been configured properly. +#if CONFIG_IDF_TARGET_ESP32 && !CONFIG_FREERTOS_UNICORE if (REG_GET_BIT(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_DIS_APP_CPU)) { - ESP_EARLY_LOGE(TAG, "Running on single core chip, but application is built with dual core support."); + ESP_EARLY_LOGE(TAG, "Running on single core chip, but FreeRTOS is built with dual core support."); ESP_EARLY_LOGE(TAG, "Please enable CONFIG_FREERTOS_UNICORE option in menuconfig."); abort(); } - -#else - #if SOC_CPU_CORES_NUM > 1 // Single core chips have no 'single core mode' - ESP_EARLY_LOGI(TAG, "Single core mode"); - DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN); - #endif -#endif // !CONFIG_FREERTOS_UNICORE +#endif // CONFIG_IDF_TARGET_ESP32 && !CONFIG_FREERTOS_UNICORE ESP_LOGI(TAG, "Starting scheduler on PRO CPU."); vTaskStartScheduler(); From 4bc53d44e3de267651d4f499782065f41d09fcdd Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Fri, 14 Feb 2020 15:03:22 +0500 Subject: [PATCH 07/17] xtensa: use early logging for trax config during startup --- components/xtensa/debug_helpers.c | 2 ++ components/xtensa/trax.c | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/components/xtensa/debug_helpers.c b/components/xtensa/debug_helpers.c index 06c7f9b23f..788f2b8c14 100644 --- a/components/xtensa/debug_helpers.c +++ b/components/xtensa/debug_helpers.c @@ -20,6 +20,8 @@ #include "soc/soc_memory_layout.h" #include "soc/cpu.h" +#include "sdkconfig.h" + #if CONFIG_IDF_TARGET_ESP32 #include "esp32/rom/ets_sys.h" #elif CONFIG_IDF_TARGET_ESP32S2 diff --git a/components/xtensa/trax.c b/components/xtensa/trax.c index 725e677d4e..0bddcb341b 100644 --- a/components/xtensa/trax.c +++ b/components/xtensa/trax.c @@ -30,12 +30,12 @@ static const char* TAG = "trax"; int trax_start_trace(trax_downcount_unit_t units_until_stop) { #if !WITH_TRAX - ESP_LOGE(TAG, "Trax_start_trace called, but trax is disabled in menuconfig!"); + ESP_EARLY_LOGE(TAG, "Trax_start_trace called, but trax is disabled in menuconfig!"); return ESP_ERR_NO_MEM; #endif uint32_t v; if (eri_read(ERI_TRAX_TRAXSTAT)&TRAXSTAT_TRACT) { - ESP_LOGI(TAG, "Stopping active trace first."); + ESP_EARLY_LOGI(TAG, "Stopping active trace first."); //Trace is active. Stop trace. eri_write(ERI_TRAX_DELAYCNT, 0); eri_write(ERI_TRAX_TRAXCTRL, eri_read(ERI_TRAX_TRAXCTRL)|TRAXCTRL_TRSTP); @@ -54,7 +54,7 @@ int trax_start_trace(trax_downcount_unit_t units_until_stop) int trax_trigger_traceend_after_delay(int delay) { #if !WITH_TRAX - ESP_LOGE(TAG, "Trax_trigger_traceend_after_delay called, but trax is disabled in menuconfig!"); + ESP_EARLY_LOGE(TAG, "Trax_trigger_traceend_after_delay called, but trax is disabled in menuconfig!"); return ESP_ERR_NO_MEM; #endif eri_write(ERI_TRAX_DELAYCNT, delay); From 362d7b8f715c21be4ce4695f34ee824c1cb21a06 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Sun, 16 Feb 2020 17:46:30 +0500 Subject: [PATCH 08/17] efuse: spelling fix --- components/efuse/src/esp_efuse_api.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/components/efuse/src/esp_efuse_api.c b/components/efuse/src/esp_efuse_api.c index ce17a58cc2..a72a77dff6 100644 --- a/components/efuse/src/esp_efuse_api.c +++ b/components/efuse/src/esp_efuse_api.c @@ -24,15 +24,15 @@ const static char *TAG = "efuse"; #if defined(BOOTLOADER_BUILD) #define EFUSE_LOCK_ACQUIRE() #define EFUSE_LOCK_RELEASE() -#define EFUSE_LOCK_ACQUIRE_RUCURSIVE() -#define EFUSE_LOCK_RELEASE_RUCURSIVE() +#define EFUSE_LOCK_ACQUIRE_RECURSIVE() +#define EFUSE_LOCK_RELEASE_RECURSIVE() #else #include static _lock_t s_efuse_lock; #define EFUSE_LOCK_ACQUIRE() _lock_acquire(&s_efuse_lock) #define EFUSE_LOCK_RELEASE() _lock_release(&s_efuse_lock) -#define EFUSE_LOCK_ACQUIRE_RUCURSIVE() _lock_acquire_recursive(&s_efuse_lock) -#define EFUSE_LOCK_RELEASE_RUCURSIVE() _lock_release_recursive(&s_efuse_lock) +#define EFUSE_LOCK_ACQUIRE_RECURSIVE() _lock_acquire_recursive(&s_efuse_lock) +#define EFUSE_LOCK_RELEASE_RECURSIVE() _lock_release_recursive(&s_efuse_lock) #endif static bool s_batch_writing_mode = false; @@ -80,7 +80,7 @@ esp_err_t esp_efuse_read_field_cnt(const esp_efuse_desc_t* field[], size_t* out_ // write array to EFUSE esp_err_t esp_efuse_write_field_blob(const esp_efuse_desc_t* field[], const void* src, size_t src_size_bits) { - EFUSE_LOCK_ACQUIRE_RUCURSIVE(); + EFUSE_LOCK_ACQUIRE_RECURSIVE(); esp_err_t err = ESP_OK; if (field == NULL || src == NULL || src_size_bits == 0) { err = ESP_ERR_INVALID_ARG; @@ -100,14 +100,14 @@ esp_err_t esp_efuse_write_field_blob(const esp_efuse_desc_t* field[], const void esp_efuse_utility_reset(); } } - EFUSE_LOCK_RELEASE_RUCURSIVE(); + EFUSE_LOCK_RELEASE_RECURSIVE(); return err; } // program cnt bits to "1" esp_err_t esp_efuse_write_field_cnt(const esp_efuse_desc_t* field[], size_t cnt) { - EFUSE_LOCK_ACQUIRE_RUCURSIVE(); + EFUSE_LOCK_ACQUIRE_RECURSIVE(); esp_err_t err = ESP_OK; if (field == NULL || cnt == 0) { err = ESP_ERR_INVALID_ARG; @@ -135,7 +135,7 @@ esp_err_t esp_efuse_write_field_cnt(const esp_efuse_desc_t* field[], size_t cnt) esp_efuse_utility_reset(); } } - EFUSE_LOCK_RELEASE_RUCURSIVE(); + EFUSE_LOCK_RELEASE_RECURSIVE(); return err; } @@ -184,7 +184,7 @@ uint32_t esp_efuse_read_reg(esp_efuse_block_t blk, unsigned int num_reg) // writing efuse register. esp_err_t esp_efuse_write_reg(esp_efuse_block_t blk, unsigned int num_reg, uint32_t val) { - EFUSE_LOCK_ACQUIRE_RUCURSIVE(); + EFUSE_LOCK_ACQUIRE_RECURSIVE(); if (s_batch_writing_mode == false) { esp_efuse_utility_reset(); } @@ -198,7 +198,7 @@ esp_err_t esp_efuse_write_reg(esp_efuse_block_t blk, unsigned int num_reg, uint3 } esp_efuse_utility_reset(); } - EFUSE_LOCK_RELEASE_RUCURSIVE(); + EFUSE_LOCK_RELEASE_RECURSIVE(); return err; } From 4d094ecccae4f5e52469357c238a40b8322c9a56 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Sun, 16 Feb 2020 17:46:50 +0500 Subject: [PATCH 09/17] esp_system: move brownout init due to dependency issue --- components/esp_system/port/cpu_start.c | 1 - components/esp_system/startup.c | 8 ++++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index 1efa5a6778..9c50c0e849 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -28,7 +28,6 @@ #if CONFIG_IDF_TARGET_ESP32 #include "esp32/cache_err_int.h" -#include "esp32/brownout.h" #include "esp32/rom/cache.h" #include "esp32/rom/rtc.h" #include "esp32/rom/uart.h" diff --git a/components/esp_system/startup.c b/components/esp_system/startup.c index 0d7bed96c0..f9bebeb48c 100644 --- a/components/esp_system/startup.c +++ b/components/esp_system/startup.c @@ -54,9 +54,11 @@ #if CONFIG_IDF_TARGET_ESP32 #include "esp32/rom/uart.h" #include "esp32/spiram.h" +#include "esp32/brownout.h" #elif CONFIG_IDF_TARGET_ESP32S2 #include "esp32s2/rom/uart.h" #include "esp32s2/spiram.h" +#include "esp32s2/brownout.h" #endif /***********************************************/ @@ -181,6 +183,12 @@ static void IRAM_ATTR do_core_init(void) #endif } +#if CONFIG_ESP32_BROWNOUT_DET || CONFIG_ESP32S2_BROWNOUT_DET + // [refactor-todo] leads to call chain rtc_is_register (driver) -> esp_intr_alloc (esp32/esp32s2) -> + // malloc (newlib) -> heap_caps_malloc (heap), so heap must be at least initialized + esp_brownout_init(); +#endif + // Now we have startup stack RAM available for heap, enable any DMA pool memory #if CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL if (g_spiram_ok) { From 20d17e648b978304f42a1f8cb44f9b2b66f0b02e Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Sun, 16 Feb 2020 18:20:58 +0500 Subject: [PATCH 10/17] esp32, esp32s2: remove dependency of cache err int init on freertos --- components/esp32/cache_err_int.c | 12 +++++++++--- components/esp32/system_api_esp32.c | 5 ----- components/esp32s2/cache_err_int.c | 14 ++++++++++---- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/components/esp32/cache_err_int.c b/components/esp32/cache_err_int.c index 9adb9effb2..f8deadbf9e 100644 --- a/components/esp32/cache_err_int.c +++ b/components/esp32/cache_err_int.c @@ -23,16 +23,22 @@ #include #include #include -#include "freertos/FreeRTOS.h" + #include "esp_err.h" -#include "esp_intr_alloc.h" #include "esp_attr.h" + +#include "esp_intr_alloc.h" #include "soc/dport_reg.h" +#include "hal/cpu_hal.h" + +#include "esp32/dport_access.h" +#include "esp32/rom/ets_sys.h" + #include "sdkconfig.h" void esp_cache_err_int_init(void) { - uint32_t core_id = xPortGetCoreID(); + uint32_t core_id = cpu_hal_get_core_id(); ESP_INTR_DISABLE(ETS_MEMACCESS_ERR_INUM); // We do not register a handler for the interrupt because it is interrupt diff --git a/components/esp32/system_api_esp32.c b/components/esp32/system_api_esp32.c index f32c59c802..66bf18f96f 100644 --- a/components/esp32/system_api_esp32.c +++ b/components/esp32/system_api_esp32.c @@ -33,12 +33,7 @@ #include "hal/wdt_hal.h" #include "freertos/xtensa_api.h" -#if CONFIG_IDF_TARGET_ESP32 #include "esp32/cache_err_int.h" -#elif CONFIG_IDF_TARGET_ESP32S2 -#include "esp32s2/cache_err_int.h" -#endif - /* "inner" restart function for after RTOS, interrupts & anything else on this * core are already stopped. Stalls other core, resets hardware, diff --git a/components/esp32s2/cache_err_int.c b/components/esp32s2/cache_err_int.c index 11c2e73103..1db8f2b080 100644 --- a/components/esp32s2/cache_err_int.c +++ b/components/esp32s2/cache_err_int.c @@ -23,19 +23,25 @@ #include #include #include -#include "freertos/FreeRTOS.h" + #include "esp_err.h" -#include "esp_intr_alloc.h" #include "esp_attr.h" + +#include "esp_intr_alloc.h" + #include "soc/extmem_reg.h" #include "soc/dport_reg.h" #include "soc/periph_defs.h" -#include "sdkconfig.h" +#include "hal/cpu_hal.h" + #include "esp32s2/dport_access.h" +#include "esp32s2/rom/ets_sys.h" + +#include "sdkconfig.h" void esp_cache_err_int_init(void) { - uint32_t core_id = xPortGetCoreID(); + uint32_t core_id = cpu_hal_get_core_id(); ESP_INTR_DISABLE(ETS_MEMACCESS_ERR_INUM); // We do not register a handler for the interrupt because it is interrupt From 67983d5c1c77c866f93a42aab5c8874f9c1763c4 Mon Sep 17 00:00:00 2001 From: Renz Christian Bagaporo Date: Sun, 16 Feb 2020 18:29:29 +0500 Subject: [PATCH 11/17] esp_system: restore order of some init functions --- components/esp32s2/include/esp_spiram.h | 12 --- .../esp_private}/startup_internal.h | 8 ++ components/esp_system/port/cpu_start.c | 15 ++-- components/esp_system/startup.c | 78 ++++++++++--------- components/freertos/xtensa/port.c | 51 ++++++++++-- 5 files changed, 99 insertions(+), 65 deletions(-) rename components/esp_system/{private_include => include/esp_private}/startup_internal.h (97%) diff --git a/components/esp32s2/include/esp_spiram.h b/components/esp32s2/include/esp_spiram.h index 414cc310af..16212e5405 100644 --- a/components/esp32s2/include/esp_spiram.h +++ b/components/esp32s2/include/esp_spiram.h @@ -78,18 +78,6 @@ size_t esp_spiram_get_size(void); void esp_spiram_writeback_cache(void); - -/** - * @brief Reserve a pool of internal memory for specific DMA/internal allocations - * - * @param size Size of reserved pool in bytes - * - * @return - * - ESP_OK on success - * - ESP_ERR_NO_MEM when no memory available for pool - */ -esp_err_t esp_spiram_reserve_dma_pool(size_t size); - #ifdef __cplusplus } #endif diff --git a/components/esp_system/private_include/startup_internal.h b/components/esp_system/include/esp_private/startup_internal.h similarity index 97% rename from components/esp_system/private_include/startup_internal.h rename to components/esp_system/include/esp_private/startup_internal.h index 9976b189e5..8a12ee3673 100644 --- a/components/esp_system/private_include/startup_internal.h +++ b/components/esp_system/include/esp_private/startup_internal.h @@ -21,6 +21,10 @@ #include "sdkconfig.h" +#ifdef __cplusplus +extern "C" { +#endif + extern bool g_spiram_ok; // [refactor-todo] better way to communicate this from port layer to common startup code // Port layer defines the entry point. It then transfer control to a `sys_startup_fn_t`, stored in this @@ -60,3 +64,7 @@ static __attribute__((used)) esp_system_init_fn_t _SECTION_ATTR_IMPL(".esp_syste static __attribute__((used)) __VA_ARGS__ void __esp_system_init_fn_##f(void) // [refactor-todo] this can be made public API if we allow components to declare init functions, // instead of calling them explicitly +#ifdef __cplusplus +} +#endif + diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index 9c50c0e849..663a29952c 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -66,7 +66,7 @@ #endif // CONFIG_APP_BUILD_TYPE_ELF_RAM #endif -#include "startup_internal.h" +#include "esp_private/startup_internal.h" extern int _bss_start; extern int _bss_end; @@ -349,10 +349,10 @@ void IRAM_ATTR call_start_cpu0(void) #if CONFIG_IDF_TARGET_ESP32 #if CONFIG_ESP32_TRAX_TWOBANKS trax_enable(TRAX_ENA_PRO_APP); - #else + #else trax_enable(TRAX_ENA_PRO); #endif -#elif CONFIG_IDF_TARGET_ESP32S2 +#elif CONFIG_IDF_TARGET_ESP32S2 trax_enable(TRAX_ENA_PRO); #endif trax_start_trace(TRAX_DOWNCOUNT_WORDS); @@ -362,11 +362,12 @@ void IRAM_ATTR call_start_cpu0(void) esp_perip_clk_init(); intr_matrix_clear(); -#if CONFIG_ESP32_BROWNOUT_DET || CONFIG_ESP32S2_BROWNOUT_DET - esp_brownout_init(); +#ifndef CONFIG_ESP_CONSOLE_UART_NONE + const int uart_clk_freq = APB_CLK_FREQ; + uart_div_modify(CONFIG_ESP_CONSOLE_UART_NUM, (uart_clk_freq << 4) / CONFIG_ESP_CONSOLE_UART_BAUDRATE); #endif - rtc_gpio_force_hold_dis_all(); + rtcio_hal_unhold_all(); esp_cache_err_int_init(); @@ -381,7 +382,7 @@ void IRAM_ATTR call_start_cpu0(void) #endif bootloader_flash_update_id(); -#if CONFIG_IDF_TARGET_ESP32 +#if CONFIG_IDF_TARGET_ESP32 #if !CONFIG_SPIRAM_BOOT_INIT // Read the application binary image header. This will also decrypt the header if the image is encrypted. esp_image_header_t fhdr = {0}; diff --git a/components/esp_system/startup.c b/components/esp_system/startup.c index f9bebeb48c..0c036ef438 100644 --- a/components/esp_system/startup.c +++ b/components/esp_system/startup.c @@ -24,8 +24,8 @@ #include "sdkconfig.h" -#include "soc/rtc_wdt.h" #include "soc/soc_caps.h" +#include "hal/wdt_hal.h" #include "esp_system.h" #include "esp_log.h" @@ -39,7 +39,7 @@ #include "esp_flash_encrypt.h" /***********************************************/ -// Headers for other components init functions +// Headers for other components init functions #include "nvs_flash.h" #include "esp_phy_init.h" #include "esp_coexist_internal.h" @@ -48,6 +48,7 @@ #include "esp_private/dbg_stubs.h" #include "esp_flash_encrypt.h" #include "esp_pm.h" +#include "esp_private/pm_impl.h" #include "esp_pthread.h" // [refactor-todo] make this file completely target-independent @@ -62,7 +63,7 @@ #endif /***********************************************/ -#include "startup_internal.h" +#include "esp_private/startup_internal.h" // Ensure that system configuration matches the underlying number of cores. // This should enable us to avoid checking for both everytime. @@ -70,6 +71,9 @@ #error "System has been configured to run on multiple cores, but target SoC only has a single core." #endif +#define STRINGIFY(s) STRINGIFY2(s) +#define STRINGIFY2(s) #s + // App entry point for core 0 extern void app_main(void); @@ -167,7 +171,6 @@ static void IRAM_ATTR do_core_init(void) app CPU, and when that is not up yet, the memory will be inaccessible and heap_caps_init may fail initializing it properly. */ heap_caps_init(); - esp_setup_syscall_table(); if (g_spiram_ok) { @@ -184,27 +187,15 @@ static void IRAM_ATTR do_core_init(void) } #if CONFIG_ESP32_BROWNOUT_DET || CONFIG_ESP32S2_BROWNOUT_DET - // [refactor-todo] leads to call chain rtc_is_register (driver) -> esp_intr_alloc (esp32/esp32s2) -> + // [refactor-todo] leads to call chain rtc_is_register (driver) -> esp_intr_alloc (esp32/esp32s2) -> // malloc (newlib) -> heap_caps_malloc (heap), so heap must be at least initialized esp_brownout_init(); #endif - // 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 - - esp_reent_init(_GLOBAL_REENT); - -#ifndef CONFIG_ESP_CONSOLE_UART_NONE - const int uart_clk_freq = APB_CLK_FREQ; - uart_div_modify(CONFIG_ESP_CONSOLE_UART_NUM, (uart_clk_freq << 4) / CONFIG_ESP_CONSOLE_UART_BAUDRATE); +#if CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE || CONFIG_ESP32S2_DISABLE_BASIC_ROM_CONSOLE + // [refactor-todo] leads to call chain `esp_efuse_read_field_blob` (efuse) -> `esp_efuse_utility_process` -> `ESP_LOGX` + // syscall table must at least be init + esp_efuse_disable_basic_rom_console(); #endif #ifdef CONFIG_VFS_SUPPORT_IO @@ -239,6 +230,27 @@ static void IRAM_ATTR do_core_init(void) esp_efuse_disable_basic_rom_console(); #endif + esp_err_t err; + + esp_timer_init(); + esp_set_time_from_rtc(); + + // [refactor-todo] move this to secondary init +#if CONFIG_APPTRACE_ENABLE + err = esp_apptrace_init(); + assert(err == ESP_OK && "Failed to init apptrace module on PRO CPU!"); +#endif +#if CONFIG_SYSVIEW_ENABLE + SEGGER_SYSVIEW_Conf(); +#endif + +#if CONFIG_ESP_DEBUG_STUBS_ENABLE + esp_dbg_stubs_init(); +#endif + + err = esp_pthread_init(); + assert(err == ESP_OK && "Failed to init pthread module!"); + spi_flash_init(); /* init default OS-aware flash access critical section */ spi_flash_guard_set(&g_flash_guard_default_ops); @@ -277,6 +289,8 @@ static void IRAM_ATTR do_secondary_init(void) void IRAM_ATTR start_cpu0_default(void) { + ESP_EARLY_LOGI(TAG, "Pro cpu start user code"); + // Display information about the current running image. if (LOG_LOCAL_LEVEL >= ESP_LOG_INFO) { const esp_app_desc_t *app_desc = esp_ota_get_app_description(); @@ -311,12 +325,12 @@ void IRAM_ATTR start_cpu0_default(void) // Now that the application is about to start, disable boot watchdog #ifndef CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE - rtc_wdt_disable(); + wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_disable(&rtc_wdt_ctx); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); #endif - // Finally, we jump to user code. - ESP_EARLY_LOGI(TAG, "Pro cpu start user code"); - #if SOC_CPU_CORES_NUM > 1 && !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE s_system_full_inited = true; #endif @@ -336,8 +350,6 @@ IRAM_ATTR ESP_SYSTEM_INIT_FN(init_components0, BIT(0)) uart_div_modify(CONFIG_ESP_CONSOLE_UART_NUM, (uart_clk_freq << 4) / CONFIG_ESP_CONSOLE_UART_BAUDRATE); #endif // CONFIG_ESP_CONSOLE_UART_NONE - esp_dbg_stubs_init(); - err = esp_pthread_init(); assert(err == ESP_OK && "Failed to init pthread module!"); @@ -372,14 +384,4 @@ IRAM_ATTR ESP_SYSTEM_INIT_FN(init_components0, BIT(0)) esp_efuse_init(efuse_partition->address, efuse_partition->size); } #endif -} - -#if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE -IRAM_ATTR ESP_SYSTEM_INIT_FN(init_components1, BIT(1)) -{ -#if CONFIG_APPTRACE_ENABLE - esp_err_t err = esp_apptrace_init(); - assert(err == ESP_OK && "Failed to init apptrace module on APP CPU!"); -#endif -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/components/freertos/xtensa/port.c b/components/freertos/xtensa/port.c index 8f8db730fa..e96f716547 100644 --- a/components/freertos/xtensa/port.c +++ b/components/freertos/xtensa/port.c @@ -103,6 +103,7 @@ #include "esp_debug_helpers.h" #include "esp_heap_caps.h" +#include "esp_heap_caps_init.h" #include "esp_private/crosscore_int.h" #include "esp_intr_alloc.h" @@ -119,6 +120,18 @@ #include "soc/dport_reg.h" #include "esp_int_wdt.h" + +#include "sdkconfig.h" + +#if CONFIG_IDF_TARGET_ESP32 +#include "esp32/spiram.h" +#elif CONFIG_IDF_TARGET_ESP32S2 +#include "esp32s2/spiram.h" +#endif + +#include "esp_private/startup_internal.h" // [refactor-todo] for g_spiram_ok +#include "esp_app_trace.h" // [refactor-todo] for esp_app_trace_init + /* Defined in portasm.h */ extern void _frxt_tick_timer_init(void); @@ -140,8 +153,8 @@ _Static_assert(tskNO_AFFINITY == CONFIG_FREERTOS_NO_AFFINITY, "incorrect tskNO_A /*-----------------------------------------------------------*/ unsigned port_xSchedulerRunning[portNUM_PROCESSORS] = {0}; // Duplicate of inaccessible xSchedulerRunning; needed at startup to avoid counting nesting 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}; +BaseType_t port_uxCriticalNesting[portNUM_PROCESSORS] = {0}; +BaseType_t port_uxOldInterruptState[portNUM_PROCESSORS] = {0}; /*-----------------------------------------------------------*/ // User exception dispatcher when exiting @@ -396,12 +409,12 @@ uint32_t xPortGetTickRateHz(void) { void __attribute__((optimize("-O3"))) vPortEnterCritical(portMUX_TYPE *mux) { BaseType_t oldInterruptLevel = portENTER_CRITICAL_NESTED(); - /* Interrupts may already be disabled (because we're doing this recursively) + /* Interrupts may already be disabled (because we're doing this recursively) * but we can't get the interrupt level after * vPortCPUAquireMutex, because it also may mess with interrupts. * Get it here first, then later figure out if we're nesting * and save for real there. - */ + */ vPortCPUAcquireMutex( mux ); BaseType_t coreID = xPortGetCoreID(); BaseType_t newNesting = port_uxCriticalNesting[coreID] + 1; @@ -419,7 +432,7 @@ void __attribute__((optimize("-O3"))) vPortExitCritical(portMUX_TYPE *mux) vPortCPUReleaseMutex( mux ); BaseType_t coreID = xPortGetCoreID(); BaseType_t nesting = port_uxCriticalNesting[coreID]; - + if(nesting > 0U) { nesting--; @@ -447,11 +460,11 @@ void __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, c esp_system_abort(buf); } -// `esp_system` calls the app entry point app_main for core 0 and app_mainX for +// `esp_system` calls the app entry point app_main for core 0 and app_mainX for // the rest of the cores which the app normally provides for non-os builds. -// If `freertos` is included in the build, wrap the call to app_main and provide +// If `freertos` is included in the build, wrap the call to app_main and provide // our own definition of app_mainX so that we can do our own initializations for each -// core and start the scheduler. +// core and start the scheduler. // // We now simply execute the real app_main in the context of the main task that // we also start. @@ -466,6 +479,20 @@ static void main_task(void* args) } #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 #ifdef CONFIG_ESP_TASK_WDT_PANIC ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, true)); @@ -501,6 +528,8 @@ static void main_task(void* args) #error "FreeRTOS and system configuration mismatch regarding the use of multiple cores." #endif + + #if !CONFIG_FREERTOS_UNICORE void app_mainX(void) { @@ -514,6 +543,12 @@ void app_mainX(void) ; } +#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(); From fe12997a07ff42d7264b54e4bc6cc349c3abdc8c Mon Sep 17 00:00:00 2001 From: Renz Bagaporo Date: Tue, 3 Mar 2020 14:29:39 +0800 Subject: [PATCH 12/17] ci: update build system tests --- tools/ci/test_build_system.sh | 8 ++++---- tools/ci/test_build_system_cmake.sh | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/ci/test_build_system.sh b/tools/ci/test_build_system.sh index bc8632647b..5c09a05e1b 100755 --- a/tools/ci/test_build_system.sh +++ b/tools/ci/test_build_system.sh @@ -69,9 +69,9 @@ function run_tests() print_status "Updating component source file rebuilds component" # touch a file & do a build take_build_snapshot - touch ${IDF_PATH}/components/esp32/cpu_start.c + touch ${IDF_PATH}/components/esp_system/port/cpu_start.c make || failure "Failed to partial build" - assert_rebuilt ${APP_BINS} esp32/libesp32.a esp32/cpu_start.o + assert_rebuilt ${APP_BINS} esp_system/libesp_system.a esp_system/port/cpu_start.o assert_not_rebuilt lwip/liblwip.a freertos/libfreertos.a ${BOOTLOADER_BINS} partitions_singleapp.bin print_status "Bootloader source file rebuilds bootloader" @@ -251,12 +251,12 @@ function run_tests() echo "project-version-2.0(012345678901234567890123456789)" > ${TESTDIR}/template/version.txt make assert_rebuilt ${APP_BINS} - assert_not_rebuilt ${BOOTLOADER_BINS} esp32/libesp32.a + assert_not_rebuilt ${BOOTLOADER_BINS} esp_system/libesp_system.a print_status "Re-building does not change app.bin" take_build_snapshot make - assert_not_rebuilt ${APP_BINS} ${BOOTLOADER_BINS} esp32/libesp32.a + assert_not_rebuilt ${APP_BINS} ${BOOTLOADER_BINS} esp_system/libesp_system.a rm -f ${TESTDIR}/template/version.txt print_status "Get the version of app from git describe. Project is not inside IDF and do not have a tag only a hash commit." diff --git a/tools/ci/test_build_system_cmake.sh b/tools/ci/test_build_system_cmake.sh index 9f8ddc43ec..b6dd56bbeb 100755 --- a/tools/ci/test_build_system_cmake.sh +++ b/tools/ci/test_build_system_cmake.sh @@ -72,9 +72,9 @@ function run_tests() print_status "Updating component source file rebuilds component" # touch a file & do a build take_build_snapshot - touch ${IDF_PATH}/components/esp32/cpu_start.c + touch ${IDF_PATH}/components/esp_system/port/cpu_start.c idf.py build || failure "Failed to partial build" - assert_rebuilt ${APP_BINS} esp-idf/esp32/libesp32.a esp-idf/esp32/CMakeFiles/${IDF_COMPONENT_PREFIX}_esp32.dir/cpu_start.c.obj + assert_rebuilt ${APP_BINS} esp-idf/esp_system/libesp_system.a esp-idf/esp-idf/esp_system/CMakeFiles/${IDF_COMPONENT_PREFIX}_esp_system.dir/port/cpu_start.c.obj assert_not_rebuilt esp-idf/lwip/liblwip.a esp-idf/freertos/libfreertos.a ${BOOTLOADER_BINS} ${PARTITION_BIN} print_status "Bootloader source file rebuilds bootloader" @@ -109,12 +109,12 @@ function run_tests() echo "project-version-2.0(012345678901234567890123456789)" > ${TESTDIR}/template/version.txt idf.py build || failure "Failed to rebuild with changed app version" assert_rebuilt ${APP_BINS} - assert_not_rebuilt ${BOOTLOADER_BINS} esp-idf/esp32/libesp32.a + assert_not_rebuilt ${BOOTLOADER_BINS} esp-idf/esp_system/libesp_system.a print_status "Re-building does not change app.bin" take_build_snapshot idf.py build - assert_not_rebuilt ${APP_BINS} ${BOOTLOADER_BINS} esp-idf/esp32/libesp32.a + assert_not_rebuilt ${APP_BINS} ${BOOTLOADER_BINS} esp-idf/esp_system/libesp_system.a rm -f ${IDF_PATH}/version.txt rm -f ${TESTDIR}/template/version.txt From 3386316f815e9531ca53331a5860020c9b1b764a Mon Sep 17 00:00:00 2001 From: Renz Bagaporo Date: Tue, 3 Mar 2020 14:31:50 +0800 Subject: [PATCH 13/17] docs: fix build issue requiring new location of cpu_start.c --- docs/en/api-guides/freertos-smp.rst | 4 ++-- tools/ci/test_build_system_cmake.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/en/api-guides/freertos-smp.rst b/docs/en/api-guides/freertos-smp.rst index 7803653945..cdcb1ff95e 100644 --- a/docs/en/api-guides/freertos-smp.rst +++ b/docs/en/api-guides/freertos-smp.rst @@ -499,8 +499,8 @@ ESP-IDF FreeRTOS configurations, see :doc:`FreeRTOS <../api-reference/kconfig>` :ref:`CONFIG_FREERTOS_UNICORE` will run ESP-IDF FreeRTOS only on **PRO_CPU**. Note that this is **not equivalent to running vanilla - FreeRTOS**. Behaviors of multiple components in ESP-IDF will be modified such - as :component_file:`esp32/cpu_start.c`. For more details regarding the + FreeRTOS**. Note that this option may affect behavior of components other than + :component:`freertos`. For more details regarding the effects of running ESP-IDF FreeRTOS on a single core, search for occurences of ``CONFIG_FREERTOS_UNICORE`` in the ESP-IDF components. diff --git a/tools/ci/test_build_system_cmake.sh b/tools/ci/test_build_system_cmake.sh index b6dd56bbeb..ad6eb60edd 100755 --- a/tools/ci/test_build_system_cmake.sh +++ b/tools/ci/test_build_system_cmake.sh @@ -74,7 +74,7 @@ function run_tests() take_build_snapshot touch ${IDF_PATH}/components/esp_system/port/cpu_start.c idf.py build || failure "Failed to partial build" - assert_rebuilt ${APP_BINS} esp-idf/esp_system/libesp_system.a esp-idf/esp-idf/esp_system/CMakeFiles/${IDF_COMPONENT_PREFIX}_esp_system.dir/port/cpu_start.c.obj + assert_rebuilt ${APP_BINS} esp-idf/esp_system/libesp_system.a esp-idf/esp_system/CMakeFiles/${IDF_COMPONENT_PREFIX}_esp_system.dir/port/cpu_start.c.obj assert_not_rebuilt esp-idf/lwip/liblwip.a esp-idf/freertos/libfreertos.a ${BOOTLOADER_BINS} ${PARTITION_BIN} print_status "Bootloader source file rebuilds bootloader" From 5e59b4a812e694972a54cab024c8ee14ab5c3150 Mon Sep 17 00:00:00 2001 From: Renz Bagaporo Date: Fri, 6 Mar 2020 14:27:23 +0800 Subject: [PATCH 14/17] freertos: mark port_xSchedulerRunning as volatile --- components/freertos/xtensa/port.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/freertos/xtensa/port.c b/components/freertos/xtensa/port.c index e96f716547..bdbfad2058 100644 --- a/components/freertos/xtensa/port.c +++ b/components/freertos/xtensa/port.c @@ -151,7 +151,7 @@ static const char* TAG = "cpu_start"; // [refactor-todo]: might be appropriate t _Static_assert(tskNO_AFFINITY == CONFIG_FREERTOS_NO_AFFINITY, "incorrect tskNO_AFFINITY value"); /*-----------------------------------------------------------*/ -unsigned port_xSchedulerRunning[portNUM_PROCESSORS] = {0}; // Duplicate of inaccessible xSchedulerRunning; needed at startup to avoid counting nesting +volatile unsigned port_xSchedulerRunning[portNUM_PROCESSORS] = {0}; // Duplicate of inaccessible xSchedulerRunning; needed at startup to avoid counting nesting 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}; From 08cbfa6187654d9a9552a088da2e87072119735e Mon Sep 17 00:00:00 2001 From: Renz Bagaporo Date: Tue, 9 Jun 2020 08:17:48 +0800 Subject: [PATCH 15/17] esp_system: fix various review issues --- components/esp32s2/clk.c | 2 +- components/esp_system/CMakeLists.txt | 4 +- components/esp_system/port/cpu_start.c | 19 +-- components/esp_system/startup.c | 27 ++-- components/freertos/xtensa/port.c | 119 +++++++++--------- components/soc/include/hal/cpu_hal.h | 7 -- .../soc/soc/esp32/include/soc/soc_caps.h | 2 +- components/soc/src/hal/cpu_hal.c | 5 - 8 files changed, 78 insertions(+), 107 deletions(-) diff --git a/components/esp32s2/clk.c b/components/esp32s2/clk.c index 4bf0e1e85f..12a26d43fa 100644 --- a/components/esp32s2/clk.c +++ b/components/esp32s2/clk.c @@ -21,7 +21,7 @@ #define MHZ (1000000) -// g_ticks_us defined in ROMs for PRO and APP CPU +// g_ticks_us defined in ROMs extern uint32_t g_ticks_per_us_pro; int IRAM_ATTR esp_clk_cpu_freq(void) diff --git a/components/esp_system/CMakeLists.txt b/components/esp_system/CMakeLists.txt index 884b6ce3e2..078f2d4e11 100644 --- a/components/esp_system/CMakeLists.txt +++ b/components/esp_system/CMakeLists.txt @@ -2,8 +2,8 @@ idf_component_register(SRCS "panic.c" "system_api.c" "startup.c" INCLUDE_DIRS include PRIV_INCLUDE_DIRS private_include PRIV_REQUIRES spi_flash app_update - # requirements due to startup code - nvs_flash pthread app_trace + # requirements due to startup code + nvs_flash pthread app_trace LDFRAGMENTS "linker.lf") add_subdirectory(port) diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index 663a29952c..174f282484 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -140,8 +140,8 @@ void IRAM_ATTR call_start_cpu1(void) s_cpu_inited[1] = true; - while(!s_resume_cores) { - cpu_hal_delay_us(100); + while (!s_resume_cores) { + ets_delay_us(100); } SYS_STARTUP_FN(); @@ -172,12 +172,12 @@ static void start_other_core(void) volatile bool cpus_up = false; - while(!cpus_up){ + while (!cpus_up){ cpus_up = true; for (int i = 0; i < SOC_CPU_CORES_NUM; i++) { cpus_up &= s_cpu_up[i]; } - cpu_hal_delay_us(100); + ets_delay_us(100); } } else { @@ -190,12 +190,7 @@ static void start_other_core(void) static void intr_matrix_clear(void) { -#if CONFIG_IDF_TARGET_ESP32 - //Clear all the interrupt matrix register - for (int i = ETS_WIFI_MAC_INTR_SOURCE; i <= ETS_CACHE_IA_INTR_SOURCE; i++) { -#elif CONFIG_IDF_TARGET_ESP32S2 for (int i = ETS_WIFI_MAC_INTR_SOURCE; i < ETS_MAX_INTR_SOURCE; i++) { -#endif intr_matrix_set(0, i, ETS_INVALID_INUM); #if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE intr_matrix_set(1, i, ETS_INVALID_INUM); @@ -232,12 +227,10 @@ void IRAM_ATTR call_start_cpu0(void) || rst_reas[1] == RTCWDT_SYS_RESET || rst_reas[1] == TG0WDT_SYS_RESET #endif ) { -#ifndef CONFIG_BOOTLOADER_WDT_ENABLE wdt_hal_context_t rtc_wdt_ctx = {.inst = WDT_RWDT, .rwdt_dev = &RTCCNTL}; wdt_hal_write_protect_disable(&rtc_wdt_ctx); wdt_hal_disable(&rtc_wdt_ctx); wdt_hal_write_protect_enable(&rtc_wdt_ctx); -#endif } #endif @@ -413,12 +406,12 @@ void IRAM_ATTR call_start_cpu0(void) volatile bool cpus_inited = false; - while(!cpus_inited) { + while (!cpus_inited) { cpus_inited = true; for (int i = 0; i < SOC_CPU_CORES_NUM; i++) { cpus_inited &= s_cpu_inited[i]; } - cpu_hal_delay_us(100); + ets_delay_us(100); } #endif diff --git a/components/esp_system/startup.c b/components/esp_system/startup.c index 0c036ef438..ae6df19f8b 100644 --- a/components/esp_system/startup.c +++ b/components/esp_system/startup.c @@ -54,10 +54,12 @@ // [refactor-todo] make this file completely target-independent #if CONFIG_IDF_TARGET_ESP32 #include "esp32/rom/uart.h" +#include "esp32/rom/ets_sys.h" #include "esp32/spiram.h" #include "esp32/brownout.h" #elif CONFIG_IDF_TARGET_ESP32S2 #include "esp32s2/rom/uart.h" +#include "esp32s2/rom/ets_sys.h" #include "esp32s2/spiram.h" #include "esp32s2/brownout.h" #endif @@ -143,8 +145,8 @@ static void IRAM_ATTR do_system_init_fn(void) #if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE static void IRAM_ATTR app_mainX_default(void) { - while(1) { - cpu_hal_delay_us(UINT32_MAX); + while (1) { + ets_delay_us(UINT32_MAX); } } @@ -152,8 +154,8 @@ static void IRAM_ATTR start_cpuX_default(void) { do_system_init_fn(); - while(!s_system_full_inited) { - cpu_hal_delay_us(100); + while (!s_system_full_inited) { + ets_delay_us(100); } app_mainX(); @@ -192,12 +194,6 @@ static void IRAM_ATTR do_core_init(void) esp_brownout_init(); #endif -#if CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE || CONFIG_ESP32S2_DISABLE_BASIC_ROM_CONSOLE - // [refactor-todo] leads to call chain `esp_efuse_read_field_blob` (efuse) -> `esp_efuse_utility_process` -> `ESP_LOGX` - // syscall table must at least be init - esp_efuse_disable_basic_rom_console(); -#endif - #ifdef CONFIG_VFS_SUPPORT_IO esp_vfs_dev_uart_register(); #endif // CONFIG_VFS_SUPPORT_IO @@ -277,12 +273,12 @@ static void IRAM_ATTR do_secondary_init(void) // Wait for all cores to finish secondary init. volatile bool system_inited = false; - while(!system_inited) { + while (!system_inited) { system_inited = true; for (int i = 0; i < SOC_CPU_CORES_NUM; i++) { system_inited &= s_system_inited[i]; } - cpu_hal_delay_us(100); + ets_delay_us(100); } #endif } @@ -336,13 +332,11 @@ void IRAM_ATTR start_cpu0_default(void) #endif app_main(); - while(1); + while (1); } IRAM_ATTR ESP_SYSTEM_INIT_FN(init_components0, BIT(0)) { - esp_err_t err; - #ifdef CONFIG_PM_ENABLE const int uart_clk_freq = REF_CLK_FREQ; /* When DFS is enabled, use REFTICK as UART clock source */ @@ -350,9 +344,6 @@ IRAM_ATTR ESP_SYSTEM_INIT_FN(init_components0, BIT(0)) uart_div_modify(CONFIG_ESP_CONSOLE_UART_NUM, (uart_clk_freq << 4) / CONFIG_ESP_CONSOLE_UART_BAUDRATE); #endif // CONFIG_ESP_CONSOLE_UART_NONE - err = esp_pthread_init(); - assert(err == ESP_OK && "Failed to init pthread module!"); - #ifdef CONFIG_PM_ENABLE esp_pm_impl_init(); #ifdef CONFIG_PM_DFS_INIT_AUTO diff --git a/components/freertos/xtensa/port.c b/components/freertos/xtensa/port.c index bdbfad2058..733e94829b 100644 --- a/components/freertos/xtensa/port.c +++ b/components/freertos/xtensa/port.c @@ -473,50 +473,50 @@ extern void __real_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) { - ; - } + // 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(); + heap_caps_enable_nonos_stack_heaps(); - // Now we have startup stack RAM available for heap, enable any DMA pool memory + // 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(); - } - } + 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 + //Initialize task wdt if configured to do so #ifdef CONFIG_ESP_TASK_WDT_PANIC - ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, true)); + ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, true)); #elif CONFIG_ESP_TASK_WDT - ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, false)); + ESP_ERROR_CHECK(esp_task_wdt_init(CONFIG_ESP_TASK_WDT_TIMEOUT_S, false)); #endif - //Add IDLE 0 to task wdt + //Add IDLE 0 to task wdt #ifdef CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0 - TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0); - if(idle_0 != NULL){ - ESP_ERROR_CHECK(esp_task_wdt_add(idle_0)); - } + TaskHandle_t idle_0 = xTaskGetIdleTaskHandleForCPU(0); + if(idle_0 != NULL){ + ESP_ERROR_CHECK(esp_task_wdt_add(idle_0)); + } #endif - //Add IDLE 1 to task wdt + //Add IDLE 1 to task wdt #ifdef CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1 - TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCPU(1); - if(idle_1 != NULL){ - ESP_ERROR_CHECK(esp_task_wdt_add(idle_1)); - } + TaskHandle_t idle_1 = xTaskGetIdleTaskHandleForCPU(1); + if(idle_1 != NULL){ + ESP_ERROR_CHECK(esp_task_wdt_add(idle_1)); + } #endif - __real_app_main(); - vTaskDelete(NULL); + __real_app_main(); + vTaskDelete(NULL); } // For now, running FreeRTOS on one core and a bare metal on the other (or other OSes) @@ -529,7 +529,6 @@ static void main_task(void* args) #endif - #if !CONFIG_FREERTOS_UNICORE void app_mainX(void) { @@ -538,63 +537,63 @@ void app_mainX(void) abort(); } - // Wait for FreeRTOS initialization to finish on PRO CPU - while (port_xSchedulerRunning[0] == 0) { - ; - } + // 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!"); + // [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(); + //Initialize the interrupt watch dog for CPU1. + esp_int_wdt_cpu_init(); #endif - esp_crosscore_int_init(); - esp_dport_access_int_init(); + esp_crosscore_int_init(); + esp_dport_access_int_init(); - ESP_EARLY_LOGI(TAG, "Starting scheduler on APP CPU."); - xPortStartScheduler(); - abort(); /* Only get to here if FreeRTOS somehow very broken */ + ESP_EARLY_LOGI(TAG, "Starting scheduler on APP CPU."); + xPortStartScheduler(); + abort(); /* Only get to here if FreeRTOS somehow very broken */ } #endif void __wrap_app_main(void) { #if CONFIG_ESP_INT_WDT - esp_int_wdt_init(); - //Initialize the interrupt watch dog for CPU0. - esp_int_wdt_cpu_init(); + esp_int_wdt_init(); + //Initialize the interrupt watch dog for CPU0. + esp_int_wdt_cpu_init(); #else #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!"); + assert(!soc_has_cache_lock_bug() && "ESP32 Rev 3 + Dual Core + PSRAM requires INT WDT enabled in project config!"); #endif #endif - esp_crosscore_int_init(); + esp_crosscore_int_init(); #ifndef CONFIG_FREERTOS_UNICORE - esp_dport_access_int_init(); + esp_dport_access_int_init(); #endif - portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main", - ESP_TASK_MAIN_STACK, NULL, - ESP_TASK_MAIN_PRIO, NULL, 0); - assert(res == pdTRUE); + portBASE_TYPE res = xTaskCreatePinnedToCore(&main_task, "main", + ESP_TASK_MAIN_STACK, NULL, + ESP_TASK_MAIN_PRIO, NULL, 0); + assert(res == pdTRUE); // ESP32 has single core variants. Check that FreeRTOS has been configured properly. #if CONFIG_IDF_TARGET_ESP32 && !CONFIG_FREERTOS_UNICORE - if (REG_GET_BIT(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_DIS_APP_CPU)) { - ESP_EARLY_LOGE(TAG, "Running on single core chip, but FreeRTOS is built with dual core support."); - ESP_EARLY_LOGE(TAG, "Please enable CONFIG_FREERTOS_UNICORE option in menuconfig."); - abort(); - } + if (REG_GET_BIT(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_DIS_APP_CPU)) { + ESP_EARLY_LOGE(TAG, "Running on single core chip, but FreeRTOS is built with dual core support."); + ESP_EARLY_LOGE(TAG, "Please enable CONFIG_FREERTOS_UNICORE option in menuconfig."); + abort(); + } #endif // CONFIG_IDF_TARGET_ESP32 && !CONFIG_FREERTOS_UNICORE - ESP_LOGI(TAG, "Starting scheduler on PRO CPU."); - vTaskStartScheduler(); + ESP_LOGI(TAG, "Starting scheduler on PRO CPU."); + vTaskStartScheduler(); } \ No newline at end of file diff --git a/components/soc/include/hal/cpu_hal.h b/components/soc/include/hal/cpu_hal.h index d5c81f4b63..7584aa4078 100644 --- a/components/soc/include/hal/cpu_hal.h +++ b/components/soc/include/hal/cpu_hal.h @@ -107,13 +107,6 @@ void cpu_hal_set_watchpoint(int id, const void* addr, size_t size, watchpoint_tr */ void cpu_hal_clear_watchpoint(int id); -/* - * Insert a delay. - * - * @param delay_us length of delay in microseconds - */ -void cpu_hal_delay_us(uint32_t delay_us); - #endif // SOC_CPU_WATCHPOINTS_NUM > 0 /** diff --git a/components/soc/soc/esp32/include/soc/soc_caps.h b/components/soc/soc/esp32/include/soc/soc_caps.h index bb01067af8..9c4a19ef53 100644 --- a/components/soc/soc/esp32/include/soc/soc_caps.h +++ b/components/soc/soc/esp32/include/soc/soc_caps.h @@ -12,4 +12,4 @@ #define SOC_CAN_SUPPORTED 1 #define SOC_EMAC_SUPPORTED 1 -#define SOC_CPU_CORES_NUM 2 +#define SOC_CPU_CORES_NUM 2 \ No newline at end of file diff --git a/components/soc/src/hal/cpu_hal.c b/components/soc/src/hal/cpu_hal.c index 98f918f7cb..02898e6bf9 100644 --- a/components/soc/src/hal/cpu_hal.c +++ b/components/soc/src/hal/cpu_hal.c @@ -67,9 +67,4 @@ void cpu_hal_clear_watchpoint(int id) void cpu_hal_set_vecbase(const void* base) { cpu_ll_set_vecbase(base); -} - -void cpu_hal_delay_us(uint32_t delay_us) -{ - ets_delay_us(delay_us); } \ No newline at end of file From 98dc1b0188f3b9c30eec0717e97207fc04fbeda7 Mon Sep 17 00:00:00 2001 From: Renz Bagaporo Date: Wed, 10 Jun 2020 21:13:31 +0800 Subject: [PATCH 16/17] esp_system: introduce intermediary function to call after system init This MR uses an intermediary function `start_app` to call after system initialization instead of `app_main`. In RTOS builds, freertos provides `start_app` and calls `app_main`. In non-RTOS builds, user provides `start_app` directly. --- components/esp_system/CMakeLists.txt | 9 ++++++--- components/esp_system/startup.c | 16 ++++++++-------- components/freertos/CMakeLists.txt | 8 +++++++- components/freertos/xtensa/port.c | 17 +++++------------ 4 files changed, 26 insertions(+), 24 deletions(-) diff --git a/components/esp_system/CMakeLists.txt b/components/esp_system/CMakeLists.txt index 078f2d4e11..5da5b2b625 100644 --- a/components/esp_system/CMakeLists.txt +++ b/components/esp_system/CMakeLists.txt @@ -8,9 +8,12 @@ idf_component_register(SRCS "panic.c" "system_api.c" "startup.c" add_subdirectory(port) -# Rely on user code to define app_main -target_link_libraries(${COMPONENT_LIB} INTERFACE "-u app_main") +# After system initialization, `start_app` (and its other cores variant) is called. +# This is provided by the user or from another component. Since we can't establish +# dependency on what we don't know, force linker to not drop the symbol regardless +# of link line order. +target_link_libraries(${COMPONENT_LIB} INTERFACE "-u start_app") if (NOT CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE) - target_link_libraries(${COMPONENT_LIB} INTERFACE "-u app_mainX") + target_link_libraries(${COMPONENT_LIB} INTERFACE "-u start_app_other_cores") endif() \ No newline at end of file diff --git a/components/esp_system/startup.c b/components/esp_system/startup.c index ae6df19f8b..85d0507c07 100644 --- a/components/esp_system/startup.c +++ b/components/esp_system/startup.c @@ -77,23 +77,23 @@ #define STRINGIFY2(s) #s // App entry point for core 0 -extern void app_main(void); +extern void start_app(void); // Entry point for core 0 from hardware init (port layer) void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default"))) __attribute__((noreturn)); #if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE // Entry point for core [1..X] from hardware init (port layer) -void start_cpuX(void) __attribute__((weak, alias("start_cpuX_default"))) __attribute__((noreturn)); +void start_cpu_other_cores(void) __attribute__((weak, alias("start_cpu_other_cores_default"))) __attribute__((noreturn)); // App entry point for core [1..X] -void app_mainX(void) __attribute__((weak, alias("app_mainX_default"))) __attribute__((noreturn)); +void start_app_other_cores(void) __attribute__((weak, alias("start_app_other_cores_default"))) __attribute__((noreturn)); static volatile bool s_system_inited[SOC_CPU_CORES_NUM] = { false }; sys_startup_fn_t g_startup_fn[SOC_CPU_CORES_NUM] = { [0] = start_cpu0, #if SOC_CPU_CORES_NUM > 1 - [1 ... SOC_CPU_CORES_NUM - 1] = start_cpuX + [1 ... SOC_CPU_CORES_NUM - 1] = start_cpu_other_cores #endif }; @@ -143,14 +143,14 @@ static void IRAM_ATTR do_system_init_fn(void) } #if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE -static void IRAM_ATTR app_mainX_default(void) +static void IRAM_ATTR start_app_other_cores_default(void) { while (1) { ets_delay_us(UINT32_MAX); } } -static void IRAM_ATTR start_cpuX_default(void) +static void IRAM_ATTR start_cpu_other_cores_default(void) { do_system_init_fn(); @@ -158,7 +158,7 @@ static void IRAM_ATTR start_cpuX_default(void) ets_delay_us(100); } - app_mainX(); + start_app_other_cores(); } #endif @@ -331,7 +331,7 @@ void IRAM_ATTR start_cpu0_default(void) s_system_full_inited = true; #endif - app_main(); + start_app(); while (1); } diff --git a/components/freertos/CMakeLists.txt b/components/freertos/CMakeLists.txt index 58bb3cbd15..5ca3475825 100644 --- a/components/freertos/CMakeLists.txt +++ b/components/freertos/CMakeLists.txt @@ -63,4 +63,10 @@ set_source_files_properties( _ESP_FREERTOS_INTERNAL ) -target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=app_main") \ No newline at end of file +# The freertos component provides the `start_app` and `start_app_other_cores` +# if it is included in the build. It then calls `app_main` +# from the main task created, which must be provided by the user. +# Like for `start_app` and `start_app_other_cores`, +# we can't establish dependency on what we don't yet know, so we force the +# linker to not drop this symbol. +target_link_libraries(${COMPONENT_LIB} INTERFACE "-u app_main") \ No newline at end of file diff --git a/components/freertos/xtensa/port.c b/components/freertos/xtensa/port.c index 733e94829b..9c9fa0dc3d 100644 --- a/components/freertos/xtensa/port.c +++ b/components/freertos/xtensa/port.c @@ -138,6 +138,8 @@ extern void _frxt_tick_timer_init(void); /* Defined in xtensa_context.S */ extern void _xt_coproc_init(void); +extern void app_main(void); + static const char* TAG = "cpu_start"; // [refactor-todo]: might be appropriate to change in the future, but // for now maintain the same log output @@ -460,15 +462,6 @@ void __attribute__((weak)) vApplicationStackOverflowHook( TaskHandle_t xTask, c esp_system_abort(buf); } -// `esp_system` calls the app entry point app_main for core 0 and app_mainX for -// the rest of the cores which the app normally provides for non-os builds. -// If `freertos` is included in the build, wrap the call to app_main and provide -// our own definition of app_mainX so that we can do our own initializations for each -// core and start the scheduler. -// -// We now simply execute the real app_main in the context of the main task that -// we also start. -extern void __real_app_main(void); static void main_task(void* args) { @@ -515,7 +508,7 @@ static void main_task(void* args) } #endif - __real_app_main(); + app_main(); vTaskDelete(NULL); } @@ -530,7 +523,7 @@ static void main_task(void* args) #if !CONFIG_FREERTOS_UNICORE -void app_mainX(void) +void start_app_other_cores(void) { // For now, we only support up to two core: 0 and 1. if (xPortGetCoreID() >= 2) { @@ -562,7 +555,7 @@ void app_mainX(void) } #endif -void __wrap_app_main(void) +void start_app(void) { #if CONFIG_ESP_INT_WDT esp_int_wdt_init(); From 98f4ccaef5ff077d7cfbabde855742259c695894 Mon Sep 17 00:00:00 2001 From: Renz Bagaporo Date: Wed, 17 Jun 2020 17:13:55 +0800 Subject: [PATCH 17/17] esp_system: fix other core init issue Core 1 was not being stopped when in single core mode resulting to GDB timing out. --- components/esp_system/port/cpu_start.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index 174f282484..9894176f05 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -180,11 +180,6 @@ static void start_other_core(void) ets_delay_us(100); } } - else { - s_cpu_inited[1] = true; - ESP_EARLY_LOGI(TAG, "Single core mode"); - DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN); - } } #endif // !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE @@ -287,9 +282,14 @@ void IRAM_ATTR call_start_cpu0(void) #endif ESP_EARLY_LOGI(TAG, "Pro cpu up."); +#if SOC_CPU_CORES_NUM > 1 // there is no 'single-core mode' for natively single-core processors #if !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE start_other_core(); -#endif +#else + ESP_EARLY_LOGI(TAG, "Single core mode"); + DPORT_CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN); // stop the other core +#endif // !CONFIG_ESP_SYSTEM_SINGLE_CORE_MODE +#endif // SOC_CPU_CORES_NUM > 1 #if CONFIG_SPIRAM_MEMTEST if (g_spiram_ok) {