flash cache is down and the app CPU is in reset. We do have a stack, so we can do the initialization in C.
*/
-// TODO: make a nice header file for ROM functions instead of adding externs all over the place
-extern void Cache_Flush(int);
void bootloader_main();
static void unpack_load_app(const esp_partition_pos_t *app_node);
uint32_t irom_size,
uint32_t entry_addr);
static void update_flash_config(const esp_image_header_t* pfhdr);
+static void clock_configure(void);
static void uart_console_configure(void);
static void wdt_reset_check(void);
void bootloader_main()
{
- /* Set CPU to 80MHz. Keep other clocks unmodified. */
- uart_tx_wait_idle(0);
- rtc_clk_config_t clk_cfg = RTC_CLK_CONFIG_DEFAULT();
- clk_cfg.xtal_freq = CONFIG_ESP32_XTAL_FREQ;
- clk_cfg.cpu_freq = RTC_CPU_FREQ_80M;
- clk_cfg.slow_freq = rtc_clk_slow_freq_get();
- clk_cfg.fast_freq = rtc_clk_fast_freq_get();
- rtc_clk_init(clk_cfg);
-
+ clock_configure();
uart_console_configure();
wdt_reset_check();
ESP_LOGI(TAG, "ESP-IDF %s 2nd stage bootloader", IDF_VER);
#endif
}
+
+static void clock_configure(void)
+{
+ /* Set CPU to 80MHz. Keep other clocks unmodified. */
+ uart_tx_wait_idle(0);
+ rtc_clk_config_t clk_cfg = RTC_CLK_CONFIG_DEFAULT();
+ clk_cfg.xtal_freq = CONFIG_ESP32_XTAL_FREQ;
+ clk_cfg.cpu_freq = RTC_CPU_FREQ_80M;
+ clk_cfg.slow_freq = rtc_clk_slow_freq_get();
+ clk_cfg.fast_freq = rtc_clk_fast_freq_get();
+ rtc_clk_init(clk_cfg);
+ /* As a slight optimization, if 32k XTAL was enabled in sdkconfig, we enable
+ * it here. Usually it needs some time to start up, so we amortize at least
+ * part of the start up time by enabling 32k XTAL early.
+ * App startup code will wait until the oscillator has started up.
+ */
+#ifdef CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
+ if (!rtc_clk_32k_enabled()) {
+ rtc_clk_32k_bootstrap();
+ }
+#endif
+}
+
static void uart_console_configure(void)
{
#if CONFIG_CONSOLE_UART_NONE
bool "External 32kHz crystal"
endchoice
+config ESP32_RTC_CLK_CAL_CYCLES
+ int "Number of cycles for RTC_SLOW_CLK calibration"
+ default 1024
+ range 0 125000
+ help
+ When the startup code initializes RTC_SLOW_CLK, it can perform
+ calibration by comparing the RTC_SLOW_CLK frequency with main XTAL
+ frequency. This option sets the number of RTC_SLOW_CLK cycles measured
+ by the calibration routine. Higher numbers increase calibration
+ precision, which may be important for applications which spend a lot of
+ time in deep sleep. Lower numbers reduce startup time.
+
+ When this option is set to 0, clock calibration will not be performed at
+ startup, and approximate clock frequencies will be assumed:
+ - 150000 Hz if internal RC oscillator is used as clock source
+ - 32768 Hz if the 32k crystal oscillator is used
+
config ESP32_DEEP_SLEEP_WAKEUP_DELAY
int "Extra delay in deep sleep wake stub (in us)"
default 0
--- /dev/null
+// 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 <stdint.h>
+#include "sdkconfig.h"
+#include "esp_attr.h"
+#include "esp_log.h"
+#include "rom/ets_sys.h"
+#include "rom/uart.h"
+#include "soc/soc.h"
+#include "soc/rtc.h"
+#include "soc/rtc_cntl_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 XTAL_32K_DETECT_CYCLES 32
+#define SLOW_CLK_CAL_CYCLES CONFIG_ESP32_RTC_CLK_CAL_CYCLES
+
+static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk);
+
+static const char* TAG = "clk";
+/*
+ * This function is not exposed as an API at this point,
+ * because FreeRTOS doesn't yet support dynamic changing of
+ * CPU frequency. Also we need to implement hooks for
+ * components which want to be notified of CPU frequency
+ * changes.
+ */
+void esp_clk_init(void)
+{
+ rtc_config_t cfg = RTC_CONFIG_DEFAULT();
+ rtc_init(cfg);
+
+#ifdef CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
+ select_rtc_slow_clk(RTC_SLOW_FREQ_32K_XTAL);
+#else
+ select_rtc_slow_clk(RTC_SLOW_FREQ_RTC);
+#endif
+
+ uint32_t freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ;
+ rtc_cpu_freq_t freq = RTC_CPU_FREQ_80M;
+ switch(freq_mhz) {
+ case 240:
+ freq = RTC_CPU_FREQ_240M;
+ break;
+ case 160:
+ freq = RTC_CPU_FREQ_160M;
+ break;
+ default:
+ freq_mhz = 80;
+ /* no break */
+ case 80:
+ freq = RTC_CPU_FREQ_80M;
+ break;
+ }
+
+ // Wait for UART TX to finish, otherwise some UART output will be lost
+ // when switching APB frequency
+ uart_tx_wait_idle(CONFIG_CONSOLE_UART_NUM);
+ rtc_clk_cpu_freq_set(freq);
+}
+
+void IRAM_ATTR ets_update_cpu_frequency(uint32_t ticks_per_us)
+{
+ extern uint32_t g_ticks_per_us_pro; // g_ticks_us defined in ROM for PRO CPU
+ extern uint32_t g_ticks_per_us_app; // same defined for APP CPU
+ g_ticks_per_us_pro = ticks_per_us;
+ g_ticks_per_us_app = ticks_per_us;
+}
+
+/* This is a cached value of RTC slow clock period; it is updated by
+ * the select_rtc_slow_clk function at start up. This cached value is used in
+ * other places, like time syscalls and deep sleep.
+ */
+static uint32_t s_rtc_slow_clk_cal = 0;
+
+static void select_rtc_slow_clk(rtc_slow_freq_t slow_clk)
+{
+ if (slow_clk == 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.
+ */
+ rtc_clk_32k_enable(true);
+ uint32_t cal_val = 0;
+ uint32_t wait = 0;
+ // increment of 'wait' counter equivalent to 3 seconds
+ const uint32_t warning_timeout = 3 /* sec */ * 32768 /* Hz */ / (2 * XTAL_32K_DETECT_CYCLES);
+ ESP_EARLY_LOGD(TAG, "waiting for 32k oscillator to start up")
+ do {
+ ++wait;
+ cal_val = rtc_clk_cal(RTC_CAL_32K_XTAL, XTAL_32K_DETECT_CYCLES);
+ if (wait % warning_timeout == 0) {
+ ESP_EARLY_LOGW(TAG, "still waiting for 32k oscillator to start up");
+ }
+ } while (cal_val == 0);
+ ESP_EARLY_LOGD(TAG, "32k oscillator ready, wait=%d", wait);
+ }
+ rtc_clk_slow_freq_set(slow_clk);
+ 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.
+ */
+ s_rtc_slow_clk_cal = rtc_clk_cal(RTC_CAL_RTC_MUX, SLOW_CLK_CAL_CYCLES);
+ } else {
+ const uint64_t cal_dividend = (1ULL << RTC_CLK_CAL_FRACT) * 1000000ULL;
+ s_rtc_slow_clk_cal = (uint32_t) (cal_dividend / rtc_clk_slow_freq_get_hz());
+ }
+ ESP_EARLY_LOGD(TAG, "RTC_SLOW_CLK calibration value: %d", s_rtc_slow_clk_cal);
+}
+
+uint32_t esp_clk_slowclk_cal_get()
+{
+ return s_rtc_slow_clk_cal;
+}
+++ /dev/null
-// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <stdint.h>
-#include "esp_attr.h"
-#include "rom/ets_sys.h"
-#include "rom/uart.h"
-#include "sdkconfig.h"
-#include "soc/soc.h"
-#include "soc/rtc.h"
-#include "soc/rtc_cntl_reg.h"
-
-/*
- * This function is not exposed as an API at this point,
- * because FreeRTOS doesn't yet support dynamic changing of
- * CPU frequency. Also we need to implement hooks for
- * components which want to be notified of CPU frequency
- * changes.
- */
-void esp_set_cpu_freq(void)
-{
- uint32_t freq_mhz = CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ;
- rtc_cpu_freq_t freq = RTC_CPU_FREQ_80M;
- switch(freq_mhz) {
- case 240:
- freq = RTC_CPU_FREQ_240M;
- break;
- case 160:
- freq = RTC_CPU_FREQ_160M;
- break;
- default:
- freq_mhz = 80;
- /* no break */
- case 80:
- freq = RTC_CPU_FREQ_80M;
- break;
- }
-
- // Wait for UART TX to finish, otherwise some UART output will be lost
- // when switching APB frequency
- uart_tx_wait_idle(CONFIG_CONSOLE_UART_NUM);
- rtc_config_t cfg = RTC_CONFIG_DEFAULT();
- rtc_init(cfg);
- rtc_clk_cpu_freq_set(freq);
-#if ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
- rtc_clk_slow_freq_set(RTC_SLOW_FREQ_32K_XTAL);
-#endif
-}
-
-void IRAM_ATTR ets_update_cpu_frequency(uint32_t ticks_per_us)
-{
- extern uint32_t g_ticks_per_us_pro; // g_ticks_us defined in ROM for PRO CPU
- extern uint32_t g_ticks_per_us_app; // same defined for APP CPU
- g_ticks_per_us_pro = ticks_per_us;
- g_ticks_per_us_app = ticks_per_us;
-}
-// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+// 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
// 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 <stdint.h>
#include <string.h>
#include "esp_panic.h"
#include "esp_core_dump.h"
#include "esp_app_trace.h"
+#include "esp_clk.h"
#include "trax.h"
#define STRINGIFY(s) STRINGIFY2(s)
#endif
trax_start_trace(TRAX_DOWNCOUNT_WORDS);
#endif
- esp_set_cpu_freq(); // set CPU frequency configured in menuconfig
+ esp_clk_init();
#ifndef CONFIG_CONSOLE_UART_NONE
uart_div_modify(CONFIG_CONSOLE_UART_NUM, (rtc_clk_apb_freq_get() << 4) / CONFIG_CONSOLE_UART_BAUDRATE);
#endif
#include "esp_attr.h"
#include "esp_deep_sleep.h"
#include "esp_log.h"
+#include "esp_clk.h"
#include "rom/cache.h"
#include "rom/rtc.h"
#include "rom/uart.h"
static void timer_wakeup_prepare()
{
- // Do calibration if not using 32k XTAL
- uint32_t period;
- if (rtc_clk_slow_freq_get() != RTC_SLOW_FREQ_32K_XTAL) {
- period = rtc_clk_cal(RTC_CAL_RTC_MUX, 128);
- } else {
- period = (uint32_t) ((1000000ULL /* us*Hz */ << RTC_CLK_CAL_FRACT) / 32768 /* Hz */);
- }
+ uint32_t period = esp_clk_slowclk_cal_get();
uint64_t rtc_count_delta = rtc_time_us_to_slowclk(s_config.sleep_duration, period);
uint64_t cur_rtc_count = rtc_time_get();
rtc_sleep_set_wakeup_time(cur_rtc_count + rtc_count_delta);
--- /dev/null
+// 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.h
+ *
+ * This file contains declarations of clock related functions.
+ * These functions are used in ESP-IDF components, but should not be considered
+ * to be part of public API.
+ */
+
+/**
+ * @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 Get the cached calibration value of RTC slow clock
+ *
+ * The value is in the same format as returned by rtc_clk_cal (microseconds,
+ * in Q13.19 fixed-point format).
+ *
+ * @return the calibration value obtained using rtc_clk_cal, at startup time
+ */
+uint32_t esp_clk_slowclk_cal_get();
+
REG_SET_FIELD(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_STG0, RTC_WDT_STG_SEL_RESET_SYSTEM);
// 64KB of core dump data (stacks of about 30 tasks) will produce ~85KB base64 data.
// @ 115200 UART speed it will take more than 6 sec to print them out.
- WRITE_PERI_REG(RTC_CNTL_WDTCONFIG1_REG, RTC_CNTL_SLOWCLK_FREQ*7);
+ WRITE_PERI_REG(RTC_CNTL_WDTCONFIG1_REG, rtc_clk_slow_freq_get_hz() * 7);
REG_SET_BIT(RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_EN);
WRITE_PERI_REG(RTC_CNTL_WDTWPROTECT_REG, 0);
}
-// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
+// 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.
#include <rom/rtc.h>
#include "esp_attr.h"
#include "esp_intr_alloc.h"
+#include "esp_clk.h"
#include "soc/soc.h"
+#include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/frc_timer_reg.h"
#include "rom/ets_sys.h"
#ifdef WITH_RTC
static uint64_t get_rtc_time_us()
{
- SET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE_M);
- while (GET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_VALID_M) == 0) {
- ;
- }
- CLEAR_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE_M);
- uint64_t low = READ_PERI_REG(RTC_CNTL_TIME0_REG);
- uint64_t high = READ_PERI_REG(RTC_CNTL_TIME1_REG);
- uint64_t ticks = (high << 32) | low;
- return ticks * 100 / (RTC_CNTL_SLOWCLK_FREQ / 10000); // scale RTC_CNTL_SLOWCLK_FREQ to avoid overflow
+ uint64_t ticks = rtc_time_get();
+ return (uint32_t) ((ticks * esp_clk_slowclk_cal_get()) >> RTC_CLK_CAL_FRACT);
}
#endif // WITH_RTC
cpu_write_itlb(0x20000000, 0);
}
-/**
- * @brief Set CPU frequency to the value defined in menuconfig
- *
- * Called from cpu_start.c, not intended to be called from other places.
- * This is a temporary function which will be replaced once dynamic
- * CPU frequency changing is implemented.
- */
-void esp_set_cpu_freq(void);
-
/**
* @brief Stall CPU using RTC controller
* @param cpu_id ID of the CPU to stall (0 = PRO, 1 = APP)
*/
bool rtc_clk_32k_enabled();
+/**
+ * @brief Enable 32k oscillator, configuring it for fast startup time.
+ * Note: to achieve higher frequency stability, rtc_clk_32k_enable function
+ * must be called one the 32k XTAL oscillator has started up. This function
+ * will initially disable the 32k XTAL oscillator, so it should not be called
+ * when the system is using 32k XTAL as RTC_SLOW_CLK.
+ */
+void rtc_clk_32k_bootstrap();
+
/**
* @brief Enable or disable 8 MHz internal oscillator
*
*/
rtc_slow_freq_t rtc_clk_slow_freq_get();
+/**
+ * @brief Get the approximate frequency of RTC_SLOW_CLK, in Hz
+ *
+ * - if RTC_SLOW_FREQ_RTC is selected, returns ~150000
+ * - if RTC_SLOW_FREQ_32K_XTAL is selected, returns 32768
+ * - if RTC_SLOW_FREQ_8MD256 is selected, returns ~33000
+ *
+ * rtc_clk_cal function can be used to get more precise value by comparing
+ * RTC_SLOW_CLK frequency to the frequency of main XTAL.
+ *
+ * @return RTC_SLOW_CLK frequency, in Hz
+ */
+uint32_t rtc_clk_slow_freq_get_hz();
+
/**
* @brief Select source for RTC_FAST_CLK
* @param fast_freq clock source (one of rtc_fast_freq_t values)
#define RTC_CNTL_TIME_VALID_V 0x1
#define RTC_CNTL_TIME_VALID_S 30
-/* frequency of RTC slow clock, Hz */
-#define RTC_CNTL_SLOWCLK_FREQ 150000
-
#define RTC_CNTL_TIME0_REG (DR_REG_RTCCNTL_BASE + 0x10)
/* RTC_CNTL_TIME_LO : RO ;bitpos:[31:0] ;default: 32'h0 ; */
/*description: RTC timer low 32 bits*/
#define MHZ (1000000)
+/* Frequency of the 8M oscillator is 8.5MHz +/- 5%, at the default DCAP setting */
+#define RTC_FAST_CLK_FREQ_8M 8500000
+#define RTC_SLOW_CLK_FREQ_150K 150000
+#define RTC_SLOW_CLK_FREQ_8MD256 (RTC_FAST_CLK_FREQ_8M / 256)
+#define RTC_SLOW_CLK_FREQ_32K 32768
+
static const char* TAG = "rtc_clk";
/* Various constants related to the analog internals of the chip.
#define XTAL_32K_DRES_VAL 3
#define XTAL_32K_DBIAS_VAL 0
+#define XTAL_32K_BOOTSTRAP_DAC_VAL 3
+#define XTAL_32K_BOOTSTRAP_DRES_VAL 3
+#define XTAL_32K_BOOTSTRAP_DBIAS_VAL 0
+#define XTAL_32K_BOOTSTRAP_TIME_US 7
+
/* Delays for various clock sources to be enabled/switched.
* All values are in microseconds.
* TODO: some of these are excessive, and should be reduced.
*/
-#define DELAY_CPU_FREQ_SWITCH_TO_XTAL 80
+#define DELAY_CPU_FREQ_SWITCH_TO_XTAL_WITH_150K 80
+#define DELAY_CPU_FREQ_SWITCH_TO_XTAL_WITH_32K 160
#define DELAY_CPU_FREQ_SWITCH_TO_PLL 10
#define DELAY_PLL_DBIAS_RAISE 3
-#define DELAY_PLL_ENABLE 80
+#define DELAY_PLL_ENABLE_WITH_150K 80
+#define DELAY_PLL_ENABLE_WITH_32K 160
#define DELAY_FAST_CLK_SWITCH 3
#define DELAY_SLOW_CLK_SWITCH 300
#define DELAY_8M_ENABLE 50
#define XTAL_FREQ_EST_CYCLES 10
+static void rtc_clk_32k_enable_internal(int dac, int dres, int dbias)
+{
+ SET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32N_MUX_SEL | RTC_IO_X32P_MUX_SEL);
+ CLEAR_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG,
+ RTC_IO_X32P_RDE | RTC_IO_X32P_RUE | RTC_IO_X32N_RUE |
+ RTC_IO_X32N_RDE | RTC_IO_X32N_MUX_SEL | RTC_IO_X32P_MUX_SEL);
+ REG_SET_FIELD(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_DAC_XTAL_32K, dac);
+ REG_SET_FIELD(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_DRES_XTAL_32K, dres);
+ REG_SET_FIELD(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_DBIAS_XTAL_32K, dbias);
+ SET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_XPD_XTAL_32K);
+}
+
void rtc_clk_32k_enable(bool enable)
{
if (enable) {
- SET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32N_MUX_SEL | RTC_IO_X32P_MUX_SEL);
- CLEAR_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG,
- RTC_IO_X32P_RDE | RTC_IO_X32P_RUE | RTC_IO_X32N_RUE |
- RTC_IO_X32N_RDE | RTC_IO_X32N_MUX_SEL | RTC_IO_X32P_MUX_SEL);
- REG_SET_FIELD(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_DAC_XTAL_32K, XTAL_32K_DAC_VAL);
- REG_SET_FIELD(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_DRES_XTAL_32K, XTAL_32K_DRES_VAL);
- REG_SET_FIELD(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_DBIAS_XTAL_32K, XTAL_32K_DBIAS_VAL);
- SET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_XPD_XTAL_32K);
+ rtc_clk_32k_enable_internal(XTAL_32K_DAC_VAL, XTAL_32K_DRES_VAL, XTAL_32K_DBIAS_VAL);
} else {
CLEAR_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_XPD_XTAL_32K);
}
}
+void rtc_clk_32k_bootstrap()
+{
+ CLEAR_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_XPD_XTAL_32K);
+ SET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_X32P_RUE | RTC_IO_X32N_RDE);
+ ets_delay_us(XTAL_32K_BOOTSTRAP_TIME_US);
+ rtc_clk_32k_enable_internal(XTAL_32K_BOOTSTRAP_DAC_VAL,
+ XTAL_32K_BOOTSTRAP_DRES_VAL, XTAL_32K_BOOTSTRAP_DBIAS_VAL);
+}
+
bool rtc_clk_32k_enabled()
{
return GET_PERI_REG_MASK(RTC_IO_XTAL_32K_PAD_REG, RTC_IO_XPD_XTAL_32K) != 0;
return REG_GET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_ANA_CLK_RTC_SEL);
}
+uint32_t rtc_clk_slow_freq_get_hz()
+{
+ switch(rtc_clk_slow_freq_get()) {
+ case RTC_SLOW_FREQ_RTC: return RTC_SLOW_CLK_FREQ_150K;
+ case RTC_SLOW_FREQ_32K_XTAL: return RTC_SLOW_CLK_FREQ_32K;
+ case RTC_SLOW_FREQ_8MD256: return RTC_SLOW_CLK_FREQ_8MD256;
+ }
+ return 0;
+}
void rtc_clk_fast_freq_set(rtc_fast_freq_t fast_freq)
{
I2C_WRITEREG_RTC(I2C_BBPLL, I2C_BBPLL_OC_LREF, i2c_bbpll_lref);
I2C_WRITEREG_RTC(I2C_BBPLL, I2C_BBPLL_OC_DIV_7_0, i2c_bbpll_div_7_0);
I2C_WRITEREG_RTC(I2C_BBPLL, I2C_BBPLL_OC_DCUR, i2c_bbpll_dcur);
- ets_delay_us(DELAY_PLL_ENABLE);
+ uint32_t delay_pll_en = (rtc_clk_slow_freq_get() == RTC_SLOW_FREQ_RTC) ?
+ DELAY_PLL_ENABLE_WITH_150K : DELAY_PLL_ENABLE_WITH_32K;
+ ets_delay_us(delay_pll_en);
}
void rtc_clk_cpu_freq_set(rtc_cpu_freq_t cpu_freq)
REG_SET_FIELD(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL, RTC_CNTL_SOC_CLK_SEL_XTL);
REG_SET_FIELD(APB_CTRL_SYSCLK_CONF_REG, APB_CTRL_PRE_DIV_CNT, 0);
ets_update_cpu_frequency(xtal_freq);
- ets_delay_us(DELAY_CPU_FREQ_SWITCH_TO_XTAL);
+ uint32_t delay_xtal_switch = (rtc_clk_slow_freq_get() == RTC_SLOW_FREQ_RTC) ?
+ DELAY_CPU_FREQ_SWITCH_TO_XTAL_WITH_150K : DELAY_CPU_FREQ_SWITCH_TO_XTAL_WITH_32K;
+ ets_delay_us(delay_xtal_switch);
REG_SET_FIELD(DPORT_CPU_PER_CONF_REG, DPORT_CPUPERIOD_SEL, 0);
SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG,
RTC_CNTL_BB_I2C_FORCE_PD | RTC_CNTL_BBPLL_FORCE_PD |
/* Slow & fast clocks setup */
if (cfg.slow_freq == RTC_SLOW_FREQ_32K_XTAL) {
- rtc_clk_32k_enable(false);
+ rtc_clk_32k_enable(true);
}
if (cfg.fast_freq == RTC_FAST_FREQ_8M) {
bool need_8md256 = cfg.slow_freq == RTC_SLOW_FREQ_8MD256;
* once, and TIMG_RTC_CALI_RDY bit is set when counting is done. One-off mode is
* enabled using TIMG_RTC_CALI_START bit.
*/
-uint32_t rtc_clk_cal_ratio(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
+
+/**
+ * @brief Clock calibration function used by rtc_clk_cal and rtc_clk_cal_ratio
+ * @param cal_clk which clock to calibrate
+ * @param slowclk_cycles number of slow clock cycles to count
+ * @return number of XTAL clock cycles within the given number of slow clock cycles
+ */
+static uint32_t rtc_clk_cal_internal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
{
/* Enable requested clock (150k clock is always on) */
if (cal_clk == RTC_CAL_32K_XTAL) {
} else {
expected_freq = 150000; /* 150k internal oscillator */
}
- uint32_t us_time_estimate = slowclk_cycles * MHZ / expected_freq;
+ uint32_t us_time_estimate = (uint32_t) (((uint64_t) slowclk_cycles) * MHZ / expected_freq);
/* Start calibration */
CLEAR_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
SET_PERI_REG_MASK(TIMG_RTCCALICFG_REG(0), TIMG_RTC_CALI_START);
return 0;
}
- uint64_t xtal_cycles = REG_GET_FIELD(TIMG_RTCCALICFG1_REG(0), TIMG_RTC_CALI_VALUE);
- uint64_t ratio_64 = (xtal_cycles << RTC_CLK_CAL_FRACT) / slowclk_cycles;
+ return REG_GET_FIELD(TIMG_RTCCALICFG1_REG(0), TIMG_RTC_CALI_VALUE);
+}
+
+uint32_t rtc_clk_cal_ratio(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
+{
+ uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles);
+ uint64_t ratio_64 = ((xtal_cycles << RTC_CLK_CAL_FRACT)) / slowclk_cycles;
uint32_t ratio = (uint32_t)(ratio_64 & UINT32_MAX);
return ratio;
}
uint32_t rtc_clk_cal(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
{
rtc_xtal_freq_t xtal_freq = rtc_clk_xtal_freq_get();
- uint32_t ratio = rtc_clk_cal_ratio(cal_clk, slowclk_cycles);
- uint32_t period = ratio / xtal_freq;
+ uint64_t xtal_cycles = rtc_clk_cal_internal(cal_clk, slowclk_cycles);
+ uint64_t divider = ((uint64_t)xtal_freq) * slowclk_cycles;
+ uint64_t period_64 = ((xtal_cycles << RTC_CLK_CAL_FRACT) + divider / 2 - 1) / divider;
+ uint32_t period = (uint32_t)(period_64 & UINT32_MAX);
return period;
}
#include "esp32/ulp.h"
#include "soc/soc.h"
+#include "soc/rtc.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/sens_reg.h"
#include "driver/rtc_io.h"
uint32_t counter = RTC_SLOW_MEM[offset] & 0xffff;
CLEAR_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN);
// compare the actual and expected numbers of iterations of ULP program
- float expected_period = (cycles_to_test[i] + 16) / (float) RTC_CNTL_SLOWCLK_FREQ + 5 / 8e6f;
+ float expected_period = (cycles_to_test[i] + 16) / (float) rtc_clk_slow_freq_get_hz() + 5 / 8e6f;
float error = 1.0f - counter * expected_period;
printf("%u\t%u\t%.01f\t%.04f\n", cycles_to_test[i], counter, 1.0f / expected_period, error);
// Should be within 15%
TEST_ASSERT_INT_WITHIN(15, 0, (int) error * 100);
- // Note: currently RTC_CNTL_SLOWCLK_FREQ is ballpark value — we need to determine it
- // Precisely by running calibration similar to the one done in deep sleep.
- // This may cause the test to fail on some chips which have the slow clock frequency
- // way off.
}
}
#include "driver/rtc_io.h"
#include "soc/rtc_cntl_reg.h"
#include "soc/sens_reg.h"
+#include "soc/rtc.h"
static RTC_DATA_ATTR struct timeval sleep_enter_time;
assert(size < ULP_DATA_OFFSET && "ULP_DATA_OFFSET needs to be greater or equal to the program size");
// Set ULP wakeup period
- const uint32_t sleep_cycles = RTC_CNTL_SLOWCLK_FREQ / measurements_per_sec;
+ const uint32_t sleep_cycles = rtc_clk_slow_freq_get_hz() / measurements_per_sec;
REG_WRITE(SENS_ULP_CP_SLEEP_CYC0_REG, sleep_cycles);
// Start ULP