]> granicus.if.org Git - esp-idf/commitdiff
bootloader_support: Fix enable rtc_wdt for resolve issue with varying supply
authorKonstantin Kondrashov <konstantin@espressif.com>
Thu, 26 Jul 2018 09:07:36 +0000 (17:07 +0800)
committerbot <bot@espressif.com>
Mon, 3 Sep 2018 05:43:01 +0000 (05:43 +0000)
Eliminates the issue with the lock up in the bootloader due to a power drawdown during its operation.

Closes https://github.com/espressif/esp-idf/issues/1814

components/bootloader/Kconfig.projbuild
components/bootloader_support/include/esp_flash_encrypt.h
components/bootloader_support/src/bootloader_init.c
components/bootloader_support/src/flash_encrypt.c
components/esp32/clk.c
components/esp32/cpu_start.c
components/soc/esp32/rtc_wdt.c
components/soc/include/soc/rtc_wdt.h

index 75dae508aedf86ea9e5e5deabfd61c178c87f6ea..bca976e102bd9e07ca723abc1ca7b325374bcc01 100644 (file)
@@ -127,6 +127,38 @@ config BOOTLOADER_HOLD_TIME_GPIO
         The GPIO must be held low continuously for this period of time after reset 
         before a factory reset or test partition boot (as applicable) is performed.
 
+config BOOTLOADER_WDT_ENABLE
+    bool "Use RTC watchdog in start code"
+    default y
+    help
+        Tracks the execution time of startup code.
+        If the execution time is exceeded, the RTC_WDT will restart system.
+        It is also useful to prevent a lock up in start code caused by an unstable power source.
+        NOTE: Tracks the execution time starts from the bootloader code - re-set timeout, while selecting the source for slow_clk - and ends calling app_main.
+        Re-set timeout is needed due to WDT uses a SLOW_CLK clock source. After changing a frequency slow_clk a time of WDT needs to re-set for new frequency.
+        slow_clk depends on ESP32_RTC_CLOCK_SOURCE (INTERNAL_RC or EXTERNAL_CRYSTAL).
+
+config BOOTLOADER_WDT_DISABLE_IN_USER_CODE
+    bool "Allows RTC watchdog disable in user code"
+    depends on BOOTLOADER_WDT_ENABLE
+    default n
+    help
+        If it is set, the client must itself reset or disable rtc_wdt in their code (app_main()).
+        Otherwise rtc_wdt will be disabled before calling app_main function.
+        Use function rtc_wdt_feed() for resetting counter of rtc_wdt.
+        Use function rtc_wdt_disable() for disabling rtc_wdt.
+
+config BOOTLOADER_WDT_TIME_MS
+    int "Timeout for RTC watchdog (ms)"
+    depends on BOOTLOADER_WDT_ENABLE
+    default 9000
+    range 0 120000
+    help
+        Verify that this parameter is correct and more then the execution time. 
+        Pay attention to options such as reset to factory, trigger test partition and encryption on boot
+        - these options can increase the execution time. 
+        Note: RTC_WDT will reset while encryption operations will be performed.
+
 endmenu  # Bootloader
 
 
index 2f4679b2a4a3492ee5c4fc1c0064ffa197c0a96a..ab22f67d4dbca36abebd1aacc84841af404f8fbb 100644 (file)
@@ -83,6 +83,8 @@ static inline /** @cond */ IRAM_ATTR /** @endcond */ bool esp_flash_encryption_e
  * @note Take care not to power off the device while this function
  * is running, or the partition currently being encrypted will be lost.
  *
+ * @note RTC_WDT will reset while encryption operations will be performed (if RTC_WDT is configured).
+ *
  * @return ESP_OK if all operations succeeded, ESP_ERR_INVALID_STATE
  * if a fatal error occured during encryption of all partitions.
  */
@@ -91,6 +93,7 @@ esp_err_t esp_flash_encrypt_check_and_update(void);
 
 /** @brief Encrypt-in-place a block of flash sectors
  *
+ * @note This function resets RTC_WDT between operations with sectors.
  * @param src_addr Source offset in flash. Should be multiple of 4096 bytes.
  * @param data_length Length of data to encrypt in bytes. Will be rounded up to next multiple of 4096 bytes.
  *
index fe0d756fb599b861c0eecaad58aeae4cb90c8f26..68e2101ef8a7cd4ae78cbba92c8954c623011bce 100644 (file)
@@ -143,8 +143,21 @@ static esp_err_t bootloader_main()
     ESP_LOGI(TAG, "compile time " __TIME__ );
     ets_set_appcpu_boot_addr(0);
 
+#ifdef CONFIG_BOOTLOADER_WDT_ENABLE
+    ESP_LOGD(TAG, "Enabling RTCWDT(%d ms)", CONFIG_BOOTLOADER_WDT_TIME_MS);
+    rtc_wdt_protect_off();
+    rtc_wdt_disable();
+    rtc_wdt_set_length_of_reset_signal(RTC_WDT_SYS_RESET_SIG, RTC_WDT_LENGTH_3_2us);
+    rtc_wdt_set_length_of_reset_signal(RTC_WDT_CPU_RESET_SIG, RTC_WDT_LENGTH_3_2us);
+    rtc_wdt_set_stage(RTC_WDT_STAGE0, RTC_WDT_STAGE_ACTION_RESET_RTC);
+    rtc_wdt_set_time(RTC_WDT_STAGE0, CONFIG_BOOTLOADER_WDT_TIME_MS);
+    rtc_wdt_enable();
+    rtc_wdt_protect_on();
+#else
     /* disable watch dog here */
     rtc_wdt_disable();
+#endif
+    REG_SET_FIELD(TIMG_WDTWPROTECT_REG(0), TIMG_WDT_WKEY,  TIMG_WDT_WKEY_VALUE);
     REG_CLR_BIT( TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN );
 
 #ifndef CONFIG_SPI_FLASH_ROM_DRIVER_PATCH
index 7b17dd45179867597875839201f90b494e70447d..e04945daec3e424e344de5abd2bac0d8a4cbfc06 100644 (file)
@@ -24,6 +24,7 @@
 #include "esp_efuse.h"
 #include "esp_log.h"
 #include "rom/secure_boot.h"
+#include "soc/rtc_wdt.h"
 
 #include "rom/cache.h"
 #include "rom/spi_flash.h"   /* TODO: Remove this */
@@ -317,6 +318,7 @@ esp_err_t esp_flash_encrypt_region(uint32_t src_addr, size_t data_length)
     }
 
     for (size_t i = 0; i < data_length; i += FLASH_SECTOR_SIZE) {
+        rtc_wdt_feed();
         uint32_t sec_start = i + src_addr;
         err = bootloader_flash_read(sec_start, buf, FLASH_SECTOR_SIZE, false);
         if (err != ESP_OK) {
index 17afaa1b342a6fcc467e9b1dba39d52ff854c809..54abc18b72dad8d1cd20f1adf401a33cd5b0d885 100644 (file)
@@ -26,6 +26,7 @@
 #include "rom/rtc.h"
 #include "soc/soc.h"
 #include "soc/rtc.h"
+#include "soc/rtc_wdt.h"
 #include "soc/rtc_cntl_reg.h"
 #include "soc/i2s_reg.h"
 #include "driver/periph_ctrl.h"
@@ -87,6 +88,18 @@ void esp_clk_init(void)
 
     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).
+    rtc_wdt_protect_off();
+    rtc_wdt_feed();
+    rtc_wdt_set_time(RTC_WDT_STAGE0, 1600);
+    rtc_wdt_protect_on();
+#endif
+
 #if defined(CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL)
     select_rtc_slow_clk(SLOW_CLK_32K_XTAL);
 #elif defined(CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_OSC)
@@ -97,6 +110,14 @@ void esp_clk_init(void)
     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.
+    rtc_wdt_protect_off();
+    rtc_wdt_feed();
+    rtc_wdt_set_time(RTC_WDT_STAGE0, CONFIG_BOOTLOADER_WDT_TIME_MS);
+    rtc_wdt_protect_on();
+#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;
index bf044bd7b265dcacc6350346e03d20f268673fd3..cfff63a2c5c1899c5e813f9894a81d1d6ae5a6c5 100644 (file)
@@ -137,7 +137,9 @@ void IRAM_ATTR call_start_cpu0()
         || rst_reas[1] == RTCWDT_SYS_RESET || rst_reas[1] == TG0WDT_SYS_RESET
 #endif
     ) {
+#ifndef CONFIG_BOOTLOADER_WDT_ENABLE
         rtc_wdt_disable();
+#endif
     }
 
     //Clear BSS. Please do not attempt to do any complex stuff (like early logging) before this.
@@ -427,9 +429,6 @@ static void do_global_ctors(void)
 
 static void main_task(void* args)
 {
-    // Now that the application is about to start, disable boot watchdogs
-    REG_CLR_BIT(TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN_S);
-    rtc_wdt_disable();
 #if !CONFIG_FREERTOS_UNICORE
     // Wait for FreeRTOS initialization to finish on APP CPU, before replacing its startup stack
     while (port_xSchedulerRunning[1] == 0) {
@@ -470,6 +469,10 @@ static void main_task(void* args)
     }
 #endif
 
+    // Now that the application is about to start, disable boot watchdog
+#ifndef CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE
+    rtc_wdt_disable();
+#endif
     app_main();
     vTaskDelete(NULL);
 }
index 5fea2fd55c688eea0e27c9e17a15f3e8b642b347..67770709bc7eb28902c5921337c47a86243c8599 100644 (file)
@@ -87,6 +87,27 @@ esp_err_t rtc_wdt_set_time(rtc_wdt_stage_t stage, unsigned int timeout_ms)
     return ESP_OK;
 }
 
+esp_err_t rtc_wdt_get_timeout(rtc_wdt_stage_t stage, unsigned int* timeout_ms)
+{
+    if (stage > 3) {
+        return ESP_ERR_INVALID_ARG;
+    }
+    uint32_t time_tick;
+    if (stage == RTC_WDT_STAGE0) {
+        time_tick = READ_PERI_REG(RTC_CNTL_WDTCONFIG1_REG);
+    } else if (stage == RTC_WDT_STAGE1) {
+        time_tick = READ_PERI_REG(RTC_CNTL_WDTCONFIG2_REG);
+    } else if (stage == RTC_WDT_STAGE2) {
+        time_tick = READ_PERI_REG(RTC_CNTL_WDTCONFIG3_REG);
+    } else {
+        time_tick = READ_PERI_REG(RTC_CNTL_WDTCONFIG4_REG);
+    }
+
+    *timeout_ms = time_tick * 1000 / rtc_clk_slow_freq_get_hz();
+
+    return ESP_OK;
+}
+
 esp_err_t rtc_wdt_set_stage(rtc_wdt_stage_t stage, rtc_wdt_stage_action_t stage_sel)
 {
     if (stage > 3 || stage_sel > 4) {
index 9094a305a004af32bbbe7d683da014a491faad9b..ec7175a0029228715dfbda6117e5bbbb59b995df 100644 (file)
@@ -142,6 +142,18 @@ void rtc_wdt_feed();
  */
 esp_err_t rtc_wdt_set_time(rtc_wdt_stage_t stage, unsigned int timeout_ms);
 
+/**
+ * @brief Get the timeout set for the required stage.
+ *
+ * @param[in]  stage Stage of rtc_wdt.
+ * @param[out] timeout_ms Timeout set for this stage. (not elapsed time).
+ *
+ * @return
+ *         - ESP_OK In case of success
+ *         - ESP_ERR_INVALID_ARG If stage has invalid value
+ */
+esp_err_t rtc_wdt_get_timeout(rtc_wdt_stage_t stage, unsigned int* timeout_ms);
+
 /**
  * @brief Set an action for required stage.
  *