From 541b1426546a4ee22089e78177ad13d380d3a3d6 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Fri, 18 Nov 2016 01:18:39 +0800 Subject: [PATCH] phy_init: reduce the amount of hardwired logic, add coexist init --- components/esp32/Kconfig | 19 +--- components/esp32/cpu_start.c | 45 +++++++--- components/esp32/include/esp_phy_init.h | 107 ++++++++++++++++++++--- components/esp32/include/soc/dport_reg.h | 1 + components/esp32/lib | 2 +- components/esp32/phy.h | 15 +++- components/esp32/phy_init.c | 104 +++++++--------------- components/nvs_flash/src/nvs_api.cpp | 14 +-- 8 files changed, 185 insertions(+), 122 deletions(-) diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index 6bf6499112..206ea669e1 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -364,21 +364,6 @@ config ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL depends on DOCUMENTATION_FOR_RTC_CNTL endchoice -config ESP32_STORE_PHY_CALIBRATION_DATA_IN_NVS - bool "Store PHY calibration data in NVS" - default y - help - Choose whether to use non-volatile storage library (NVS) - to store PHY calibration data obtained at run time. - If enabled, this will use approximately 2kB of NVS storage - for PHY calibration data. - If this option is not enabled, calibration data will not be stored, - unless application provides its own implementations of - esp_phy_store_cal_data and esp_phy_load_cal_data functions. - See esp_phy_init.h for details. - - If unsure, choose 'y'. - config ESP32_PHY_AUTO_INIT bool "Initialize PHY in startup code" @@ -389,8 +374,8 @@ config ESP32_PHY_AUTO_INIT If this is undesired, disable this option and call esp_phy_init from the application before enabling WiFi or BT. - If this option is enabled along with ESP32_STORE_PHY_CALIBRATION_DATA_IN_NVS, - startup code will also initialize NVS prior to initializing PHY. + If this option is enabled, startup code will also initialize + NVS prior to initializing PHY. If unsure, choose 'y'. diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index df839069f9..1eb0a5355e 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -63,6 +63,7 @@ static bool app_cpu_started = false; #endif //!CONFIG_FREERTOS_UNICORE static void do_global_ctors(void); +static void do_phy_init(); static void main_task(void* args); extern void app_main(void); @@ -189,17 +190,8 @@ void start_cpu0_default(void) spi_flash_init(); #if CONFIG_ESP32_PHY_AUTO_INIT -#if CONFIG_ESP32_STORE_PHY_CALIBRATION_DATA_IN_NVS nvs_flash_init(); -#endif - esp_phy_calibration_mode_t calibration_mode = PHY_RF_CAL_PARTIAL; - if (rtc_get_reset_reason(0) == DEEPSLEEP_RESET) { - calibration_mode = PHY_RF_CAL_NONE; - } - if (esp_phy_init(calibration_mode) != ESP_OK) { - ESP_LOGD(TAG, "phy init has failed"); - abort(); - } + do_phy_init(); #endif xTaskCreatePinnedToCore(&main_task, "main", @@ -239,3 +231,36 @@ static void main_task(void* args) vTaskDelete(NULL); } +static void do_phy_init() +{ + esp_phy_calibration_mode_t calibration_mode = PHY_RF_CAL_PARTIAL; + if (rtc_get_reset_reason(0) == DEEPSLEEP_RESET) { + calibration_mode = PHY_RF_CAL_NONE; + } + const esp_phy_init_data_t* init_data = esp_phy_get_init_data(); + if (init_data == NULL) { + ESP_LOGE(TAG, "failed to obtain PHY init data"); + abort(); + } + esp_phy_calibration_data_t* cal_data = + (esp_phy_calibration_data_t*) calloc(sizeof(esp_phy_calibration_data_t), 1); + if (cal_data == NULL) { + ESP_LOGE(TAG, "failed to allocate memory for RF calibration data"); + abort(); + } + esp_err_t err = esp_phy_load_cal_data_from_nvs(cal_data); + if (err != ESP_OK) { + ESP_LOGW(TAG, "failed to load RF calibration data, falling back to full calibration"); + calibration_mode = PHY_RF_CAL_FULL; + } + + esp_phy_init(init_data, calibration_mode, cal_data); + + if (calibration_mode != PHY_RF_CAL_NONE) { + err = esp_phy_store_cal_data_to_nvs(cal_data); + } else { + err = ESP_OK; + } + esp_phy_release_init_data(init_data); + free(cal_data); // PHY maintains a copy of calibration data, so we can free this +} diff --git a/components/esp32/include/esp_phy_init.h b/components/esp32/include/esp_phy_init.h index f911276dff..7bc0536103 100644 --- a/components/esp32/include/esp_phy_init.h +++ b/components/esp32/include/esp_phy_init.h @@ -20,6 +20,14 @@ extern "C" { #endif +/** + * @file PHY init parameters and API + */ + + +/** + * @brief Structure holding PHY init parameters + */ typedef struct { uint8_t param_ver_id; /*!< init_data structure version */ uint8_t crystal_select; /*!< 0: 40MHz, 1: 26 MHz, 2: 24 MHz, 3: auto */ @@ -129,8 +137,11 @@ typedef struct { uint8_t reserved[23]; /*!< reserved for future expansion */ } esp_phy_init_data_t; +/** + * @brief Opaque PHY calibration data + */ typedef struct { - uint8_t opaque[1904]; /*!< opaque calibration data */ + uint8_t opaque[1904]; /*!< calibration data */ } esp_phy_calibration_data_t; typedef enum { @@ -140,29 +151,97 @@ typedef enum { } esp_phy_calibration_mode_t; /** + * @brief Get PHY init data * - * @param mode - * @return + * If "Use a partition to store PHY init data" option is set in menuconfig, + * This function will load PHY init data from a partition. Otherwise, + * PHY init data will be compiled into the application itself, and this function + * will return a pointer to PHY init data located in read-only memory (DROM). + * + * If "Use a partition to store PHY init data" option is enabled, this function + * may return NULL if the data loaded from flash is not valid. + * + * @note Call esp_phy_release_init_data to release the pointer obtained using + * this function after the call to esp_wifi_init. + * + * @return pointer to PHY init data structure */ -esp_err_t esp_phy_init(esp_phy_calibration_mode_t mode); - -#ifndef CONFIG_ESP32_STORE_PHY_CALIBRATION_DATA_IN_NVS +const esp_phy_init_data_t* esp_phy_get_init_data(); /** - * - * @param cal_data - * @return + * @brief Release PHY init data + * @param data pointer to PHY init data structure obtained from + * esp_phy_get_init_data function */ -esp_err_t esp_phy_store_cal_data(const esp_phy_calibration_data_t* cal_data); +void esp_phy_release_init_data(const esp_phy_init_data_t* data); /** + * @brief Function called by esp_phy_init to load PHY calibration data * - * @param out_cal_data - * @return + * This is a convenience function which can be used to load PHY calibration + * data from NVS. Data can be stored to NVS using esp_phy_store_cal_data_to_nvs + * function. + * + * If calibration data is not present in the NVS, or + * data is not valid (was obtained for a chip with a different MAC address, + * or obtained for a different version of software), this function will + * return an error. + * + * If "Initialize PHY in startup code" option is set in menuconfig, this + * function will be used to load calibration data. To provide a different + * mechanism for loading calibration data, disable + * "Initialize PHY in startup code" option in menuconfig and call esp_phy_init + * function from the application. For an example usage of esp_phy_init and + * this function, see do_phy_init function in cpu_start.c + * + * @param out_cal_data pointer to calibration data structure to be filled with + * loaded data. + * @return ESP_OK on success */ -esp_err_t esp_phy_load_cal_data(esp_phy_calibration_data_t* out_cal_data); +esp_err_t esp_phy_load_cal_data_from_nvs(esp_phy_calibration_data_t* out_cal_data); + +/** + * @brief Function called by esp_phy_init to store PHY calibration data + * + * This is a convenience function which can be used to store PHY calibration + * data to the NVS. Calibration data is returned by esp_phy_init function. + * Data saved using this function to the NVS can later be loaded using + * esp_phy_store_cal_data_to_nvs function. + * + * If "Initialize PHY in startup code" option is set in menuconfig, this + * function will be used to store calibration data. To provide a different + * mechanism for storing calibration data, disable + * "Initialize PHY in startup code" option in menuconfig and call esp_phy_init + * function from the application. + * + * @param cal_data pointer to calibration data which has to be saved. + * @return ESP_OK on success + */ +esp_err_t esp_phy_store_cal_data_to_nvs(const esp_phy_calibration_data_t* cal_data); + +/** + * @brief Initialize PHY module + * + * PHY module should be initialized in order to use WiFi or BT. + * If "Initialize PHY in startup code" option is set in menuconfig, + * this function will be called automatically before app_main is called, + * using parameters obtained from esp_phy_get_init_data. + * + * Applications which don't need to enable PHY on every start up should + * disable this menuconfig option and call esp_phy_init before calling + * esp_wifi_init or bt_controller_init. See do_phy_init function in + * cpu_start.c for an example of using this function. + * + * @param init_data PHY parameters. Default set of parameters can + * be obtained by calling esp_phy_get_default_init_data + * function. + * @param mode Calibration mode (Full, partial, or no calibration) + * @param[inout] calibration_data + * @return ESP_OK on success. + */ +esp_err_t esp_phy_init(const esp_phy_init_data_t* init_data, + esp_phy_calibration_mode_t mode, esp_phy_calibration_data_t* calibration_data); -#endif // CONFIG_ESP32_STORE_PHY_CALIBRATION_DATA_IN_NVS #ifdef __cplusplus } diff --git a/components/esp32/include/soc/dport_reg.h b/components/esp32/include/soc/dport_reg.h index 0c43c08740..1be0fdee14 100644 --- a/components/esp32/include/soc/dport_reg.h +++ b/components/esp32/include/soc/dport_reg.h @@ -1028,6 +1028,7 @@ #define DPORT_WIFI_RST_EN_REG (DR_REG_DPORT_BASE + 0x0D0) /* DPORT_WIFI_RST : R/W ;bitpos:[31:0] ;default: 32'h0 ; */ /*description: */ +#define DPORT_MAC_RST (BIT(2)) #define DPORT_WIFI_RST 0xFFFFFFFF #define DPORT_WIFI_RST_M ((DPORT_WIFI_RST_V)<<(DPORT_WIFI_RST_S)) #define DPORT_WIFI_RST_V 0xFFFFFFFF diff --git a/components/esp32/lib b/components/esp32/lib index db867fe912..a580f70a64 160000 --- a/components/esp32/lib +++ b/components/esp32/lib @@ -1 +1 @@ -Subproject commit db867fe9128cc1fc273d76af5a412f6743519149 +Subproject commit a580f70a64872a7cc291b1f22455f6adbc2e35cf diff --git a/components/esp32/phy.h b/components/esp32/phy.h index ad6b9003ec..81990f2e36 100644 --- a/components/esp32/phy.h +++ b/components/esp32/phy.h @@ -41,10 +41,23 @@ int register_chipv7_phy(const esp_phy_init_data_t* init_data, esp_phy_calibratio /** * @brief Get the format version of calibration data used by PHY library. - * @return Format version number + * @return Format version number, OR'ed with BIT(16) if PHY is in WIFI only mode. */ uint32_t phy_get_rf_cal_version(); +/** + * @brief Set RF/BB for only WIFI mode or coexist(WIFI & BT) mode + * @param[in] true is for only WIFI mode, false is for coexist mode. default is 0. + * @return NULL + */ +void phy_set_wifi_mode_only(bool wifi_only); + +/** + * @brief Set BT the highest priority in coexist mode. + * @return NULL + */ +void coex_bt_high_prio(void); + #ifdef __cplusplus } #endif diff --git a/components/esp32/phy_init.c b/components/esp32/phy_init.c index 11d571f04e..32d8f64edf 100644 --- a/components/esp32/phy_init.c +++ b/components/esp32/phy_init.c @@ -25,60 +25,37 @@ #include "esp_system.h" #include "phy.h" #include "esp_log.h" +#include "nvs.h" #include "sdkconfig.h" #include "phy_init_data.h" static const char* TAG = "phy_init"; -static const esp_phy_init_data_t* phy_get_init_data(); -static void phy_release_init_data(const esp_phy_init_data_t*); -esp_err_t esp_phy_init(esp_phy_calibration_mode_t mode) +esp_err_t esp_phy_init(const esp_phy_init_data_t* init_data, + esp_phy_calibration_mode_t mode, esp_phy_calibration_data_t* calibration_data) { - ESP_LOGD(TAG, "esp_phy_init, mode=%d", mode); - esp_err_t err; - const esp_phy_init_data_t* init_data = phy_get_init_data(); - if (init_data == NULL) { - ESP_LOGE(TAG, "failed to obtain PHY init data"); - return ESP_FAIL; - } - esp_phy_calibration_data_t* cal_data = - (esp_phy_calibration_data_t*) calloc(sizeof(esp_phy_calibration_data_t), 1); - if (cal_data == NULL) { - ESP_LOGE(TAG, "failed to allocate memory for RF calibration data"); - return ESP_ERR_NO_MEM; - } - // Initialize PHY function pointer table + assert(init_data); + assert(calibration_data); + // Initialize PHY pointer table phy_get_romfunc_addr(); + REG_SET_BIT(DPORT_WIFI_RST_EN_REG, DPORT_MAC_RST); + REG_CLR_BIT(DPORT_WIFI_RST_EN_REG, DPORT_MAC_RST); // Enable WiFi peripheral clock SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, 0x87cf); - // If full calibration is requested, don't need to load previous calibration data - if (mode != PHY_RF_CAL_FULL) { - err = esp_phy_load_cal_data(cal_data); - if (err != ESP_OK) { - ESP_LOGW(TAG, "failed to load RF calibration data, falling back to full calibration"); - mode = PHY_RF_CAL_FULL; - } - } - ESP_LOGV(TAG, "calling register_chipv7_phy, init_data=%p, cal_data=%p, mode=%d", init_data, cal_data, mode); - register_chipv7_phy(init_data, cal_data, mode); - if (mode != PHY_RF_CAL_NONE) { - err = esp_phy_store_cal_data(cal_data); - } else { - err = ESP_OK; - } - phy_release_init_data(init_data); - free(cal_data); // PHY maintains a copy of calibration data, so we can free this - return err; + ESP_LOGV(TAG, "register_chipv7_phy, init_data=%p, cal_data=%p, mode=%d", + init_data, calibration_data, mode); + phy_set_wifi_mode_only(0); + register_chipv7_phy(init_data, calibration_data, mode); + coex_bt_high_prio(); + return ESP_OK; } // PHY init data handling functions - #if CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION -#define NO_DEFAULT_INIT_DATA #include "esp_partition.h" -static const esp_phy_init_data_t* phy_get_init_data() +const esp_phy_init_data_t* esp_phy_get_init_data() { const esp_partition_t* partition = esp_partition_find_first( ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_PHY, NULL); @@ -109,7 +86,7 @@ static const esp_phy_init_data_t* phy_get_init_data() return (const esp_phy_init_data_t*) (init_data_store + sizeof(phy_init_magic_pre)); } -static void phy_release_init_data(const esp_phy_init_data_t* init_data) +void esp_phy_release_init_data(const esp_phy_init_data_t* init_data) { free((uint8_t*) init_data - sizeof(phy_init_magic_pre)); } @@ -118,13 +95,13 @@ static void phy_release_init_data(const esp_phy_init_data_t* init_data) // phy_init_data.h will declare static 'phy_init_data' variable initialized with default init data -static const esp_phy_init_data_t* phy_get_init_data() +const esp_phy_init_data_t* esp_phy_get_init_data() { ESP_LOGD(TAG, "loading PHY init data from application binary"); return &phy_init_data; } -static void phy_release_init_data(const esp_phy_init_data_t* init_data) +void esp_phy_release_init_data(const esp_phy_init_data_t* init_data) { // no-op } @@ -132,22 +109,18 @@ static void phy_release_init_data(const esp_phy_init_data_t* init_data) // PHY calibration data handling functions - -#if CONFIG_ESP32_STORE_PHY_CALIBRATION_DATA_IN_NVS -#include "nvs.h" - static const char* PHY_NAMESPACE = "phy"; static const char* PHY_CAL_VERSION_KEY = "cal_version"; static const char* PHY_CAL_MAC_KEY = "cal_mac"; static const char* PHY_CAL_DATA_KEY = "cal_data"; -static esp_err_t load_cal_data_from_nvs(nvs_handle handle, +static esp_err_t load_cal_data_from_nvs_handle(nvs_handle handle, esp_phy_calibration_data_t* out_cal_data); -static esp_err_t store_cal_data_to_nvs(nvs_handle handle, +static esp_err_t store_cal_data_to_nvs_handle(nvs_handle handle, const esp_phy_calibration_data_t* cal_data); -esp_err_t esp_phy_load_cal_data(esp_phy_calibration_data_t* out_cal_data) +esp_err_t esp_phy_load_cal_data_from_nvs(esp_phy_calibration_data_t* out_cal_data) { nvs_handle handle; esp_err_t err = nvs_open(PHY_NAMESPACE, NVS_READONLY, &handle); @@ -156,13 +129,13 @@ esp_err_t esp_phy_load_cal_data(esp_phy_calibration_data_t* out_cal_data) return err; } else { - err = load_cal_data_from_nvs(handle, out_cal_data); + err = load_cal_data_from_nvs_handle(handle, out_cal_data); nvs_close(handle); return err; } } -esp_err_t esp_phy_store_cal_data(const esp_phy_calibration_data_t* cal_data) +esp_err_t esp_phy_store_cal_data_to_nvs(const esp_phy_calibration_data_t* cal_data) { nvs_handle handle; esp_err_t err = nvs_open(PHY_NAMESPACE, NVS_READWRITE, &handle); @@ -171,13 +144,14 @@ esp_err_t esp_phy_store_cal_data(const esp_phy_calibration_data_t* cal_data) return err; } else { - err = store_cal_data_to_nvs(handle, cal_data); + err = store_cal_data_to_nvs_handle(handle, cal_data); nvs_close(handle); return err; } } -static esp_err_t load_cal_data_from_nvs(nvs_handle handle, esp_phy_calibration_data_t* out_cal_data) +static esp_err_t load_cal_data_from_nvs_handle(nvs_handle handle, + esp_phy_calibration_data_t* out_cal_data) { esp_err_t err; uint32_t cal_data_version; @@ -186,7 +160,8 @@ static esp_err_t load_cal_data_from_nvs(nvs_handle handle, esp_phy_calibration_d ESP_LOGD(TAG, "%s: failed to get cal_version (%d)", __func__, err); return err; } - uint32_t cal_format_version = phy_get_rf_cal_version(); + uint32_t cal_format_version = phy_get_rf_cal_version() & (~BIT(16)); + ESP_LOGV(TAG, "phy_get_rf_cal_version: %d\n", cal_format_version); if (cal_data_version != cal_format_version) { ESP_LOGD(TAG, "%s: expected calibration data format %d, found %d", __func__, cal_format_version, cal_data_version); @@ -224,11 +199,12 @@ static esp_err_t load_cal_data_from_nvs(nvs_handle handle, esp_phy_calibration_d return ESP_OK; } -static esp_err_t store_cal_data_to_nvs(nvs_handle handle, +static esp_err_t store_cal_data_to_nvs_handle(nvs_handle handle, const esp_phy_calibration_data_t* cal_data) { esp_err_t err; - uint32_t cal_format_version = phy_get_rf_cal_version(); + uint32_t cal_format_version = phy_get_rf_cal_version() & (~BIT(16)); + ESP_LOGV(TAG, "phy_get_rf_cal_version: %d\n", cal_format_version); err = nvs_set_u32(handle, PHY_CAL_VERSION_KEY, cal_format_version); if (err != ESP_OK) { return err; @@ -243,22 +219,6 @@ static esp_err_t store_cal_data_to_nvs(nvs_handle handle, return err; } -#else // CONFIG_ESP32_STORE_PHY_CALIBRATION_DATA_IN_NVS - -// Default implementation: don't store or load calibration data. -// These functions are defined as weak and can be overridden in the application. - -esp_err_t esp_phy_store_cal_data(const esp_phy_calibration_data_t* cal_data) __attribute__((weak)) +void register_chipv7_phy_stub() { - // pretend that calibration data is stored - return ESP_OK; } - -esp_err_t esp_phy_load_cal_data(const esp_phy_calibration_data_t* cal_data) __attribute__((weak)) -{ - // nowhere to load data from - return ESP_ERR_NOT_SUPPORTED; -} - -#endif // CONFIG_ESP32_STORE_PHY_CALIBRATION_DATA_IN_NVS - diff --git a/components/nvs_flash/src/nvs_api.cpp b/components/nvs_flash/src/nvs_api.cpp index 751542ee12..7c9ec89a6f 100644 --- a/components/nvs_flash/src/nvs_api.cpp +++ b/components/nvs_flash/src/nvs_api.cpp @@ -62,6 +62,13 @@ extern "C" void nvs_dump() s_nvs_storage.debugDump(); } +extern "C" esp_err_t nvs_flash_init_custom(uint32_t baseSector, uint32_t sectorCount) +{ + ESP_LOGD(TAG, "nvs_flash_init_custom start=%d count=%d", baseSector, sectorCount); + s_nvs_handles.clear(); + return s_nvs_storage.init(baseSector, sectorCount); +} + #ifdef ESP_PLATFORM extern "C" esp_err_t nvs_flash_init(void) { @@ -81,13 +88,6 @@ extern "C" esp_err_t nvs_flash_init(void) } #endif -extern "C" esp_err_t nvs_flash_init_custom(uint32_t baseSector, uint32_t sectorCount) -{ - ESP_LOGD(TAG, "nvs_flash_init_custom start=%d count=%d", baseSector, sectorCount); - s_nvs_handles.clear(); - return s_nvs_storage.init(baseSector, sectorCount); -} - static esp_err_t nvs_find_ns_handle(nvs_handle handle, HandleEntry& entry) { auto it = find_if(begin(s_nvs_handles), end(s_nvs_handles), [=](HandleEntry& e) -> bool {