kopia lustrzana https://github.com/espressif/esp-idf
add PHY init support
rodzic
a0feea8daa
commit
4db29f74a0
|
@ -364,4 +364,58 @@ 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"
|
||||
default y
|
||||
help
|
||||
If enabled, PHY will be initialized in startup code, before
|
||||
app_main function runs.
|
||||
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 unsure, choose 'y'.
|
||||
|
||||
config ESP32_PHY_INIT_DATA_IN_PARTITION
|
||||
bool "Use a partition to store PHY init data"
|
||||
default n
|
||||
help
|
||||
If enabled, PHY init data will be loaded from a partition.
|
||||
When using a custom partition table, make sure that PHY data
|
||||
partition is included (type: 'data', subtype: 'phy').
|
||||
With default partition tables, this is done automatically.
|
||||
If PHY init data is stored in a partition, it has to be flashed there,
|
||||
otherwise runtime error will occur.
|
||||
|
||||
If this option is not enabled, PHY init data will be embedded
|
||||
into the application binary.
|
||||
|
||||
If unsure, choose 'n'.
|
||||
|
||||
config ESP32_PHY_MAX_TX_POWER
|
||||
int "Max TX power (dBm)"
|
||||
range 0 20
|
||||
default 20
|
||||
help
|
||||
Set maximum transmit power. Actual transmit power for high
|
||||
data rates may be lower than this setting.
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
ifdef CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION
|
||||
|
||||
PHY_INIT_DATA_OBJ = $(BUILD_DIR_BASE)/phy_init_data.o
|
||||
PHY_INIT_DATA_BIN = $(BUILD_DIR_BASE)/phy_init_data.bin
|
||||
|
||||
PARTITION_TABLE_COMPONENT_PATH := $(COMPONENT_PATH)/../partition_table
|
||||
ESP32_COMPONENT_PATH := $(COMPONENT_PATH)
|
||||
|
||||
GEN_ESP32PART := $(PYTHON) $(PARTITION_TABLE_COMPONENT_PATH)/gen_esp32part.py -q
|
||||
|
||||
# Path to partition CSV file is relative to project path for custom
|
||||
# partition CSV files, but relative to component dir otherwise.
|
||||
PARTITION_TABLE_ROOT := $(call dequote,$(if $(CONFIG_PARTITION_TABLE_CUSTOM),$(PROJECT_PATH),$(PARTITION_TABLE_COMPONENT_PATH)))
|
||||
PARTITION_TABLE_CSV_PATH := $(call dequote,$(abspath $(PARTITION_TABLE_ROOT)/$(subst $(quote),,$(CONFIG_PARTITION_TABLE_FILENAME))))
|
||||
PARTITION_TABLE_BIN := $(BUILD_DIR_BASE)/$(notdir $(PARTITION_TABLE_CSV_PATH:.csv=.bin))
|
||||
|
||||
# Parse partition table and get offset of PHY init data partition
|
||||
PHY_INIT_GET_ADDR_CMD := $(GEN_ESP32PART) $(PARTITION_TABLE_CSV_PATH) | $(GEN_ESP32PART) - | sed -n -e "s/[^,]*,data,phy,\\([^,]*\\),.*/\\1/p"
|
||||
PHY_INIT_DATA_ADDR = $(shell $(PHY_INIT_GET_ADDR_CMD))
|
||||
|
||||
# Command to flash PHY init data partition
|
||||
PHY_INIT_DATA_FLASH_CMD = $(ESPTOOLPY_SERIAL) write_flash $(PHY_INIT_DATA_ADDR) $(PHY_INIT_DATA_BIN)
|
||||
ESPTOOL_ALL_FLASH_ARGS += $(PHY_INIT_DATA_ADDR) $(PHY_INIT_DATA_BIN)
|
||||
|
||||
$(PHY_INIT_DATA_OBJ): $(ESP32_COMPONENT_PATH)/phy_init_data.h $(BUILD_DIR_BASE)/include/sdkconfig.h
|
||||
$(summary) CC $(notdir $@)
|
||||
printf "#include \"phy_init_data.h\"\n" | $(CC) -I $(BUILD_DIR_BASE)/include -I $(ESP32_COMPONENT_PATH) -I $(ESP32_COMPONENT_PATH)/include -c -o $@ -xc -
|
||||
|
||||
$(PHY_INIT_DATA_BIN): $(PHY_INIT_DATA_OBJ)
|
||||
$(summary) BIN $(notdir $@)
|
||||
$(OBJCOPY) -O binary $< $@
|
||||
|
||||
phy_init_data: $(PHY_INIT_DATA_BIN)
|
||||
|
||||
phy_init_data-flash: $(BUILD_DIR_BASE)/phy_init_data.bin
|
||||
@echo "Flashing PHY init data..."
|
||||
$(PHY_INIT_DATA_FLASH_CMD)
|
||||
|
||||
phy_init_data-clean:
|
||||
rm -f $(PHY_INIT_DATA_BIN) $(PHY_INIT_DATA_OBJ)
|
||||
|
||||
endif # CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION
|
|
@ -50,6 +50,7 @@
|
|||
#include "esp_brownout.h"
|
||||
#include "esp_int_wdt.h"
|
||||
#include "esp_task_wdt.h"
|
||||
#include "esp_phy_init.h"
|
||||
#include "trax.h"
|
||||
|
||||
void start_cpu0(void) __attribute__((weak, alias("start_cpu0_default")));
|
||||
|
@ -187,6 +188,20 @@ void start_cpu0_default(void)
|
|||
esp_ipc_init();
|
||||
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();
|
||||
}
|
||||
#endif
|
||||
|
||||
xTaskCreatePinnedToCore(&main_task, "main",
|
||||
ESP_TASK_MAIN_STACK, NULL,
|
||||
ESP_TASK_MAIN_PRIO, NULL, 0);
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
// Copyright 2015-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.
|
||||
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
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 */
|
||||
uint8_t wifi_rx_gain_swp_step_1; /*!< do not change */
|
||||
uint8_t wifi_rx_gain_swp_step_2; /*!< do not change */
|
||||
uint8_t wifi_rx_gain_swp_step_3; /*!< do not change */
|
||||
uint8_t wifi_rx_gain_swp_step_4; /*!< do not change */
|
||||
uint8_t wifi_rx_gain_swp_step_5; /*!< do not change */
|
||||
uint8_t wifi_rx_gain_swp_step_6; /*!< do not change */
|
||||
uint8_t wifi_rx_gain_swp_step_7; /*!< do not change */
|
||||
uint8_t wifi_rx_gain_swp_step_8; /*!< do not change */
|
||||
uint8_t wifi_rx_gain_swp_step_9; /*!< do not change */
|
||||
uint8_t wifi_rx_gain_swp_step_10; /*!< do not change */
|
||||
uint8_t wifi_rx_gain_swp_step_11; /*!< do not change */
|
||||
uint8_t wifi_rx_gain_swp_step_12; /*!< do not change */
|
||||
uint8_t wifi_rx_gain_swp_step_13; /*!< do not change */
|
||||
uint8_t wifi_rx_gain_swp_step_14; /*!< do not change */
|
||||
uint8_t wifi_rx_gain_swp_step_15; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_1; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_2; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_3; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_4; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_5; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_6; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_7; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_8; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_9; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_10; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_11; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_12; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_13; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_14; /*!< do not change */
|
||||
uint8_t bt_rx_gain_swp_step_15; /*!< do not change */
|
||||
uint8_t gain_cmp_1; /*!< do not change */
|
||||
uint8_t gain_cmp_6; /*!< do not change */
|
||||
uint8_t gain_cmp_11; /*!< do not change */
|
||||
uint8_t gain_cmp_ext2_1; /*!< do not change */
|
||||
uint8_t gain_cmp_ext2_6; /*!< do not change */
|
||||
uint8_t gain_cmp_ext2_11; /*!< do not change */
|
||||
uint8_t gain_cmp_ext3_1; /*!< do not change */
|
||||
uint8_t gain_cmp_ext3_6; /*!< do not change */
|
||||
uint8_t gain_cmp_ext3_11; /*!< do not change */
|
||||
uint8_t gain_cmp_bt_ofs_1; /*!< do not change */
|
||||
uint8_t gain_cmp_bt_ofs_6; /*!< do not change */
|
||||
uint8_t gain_cmp_bt_ofs_11; /*!< do not change */
|
||||
uint8_t target_power_qdb_0; /*!< 78 means target power is 78/4=19.5dbm */
|
||||
uint8_t target_power_qdb_1; /*!< 76 means target power is 76/4=19dbm */
|
||||
uint8_t target_power_qdb_2; /*!< 74 means target power is 74/4=18.5dbm */
|
||||
uint8_t target_power_qdb_3; /*!< 68 means target power is 68/4=17dbm */
|
||||
uint8_t target_power_qdb_4; /*!< 64 means target power is 64/4=16dbm */
|
||||
uint8_t target_power_qdb_5; /*!< 52 means target power is 52/4=13dbm */
|
||||
uint8_t target_power_index_mcs0; /*!< target power index is 0, means target power is target_power_qdb_0 19.5dbm; (1m,2m,5.5m,11m,6m,9m) */
|
||||
uint8_t target_power_index_mcs1; /*!< target power index is 0, means target power is target_power_qdb_0 19.5dbm; (12m) */
|
||||
uint8_t target_power_index_mcs2; /*!< target power index is 1, means target power is target_power_qdb_1 19dbm; (18m) */
|
||||
uint8_t target_power_index_mcs3; /*!< target power index is 1, means target power is target_power_qdb_1 19dbm; (24m) */
|
||||
uint8_t target_power_index_mcs4; /*!< target power index is 2, means target power is target_power_qdb_2 18.5dbm; (36m) */
|
||||
uint8_t target_power_index_mcs5; /*!< target power index is 3, means target power is target_power_qdb_3 17dbm; (48m) */
|
||||
uint8_t target_power_index_mcs6; /*!< target power index is 4, means target power is target_power_qdb_4 16dbm; (54m) */
|
||||
uint8_t target_power_index_mcs7; /*!< target power index is 5, means target power is target_power_qdb_5 13dbm */
|
||||
uint8_t pwr_ind_11b_en; /*!< 0: 11b power is same as mcs0 and 6m, 1: 11b power different with OFDM */
|
||||
uint8_t pwr_ind_11b_0; /*!< 1m, 2m power index [0~5] */
|
||||
uint8_t pwr_ind_11b_1; /*!< 5.5m, 11m power index [0~5] */
|
||||
uint8_t chan_backoff_en; /*!< 0: channel backoff disable, 1:channel backoff enable */
|
||||
uint8_t chan1_power_backoff_qdb; /*!< 4 means backoff is 1db */
|
||||
uint8_t chan2_power_backoff_qdb; /*!< see chan1_power_backoff_qdb */
|
||||
uint8_t chan3_power_backoff_qdb; /*!< chan1_power_backoff_qdb */
|
||||
uint8_t chan4_power_backoff_qdb; /*!< chan1_power_backoff_qdb */
|
||||
uint8_t chan5_power_backoff_qdb; /*!< chan1_power_backoff_qdb */
|
||||
uint8_t chan6_power_backoff_qdb; /*!< chan1_power_backoff_qdb */
|
||||
uint8_t chan7_power_backoff_qdb; /*!< chan1_power_backoff_qdb */
|
||||
uint8_t chan8_power_backoff_qdb; /*!< chan1_power_backoff_qdb */
|
||||
uint8_t chan9_power_backoff_qdb; /*!< chan1_power_backoff_qdb */
|
||||
uint8_t chan10_power_backoff_qdb; /*!< chan1_power_backoff_qdb */
|
||||
uint8_t chan11_power_backoff_qdb; /*!< chan1_power_backoff_qdb */
|
||||
uint8_t chan12_power_backoff_qdb; /*!< chan1_power_backoff_qdb */
|
||||
uint8_t chan13_power_backoff_qdb; /*!< chan1_power_backoff_qdb */
|
||||
uint8_t chan14_power_backoff_qdb; /*!< chan1_power_backoff_qdb */
|
||||
uint8_t chan1_rate_backoff_index; /*!< if bit i is set, backoff data rate is target_power_qdb_i */
|
||||
uint8_t chan2_rate_backoff_index; /*!< see chan1_rate_backoff_index */
|
||||
uint8_t chan3_rate_backoff_index; /*!< see chan1_rate_backoff_index */
|
||||
uint8_t chan4_rate_backoff_index; /*!< see chan1_rate_backoff_index */
|
||||
uint8_t chan5_rate_backoff_index; /*!< see chan1_rate_backoff_index */
|
||||
uint8_t chan6_rate_backoff_index; /*!< see chan1_rate_backoff_index */
|
||||
uint8_t chan7_rate_backoff_index; /*!< see chan1_rate_backoff_index */
|
||||
uint8_t chan8_rate_backoff_index; /*!< see chan1_rate_backoff_index */
|
||||
uint8_t chan9_rate_backoff_index; /*!< see chan1_rate_backoff_index */
|
||||
uint8_t chan10_rate_backoff_index; /*!< see chan1_rate_backoff_index */
|
||||
uint8_t chan11_rate_backoff_index; /*!< see chan1_rate_backoff_index */
|
||||
uint8_t chan12_rate_backoff_index; /*!< see chan1_rate_backoff_index */
|
||||
uint8_t chan13_rate_backoff_index; /*!< see chan1_rate_backoff_index */
|
||||
uint8_t chan14_rate_backoff_index; /*!< see chan1_rate_backoff_index */
|
||||
uint8_t spur_freq_cfg_msb_1; /*!< first spur: */
|
||||
uint8_t spur_freq_cfg_1; /*!< spur_freq_cfg = (spur_freq_cfg_msb_1 <<8) | spur_freq_cfg_1 */
|
||||
uint8_t spur_freq_cfg_div_1; /*!< spur_freq=spur_freq_cfg/spur_freq_cfg_div_1 */
|
||||
uint8_t spur_freq_en_h_1; /*!< the seventh bit for total enable */
|
||||
uint8_t spur_freq_en_l_1; /*!< each bit for 1 channel, and use [spur_freq_en_h, spur_freq_en_l] to select the spur's channel priority */
|
||||
uint8_t spur_freq_cfg_msb_2; /*!< second spur: */
|
||||
uint8_t spur_freq_cfg_2; /*!< spur_freq_cfg = (spur_freq_cfg_msb_2 <<8) | spur_freq_cfg_2 */
|
||||
uint8_t spur_freq_cfg_div_2; /*!< spur_freq=spur_freq_cfg/spur_freq_cfg_div_2 */
|
||||
uint8_t spur_freq_en_h_2; /*!< the seventh bit for total enable */
|
||||
uint8_t spur_freq_en_l_2; /*!< each bit for 1 channel, and use [spur_freq_en_h, spur_freq_en_l] to select the spur's channel priority */
|
||||
uint8_t spur_freq_cfg_msb_3; /*!< third spur: */
|
||||
uint8_t spur_freq_cfg_3; /*!< spur_freq_cfg = (spur_freq_cfg_msb_3 <<8) | spur_freq_cfg_3 */
|
||||
uint8_t spur_freq_cfg_div_3; /*!< spur_freq=spur_freq_cfg/spur_freq_cfg_div_3 */
|
||||
uint8_t spur_freq_en_h_3; /*!< the seventh bit for total enable */
|
||||
uint8_t spur_freq_en_l_3; /*!< each bit for 1 channel, and use [spur_freq_en_h, spur_freq_en_l] to select the spur's channel priority, */
|
||||
uint8_t reserved[23]; /*!< reserved for future expansion */
|
||||
} esp_phy_init_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t opaque[1904]; /*!< opaque calibration data */
|
||||
} esp_phy_calibration_data_t;
|
||||
|
||||
typedef enum {
|
||||
PHY_RF_CAL_PARTIAL = 0x00000000, /*!< Do part of RF calibration. This should be used after power-on reset. */
|
||||
PHY_RF_CAL_NONE = 0x00000001, /*!< Don't do any RF calibration. This mode is only suggested to be used after deep sleep reset. */
|
||||
PHY_RF_CAL_FULL = 0x00000002 /*!< Do full RF calibration. Produces best results, but also consumes a lot of time and current. Suggested to be used once. */
|
||||
} esp_phy_calibration_mode_t;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param mode
|
||||
* @return
|
||||
*/
|
||||
esp_err_t esp_phy_init(esp_phy_calibration_mode_t mode);
|
||||
|
||||
#ifndef CONFIG_ESP32_STORE_PHY_CALIBRATION_DATA_IN_NVS
|
||||
|
||||
/**
|
||||
*
|
||||
* @param cal_data
|
||||
* @return
|
||||
*/
|
||||
esp_err_t esp_phy_store_cal_data(const esp_phy_calibration_data_t* cal_data);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param out_cal_data
|
||||
* @return
|
||||
*/
|
||||
esp_err_t esp_phy_load_cal_data(esp_phy_calibration_data_t* out_cal_data);
|
||||
|
||||
#endif // CONFIG_ESP32_STORE_PHY_CALIBRATION_DATA_IN_NVS
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit e188536a6315cc3ce4f1006ac3a4450faea6abc6
|
||||
Subproject commit db867fe9128cc1fc273d76af5a412f6743519149
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright 2015-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.
|
||||
|
||||
#pragma once
|
||||
#include "esp_phy_init.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file phy.h
|
||||
* @brief Declarations for functions provided by libphy.a
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Initialize function pointer table in PHY library.
|
||||
* @note This function should be called before register_chipv7_phy.
|
||||
*/
|
||||
void phy_get_romfunc_addr(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize PHY module and do RF calibration
|
||||
* @param[in] init_data Initialization parameters to be used by the PHY
|
||||
* @param[inout] cal_data As input, calibration data previously obtained. As output, will contain new calibration data.
|
||||
* @param[in] cal_mode RF calibration mode
|
||||
* @return reserved for future use
|
||||
*/
|
||||
int register_chipv7_phy(const esp_phy_init_data_t* init_data, esp_phy_calibration_data_t *cal_data, esp_phy_calibration_mode_t cal_mode);
|
||||
|
||||
/**
|
||||
* @brief Get the format version of calibration data used by PHY library.
|
||||
* @return Format version number
|
||||
*/
|
||||
uint32_t phy_get_rf_cal_version();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,264 @@
|
|||
// Copyright 2015-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 <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "rom/ets_sys.h"
|
||||
#include "soc/dport_reg.h"
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_phy_init.h"
|
||||
#include "esp_system.h"
|
||||
#include "phy.h"
|
||||
#include "esp_log.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_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
|
||||
phy_get_romfunc_addr();
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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_partition_t* partition = esp_partition_find_first(
|
||||
ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_PHY, NULL);
|
||||
if (partition == NULL) {
|
||||
ESP_LOGE(TAG, "PHY data partition not found");
|
||||
return NULL;
|
||||
}
|
||||
ESP_LOGD(TAG, "loading PHY init data from partition at offset 0x%x", partition->address);
|
||||
size_t init_data_store_length = sizeof(phy_init_magic_pre) +
|
||||
sizeof(esp_phy_init_data_t) + sizeof(phy_init_magic_post);
|
||||
uint8_t* init_data_store = (uint8_t*) malloc(init_data_store_length);
|
||||
if (init_data_store == NULL) {
|
||||
ESP_LOGE(TAG, "failed to allocate memory for PHY init data");
|
||||
return NULL;
|
||||
}
|
||||
esp_err_t err = esp_partition_read(partition, 0, init_data_store, init_data_store_length);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "failed to read PHY data partition (%d)", err);
|
||||
return NULL;
|
||||
}
|
||||
if (memcmp(init_data_store, PHY_INIT_MAGIC, sizeof(phy_init_magic_pre)) != 0 ||
|
||||
memcmp(init_data_store + init_data_store_length - sizeof(phy_init_magic_post),
|
||||
PHY_INIT_MAGIC, sizeof(phy_init_magic_post)) != 0) {
|
||||
ESP_LOGE(TAG, "failed to validate PHY data partition");
|
||||
return NULL;
|
||||
}
|
||||
ESP_LOGE(TAG, "PHY data partition validated");
|
||||
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)
|
||||
{
|
||||
free((uint8_t*) init_data - sizeof(phy_init_magic_pre));
|
||||
}
|
||||
|
||||
#else // CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION
|
||||
|
||||
// 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()
|
||||
{
|
||||
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)
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
#endif // CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION
|
||||
|
||||
|
||||
// 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,
|
||||
esp_phy_calibration_data_t* out_cal_data);
|
||||
|
||||
static esp_err_t store_cal_data_to_nvs(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)
|
||||
{
|
||||
nvs_handle handle;
|
||||
esp_err_t err = nvs_open(PHY_NAMESPACE, NVS_READONLY, &handle);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGD(TAG, "%s: failed to open NVS namespace (%d)", __func__, err);
|
||||
return err;
|
||||
}
|
||||
else {
|
||||
err = load_cal_data_from_nvs(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)
|
||||
{
|
||||
nvs_handle handle;
|
||||
esp_err_t err = nvs_open(PHY_NAMESPACE, NVS_READWRITE, &handle);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGD(TAG, "%s: failed to open NVS namespace (%d)", __func__, err);
|
||||
return err;
|
||||
}
|
||||
else {
|
||||
err = store_cal_data_to_nvs(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)
|
||||
{
|
||||
esp_err_t err;
|
||||
uint32_t cal_data_version;
|
||||
err = nvs_get_u32(handle, PHY_CAL_VERSION_KEY, &cal_data_version);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGD(TAG, "%s: failed to get cal_version (%d)", __func__, err);
|
||||
return err;
|
||||
}
|
||||
uint32_t cal_format_version = phy_get_rf_cal_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);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
uint8_t cal_data_mac[6];
|
||||
size_t length = sizeof(cal_data_mac);
|
||||
err = nvs_get_blob(handle, PHY_CAL_MAC_KEY, cal_data_mac, &length);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGD(TAG, "%s: failed to get cal_mac (%d)", __func__, err);
|
||||
return err;
|
||||
}
|
||||
if (length != sizeof(cal_data_mac)) {
|
||||
ESP_LOGD(TAG, "%s: invalid length of cal_mac (%d)", __func__, length);
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
uint8_t sta_mac[6];
|
||||
system_efuse_read_mac(sta_mac);
|
||||
if (memcmp(sta_mac, cal_data_mac, sizeof(sta_mac)) != 0) {
|
||||
ESP_LOGE(TAG, "%s: calibration data MAC check failed: expected " \
|
||||
MACSTR ", found " MACSTR,
|
||||
__func__, MAC2STR(sta_mac), MAC2STR(cal_data_mac));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
length = sizeof(*out_cal_data);
|
||||
err = nvs_get_blob(handle, PHY_CAL_DATA_KEY, out_cal_data, &length);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "%s: failed to get cal_data(%d)", __func__, err);
|
||||
return err;
|
||||
}
|
||||
if (length != sizeof(*out_cal_data)) {
|
||||
ESP_LOGD(TAG, "%s: invalid length of cal_data (%d)", __func__, length);
|
||||
return ESP_ERR_INVALID_SIZE;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t store_cal_data_to_nvs(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();
|
||||
err = nvs_set_u32(handle, PHY_CAL_VERSION_KEY, cal_format_version);
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
uint8_t sta_mac[6];
|
||||
system_efuse_read_mac(sta_mac);
|
||||
err = nvs_set_blob(handle, PHY_CAL_MAC_KEY, sta_mac, sizeof(sta_mac));
|
||||
if (err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
err = nvs_set_blob(handle, PHY_CAL_DATA_KEY, cal_data, sizeof(*cal_data));
|
||||
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))
|
||||
{
|
||||
// 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
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
// Copyright 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.
|
||||
|
||||
#pragma once
|
||||
#include "esp_phy_init.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
// constrain a value between 'low' and 'high', inclusive
|
||||
#define LIMIT(val, low, high) ((val < low) ? low : (val > high) ? high : val)
|
||||
|
||||
#define PHY_INIT_MAGIC "PHYINIT"
|
||||
|
||||
static const char phy_init_magic_pre[] = PHY_INIT_MAGIC;
|
||||
|
||||
/**
|
||||
* @brief Structure containing default recommended PHY initialization parameters.
|
||||
*/
|
||||
static const esp_phy_init_data_t phy_init_data= {
|
||||
.param_ver_id = 0,
|
||||
.crystal_select = 3,
|
||||
.wifi_rx_gain_swp_step_1 = 0x05,
|
||||
.wifi_rx_gain_swp_step_2 = 0x04,
|
||||
.wifi_rx_gain_swp_step_3 = 0x06,
|
||||
.wifi_rx_gain_swp_step_4 = 0x05,
|
||||
.wifi_rx_gain_swp_step_5 = 0x01,
|
||||
.wifi_rx_gain_swp_step_6 = 0x06,
|
||||
.wifi_rx_gain_swp_step_7 = 0x05,
|
||||
.wifi_rx_gain_swp_step_8 = 0x04,
|
||||
.wifi_rx_gain_swp_step_9 = 0x06,
|
||||
.wifi_rx_gain_swp_step_10 = 0x04,
|
||||
.wifi_rx_gain_swp_step_11 = 0x05,
|
||||
.wifi_rx_gain_swp_step_12 = 0x00,
|
||||
.wifi_rx_gain_swp_step_13 = 0x00,
|
||||
.wifi_rx_gain_swp_step_14 = 0x00,
|
||||
.wifi_rx_gain_swp_step_15 = 0x00,
|
||||
.bt_rx_gain_swp_step_1 = 0x05,
|
||||
.bt_rx_gain_swp_step_2 = 0x04,
|
||||
.bt_rx_gain_swp_step_3 = 0x06,
|
||||
.bt_rx_gain_swp_step_4 = 0x05,
|
||||
.bt_rx_gain_swp_step_5 = 0x01,
|
||||
.bt_rx_gain_swp_step_6 = 0x06,
|
||||
.bt_rx_gain_swp_step_7 = 0x05,
|
||||
.bt_rx_gain_swp_step_8 = 0x00,
|
||||
.bt_rx_gain_swp_step_9 = 0x00,
|
||||
.bt_rx_gain_swp_step_10 = 0x00,
|
||||
.bt_rx_gain_swp_step_11 = 0x00,
|
||||
.bt_rx_gain_swp_step_12 = 0x00,
|
||||
.bt_rx_gain_swp_step_13 = 0x00,
|
||||
.bt_rx_gain_swp_step_14 = 0x00,
|
||||
.bt_rx_gain_swp_step_15 = 0x00,
|
||||
.gain_cmp_1 = 0x0a,
|
||||
.gain_cmp_6 = 0x0a,
|
||||
.gain_cmp_11 = 0x0c,
|
||||
.gain_cmp_ext2_1 = 0xf0,
|
||||
.gain_cmp_ext2_6 = 0xf0,
|
||||
.gain_cmp_ext2_11 = 0xf0,
|
||||
.gain_cmp_ext3_1 = 0xe0,
|
||||
.gain_cmp_ext3_6 = 0xe0,
|
||||
.gain_cmp_ext3_11 = 0xe0,
|
||||
.gain_cmp_bt_ofs_1 = 0x18,
|
||||
.gain_cmp_bt_ofs_6 = 0x18,
|
||||
.gain_cmp_bt_ofs_11 = 0x18,
|
||||
.target_power_qdb_0 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 78),
|
||||
.target_power_qdb_1 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 76),
|
||||
.target_power_qdb_2 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 74),
|
||||
.target_power_qdb_3 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 68),
|
||||
.target_power_qdb_4 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 64),
|
||||
.target_power_qdb_5 = LIMIT(CONFIG_ESP32_PHY_MAX_TX_POWER * 4, 0, 52),
|
||||
.target_power_index_mcs0 = 0,
|
||||
.target_power_index_mcs1 = 0,
|
||||
.target_power_index_mcs2 = 1,
|
||||
.target_power_index_mcs3 = 1,
|
||||
.target_power_index_mcs4 = 2,
|
||||
.target_power_index_mcs5 = 3,
|
||||
.target_power_index_mcs6 = 4,
|
||||
.target_power_index_mcs7 = 5,
|
||||
.pwr_ind_11b_en = 0,
|
||||
.pwr_ind_11b_0 = 0,
|
||||
.pwr_ind_11b_1 = 0,
|
||||
.chan_backoff_en = 0,
|
||||
.chan1_power_backoff_qdb = 0,
|
||||
.chan2_power_backoff_qdb = 0,
|
||||
.chan3_power_backoff_qdb = 0,
|
||||
.chan4_power_backoff_qdb = 0,
|
||||
.chan5_power_backoff_qdb = 0,
|
||||
.chan6_power_backoff_qdb = 0,
|
||||
.chan7_power_backoff_qdb = 0,
|
||||
.chan8_power_backoff_qdb = 0,
|
||||
.chan9_power_backoff_qdb = 0,
|
||||
.chan10_power_backoff_qdb = 0,
|
||||
.chan11_power_backoff_qdb = 0,
|
||||
.chan12_power_backoff_qdb = 0,
|
||||
.chan13_power_backoff_qdb = 0,
|
||||
.chan14_power_backoff_qdb = 0,
|
||||
.chan1_rate_backoff_index = 0,
|
||||
.chan2_rate_backoff_index = 0,
|
||||
.chan3_rate_backoff_index = 0,
|
||||
.chan4_rate_backoff_index = 0,
|
||||
.chan5_rate_backoff_index = 0,
|
||||
.chan6_rate_backoff_index = 0,
|
||||
.chan7_rate_backoff_index = 0,
|
||||
.chan8_rate_backoff_index = 0,
|
||||
.chan9_rate_backoff_index = 0,
|
||||
.chan10_rate_backoff_index = 0,
|
||||
.chan11_rate_backoff_index = 0,
|
||||
.chan12_rate_backoff_index = 0,
|
||||
.chan13_rate_backoff_index = 0,
|
||||
.chan14_rate_backoff_index = 0,
|
||||
.spur_freq_cfg_msb_1 = 0,
|
||||
.spur_freq_cfg_1 = 0,
|
||||
.spur_freq_cfg_div_1 = 0,
|
||||
.spur_freq_en_h_1 = 0,
|
||||
.spur_freq_en_l_1 = 0,
|
||||
.spur_freq_cfg_msb_2 = 0,
|
||||
.spur_freq_cfg_2 = 0,
|
||||
.spur_freq_cfg_div_2 = 0,
|
||||
.spur_freq_en_h_2 = 0,
|
||||
.spur_freq_en_l_2 = 0,
|
||||
.spur_freq_cfg_msb_3 = 0,
|
||||
.spur_freq_cfg_3 = 0,
|
||||
.spur_freq_cfg_div_3 = 0,
|
||||
.spur_freq_en_h_3 = 0,
|
||||
.spur_freq_en_l_3 = 0,
|
||||
.reserved = {0}
|
||||
};
|
||||
|
||||
static const char phy_init_magic_post[] = PHY_INIT_MAGIC;
|
||||
|
Ładowanie…
Reference in New Issue