From 8b2f933a51905ea357cf91d37923049396a8625e Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 21 Nov 2016 17:15:37 +0800 Subject: [PATCH] Implement system_* APIs in IDF --- components/esp32/cpu_start.c | 4 +- components/esp32/cpu_util.c | 44 ++++ components/esp32/include/esp_system.h | 166 +++++----------- components/esp32/include/esp_wifi.h | 15 ++ components/esp32/include/esp_wifi_internal.h | 22 +- components/esp32/include/soc/cpu.h | 21 +- components/esp32/panic.c | 20 +- components/esp32/system_api.c | 199 +++++++++++++++++++ components/newlib/time.c | 26 +++ 9 files changed, 365 insertions(+), 152 deletions(-) create mode 100644 components/esp32/cpu_util.c create mode 100644 components/esp32/system_api.c diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index 1eb0a5355e..293be565df 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -116,9 +116,7 @@ void IRAM_ATTR call_start_cpu0() //Flush and enable icache for APP CPU Cache_Flush(1); Cache_Read_Enable(1); - //Un-stall the app cpu; the panic handler may have stalled it. - CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, RTC_CNTL_SW_STALL_APPCPU_C1_M); - CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_STALL_APPCPU_C0_M); + esp_cpu_unstall(1); //Enable clock gating and reset the app cpu. SET_PERI_REG_MASK(DPORT_APPCPU_CTRL_B_REG, DPORT_APPCPU_CLKGATE_EN); CLEAR_PERI_REG_MASK(DPORT_APPCPU_CTRL_C_REG, DPORT_APPCPU_RUNSTALL); diff --git a/components/esp32/cpu_util.c b/components/esp32/cpu_util.c new file mode 100644 index 0000000000..cff61ab796 --- /dev/null +++ b/components/esp32/cpu_util.c @@ -0,0 +1,44 @@ +// Copyright 2013-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 "esp_attr.h" +#include "soc/cpu.h" +#include "soc/soc.h" +#include "soc/rtc_cntl_reg.h" + +void IRAM_ATTR esp_cpu_stall(int cpu_id) +{ + if (cpu_id == 1) { + CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, RTC_CNTL_SW_STALL_APPCPU_C1_M); + SET_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, 0x21<|<----------- user data(1024 bytes) --------->| - * - * @attention Read and write unit for data stored in the RTC memory is 4 bytes. - * @attention src_addr is the block number (4 bytes per block). So when reading data - * at the beginning of the user data segment, src_addr will be 512/4 = 128, - * n will be data length. - * - * @param uint16 src : source address of rtc memory, src_addr >= 128 - * @param void *dst : data pointer - * @param uint16 n : data length, unit: byte - * - * @return true : succeed - * @return false : fail - */ -bool system_rtc_mem_read(uint16_t src, void *dst, uint16_t n); - -/** - * @brief Write user data to the RTC memory. - * - * During deep-sleep, only RTC is working. So users can store their data - * in RTC memory if it is needed. The user data segment below (1024 bytes) - * is used to store the user data. - * - * |<---- system data(512 bytes) ---->|<----------- user data(1024 bytes) --------->| - * - * @attention Read and write unit for data stored in the RTC memory is 4 bytes. - * @attention src_addr is the block number (4 bytes per block). So when storing data - * at the beginning of the user data segment, src_addr will be 512/4 = 128, - * n will be data length. - * - * @param uint16 src : source address of rtc memory, src_addr >= 128 - * @param void *dst : data pointer - * @param uint16 n : data length, unit: byte - * - * @return true : succeed - * @return false : fail - */ -bool system_rtc_mem_write(uint16_t dst, const void *src, uint16_t n); - -/** \defgroup System_boot_APIs Boot APIs - * @brief boot APIs - */ - -/** @addtogroup System_boot_APIs - * @{ - */ - -/** - * @} - */ - -/** \defgroup Hardware_MAC_APIs Hardware MAC APIs - * @brief Hardware MAC address APIs - * - * In WiFi MAC, only ESP32 station MAC is the hardware MAC, ESP32 softAP MAC is a software MAC - * calculated from ESP32 station MAC. - * So users need to call wifi_get_macaddr to query the ESP32 softAP MAC if ESP32 station MAC changed. - * - */ - -/** @addtogroup Hardware_MAC_APIs - * @{ - */ + * @brief Get one random 32-bit word from hardware RNG + * + * @return random value between 0 and UINT32_MAX + */ +uint32_t esp_random(void); /** * @brief Read hardware MAC address. * - * @param uint8 mac[6] : the hardware MAC address, length: 6 bytes. + * In WiFi MAC, only ESP32 station MAC is the hardware MAC, ESP32 softAP MAC is a software MAC + * calculated from ESP32 station MAC. + * So users need to call esp_wifi_get_macaddr to query the ESP32 softAP MAC if ESP32 station MAC changed. * - * @return esp_err_t + * @param mac hardware MAC address, length: 6 bytes. + * + * @return ESP_OK on success */ -esp_err_t system_efuse_read_mac(uint8_t mac[6]); - +esp_err_t esp_efuse_read_mac(uint8_t mac[6]); /** - * @} + * @brief Read hardware MAC address. + * + * Function has been renamed to esp_efuse_read_mac. + * This name will be removed in a future release. + * + * @param mac hardware MAC address, length: 6 bytes. + * @return ESP_OK on success */ +esp_err_t system_efuse_read_mac(uint8_t mac[6]) __attribute__ ((deprecated)); -/** - * @} - */ - #ifdef __cplusplus } #endif diff --git a/components/esp32/include/esp_wifi.h b/components/esp32/include/esp_wifi.h index 65a91929dd..572a7dc744 100644 --- a/components/esp32/include/esp_wifi.h +++ b/components/esp32/include/esp_wifi.h @@ -186,6 +186,21 @@ esp_err_t esp_wifi_start(void); */ esp_err_t esp_wifi_stop(void); +/** + * @brief Restore WiFi stack persistent settings to default values + * + * This function will reset settings made using the following APIs: + * - esp_wifi_get_auto_connect, + * - esp_wifi_set_protocol, + * - esp_wifi_set_config related + * - esp_wifi_set_mode + * + * @return + * - ESP_OK: succeed + * - ESP_ERR_WIFI_NOT_INIT: WiFi is not initialized by eps_wifi_init + */ +esp_err_t esp_wifi_restore(void); + /** * @brief Connect the ESP32 WiFi station to the AP. * diff --git a/components/esp32/include/esp_wifi_internal.h b/components/esp32/include/esp_wifi_internal.h index 2015b5063d..09813bfa1b 100644 --- a/components/esp32/include/esp_wifi_internal.h +++ b/components/esp32/include/esp_wifi_internal.h @@ -43,10 +43,9 @@ extern "C" { /** * @brief get whether the wifi driver is allowed to transmit data or not * - * @param none - * - * @return true : upper layer should stop to transmit data to wifi driver - * @return false : upper layer can transmit data to wifi driver + * @return + * - true : upper layer should stop to transmit data to wifi driver + * - false : upper layer can transmit data to wifi driver */ bool esp_wifi_internal_tx_is_stop(void); @@ -54,8 +53,6 @@ bool esp_wifi_internal_tx_is_stop(void); * @brief free the rx buffer which allocated by wifi driver * * @param void* buffer: rx buffer pointer - * - * @return nonoe */ void esp_wifi_internal_free_rx_buffer(void* buffer); @@ -78,7 +75,6 @@ int esp_wifi_internal_tx(wifi_interface_t wifi_if, void *buffer, u16_t len); * @brief The WiFi RX callback function * * Each time the WiFi need to forward the packets to high layer, the callback function will be called - * */ typedef esp_err_t (*wifi_rxcb_t)(void *buffer, uint16_t len, void *eb); @@ -90,18 +86,18 @@ typedef esp_err_t (*wifi_rxcb_t)(void *buffer, uint16_t len, void *eb); * @param wifi_interface_t ifx : interface * @param wifi_rxcb_t fn : WiFi RX callback * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - others : fail */ esp_err_t esp_wifi_internal_reg_rxcb(wifi_interface_t ifx, wifi_rxcb_t fn); /** * @brief Notify WIFI driver that the station got ip successfully * - * @param none - * - * @return ESP_OK : succeed - * @return others : fail + * @return + * - ESP_OK : succeed + * - others : fail */ esp_err_t esp_wifi_internal_set_sta_ip(void); diff --git a/components/esp32/include/soc/cpu.h b/components/esp32/include/soc/cpu.h index ee2907493e..4457c81a22 100644 --- a/components/esp32/include/soc/cpu.h +++ b/components/esp32/include/soc/cpu.h @@ -51,7 +51,10 @@ static inline void cpu_write_itlb(unsigned vpn, unsigned attr) asm volatile ("witlb %1, %0; isync\n" :: "r" (vpn), "r" (attr)); } -/* Make page 0 access raise an exception. +/** + * @brief Configure memory region protection + * + * Make page 0 access raise an exception. * Also protect some other unused pages so we can catch weirdness. * Useful attribute values: * 0 — cached, RW @@ -70,9 +73,7 @@ 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. @@ -81,4 +82,16 @@ static inline void cpu_configure_region_protection() */ 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) + */ +void esp_cpu_stall(int cpu_id); + +/** + * @brief Un-stall CPU using RTC controller + * @param cpu_id ID of the CPU to un-stall (0 = PRO, 1 = APP) + */ +void esp_cpu_unstall(int cpu_id); + #endif diff --git a/components/esp32/panic.c b/components/esp32/panic.c index c5d8aa669e..8f51994401 100644 --- a/components/esp32/panic.c +++ b/components/esp32/panic.c @@ -27,6 +27,7 @@ #include "soc/rtc_cntl_reg.h" #include "soc/timer_group_struct.h" #include "soc/timer_group_reg.h" +#include "soc/cpu.h" #include "esp_gdbstub.h" #include "esp_panic.h" @@ -108,21 +109,10 @@ static const char *edesc[]={ void commonErrorHandler(XtExcFrame *frame); //The fact that we've panic'ed probably means the other CPU is now running wild, possibly -//messing up the serial output, so we kill it here. -static void haltOtherCore() { - if (xPortGetCoreID()==0) { - //Kill app cpu - CLEAR_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, RTC_CNTL_SW_STALL_APPCPU_C1_M); - SET_PERI_REG_MASK(RTC_CNTL_SW_CPU_STALL_REG, 0x21<> 8; + mac[1] = mac_high; + mac[2] = mac_low >> 24; + mac[3] = mac_low >> 16; + mac[4] = mac_low >> 8; + mac[5] = mac_low; + + efuse_crc = mac_high >> 16; + calc_crc = esp_crc8(mac, 6); + + if (efuse_crc != calc_crc) { + // Small range of MAC addresses are accepted even if CRC is invalid. + // These addresses are reserved for Espressif internal use. + if ((mac_high & 0xFFFF) == 0x18fe) { + if ((mac_low >= 0x346a85c7) && (mac_low <= 0x346a85f8)) { + return ESP_OK; + } + } else { + ESP_LOGE(TAG, "MAC address CRC error, efuse_crc = 0x%02x; calc_crc = 0x%02x", efuse_crc, calc_crc); + abort(); + } + } + return ESP_OK; +} + + +void IRAM_ATTR system_restart(void) +{ + esp_wifi_stop(); + + // Disable scheduler on this core. + vTaskSuspendAll(); + const uint32_t core_id = xPortGetCoreID(); + const uint32_t other_core_id = core_id == 0 ? 1 : 0; + esp_cpu_stall(other_core_id); + + // We need to disable TG0/TG1 watchdogs + // First enable RTC watchdog to be on the safe side + REG_WRITE(RTC_CNTL_WDTWPROTECT_REG, RTC_CNTL_WDT_WKEY_VALUE); + REG_WRITE(RTC_CNTL_WDTCONFIG0_REG, + RTC_CNTL_WDT_FLASHBOOT_MOD_EN_M | + (1 << RTC_CNTL_WDT_SYS_RESET_LENGTH_S) | + (1 << RTC_CNTL_WDT_CPU_RESET_LENGTH_S) ); + REG_WRITE(RTC_CNTL_WDTCONFIG1_REG, 128000); + + // Disable TG0/TG1 watchdogs + TIMERG0.wdt_wprotect=TIMG_WDT_WKEY_VALUE; + TIMERG0.wdt_config0.en = 0; + TIMERG0.wdt_wprotect=0; + TIMERG1.wdt_wprotect=TIMG_WDT_WKEY_VALUE; + TIMERG1.wdt_config0.en = 0; + TIMERG1.wdt_wprotect=0; + + // Disable all interrupts + xt_ints_off(0xFFFFFFFF); + + // Disable cache + Cache_Read_Disable(0); + Cache_Read_Disable(1); + + // Flush any data left in UART FIFO + uart_tx_flush(0); + uart_tx_flush(1); + uart_tx_flush(2); + + // Reset wifi/bluetooth (bb/mac) + SET_PERI_REG_MASK(DPORT_WIFI_RST_EN_REG, 0x1f); + REG_WRITE(DPORT_WIFI_RST_EN_REG, 0); + + // Reset timer/spi/uart + SET_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, + DPORT_TIMERS_RST | DPORT_SPI_RST_1 | DPORT_UART_RST); + REG_WRITE(DPORT_PERIP_RST_EN_REG, 0); + + // Reset CPUs + if (core_id == 0) { + // Running on PRO CPU: APP CPU is stalled. Can reset both CPUs. + SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, + RTC_CNTL_SW_PROCPU_RST_M | RTC_CNTL_SW_APPCPU_RST_M); + } else { + // Running on APP CPU: need to reset PRO CPU and unstall it, + // then stall APP CPU + SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_SW_PROCPU_RST_M); + esp_cpu_unstall(0); + esp_cpu_stall(1); + } + while(true) { + ; + } +} + +void system_restore(void) +{ + esp_wifi_restore(); +} + +#if 0 +void system_deep_sleep_instant(uint64_t time_in_us) +{ + u32 period, cycle_h, cycle_l; + + { + struct rst_info debug_data; + memset(&debug_data, 0, sizeof(struct rst_info)); + + WRITE_PERI_REG(RTC_STORE0, DEEP_SLEEP_AWAKE_FLAG); + debug_data.flag = DEEP_SLEEP_AWAKE_FLAG; + + system_write_rtc_mem(0, &debug_data, sizeof(struct rst_info)); + } + + rtc_set_cpu_freq(XTAL_AUTO, CPU_XTAL); + esp_set_deep_sleep_wake_stub(esp_wake_deep_sleep); + + period = rtc_slowck_cali(CALI_RTC_MUX, 128, XTAL_AUTO); + rtc_usec2rtc(time_in_us >> 32, time_in_us, period, &cycle_h, &cycle_l); + + rtc_slp_prep_lite(1, 0); + rtc_sleep(cycle_h, cycle_l, TIMER_EXPIRE_EN, 0); +} + +static uint64_t deep_sleep_time; + +static void system_deep_sleep_step2(void) +{ + system_deep_sleep_instant(deep_sleep_time); +} + +void system_deep_sleep(uint64 time_in_us) +{ + wifi_set_sleep_flag(1); + + deep_sleep_time = time_in_us; + + os_timer_disarm(&sta_con_timer); + os_timer_setfn(&sta_con_timer, (os_timer_func_t *)system_deep_sleep_step2, NULL); + os_timer_arm(&sta_con_timer, 100, 0); +} + +#endif + +uint32_t system_get_free_heap_size(void) +{ + return xPortGetFreeHeapSize(); +} + + +struct rst_info *system_get_rst_info(void) +{ + return NULL; +} + +const char* system_get_sdk_version(void) +{ + return "master"; +} + + diff --git a/components/newlib/time.c b/components/newlib/time.c index 3426a01bfb..1baa955759 100644 --- a/components/newlib/time.c +++ b/components/newlib/time.c @@ -184,3 +184,29 @@ int settimeofday(const struct timeval *tv, const struct timezone *tz) return -1; #endif } + +uint32_t system_get_time(void) +{ +#if defined( WITH_FRC1 ) || defined( WITH_RTC ) + return get_time_since_boot(); +#else + return 0; +#endif +} + +uint32_t system_get_current_time(void) __attribute__((alias("system_get_time"))); + +uint32_t system_relative_time(uint32_t current_time) +{ + return system_get_time() - current_time; +} + +uint64_t system_get_rtc_time(void) +{ +#ifdef WITH_RTC + return get_rtc_time_us(); +#else + return 0; +#endif +} +