diff --git a/components/aws_iot/port/network_mbedtls_wrapper.c b/components/aws_iot/port/network_mbedtls_wrapper.c index be33fdb7..515f6745 100644 --- a/components/aws_iot/port/network_mbedtls_wrapper.c +++ b/components/aws_iot/port/network_mbedtls_wrapper.c @@ -99,7 +99,7 @@ IoT_Error_t iot_tls_connect(Network *pNetwork, TLSConnectParams *params) { cfg.alpn_protos = alpnProtocols; } - rtc_clk_cpu_freq_set(RTC_CPU_FREQ_160M); + esp_set_cpu_freq(ESP_CPU_FREQ_160M); struct esp_tls *tls = esp_tls_conn_new(pNetwork->tlsConnectParams.pDestinationURL, strlen(pNetwork->tlsConnectParams.pDestinationURL), pNetwork->tlsConnectParams.DestinationPort, &cfg); @@ -110,7 +110,7 @@ IoT_Error_t iot_tls_connect(Network *pNetwork, TLSConnectParams *params) { tlsDataParams->timeout = pNetwork->tlsConnectParams.timeout_ms; tlsDataParams->handle = (esp_network_handle_t)tls; - rtc_clk_cpu_freq_set(RTC_CPU_FREQ_80M); + esp_set_cpu_freq(ESP_CPU_FREQ_80M); return (IoT_Error_t) ret; } diff --git a/components/esp8266/CMakeLists.txt b/components/esp8266/CMakeLists.txt index 36c8ee0d..2a6ba7bc 100644 --- a/components/esp8266/CMakeLists.txt +++ b/components/esp8266/CMakeLists.txt @@ -24,6 +24,7 @@ else() set(srcs "source/chip_boot.c" "source/backtrace.c" + "source/esp_sleep.c" "source/esp_err_to_name.c" "source/esp_timer.c" "source/esp_wifi_os_adapter.c" @@ -60,7 +61,7 @@ else() target_link_libraries(${COMPONENT_LIB} PUBLIC "-L ${CMAKE_CURRENT_SOURCE_DIR}/lib" "-lstdc++") if(NOT CONFIG_NO_BLOBS) - set(blobs "gcc" "hal" "core" "net80211" "phy" "pp" "smartconfig" "ssc" "wpa" "espnow" "wps") + set(blobs "gcc" "hal" "core" "net80211" "phy" "clk" "pp" "smartconfig" "ssc" "wpa" "espnow" "wps") foreach(blob ${blobs}) add_library(${blob} STATIC IMPORTED) set_property(TARGET ${blob} PROPERTY IMPORTED_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/lib/lib${blob}.a) diff --git a/components/esp8266/component.mk b/components/esp8266/component.mk index 181b36d5..53b0ad2a 100644 --- a/components/esp8266/component.mk +++ b/components/esp8266/component.mk @@ -13,10 +13,10 @@ LIBS ?= ifndef CONFIG_NO_BLOBS ifndef CONFIG_ESP8266_WIFI_DEBUG_LOG_ENABLE LIBS += gcc hal core net80211 \ - phy pp smartconfig ssc wpa espnow wps + phy clk pp smartconfig ssc wpa espnow wps else LIBS += gcc hal core_dbg net80211_dbg \ - phy pp_dbg smartconfig ssc wpa_dbg espnow_dbg wps_dbg + phy clk pp_dbg smartconfig ssc wpa_dbg espnow_dbg wps_dbg endif endif diff --git a/components/esp8266/include/driver/rtc.h b/components/esp8266/include/driver/rtc.h new file mode 100644 index 00000000..aaa7e94c --- /dev/null +++ b/components/esp8266/include/driver/rtc.h @@ -0,0 +1,120 @@ +// Copyright 2019-2020 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 + +#include +#include "esp8266/eagle_soc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Wakeup option + */ +#define RTC_GPIO_TRIG_EN BIT(2) //!< GPIO wakeup (light sleep only) +#define RTC_TIMER_TRIG_EN BIT(3) //!< Timer wakeup + +/** + * @brief CPU frequency values + */ +typedef enum { + RTC_CPU_FREQ_80M = 0, //!< 80 MHz + RTC_CPU_FREQ_160M = 1, //!< 160 MHz +} rtc_cpu_freq_t; + +/** + * @brief Initialize RTC hardware + */ +void rtc_clk_init(void); + +/** + * @brief Get the currently used CPU frequency configuration + * + * @return CPU frequency + */ +rtc_cpu_freq_t rtc_clk_cpu_freq_get(void); + +/** + * @brief Switch CPU frequency + * + * This function sets CPU frequency according to the given configuration + * structure. It enables PLLs, if necessary. + * + * @note This function in not intended to be called by applications in FreeRTOS + * environment. This is because it does not adjust various timers based on the + * new CPU frequency. + * + * @param cpu_freq CPU frequency + */ +void rtc_clk_cpu_freq_set(rtc_cpu_freq_t cpu_freq); + +/** + * @brief Enter light sleep mode + * + * @note CPU wakeup has 2672 ms time cost, so the real sleeping time is to_sleep_time_in_us - 2672 + * + * @param rtc_ticks value of RTC counter at which wakeup from sleep will happen + * + * @param wakeup_opt bit mask wake up reasons to enable (RTC_xxx_TRIG_EN flags + * combined with OR) + * @param reject_opt bit mask of sleep reject reasons: + * - RTC_CNTL_GPIO_REJECT_EN + * - RTC_CNTL_SDIO_REJECT_EN + * These flags are used to prevent entering sleep when e.g. + * an external host is communicating via SDIO slave + * @return non-zero if sleep was rejected by hardware + */ +uint32_t rtc_light_sleep_start(uint32_t rtc_ticks, uint32_t wakeup_opt, uint32_t reject_opt); + +/** + * @brief Convert time interval from microseconds to RTC_CLK cycles + * + * @param time_in_us Time interval in microseconds + * @param period Period of clock in microseconds (as returned by esp_clk_cal_get) + * + * @return number of clock cycles + */ +uint32_t rtc_time_us_to_clk(uint32_t time_in_us, uint32_t period); + +/** + * @brief Convert time interval from RTC_CLK to microseconds + * + * @param rtc_cycles Time interval in RTC_CLK cycles + * @param period Period of clock in microseconds (as returned by esp_clk_cal_get) + * + * @return time interval in microseconds + */ +uint32_t rtc_time_clk_to_us(uint32_t rtc_cycles, uint32_t period); + +/** + * @brief Get the calibration value of RTC clock + * + * @param xtal_freq XTAL frequency, unit is MHz + * + * @return the calibration value + */ +uint32_t esp_clk_cal_get(uint32_t xtal_freq); + +/** + * @brief Get current value of RTC counter + * + * @return current value of RTC counter + */ +uint32_t rtc_time_get(void); + +#ifdef __cplusplus +} +#endif diff --git a/components/esp8266/include/esp_sleep.h b/components/esp8266/include/esp_sleep.h index beee56bf..5dcb5885 100644 --- a/components/esp8266/include/esp_sleep.h +++ b/components/esp8266/include/esp_sleep.h @@ -178,6 +178,31 @@ void esp_wifi_enable_gpio_wakeup(uint32_t gpio_num, gpio_int_type_t intr_status) */ void esp_wifi_disable_gpio_wakeup(void); +/** + * @brief Enable wakeup by timer + * @param time_in_us time before wakeup, in microseconds + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG if value is out of range (TBD) + */ +esp_err_t esp_sleep_enable_timer_wakeup(uint32_t time_in_us); + +/** + * @brief Enter light sleep with the configured wakeup options + * + * @return + * - ESP_OK on success (returned after wakeup) + * - ESP_ERR_INVALID_STATE if WiFi or BT is not stopped + */ +esp_err_t esp_light_sleep_start(void); + +/** + * @brief Operation system start check time and enter sleep + * + * @note This function is called by system, user should not call this + */ +void esp_sleep_start(void); + #ifdef __cplusplus } #endif diff --git a/components/esp8266/include/esp_system.h b/components/esp8266/include/esp_system.h index 7d052b5a..e8e6b4c3 100644 --- a/components/esp8266/include/esp_system.h +++ b/components/esp8266/include/esp_system.h @@ -123,9 +123,9 @@ esp_err_t esp_derive_local_mac(uint8_t* local_mac, const uint8_t* universal_mac) * @brief CPU frequency values */ typedef enum { - RTC_CPU_FREQ_80M = 1, //!< 80 MHz - RTC_CPU_FREQ_160M = 2, //!< 160 MHz -} rtc_cpu_freq_t; + ESP_CPU_FREQ_80M = 1, //!< 80 MHz + ESP_CPU_FREQ_160M = 2, //!< 160 MHz +} esp_cpu_freq_t; /** * @brief Switch CPU frequency @@ -137,7 +137,7 @@ typedef enum { * * @param cpu_freq new CPU frequency */ -void rtc_clk_cpu_freq_set(rtc_cpu_freq_t cpu_freq); +void esp_set_cpu_freq(esp_cpu_freq_t cpu_freq); /** * @brief Reset to default settings. diff --git a/components/esp8266/lib/VERSION b/components/esp8266/lib/VERSION index 919f4e77..98b39cc0 100644 --- a/components/esp8266/lib/VERSION +++ b/components/esp8266/lib/VERSION @@ -1,10 +1,10 @@ gwen: - core: 7f8c705 + core: f467b5d net80211: 7f8c705 pp: 7f8c705 - wpa: 7f8c705 + wpa: f467b5d espnow: 7f8c705 wps: 7f8c705 - smartconfig: 2.8.1 + smartconfig: 2.8.2 phy: 1055_22 diff --git a/components/esp8266/lib/libclk.a b/components/esp8266/lib/libclk.a new file mode 100644 index 00000000..e8542b1b Binary files /dev/null and b/components/esp8266/lib/libclk.a differ diff --git a/components/esp8266/lib/libcore.a b/components/esp8266/lib/libcore.a index 3fb58124..8bbc0bde 100644 Binary files a/components/esp8266/lib/libcore.a and b/components/esp8266/lib/libcore.a differ diff --git a/components/esp8266/lib/libcore_dbg.a b/components/esp8266/lib/libcore_dbg.a index 072cf685..9c6bf691 100644 Binary files a/components/esp8266/lib/libcore_dbg.a and b/components/esp8266/lib/libcore_dbg.a differ diff --git a/components/esp8266/lib/libsmartconfig.a b/components/esp8266/lib/libsmartconfig.a index b29f331b..039759dc 100644 Binary files a/components/esp8266/lib/libsmartconfig.a and b/components/esp8266/lib/libsmartconfig.a differ diff --git a/components/esp8266/lib/libwpa.a b/components/esp8266/lib/libwpa.a index e6ff4023..c1fcec88 100644 Binary files a/components/esp8266/lib/libwpa.a and b/components/esp8266/lib/libwpa.a differ diff --git a/components/esp8266/lib/libwpa_dbg.a b/components/esp8266/lib/libwpa_dbg.a index 304b8dd0..a9f587c3 100644 Binary files a/components/esp8266/lib/libwpa_dbg.a and b/components/esp8266/lib/libwpa_dbg.a differ diff --git a/components/esp8266/linker.lf b/components/esp8266/linker.lf index fdd63250..5cb19c78 100644 --- a/components/esp8266/linker.lf +++ b/components/esp8266/linker.lf @@ -14,3 +14,8 @@ entries: archive: libphy.a entries: * (noflash_text) + +[mapping:rtc] +archive: librtc_opensource.a +entries: + * (noflash_text) diff --git a/components/esp8266/source/esp_sleep.c b/components/esp8266/source/esp_sleep.c new file mode 100644 index 00000000..9ef654df --- /dev/null +++ b/components/esp8266/source/esp_sleep.c @@ -0,0 +1,156 @@ +// Copyright 2019-2020 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 +#include "esp_timer.h" +#include "esp_log.h" +#include "esp_attr.h" +#include "esp_system.h" +#include "esp_sleep.h" +#include "FreeRTOS.h" +#include "freertos/task.h" +#include "driver/soc.h" +#include "esp8266/timer_struct.h" +#include "esp8266/uart_struct.h" +#include "esp8266/rom_functions.h" +#include "driver/rtc.h" + + +#define MIN_SLEEP_US (3 * 1000) +#define WAKEUP_EARLY_US (2520) + +#define TAG "esp8266_pm" + +typedef struct pm_soc_clk { + uint32_t ccount; +} pm_soc_clk_t; + +static uint32_t s_lock_cnt = 1; +static uint32_t s_sleep_wakup_triggers; +static uint32_t s_sleep_duration; + +static inline uint32_t save_local_wdev(void) +{ + extern uint32_t WDEV_INTEREST_EVENT; + + uint32_t reg = WDEV_INTEREST_EVENT; + + REG_WRITE(INT_ENA_WDEV, WDEV_TSF0_REACH_INT); + + return reg; +} + +static inline void restore_local_wdev(uint32_t reg) +{ + REG_WRITE(INT_ENA_WDEV, reg); +} + +static inline void save_soc_clk(pm_soc_clk_t *clk) +{ + clk->ccount = soc_get_ccount(); +} + +static inline uint32_t min_sleep_us(pm_soc_clk_t *clk) +{ + const int32_t os_sleep_us = ((int32_t)soc_get_ccompare() - (int32_t)clk->ccount) / g_esp_ticks_per_us + + prvGetExpectedIdleTime() * portTICK_RATE_MS * 1000; + const uint32_t ccompare_sleep_us = os_sleep_us > 0 ? os_sleep_us : 0; + + return MIN(ccompare_sleep_us, ccompare_sleep_us); +} + +static inline void update_soc_clk(pm_soc_clk_t *clk, uint32_t us) +{ + const uint32_t os_ccount = us * g_esp_ticks_per_us + clk->ccount; + + if (os_ccount >= _xt_tick_divisor) + soc_set_ccompare(os_ccount + 32); + soc_set_ccount(os_ccount); +} + +esp_err_t esp_sleep_enable_timer_wakeup(uint32_t time_in_us) +{ + if (time_in_us <= MIN_SLEEP_US) + return ESP_ERR_INVALID_ARG; + + s_sleep_duration = time_in_us; + s_sleep_wakup_triggers |= RTC_TIMER_TRIG_EN; + + return ESP_OK; +} + +esp_err_t esp_light_sleep_start(void) +{ + const uint32_t rtc_cal = esp_clk_cal_get(CRYSTAL_USED); + const uint32_t sleep_rtc_ticks = rtc_time_us_to_clk(s_sleep_duration - WAKEUP_EARLY_US, rtc_cal); + const rtc_cpu_freq_t cpu_freq = rtc_clk_cpu_freq_get(); + + rtc_light_sleep_start(sleep_rtc_ticks, s_sleep_wakup_triggers, 0); + + rtc_clk_init(); + rtc_clk_cpu_freq_set(cpu_freq); + + return ESP_OK; +} + +void esp_sleep_lock(void) +{ + const esp_irqflag_t irqflag = soc_save_local_irq(); + s_lock_cnt++; + soc_restore_local_irq(irqflag); +} + +void esp_sleep_unlock(void) +{ + const esp_irqflag_t irqflag = soc_save_local_irq(); + s_lock_cnt--; + soc_restore_local_irq(irqflag); +} + +void IRAM_ATTR esp_sleep_start(void) +{ + if (s_lock_cnt) { + soc_wait_int(); + return ; + } + + int slept = 0; + pm_soc_clk_t clk; + const esp_irqflag_t irqflag = soc_save_local_irq(); + const uint32_t wdevflag = save_local_wdev(); + + save_soc_clk(&clk); + + const uint32_t sleep_us = min_sleep_us(&clk); + if (sleep_us > MIN_SLEEP_US) { + const uint32_t rtc_cal = esp_clk_cal_get(CRYSTAL_USED); + const uint32_t sleep_rtc_ticks = rtc_time_us_to_clk(sleep_us - WAKEUP_EARLY_US, rtc_cal); + const rtc_cpu_freq_t cpu_freq = rtc_clk_cpu_freq_get(); + + rtc_light_sleep_start(sleep_rtc_ticks, s_sleep_wakup_triggers | RTC_TIMER_TRIG_EN, 0); + + rtc_clk_init(); + rtc_clk_cpu_freq_set(cpu_freq); + + update_soc_clk(&clk, sleep_us); + + slept = 1; + } + + restore_local_wdev(wdevflag); + soc_restore_local_irq(irqflag); + + if (!slept) + soc_wait_int(); +} diff --git a/components/esp8266/source/esp_timer.c b/components/esp8266/source/esp_timer.c index 645f9379..4795a36d 100644 --- a/components/esp8266/source/esp_timer.c +++ b/components/esp8266/source/esp_timer.c @@ -200,9 +200,9 @@ esp_err_t esp_timer_delete(esp_timer_handle_t timer) return os_ret == pdPASS ? ESP_OK : ESP_ERR_INVALID_STATE; } -int64_t esp_timer_get_time() +int64_t esp_timer_get_time(void) { extern uint64_t g_esp_os_us; - return (int64_t)g_esp_os_us; + return (int64_t)(g_esp_os_us + soc_get_ccount() / g_esp_ticks_per_us); } diff --git a/components/esp8266/source/startup.c b/components/esp8266/source/startup.c index 431741af..0b8ed07f 100644 --- a/components/esp8266/source/startup.c +++ b/components/esp8266/source/startup.c @@ -117,7 +117,7 @@ static void user_init_entry(void *param) #endif #ifdef CONFIG_ESP8266_DEFAULT_CPU_FREQ_160 - rtc_clk_cpu_freq_set(RTC_CPU_FREQ_160M); + esp_set_cpu_freq(ESP_CPU_FREQ_160M); #endif app_main(); diff --git a/components/freertos/port/esp8266/include/freertos/portmacro.h b/components/freertos/port/esp8266/include/freertos/portmacro.h index 4abc6267..83f33b4b 100644 --- a/components/freertos/port/esp8266/include/freertos/portmacro.h +++ b/components/freertos/port/esp8266/include/freertos/portmacro.h @@ -208,6 +208,15 @@ void esp_increase_tick_cnt(const TickType_t ticks); extern void esp_vApplicationIdleHook( void ); extern void esp_vApplicationTickHook( void ); +extern const uint32_t g_esp_ticks_per_us; + +/* + * @brief Get FreeRTOS system idle ticks + * + * @return idle ticks + */ +TickType_t prvGetExpectedIdleTime(void); + #ifdef __cplusplus } #endif diff --git a/components/freertos/port/esp8266/port.c b/components/freertos/port/esp8266/port.c index 830bc1dc..10e0c492 100644 --- a/components/freertos/port/esp8266/port.c +++ b/components/freertos/port/esp8266/port.c @@ -41,6 +41,8 @@ #include "esp_attr.h" #include "esp_libc.h" +#include "esp_task_wdt.h" +#include "esp_sleep.h" #include "esp8266/eagle_soc.h" #include "rom/ets_sys.h" @@ -151,13 +153,9 @@ void IRAM_ATTR xPortSysTickHandle(void *p) * * So add code here to calibrate system time. */ - if (_xt_tick_divisor == (CPU_FREQ_80MHz / XT_TICK_PER_SEC)) { - ccount = soc_get_ccount(); - us = ccount / CPU_80M_TICKS_PRT_US; - } else { - ccount = soc_get_ccount(); - us = ccount / CPU_160M_TICKS_PRT_US; - } + ccount = soc_get_ccount(); + us = ccount / g_esp_ticks_per_us; + g_esp_os_us += us; g_esp_os_cpu_clk += ccount; @@ -166,7 +164,6 @@ void IRAM_ATTR xPortSysTickHandle(void *p) ticks = us / 1000 / portTICK_PERIOD_MS; if (!ticks) { - ets_printf("\r\nERROR: CCOMPARE timer period"); ticks = 1; } diff --git a/components/log/log.c b/components/log/log.c index 13599c7f..264df9ba 100644 --- a/components/log/log.c +++ b/components/log/log.c @@ -63,7 +63,7 @@ uint32_t IRAM_ATTR esp_log_early_timestamp() extern uint64_t g_esp_os_us; extern uint64_t g_esp_boot_ccount; - const uint32_t ticks_per_ms = _xt_tick_divisor * configTICK_RATE_HZ / 1000; + const uint32_t ticks_per_ms = g_esp_ticks_per_us * 1000; const uint32_t ms = g_esp_os_us / 1000 + g_esp_boot_ccount / ((CRYSTAL_USED * 2) * 1000); #else const uint32_t ticks_per_ms = ((CRYSTAL_USED * 2) * 1000); diff --git a/components/ssl/mbedtls/port/openssl/include/platform/ssl_port.h b/components/ssl/mbedtls/port/openssl/include/platform/ssl_port.h index dbee9fd3..49ae231b 100644 --- a/components/ssl/mbedtls/port/openssl/include/platform/ssl_port.h +++ b/components/ssl/mbedtls/port/openssl/include/platform/ssl_port.h @@ -32,8 +32,8 @@ #define ssl_memcpy memcpy #define ssl_strlen strlen -#define ssl_speed_up_enter() rtc_clk_cpu_freq_set(RTC_CPU_FREQ_160M) -#define ssl_speed_up_exit() rtc_clk_cpu_freq_set(RTC_CPU_FREQ_80M) +#define ssl_speed_up_enter() esp_set_cpu_freq(ESP_CPU_FREQ_160M) +#define ssl_speed_up_exit() esp_set_cpu_freq(ESP_CPU_FREQ_80M) #define SSL_DEBUG_LOG printf