mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/32k_xtal' into 'master'
add support for 32k XTAL as RTC_SLOW_CLK source - RTC_CNTL_SLOWCLK_FREQ define is removed; rtc_clk_slow_freq_get_hz function can be used instead to get an approximate RTC_SLOW_CLK frequency - Clock calibration is performed at startup. The value is saved and used for timekeeping and when entering deep sleep. - When using the 32k XTAL, startup code will wait for the oscillator to start up. This can be possibly optimized by starting a separate task to wait for oscillator startup, and performing clock switch in that task. - Fix a bug that 32k XTAL would be disabled in rtc_clk_init. - Fix a rounding error in rtc_clk_cal, which caused systematic frequency error. - Fix an overflow bug which caused rtc_clk_cal to timeout early if the slow_clk_cycles argument would exceed certain value - Improve 32k XTAL oscillator startup time by introducing bootstrapping code, which uses internal pullup/pulldown resistors on 32K_N/32K_P pins to set better initial conditions for the oscillator. Ref TW11683. Ref https://esp32.com/viewtopic.php?f=13&t=1570 Fixes https://github.com/espressif/esp-idf/issues/337. See merge request !696
This commit is contained in:
commit
0fe765a977
@ -60,8 +60,6 @@ We arrive here after the bootloader finished loading the program from flash. The
|
||||
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);
|
||||
@ -74,6 +72,7 @@ static void set_cache_and_start_app(uint32_t drom_addr,
|
||||
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);
|
||||
|
||||
@ -238,15 +237,7 @@ static bool ota_select_valid(const esp_ota_select_entry_t *s)
|
||||
|
||||
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);
|
||||
@ -704,6 +695,29 @@ void print_flash_info(const esp_image_header_t* phdr)
|
||||
#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
|
||||
|
@ -542,6 +542,23 @@ config ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL
|
||||
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
|
||||
|
131
components/esp32/clk.c
Normal file
131
components/esp32/clk.c
Normal file
@ -0,0 +1,131 @@
|
||||
// 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;
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
// 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;
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
// 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
|
||||
@ -11,6 +11,7 @@
|
||||
// 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>
|
||||
|
||||
@ -60,6 +61,7 @@
|
||||
#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)
|
||||
@ -202,7 +204,7 @@ void start_cpu0_default(void)
|
||||
#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
|
||||
|
@ -17,6 +17,7 @@
|
||||
#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"
|
||||
@ -183,13 +184,7 @@ esp_err_t esp_deep_sleep_enable_timer_wakeup(uint64_t time_in_us)
|
||||
|
||||
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);
|
||||
|
44
components/esp32/include/esp_clk.h
Normal file
44
components/esp32/include/esp_clk.h
Normal file
@ -0,0 +1,44 @@
|
||||
// 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();
|
||||
|
@ -317,7 +317,7 @@ static void esp_panic_wdt_start()
|
||||
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);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// 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.
|
||||
@ -24,7 +24,9 @@
|
||||
#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"
|
||||
@ -44,15 +46,8 @@
|
||||
#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
|
||||
|
||||
|
@ -73,15 +73,6 @@ static inline void cpu_configure_region_protection()
|
||||
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)
|
||||
|
@ -168,6 +168,15 @@ void rtc_clk_32k_enable(bool en);
|
||||
*/
|
||||
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
|
||||
*
|
||||
@ -229,6 +238,20 @@ void rtc_clk_slow_freq_set(rtc_slow_freq_t slow_freq);
|
||||
*/
|
||||
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)
|
||||
|
@ -239,9 +239,6 @@
|
||||
#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*/
|
||||
|
@ -32,6 +32,12 @@
|
||||
|
||||
#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.
|
||||
@ -55,14 +61,21 @@ static const char* TAG = "rtc_clk";
|
||||
#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
|
||||
@ -73,22 +86,36 @@ static const char* TAG = "rtc_clk";
|
||||
#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;
|
||||
@ -172,6 +199,15 @@ rtc_slow_freq_t rtc_clk_slow_freq_get()
|
||||
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)
|
||||
{
|
||||
@ -280,7 +316,9 @@ void rtc_clk_bbpll_set(rtc_xtal_freq_t xtal_freq, rtc_cpu_freq_t cpu_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)
|
||||
@ -291,7 +329,9 @@ 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 |
|
||||
@ -518,7 +558,7 @@ void rtc_clk_init(rtc_clk_config_t cfg)
|
||||
|
||||
/* 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;
|
||||
|
@ -31,7 +31,14 @@
|
||||
* 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) {
|
||||
@ -56,7 +63,7 @@ uint32_t rtc_clk_cal_ratio(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
|
||||
} 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);
|
||||
@ -83,8 +90,13 @@ uint32_t rtc_clk_cal_ratio(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
|
||||
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;
|
||||
}
|
||||
@ -92,8 +104,10 @@ uint32_t rtc_clk_cal_ratio(rtc_cal_sel_t cal_clk, uint32_t slowclk_cycles)
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
#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"
|
||||
@ -321,15 +322,11 @@ TEST_CASE("ulp timer setting", "[ulp]")
|
||||
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.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
#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;
|
||||
|
||||
@ -286,7 +287,7 @@ static void start_ulp_temperature_monitoring()
|
||||
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
|
||||
|
Loading…
x
Reference in New Issue
Block a user