/* * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 *//* ... */#include<stdint.h>#include<string.h>#include<sys/param.h>#include<sys/lock.h>#include"freertos/FreeRTOS.h"#include"esp_attr.h"#include"soc/rtc.h"#include"soc/soc_caps.h"#include"esp_rom_caps.h"#include"esp_rom_sys.h"#include"esp_private/esp_clk.h"#include"hal/clk_tree_ll.h"12 includes#ifCONFIG_IDF_TARGET_ESP32#include"esp32/rom/rtc.h"#include"esp32/rtc.h"/* ... */#elifCONFIG_IDF_TARGET_ESP32S2#include"esp32s2/rom/rtc.h"#include"esp32s2/rtc.h"/* ... */#elifCONFIG_IDF_TARGET_ESP32S3#include"esp32s3/rom/rtc.h"#include"esp32s3/rtc.h"/* ... */#elifCONFIG_IDF_TARGET_ESP32C3#include"esp32c3/rom/rtc.h"#include"esp32c3/rtc.h"/* ... */#elifCONFIG_IDF_TARGET_ESP32C2#include"esp32c2/rom/rtc.h"#include"esp32c2/rtc.h"/* ... */#elifCONFIG_IDF_TARGET_ESP32C6#include"esp32c6/rom/rtc.h"#include"esp32c6/rtc.h"/* ... */#elifCONFIG_IDF_TARGET_ESP32C61//TODO: IDF-9526, refactor this#include"esp32c61/rom/rtc.h"#include"esp32c61/rtc.h"/* ... */#elifCONFIG_IDF_TARGET_ESP32H2#include"esp32h2/rom/rtc.h"#include"esp32h2/rtc.h"/* ... */#elifCONFIG_IDF_TARGET_ESP32P4#include"esp32p4/rom/rtc.h"#include"esp32p4/rtc.h"/* ... */#endif#defineMHZ(1000000)// g_ticks_us defined in ROMs for PRO and APP CPUexternuint32_tg_ticks_per_us_pro;staticportMUX_TYPEs_esp_rtc_time_lock=portMUX_INITIALIZER_UNLOCKED;#ifSOC_RTC_MEM_SUPPORTEDtypedefstruct{uint64_trtc_time_us;uint64_trtc_last_ticks;uint32_treserve;uint32_tchecksum;}{ ... }retain_mem_t;_Static_assert(sizeof(retain_mem_t)==24,"retain_mem_t must be 24 bytes");_Static_assert(offsetof(retain_mem_t,checksum)==sizeof(retain_mem_t)-sizeof(uint32_t),"Wrong offset for checksum field in retain_mem_t structure");static__attribute__((section(".rtc_timer_data_in_rtc_mem")))retain_mem_ts_rtc_timer_retain_mem;staticuint32_tcalc_checksum(void){uint32_tchecksum=0;uint32_t*data=(uint32_t*)&s_rtc_timer_retain_mem;for(uint32_ti=0;i<(sizeof(retain_mem_t)-sizeof(s_rtc_timer_retain_mem.checksum))/4;i++){checksum=((checksum<<5)-checksum)^data[i];}{...}returnchecksum;}{ ... }#defineIS_RETAIN_MEM_VALID()(s_rtc_timer_retain_mem.checksum==calc_checksum())/* ... */#endif// SOC_RTC_MEM_SUPPORTEDinlinestaticintIRAM_ATTRs_get_cpu_freq_mhz(void){#ifESP_ROM_GET_CLK_FREQreturnesp_rom_get_cpu_ticks_per_us();#elsereturng_ticks_per_us_pro;#endif}{ ... }intIRAM_ATTResp_clk_cpu_freq(void){returns_get_cpu_freq_mhz()*MHZ;}{ ... }intIRAM_ATTResp_clk_apb_freq(void){// TODO: IDF-5173 Require cleanup, implementation should be unified#ifCONFIG_IDF_TARGET_ESP32C6||CONFIG_IDF_TARGET_ESP32H2||CONFIG_IDF_TARGET_ESP32P4||CONFIG_IDF_TARGET_ESP32C5||CONFIG_IDF_TARGET_ESP32C61returnrtc_clk_apb_freq_get();#elsereturnMIN(s_get_cpu_freq_mhz()*MHZ,APB_CLK_FREQ);#endif}{ ... }intIRAM_ATTResp_clk_xtal_freq(void){returnrtc_clk_xtal_freq_get()*MHZ;}{ ... }uint64_tesp_rtc_get_time_us(void){portENTER_CRITICAL_SAFE(&s_esp_rtc_time_lock);constuint32_tcal=esp_clk_slowclk_cal_get();#ifSOC_RTC_MEM_SUPPORTEDstaticboolfirst_call=true;if(cal==0||(first_call&&!IS_RETAIN_MEM_VALID())){/* If cal is 0, then this is the first power-up. Cal is keeping valid after reboot and deepsleep. If s_rtc_timer_retain_mem is invalid, it means that something unexpected happened (the structure was moved around after OTA update). To keep the system time valid even after OTA we reset the s_rtc_timer_retain_mem. But the resetting can also lead to some drift of the system time, because only the last current calibration value will be applied to all rtc ticks. To mitigate this effect you might need updating of the system time (via SNTP). *//* ... */memset(&s_rtc_timer_retain_mem,0,sizeof(retain_mem_t));}{...}first_call=false;constuint64_trtc_this_ticks=rtc_time_get();constuint64_tticks=rtc_this_ticks-s_rtc_timer_retain_mem.rtc_last_ticks;/* ... */#elseconstuint64_tticks=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 * * An overflow in the (ticks * cal) multiplication would cause time to * wrap around after approximately 13 days, which is probably not enough * for some applications. * Therefore multiplication is split into two terms, for the lower 32-bit * and the upper 16-bit parts of "ticks", i.e.: * ((ticks_low + 2^32 * ticks_high) * cal) >> RTC_CLK_CAL_FRACT *//* ... */constuint64_tticks_low=ticks&UINT32_MAX;constuint64_tticks_high=ticks>>32;constuint64_tdelta_time_us=((ticks_low*cal)>>RTC_CLK_CAL_FRACT)+((ticks_high*cal)<<(32-RTC_CLK_CAL_FRACT));#ifSOC_RTC_MEM_SUPPORTEDs_rtc_timer_retain_mem.rtc_time_us+=delta_time_us;s_rtc_timer_retain_mem.rtc_last_ticks=rtc_this_ticks;s_rtc_timer_retain_mem.checksum=calc_checksum();uint64_tesp_rtc_time_us=s_rtc_timer_retain_mem.rtc_time_us;portEXIT_CRITICAL_SAFE(&s_esp_rtc_time_lock);returnesp_rtc_time_us;/* ... */#elseuint64_tesp_rtc_time_us=delta_time_us+clk_ll_rtc_slow_load_rtc_fix_us();portEXIT_CRITICAL_SAFE(&s_esp_rtc_time_lock);returnesp_rtc_time_us;/* ... */#endif}{ ... }voidesp_clk_slowclk_cal_set(uint32_tnew_cal){#ifdefined(CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER)/* To force monotonic time values even when clock calibration value changes, * we adjust esp_rtc_time *//* ... */#ifSOC_RTC_MEM_SUPPORTEDesp_rtc_get_time_us();#elseportENTER_CRITICAL_SAFE(&s_esp_rtc_time_lock);uint32_told_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_tticks=rtc_time_get();constuint64_tticks_low=ticks&UINT32_MAX;constuint64_tticks_high=ticks>>32;uint64_told_fix_us=clk_ll_rtc_slow_load_rtc_fix_us();uint64_tnew_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_MEM_SUPPORTED/* ... */#endif// CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMERclk_ll_rtc_slow_store_cal(new_cal);}{ ... }uint32_tesp_clk_slowclk_cal_get(void){returnclk_ll_rtc_slow_load_cal();}{ ... }uint64_tesp_clk_rtc_time(void){#ifdefCONFIG_ESP_TIME_FUNCS_USE_RTC_TIMERreturnesp_rtc_get_time_us();#elsereturn0;#endif}{ ... }voidesp_clk_private_lock(void){portENTER_CRITICAL(&s_esp_rtc_time_lock);}{ ... }voidesp_clk_private_unlock(void){portEXIT_CRITICAL(&s_esp_rtc_time_lock);}{ ... }
Details
Show: from
Types: Columns:
All items filtered out
All items filtered out
This file uses the notable symbols shown below. Click anywhere in the file to view more details.