phy_init: reduce the amount of hardwired logic, add coexist init

This commit is contained in:
Ivan Grokhotkov 2016-11-18 01:18:39 +08:00
parent 6d4ab76db2
commit 541b142654
8 changed files with 185 additions and 122 deletions

View file

@ -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'.

View file

@ -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
}

View file

@ -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
}

View file

@ -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

@ -1 +1 @@
Subproject commit db867fe9128cc1fc273d76af5a412f6743519149
Subproject commit a580f70a64872a7cc291b1f22455f6adbc2e35cf

View file

@ -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

View file

@ -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

View file

@ -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 {