mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
esp32c2: support rtc time feature depend on rtc memory, since c2 does not have rtc memory
This commit is contained in:
parent
fb1902773f
commit
f8cc2ec86d
@ -52,8 +52,9 @@ extern uint32_t g_ticks_per_us_app;
|
||||
|
||||
static portMUX_TYPE s_esp_rtc_time_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
// TODO: IDF-4239
|
||||
#if SOC_RTC_FAST_MEM_SUPPORTED
|
||||
static RTC_NOINIT_ATTR uint64_t s_esp_rtc_time_us, s_rtc_last_ticks;
|
||||
#endif
|
||||
|
||||
inline static int IRAM_ATTR s_get_cpu_freq_mhz(void)
|
||||
{
|
||||
@ -99,18 +100,18 @@ void IRAM_ATTR ets_update_cpu_frequency(uint32_t ticks_per_us)
|
||||
|
||||
uint64_t esp_rtc_get_time_us(void)
|
||||
{
|
||||
#if !SOC_RTC_FAST_MEM_SUPPORTED
|
||||
//IDF-3901
|
||||
return 0;
|
||||
#endif
|
||||
portENTER_CRITICAL_SAFE(&s_esp_rtc_time_lock);
|
||||
const uint32_t cal = esp_clk_slowclk_cal_get();
|
||||
#if SOC_RTC_FAST_MEM_SUPPORTED
|
||||
if (cal == 0) {
|
||||
s_esp_rtc_time_us = 0;
|
||||
s_rtc_last_ticks = 0;
|
||||
}
|
||||
const uint64_t rtc_this_ticks = rtc_time_get();
|
||||
const uint64_t ticks = rtc_this_ticks - s_rtc_last_ticks;
|
||||
#else
|
||||
const uint64_t ticks = rtc_time_get();
|
||||
#endif
|
||||
/* RTC counter result is up to 2^48, calibration factor is up to 2^24,
|
||||
* for a 32kHz clock. We need to calculate (assuming no overflow):
|
||||
* (ticks * cal) >> RTC_CLK_CAL_FRACT
|
||||
@ -126,10 +127,16 @@ uint64_t esp_rtc_get_time_us(void)
|
||||
const uint64_t ticks_high = ticks >> 32;
|
||||
const uint64_t delta_time_us = ((ticks_low * cal) >> RTC_CLK_CAL_FRACT) +
|
||||
((ticks_high * cal) << (32 - RTC_CLK_CAL_FRACT));
|
||||
#if SOC_RTC_FAST_MEM_SUPPORTED
|
||||
s_esp_rtc_time_us += delta_time_us;
|
||||
s_rtc_last_ticks = rtc_this_ticks;
|
||||
portEXIT_CRITICAL_SAFE(&s_esp_rtc_time_lock);
|
||||
return s_esp_rtc_time_us;
|
||||
#else
|
||||
uint64_t esp_rtc_time_us = delta_time_us + clk_ll_rtc_slow_load_rtc_fix_us();
|
||||
portEXIT_CRITICAL_SAFE(&s_esp_rtc_time_lock);
|
||||
return esp_rtc_time_us;
|
||||
#endif
|
||||
}
|
||||
|
||||
void esp_clk_slowclk_cal_set(uint32_t new_cal)
|
||||
@ -138,7 +145,34 @@ void esp_clk_slowclk_cal_set(uint32_t new_cal)
|
||||
/* To force monotonic time values even when clock calibration value changes,
|
||||
* we adjust esp_rtc_time
|
||||
*/
|
||||
#if SOC_RTC_FAST_MEM_SUPPORTED
|
||||
esp_rtc_get_time_us();
|
||||
#else
|
||||
portENTER_CRITICAL_SAFE(&s_esp_rtc_time_lock);
|
||||
uint32_t old_cal = clk_ll_rtc_slow_load_cal();
|
||||
if (old_cal != 0) {
|
||||
/**
|
||||
* The logic of time correction is:
|
||||
* old_rtc_us = ticks * old_cal >> RTC_CLK_CAL_FRACT + old_fix_us
|
||||
* new_rtc_us = ticks * new_cal >> RTC_CLK_CAL_FRACT + new_fix_us
|
||||
*
|
||||
* Keep "old_rtc_us == new_rtc_us" to make time monotonically increasing,
|
||||
* then we can get new_fix_us:
|
||||
* new_fix_us = (ticks * old_cal >> RTC_CLK_CAL_FRACT + old_fix_us) - (ticks * new_cal >> RTC_CLK_CAL_FRACT)
|
||||
*/
|
||||
uint64_t ticks = rtc_time_get();
|
||||
const uint64_t ticks_low = ticks & UINT32_MAX;
|
||||
const uint64_t ticks_high = ticks >> 32;
|
||||
uint64_t old_fix_us = clk_ll_rtc_slow_load_rtc_fix_us();
|
||||
uint64_t new_fix_us;
|
||||
|
||||
old_fix_us += ((ticks_low * old_cal) >> RTC_CLK_CAL_FRACT) + ((ticks_high * old_cal) << (32 - RTC_CLK_CAL_FRACT));
|
||||
new_fix_us = ((ticks_low * new_cal) >> RTC_CLK_CAL_FRACT) + ((ticks_high * new_cal) << (32 - RTC_CLK_CAL_FRACT));
|
||||
new_fix_us = old_fix_us - new_fix_us;
|
||||
clk_ll_rtc_slow_store_rtc_fix_us(new_fix_us);
|
||||
}
|
||||
portEXIT_CRITICAL_SAFE(&s_esp_rtc_time_lock);
|
||||
#endif // SOC_RTC_FAST_MEM_SUPPORTED
|
||||
#endif // CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER
|
||||
clk_ll_rtc_slow_store_cal(new_cal);
|
||||
}
|
||||
|
@ -490,14 +490,7 @@ esp_err_t esp_intr_alloc_intrstatus(int source, int flags, uint32_t intrstatusre
|
||||
//ToDo: if we are to allow placing interrupt handlers into the 0x400c0000—0x400c2000 region,
|
||||
//we need to make sure the interrupt is connected to the CPU0.
|
||||
//CPU1 does not have access to the RTC fast memory through this region.
|
||||
if ((flags & ESP_INTR_FLAG_IRAM)
|
||||
&& handler
|
||||
&& !esp_ptr_in_iram(handler)
|
||||
#if SOC_RTC_FAST_MEM_SUPPORTED
|
||||
// IDF-3901.
|
||||
&& !esp_ptr_in_rtc_iram_fast(handler)
|
||||
#endif
|
||||
) {
|
||||
if ((flags & ESP_INTR_FLAG_IRAM) && handler && !esp_ptr_in_iram(handler) && !esp_ptr_in_rtc_iram_fast(handler)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
|
@ -176,85 +176,6 @@ uint32_t rtc_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp
|
||||
return rtc_sleep_finish(lslp_mem_inf_fpu);
|
||||
}
|
||||
|
||||
#define STR2(X) #X
|
||||
#define STR(X) STR2(X)
|
||||
|
||||
uint32_t rtc_deep_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt)
|
||||
{
|
||||
REG_SET_FIELD(RTC_CNTL_WAKEUP_STATE_REG, RTC_CNTL_WAKEUP_ENA, wakeup_opt);
|
||||
WRITE_PERI_REG(RTC_CNTL_SLP_REJECT_CONF_REG, reject_opt);
|
||||
|
||||
SET_PERI_REG_MASK(RTC_CNTL_INT_CLR_REG,
|
||||
RTC_CNTL_SLP_REJECT_INT_CLR | RTC_CNTL_SLP_WAKEUP_INT_CLR);
|
||||
|
||||
/* Calculate RTC Fast Memory CRC (for wake stub) & go to deep sleep
|
||||
|
||||
Because we may be running from RTC memory as stack, we can't easily call any
|
||||
functions to do this (as registers will spill to stack, corrupting the CRC).
|
||||
|
||||
Instead, load all the values we need into registers then use register ops only to calculate
|
||||
the CRC value, write it to the RTC CRC value register, and immediately go into deep sleep.
|
||||
*/
|
||||
|
||||
/* Values used to set the SYSTEM_RTC_FASTMEM_CONFIG_REG value */
|
||||
const unsigned CRC_START_ADDR = 0;
|
||||
const unsigned CRC_LEN = 0x7ff;
|
||||
|
||||
asm volatile(
|
||||
/* Start CRC calculation */
|
||||
"sw %1, 0(%0)\n" // set RTC_MEM_CRC_ADDR & RTC_MEM_CRC_LEN
|
||||
"or t0, %1, %2\n"
|
||||
"sw t0, 0(%0)\n" // set RTC_MEM_CRC_START
|
||||
|
||||
/* Wait for the CRC calculation to finish */
|
||||
".Lwaitcrc:\n"
|
||||
"fence\n"
|
||||
"lw t0, 0(%0)\n"
|
||||
"li t1, "STR(SYSTEM_RTC_MEM_CRC_FINISH)"\n"
|
||||
"and t0, t0, t1\n"
|
||||
"beqz t0, .Lwaitcrc\n"
|
||||
"not %2, %2\n" // %2 -> ~DPORT_RTC_MEM_CRC_START
|
||||
"and t0, t0, %2\n"
|
||||
"sw t0, 0(%0)\n" // clear RTC_MEM_CRC_START
|
||||
"fence\n"
|
||||
"not %2, %2\n" // %2 -> DPORT_RTC_MEM_CRC_START, probably unnecessary but gcc assumes inputs unchanged
|
||||
|
||||
/* Store the calculated value in RTC_MEM_CRC_REG */
|
||||
"lw t0, 0(%3)\n"
|
||||
"sw t0, 0(%4)\n"
|
||||
"fence\n"
|
||||
|
||||
/* Set register bit to go into deep sleep */
|
||||
"lw t0, 0(%5)\n"
|
||||
"or t0, t0, %6\n"
|
||||
"sw t0, 0(%5)\n"
|
||||
"fence\n"
|
||||
|
||||
/* Wait for sleep reject interrupt (never finishes if successful) */
|
||||
".Lwaitsleep:"
|
||||
"fence\n"
|
||||
"lw t0, 0(%7)\n"
|
||||
"and t0, t0, %8\n"
|
||||
"beqz t0, .Lwaitsleep\n"
|
||||
|
||||
:
|
||||
:
|
||||
"r" (SYSTEM_RTC_FASTMEM_CONFIG_REG), // %0
|
||||
"r" ( (CRC_START_ADDR << SYSTEM_RTC_MEM_CRC_START_S)
|
||||
| (CRC_LEN << SYSTEM_RTC_MEM_CRC_LEN_S)), // %1
|
||||
"r" (SYSTEM_RTC_MEM_CRC_START), // %2
|
||||
"r" (SYSTEM_RTC_FASTMEM_CRC_REG), // %3
|
||||
"r" (RTC_MEMORY_CRC_REG), // %4
|
||||
"r" (RTC_CNTL_STATE0_REG), // %5
|
||||
"r" (RTC_CNTL_SLEEP_EN), // %6
|
||||
"r" (RTC_CNTL_INT_RAW_REG), // %7
|
||||
"r" (RTC_CNTL_SLP_REJECT_INT_RAW | RTC_CNTL_SLP_WAKEUP_INT_RAW) // %8
|
||||
: "t0", "t1" // working registers
|
||||
);
|
||||
|
||||
return rtc_sleep_finish(0);
|
||||
}
|
||||
|
||||
static uint32_t rtc_sleep_finish(uint32_t lslp_mem_inf_fpu)
|
||||
{
|
||||
/* In deep sleep mode, we never get here */
|
||||
|
@ -217,6 +217,7 @@ static void touch_wakeup_prepare(void);
|
||||
static void gpio_deep_sleep_wakeup_prepare(void);
|
||||
#endif
|
||||
|
||||
#if SOC_RTC_FAST_MEM_SUPPORTED
|
||||
#if SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY
|
||||
static RTC_FAST_ATTR esp_deep_sleep_wake_stub_fn_t wake_stub_fn_handler = NULL;
|
||||
|
||||
@ -297,6 +298,7 @@ void RTC_IRAM_ATTR esp_default_wake_deep_sleep(void)
|
||||
}
|
||||
|
||||
void __attribute__((weak, alias("esp_default_wake_deep_sleep"))) esp_wake_deep_sleep(void);
|
||||
#endif // SOC_RTC_FAST_MEM_SUPPORTED
|
||||
|
||||
void esp_deep_sleep(uint64_t time_in_us)
|
||||
{
|
||||
@ -544,8 +546,7 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags)
|
||||
#else
|
||||
#if !CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP
|
||||
/* If not possible stack is in RTC FAST memory, use the ROM function to calculate the CRC and save ~140 bytes IRAM */
|
||||
#if !CONFIG_IDF_TARGET_ESP32C2
|
||||
// RTC has no rtc memory, IDF-3901
|
||||
#if SOC_RTC_FAST_MEM_SUPPORTED
|
||||
set_rtc_memory_crc();
|
||||
#endif
|
||||
result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu, 0);
|
||||
@ -614,10 +615,12 @@ void IRAM_ATTR esp_deep_sleep_start(void)
|
||||
// record current RTC time
|
||||
s_config.rtc_ticks_at_sleep_start = rtc_time_get();
|
||||
|
||||
#if SOC_RTC_FAST_MEM_SUPPORTED
|
||||
// Configure wake stub
|
||||
if (esp_get_deep_sleep_wake_stub() == NULL) {
|
||||
esp_set_deep_sleep_wake_stub(esp_wake_deep_sleep);
|
||||
}
|
||||
#endif // SOC_RTC_FAST_MEM_SUPPORTED
|
||||
|
||||
// Decide which power domains can be powered down
|
||||
uint32_t pd_flags = get_power_down_flags();
|
||||
|
@ -45,29 +45,35 @@ extern "C" {
|
||||
*
|
||||
*************************************************************************************
|
||||
* RTC store registers usage
|
||||
* RTC_CNTL_STORE0_REG Reserved
|
||||
* RTC_CNTL_STORE0_REG RTC fix us, high 32 bits
|
||||
* RTC_CNTL_STORE1_REG RTC_SLOW_CLK calibration value
|
||||
* RTC_CNTL_STORE2_REG Boot time, low word
|
||||
* RTC_CNTL_STORE3_REG Boot time, high word
|
||||
* RTC_CNTL_STORE4_REG External XTAL frequency
|
||||
* RTC_CNTL_STORE5_REG APB bus frequency
|
||||
* RTC_CNTL_STORE6_REG FAST_RTC_MEMORY_ENTRY
|
||||
* RTC_CNTL_STORE7_REG FAST_RTC_MEMORY_CRC
|
||||
* RTC_CNTL_STORE6_REG rtc reset cause
|
||||
* RTC_CNTL_STORE7_REG RTC fix us, low 32 bits
|
||||
*************************************************************************************
|
||||
*
|
||||
* Since esp32c2 does not support RTC fast mem, so use RTC store regs to record rtc time:
|
||||
*
|
||||
* |------------------------|----------------------------------------|
|
||||
* | RTC_CNTL_STORE0_REG | RTC_CNTL_STORE7_REG |
|
||||
* | rtc_fix_us(MSB) | rtc_fix_us(LSB) |
|
||||
* |------------------------|----------------------------------------|
|
||||
*/
|
||||
|
||||
#define RTC_FIX_US_HIGH_REG RTC_CNTL_STORE0_REG
|
||||
#define RTC_SLOW_CLK_CAL_REG RTC_CNTL_STORE1_REG
|
||||
#define RTC_BOOT_TIME_LOW_REG RTC_CNTL_STORE2_REG
|
||||
#define RTC_BOOT_TIME_HIGH_REG RTC_CNTL_STORE3_REG
|
||||
#define RTC_XTAL_FREQ_REG RTC_CNTL_STORE4_REG
|
||||
#define RTC_APB_FREQ_REG RTC_CNTL_STORE5_REG
|
||||
#define RTC_ENTRY_ADDR_REG RTC_CNTL_STORE6_REG
|
||||
#define RTC_RESET_CAUSE_REG RTC_CNTL_STORE6_REG
|
||||
#define RTC_MEMORY_CRC_REG RTC_CNTL_STORE7_REG
|
||||
#define RTC_FIX_US_LOW_REG RTC_CNTL_STORE7_REG
|
||||
|
||||
#define RTC_DISABLE_ROM_LOG ((1 << 0) | (1 << 16)) //!< Disable logging from the ROM code.
|
||||
|
||||
|
||||
typedef enum {
|
||||
AWAKE = 0, //<CPU ON
|
||||
LIGHT_SLEEP = BIT0, //CPU waiti, PLL ON. We don't need explicitly set this mode.
|
||||
|
@ -65,16 +65,10 @@ esp_reset_reason_t esp_reset_reason(void)
|
||||
return s_reset_reason;
|
||||
}
|
||||
|
||||
/* Reset reason hint is stored in RTC_RESET_CAUSE_REG, a.k.a. RTC_CNTL_STORE6_REG,
|
||||
* a.k.a. RTC_ENTRY_ADDR_REG. It is safe to use this register both for the
|
||||
* deep sleep wake stub entry address and for reset reason hint, since wake stub
|
||||
* is only used for deep sleep reset, and in this case the reason provided by
|
||||
* esp_rom_get_reset_reason is unambiguous.
|
||||
/* Reset reason hint is stored in RTC_RESET_CAUSE_REG, a.k.a. RTC_CNTL_STORE6_REG.
|
||||
*
|
||||
* Same layout is used as for RTC_APB_FREQ_REG (a.k.a. RTC_CNTL_STORE5_REG):
|
||||
* the value is replicated in low and high half-words. In addition to that,
|
||||
* MSB is set to 1, which doesn't happen when RTC_CNTL_STORE6_REG contains
|
||||
* deep sleep wake stub address.
|
||||
* the value is replicated in low and high half-words.
|
||||
*/
|
||||
|
||||
#define RST_REASON_BIT 0x80000000
|
||||
|
@ -600,6 +600,27 @@ static inline uint32_t clk_ll_rtc_slow_load_cal(void)
|
||||
return REG_READ(RTC_SLOW_CLK_CAL_REG);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Store rtc_fix_us in RTC storage register
|
||||
*
|
||||
* @param rtc_fix_us The value used to correct the time obtained from the rtc timer when the calibration value changes
|
||||
*/
|
||||
static inline void clk_ll_rtc_slow_store_rtc_fix_us(uint64_t rtc_fix_us)
|
||||
{
|
||||
REG_WRITE(RTC_FIX_US_LOW_REG, rtc_fix_us);
|
||||
REG_WRITE(RTC_FIX_US_HIGH_REG, rtc_fix_us >> 32);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Load the rtc_fix_ticks from RTC storage register
|
||||
*
|
||||
* @return The value used to correct the time obtained from the rtc timer when the calibration value changes
|
||||
*/
|
||||
static inline uint64_t clk_ll_rtc_slow_load_rtc_fix_us(void)
|
||||
{
|
||||
return REG_READ(RTC_FIX_US_LOW_REG) | ((uint64_t)REG_READ(RTC_FIX_US_HIGH_REG) << 32);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user