Merge pull request #135 from SuperHouse/feature/phy

PHY management features
This commit is contained in:
Angus Gratton 2016-05-16 07:51:44 +10:00
commit 3da022c132
8 changed files with 770 additions and 40 deletions

View file

@ -24,6 +24,7 @@
#include "os_version.h" #include "os_version.h"
#include "espressif/esp_common.h" #include "espressif/esp_common.h"
#include "espressif/phy_info.h"
#include "sdk_internal.h" #include "sdk_internal.h"
/* This is not declared in any header file (but arguably should be) */ /* This is not declared in any header file (but arguably should be) */
@ -31,8 +32,6 @@
void user_init(void); void user_init(void);
#define BOOT_INFO_SIZE 28 #define BOOT_INFO_SIZE 28
//TODO: phy_info should probably be a struct (no idea about its organization, though)
#define PHY_INFO_SIZE 128
// These are the offsets of these values within the RTCMEM regions. It appears // These are the offsets of these values within the RTCMEM regions. It appears
// that the ROM saves them to RTCMEM before calling us, and we pull them out of // that the ROM saves them to RTCMEM before calling us, and we pull them out of
@ -45,26 +44,6 @@ void user_init(void);
extern uint32_t _bss_start; extern uint32_t _bss_start;
extern uint32_t _bss_end; extern uint32_t _bss_end;
// .Ldata003 -- .irom.text+0x0
static const uint8_t IROM default_phy_info[PHY_INFO_SIZE] = {
0x05, 0x00, 0x04, 0x02, 0x05, 0x05, 0x05, 0x02,
0x05, 0x00, 0x04, 0x05, 0x05, 0x04, 0x05, 0x05,
0x04, 0xfe, 0xfd, 0xff, 0xf0, 0xf0, 0xf0, 0xe0,
0xe0, 0xe0, 0xe1, 0x0a, 0xff, 0xff, 0xf8, 0x00,
0xf8, 0xf8, 0x52, 0x4e, 0x4a, 0x44, 0x40, 0x38,
0x00, 0x00, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xe1, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x93, 0x43, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
// user_init_flag -- .bss+0x0 // user_init_flag -- .bss+0x0
uint8_t sdk_user_init_flag; uint8_t sdk_user_init_flag;
@ -82,7 +61,7 @@ xTaskHandle sdk_xWatchDogTaskHandle;
static void IRAM get_otp_mac_address(uint8_t *buf); static void IRAM get_otp_mac_address(uint8_t *buf);
static void IRAM set_spi0_divisor(uint32_t divisor); static void IRAM set_spi0_divisor(uint32_t divisor);
static void zero_bss(void); static void zero_bss(void);
static void init_networking(uint8_t *phy_info, uint8_t *mac_addr); static void init_networking(sdk_phy_info_t *phy_info, uint8_t *mac_addr);
static void init_g_ic(void); static void init_g_ic(void);
static void dump_excinfo(void); static void dump_excinfo(void);
static void user_start_phase2(void); static void user_start_phase2(void);
@ -273,7 +252,7 @@ static void zero_bss(void) {
} }
// .Lfunc006 -- .irom0.text+0x70 // .Lfunc006 -- .irom0.text+0x70
static void init_networking(uint8_t *phy_info, uint8_t *mac_addr) { static void init_networking(sdk_phy_info_t *phy_info, uint8_t *mac_addr) {
if (sdk_register_chipv6_phy(phy_info)) { if (sdk_register_chipv6_phy(phy_info)) {
printf("FATAL: sdk_register_chipv6_phy failed"); printf("FATAL: sdk_register_chipv6_phy failed");
halt(); halt();
@ -413,7 +392,7 @@ extern void (*__init_array_end)(void);
// .Lfunc009 -- .irom0.text+0x5b4 // .Lfunc009 -- .irom0.text+0x5b4
static __attribute__((noinline)) void user_start_phase2(void) { static __attribute__((noinline)) void user_start_phase2(void) {
uint8_t *buf; uint8_t *buf;
uint8_t *phy_info; sdk_phy_info_t phy_info, default_phy_info;
sdk_system_rtc_mem_read(0, &sdk_rst_if, sizeof(sdk_rst_if)); sdk_system_rtc_mem_read(0, &sdk_rst_if, sizeof(sdk_rst_if));
if (sdk_rst_if.version > 3) { if (sdk_rst_if.version > 3) {
@ -431,8 +410,16 @@ static __attribute__((noinline)) void user_start_phase2(void) {
sdk_info._unknown1 = 0x00ffffff; sdk_info._unknown1 = 0x00ffffff;
sdk_info._unknown2 = 0x0104a8c0; sdk_info._unknown2 = 0x0104a8c0;
init_g_ic(); init_g_ic();
phy_info = malloc(PHY_INFO_SIZE);
sdk_spi_flash_read(sdk_flashchip.chip_size - sdk_flashchip.sector_size * 4, (uint32_t *)phy_info, PHY_INFO_SIZE); read_saved_phy_info(&phy_info);
get_default_phy_info(&default_phy_info);
if (phy_info.version != default_phy_info.version) {
/* Versions don't match, use default for PHY info
(may be a blank config sector, or a new default version.)
*/
memcpy(&phy_info, &default_phy_info, sizeof(sdk_phy_info_t));
}
// Disable default buffering on stdout // Disable default buffering on stdout
setbuf(stdout, NULL); setbuf(stdout, NULL);
@ -440,13 +427,7 @@ static __attribute__((noinline)) void user_start_phase2(void) {
uart_flush_txfifo(0); uart_flush_txfifo(0);
uart_flush_txfifo(1); uart_flush_txfifo(1);
if (phy_info[0] != 5) { init_networking(&phy_info, sdk_info.sta_mac_addr);
// Bad version byte. Discard what we read and use default values
// instead.
memcpy(phy_info, default_phy_info, PHY_INFO_SIZE);
}
init_networking(phy_info, sdk_info.sta_mac_addr);
free(phy_info);
// Call gcc constructor functions // Call gcc constructor functions
void (**ctor)(void); void (**ctor)(void);
@ -487,7 +468,7 @@ static __attribute__((noinline)) void dump_flash_config_sectors(uint32_t start_s
printf("system param error\n"); printf("system param error\n");
// Note: original SDK code didn't dump PHY info // Note: original SDK code didn't dump PHY info
printf("phy_info:\n"); printf("phy_info:\n");
dump_flash_sector(start_sector, PHY_INFO_SIZE); dump_flash_sector(start_sector, sizeof(sdk_phy_info_t));
printf("\ng_ic saved 0:\n"); printf("\ng_ic saved 0:\n");
dump_flash_sector(start_sector + 1, sizeof(struct sdk_g_ic_saved_st)); dump_flash_sector(start_sector + 1, sizeof(struct sdk_g_ic_saved_st));
printf("\ng_ic saved 1:\n"); printf("\ng_ic saved 1:\n");

32
core/esp_phy.c Normal file
View file

@ -0,0 +1,32 @@
/** esp/phy.h
*
* PHY hardware management functions.
*
* Part of esp-open-rtos
* Copyright (C) 2016 ChefSteps, Inc
* BSD Licensed as described in the file LICENSE
*/
#include <esp/phy.h>
#include <esp/gpio.h>
void bt_coexist_configure(bt_coexist_mode_t mode, uint8_t bt_active_pin, uint8_t bt_priority_pin)
{
/* Disable coexistence entirely before changing pin assignments */
GPIO.OUT &= ~(GPIO_OUT_BT_COEXIST_MASK);
uint32_t new_mask = 0;
new_mask = VAL2FIELD_M(GPIO_OUT_BT_ACTIVE_PIN, bt_active_pin) +
VAL2FIELD_M(GPIO_OUT_BT_PRIORITY_PIN, bt_priority_pin);
if(mode == BT_COEXIST_USE_BT_ACTIVE || mode == BT_COEXIST_USE_BT_ACTIVE_PRIORITY) {
gpio_enable(bt_active_pin, GPIO_INPUT);
new_mask |= GPIO_OUT_BT_ACTIVE_ENABLE;
}
if(mode == BT_COEXIST_USE_BT_ACTIVE_PRIORITY) {
gpio_enable(bt_priority_pin, GPIO_INPUT);
new_mask |= GPIO_OUT_BT_PRIORITY_ENABLE;
}
GPIO.OUT |= new_mask;
}

View file

@ -81,9 +81,9 @@ static inline void gpio_set_output_on_sleep(const uint8_t gpio_num, bool enabled
static inline void gpio_write(const uint8_t gpio_num, const bool set) static inline void gpio_write(const uint8_t gpio_num, const bool set)
{ {
if (set) if (set)
GPIO.OUT_SET = BIT(gpio_num); GPIO.OUT_SET = BIT(gpio_num) & GPIO_OUT_PIN_MASK;
else else
GPIO.OUT_CLEAR = BIT(gpio_num); GPIO.OUT_CLEAR = BIT(gpio_num) & GPIO_OUT_PIN_MASK;
} }
/* Toggle output of a pin /* Toggle output of a pin
@ -102,9 +102,9 @@ static inline void gpio_toggle(const uint8_t gpio_num)
task's pins, without needing to disable/enable interrupts. task's pins, without needing to disable/enable interrupts.
*/ */
if(GPIO.OUT & BIT(gpio_num)) if(GPIO.OUT & BIT(gpio_num))
GPIO.OUT_CLEAR = BIT(gpio_num); GPIO.OUT_CLEAR = BIT(gpio_num) & GPIO_OUT_PIN_MASK;
else else
GPIO.OUT_SET = BIT(gpio_num); GPIO.OUT_SET = BIT(gpio_num) & GPIO_OUT_PIN_MASK;
} }
/* Read input value of a GPIO pin. /* Read input value of a GPIO pin.

View file

@ -61,6 +61,21 @@ struct GPIO_REGS {
_Static_assert(sizeof(struct GPIO_REGS) == 0x74, "GPIO_REGS is the wrong size"); _Static_assert(sizeof(struct GPIO_REGS) == 0x74, "GPIO_REGS is the wrong size");
/* Details for additional OUT register fields */
/* Bottom 16 bits of GPIO.OUT are for GPIOs 0-15, but upper 16 bits
are used to configure the input signalling pins for Bluetooth
Coexistence config (see esp/phy.h for a wrapper function).
*/
#define GPIO_OUT_PIN_MASK 0x0000FFFF
#define GPIO_OUT_BT_COEXIST_MASK 0x03FF0000
#define GPIO_OUT_BT_ACTIVE_ENABLE BIT(24)
#define GPIO_OUT_BT_PRIORITY_ENABLE BIT(25)
#define GPIO_OUT_BT_ACTIVE_PIN_M 0x0F
#define GPIO_OUT_BT_ACTIVE_PIN_S 16
#define GPIO_OUT_BT_PRIORITY_PIN_M 0x0F
#define GPIO_OUT_BT_PRIORITY_PIN_S 20
/* Details for CONF[i] registers */ /* Details for CONF[i] registers */
/* GPIO.CONF[i] control the pin behavior for the corresponding GPIO in/output. /* GPIO.CONF[i] control the pin behavior for the corresponding GPIO in/output.

58
core/include/esp/phy.h Normal file
View file

@ -0,0 +1,58 @@
/** esp/phy.h
*
* PHY hardware management functions.
*
* These are not enough to configure the ESP8266 PHY by themselves
* (yet), but they provide utilities to modify the configuration set
* up via the SDK.
*
* Functions implemented here deal directly with the hardware, not the
* SDK software layers.
*
* Part of esp-open-rtos
* Copyright (C) 2016 ChefSteps, Inc
* BSD Licensed as described in the file LICENSE
*/
#ifndef _ESP_PHY_H
#define _ESP_PHY_H
#include <esp/types.h>
#include <common_macros.h>
#include <stdint.h>
typedef enum {
BT_COEXIST_NONE,
BT_COEXIST_USE_BT_ACTIVE,
BT_COEXIST_USE_BT_ACTIVE_PRIORITY,
} bt_coexist_mode_t;
/** Override the Bluetooth Coexistence BT_ACTIVE pin setting
taken from the phy_info structure.
This enables other pins to be used for Bluetooth Coexistence
signals (rather than just the two provided for by phy_info). (Note
that not that not all pins are confirmed to work, GPIO 0 is
confirmed not usable as the SDK configures it as the WLAN_ACTIVE
output - even if you change the pin mode the SDK will change it
back.)
To change pins and have coexistence work successfully the BT
coexistence feature must be enabled in the phy_info configuration
(get_default_phy_info()). You can then modify the initial
configuration by calling this function from your own user_init
function.
(Eventually we should be able to support enough PHY registers
to enable coexistence without SDK support at all, but not yet.)
This function will enable bt_active_pin & bt_priority_as GPIO
inputs, according to the mode parameter.
Remember that the default Bluetooth Coexistence pins will be
configured as GPIOs by the SDK already, so you may want to
reconfigure/re-iomux them after calling this function.
*/
void bt_coexist_configure(bt_coexist_mode_t mode, uint8_t bt_active_pin, uint8_t bt_priority_pin);
#endif

View file

@ -3,6 +3,7 @@
#include "espressif/esp_wifi.h" #include "espressif/esp_wifi.h"
#include "espressif/spi_flash.h" #include "espressif/spi_flash.h"
#include "espressif/phy_info.h"
#include "lwip/netif.h" #include "lwip/netif.h"
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -217,7 +218,7 @@ void sdk_phy_enable_agc(void);
void sdk_pm_attach(void); void sdk_pm_attach(void);
void sdk_pp_attach(void); void sdk_pp_attach(void);
void sdk_pp_soft_wdt_init(void); void sdk_pp_soft_wdt_init(void);
int sdk_register_chipv6_phy(uint8_t *); int sdk_register_chipv6_phy(sdk_phy_info_t *);
void sdk_sleep_reset_analog_rtcreg_8266(void); void sdk_sleep_reset_analog_rtcreg_8266(void);
uint32_t sdk_system_get_checksum(uint8_t *, uint32_t); uint32_t sdk_system_get_checksum(uint8_t *, uint32_t);
void sdk_system_restart_in_nmi(void); void sdk_system_restart_in_nmi(void);

161
core/phy_info.c Normal file
View file

@ -0,0 +1,161 @@
/* Routines to allow custom access to the Internal Espressif
SDK PHY datastructures.
Matches espressif/phy_internal.h
Part of esp-open-rtos. Copyright (C) 2016 Angus Gratton,
BSD Licensed as described in the file LICENSE.
*/
#include <espressif/phy_info.h>
#include <espressif/esp_common.h>
#include <common_macros.h>
#include <string.h>
static const sdk_phy_info_t IROM default_phy_info = {
._reserved00 = { 0x05, 0x00, 0x04, 0x02, 0x05 },
.version = 5,
._reserved06 = { 0x05, 0x02, 0x05, 0x00, 0x04, 0x05, 0x05, 0x04,
0x05, 0x05, 0x04,-0x02,-0x03,-0x01,-0x10,-0x10,
-0x10,-0x20,-0x20, -0x20},
.spur_freq_primary = 225,
.spur_freq_divisor = 10,
.spur_freq_en_h = 0xFF,
.spur_freq_en_l = 0xFF,
._reserved1e = { 0xf8, 0, 0xf8, 0xf8 },
.target_power = { 82, 78, 74, 68, 64, 56 },
.target_power_index_mcs = { 0, 0, 1, 1, 2, 3, 4, 5 },
.crystal_freq = CRYSTAL_FREQ_26M,
.sdio_config = SDIO_CONFIG_AUTO,
.bt_coexist_config = BT_COEXIST_CONFIG_NONE,
.bt_coexist_protocol = BT_COEXIST_PROTOCOL_WIFI_ONLY,
.dual_ant_config = DUAL_ANT_CONFIG_NONE,
._reserved34 = 0x02,
.crystal_sleep = CRYSTAL_SLEEP_OFF,
.spur_freq_2_primary = 225,
.spur_freq_2_divisor = 10,
.spur_freq_2_en_h = 0x00,
.spur_freq_2_en_l = 0x00,
.spur_freq_cfg_msb = 0x00,
.spur_freq_2_cfg_msb = 0x00,
.spur_freq_3_cfg = 0x0000,
.spur_freq_4_cfg = 0x0000,
._reserved4a = { 0x01, 0x93, 0x43, 0x00 },
.low_power_en = false,
.lp_atten_stage01 = LP_ATTEN_STAGE01_23DB,
.lp_atten_bb = 0,
.pwr_ind_11b_en = false,
.pwr_ind_11b_0 = 0,
.pwr_ind_11b_1 = 0,
/* Nominal 3.3V VCC. NOTE: This value is 0 in the
esp-open-rtos SDK default config sector, and may be unused
by that version of the SDK?
*/
.pa_vdd = 33,
/* Note: untested with the esp-open-rtos SDK default config sector, may be unused? */
.freq_correct_mode = FREQ_CORRECT_DISABLE,
.force_freq_offset = 0,
/* Note: is zero with the esp-open-rtos SDK default config sector, may be unused? */
.rf_cal_mode = RF_CAL_MODE_SAVED,
};
void get_default_phy_info(sdk_phy_info_t *info) __attribute__((weak, alias("get_sdk_default_phy_info")));
void get_sdk_default_phy_info(sdk_phy_info_t *info)
{
memcpy(info, &default_phy_info, sizeof(sdk_phy_info_t));
}
void read_saved_phy_info(sdk_phy_info_t *info)
{
sdk_spi_flash_read(sdk_flashchip.chip_size - sdk_flashchip.sector_size * 4, (uint32_t *)info, sizeof(sdk_phy_info_t));
}
void write_saved_phy_info(const sdk_phy_info_t *info)
{
sdk_spi_flash_write(sdk_flashchip.chip_size - sdk_flashchip.sector_size * 4, (uint32_t *)info, sizeof(sdk_phy_info_t));
}
void dump_phy_info(const sdk_phy_info_t *info, bool raw)
{
printf("version=%d\n", info->version);
printf("spur_freq = %.3f (%d/%d)\n",
(float)info->spur_freq_primary / info->spur_freq_divisor,
info->spur_freq_primary,
info->spur_freq_divisor);
printf("spur_freq_en = 0x%02x 0x%02x\n", info->spur_freq_en_h,
info->spur_freq_en_l);
printf("target_power\n");
for(int i = 0; i < 6; i++) {
printf(" %d: %.2fdB (raw 0x%02x)\n", i,
info->target_power[i]/4.0,
info->target_power[i]);
}
printf("target_power_index_mcs:");
for(int i = 0; i < 8; i++) {
printf(" %d%c", info->target_power_index_mcs[i],
i == 7 ? '\n' : ',');
}
printf("crystal_freq: %s (raw %d)\n",
(info->crystal_freq == CRYSTAL_FREQ_40M ? "40MHz" :
(info->crystal_freq == CRYSTAL_FREQ_26M ? "26MHz" :
(info->crystal_freq == CRYSTAL_FREQ_24M ? "24MHz" : "???"))),
info->crystal_freq);
printf("sdio_config: %d\n", info->sdio_config);
printf("bt_coexist config: %d protocol: 0x%02x\n",
info->bt_coexist_config, info->bt_coexist_protocol);
printf("dual_ant_config: %d\n", info->dual_ant_config);
printf("crystal_sleep: %d\n", info->crystal_sleep);
printf("spur_freq_2 = %.3f (%d/%d)\n",
(float)info->spur_freq_2_primary / info->spur_freq_2_divisor,
info->spur_freq_2_primary,
info->spur_freq_2_divisor);
printf("spur_freq_2_en = 0x%02x 0x%02x\n", info->spur_freq_2_en_h,
info->spur_freq_2_en_l);
printf("spur_freq_cfg_msb = 0x%02x\n", info->spur_freq_cfg_msb);
printf("spur_freq_2_)cfg_msb = 0x%02x\n", info->spur_freq_2_cfg_msb);
printf("spur_freq_3_cfg = 0x%04x\n", info->spur_freq_3_cfg);
printf("spur_freq_4_cfg = 0x%04x\n", info->spur_freq_4_cfg);
printf("low_power_en = %d\n", info->low_power_en);
printf("lp_atten_stage01 = 0x%02x\n", info->lp_atten_stage01);
printf("lp_atten_bb = %.2f (raw 0x%02x)\n", info->lp_atten_bb / 4.0,
info->lp_atten_bb);
printf("pa_vdd = %d\n", info->pa_vdd);
printf("freq_correct_mode = 0x%02x\n", info->freq_correct_mode);
printf("force_freq_offset = %d\n", info->force_freq_offset);
printf("rf_cal_mode = 0x%02x\n", info->rf_cal_mode);
if(raw) {
printf("Raw values:");
uint8_t *p = (uint8_t *)info;
for(int i = 0; i < sizeof(sdk_phy_info_t); i ++) {
if(i % 8 == 0) {
printf("\n0x%02x:", i);
}
printf(" %02x", p[i]);
}
printf("\n\n");
}
}

View file

@ -0,0 +1,482 @@
/** Internal Espressif SDK "PHY info" data structure
The data structure (sdk_phy_info_t) is used to configure the
ESP8266 PHY layer via the SDK. The fields here are not written
directly to hardware, the SDK code (mostly in libphy) parses this
structure and configures the hardware.
The structure loaded at reset time from a flash configuration
sector (see read_saved_phy_info()) (Espressif's SDK sources this
from a file "esp_init_data_default.bin"). If no valid structure is
found in the flash config sector then the SDK loads default values
(see get_default_phy_info()). It is possible to implement a custom
get_default_phy_info() to change the PHY default settings (see the
'version' field below).
@note It is possible that the SDK will quietly write a new
configuration sector to flash itself following internal
calibration, etc. However this does not seem to happen, you need to
flash it explicitly if you want it stored there.
@note Most of what is below is unconfirmed, except where a @note
says that it has been confirmed to work as expected. Please
consider submitting notes if you find behaviour here that works or
doesn't work as expected.
Information on the meaning/offset of fields comes from Espressif's
flash download tool, which uses an Excel spreadsheet (in the
init_data directory of the ZIP file) to configure and a Python
script to convert an esp_init_data_custom.bin file to flash:
http://bbs.espressif.com/viewtopic.php?f=5&t=433
Many fields remain undocumented (& disassembly of libphy suggests
that some documented fields supported undocumented values.)
A few additional notes about the phy_info fields can be found
in the ESP Arduino ESP8266 phy_init_data structure (however most of
that content is verbatim from Espressif's spreadsheet):
https://github.com/esp8266/Arduino/blob/master/cores/esp8266/core_esp8266_phy.c#L29
Part of esp-open-rtos. Copyright (C) 2016 Angus Gratton,
BSD Licensed as described in the file LICENSE.
*/
#ifndef _ESPRESSIF_PHY_INFO_H
#define _ESPRESSIF_PHY_INFO_H
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
/* CRYSTAL_FREQ_xx values as used by sdk_phy_info_t.crystal_freq */
#define CRYSTAL_FREQ_40M 0
#define CRYSTAL_FREQ_26M 1
#define CRYSTAL_FREQ_24M 2
/* SDIO_CONFIG_xx values as used by sdk_phy_info_t.sdio_config */
#define SDIO_CONFIG_AUTO 0 /* Uses pin strapping to determine */
#define SDIO_CONFIG_SDIOV1_1 /* Data output on negative edge */
#define SDIO_CONFIG_SDIOV2_0 /* data output on positive edge */
/* BT_COEXIST_CONFIG_xx values as used by sdk_phy_info_t.bt_coexist */
/* No bluetooth */
#define BT_COEXIST_CONFIG_NONE 0
/* Coexistence configuration A:
GPIO 0 - WLAN_ACTIVE
GPIO 14 - BT_ACTIVE
GPIO 13 - BT_PRIORITY
GPIO 3 - ANT_SEL_BT
*/
#define BT_COEXIST_CONFIG_A 1
/* No coexistence, but Bluetooth enabled?
Unsure how this works?
*/
#define BT_COEXIST_CONFIG_PRESENT 2
/* Coexistence configuration B:
GPIO 0 - WLAN_ACTIVE
GPIO 14 - BT_PRIORITY
GPIO 13 - BT_ACTIVE
GPIO 3 - ANT_SEL_BT
*/
#define BT_COEXIST_CONFIG_B 3
/* BT_COEXIST_PROTOCOL_xx values for coexistence protocol,
field sdk_phy_info_t.bt_coexist_protocol
*/
#define BT_COEXIST_PROTOCOL_WIFI_ONLY 0
#define BT_COEXIST_PROTOCOL_BT_ONLY 1
/* Coexistence is enabled, Bluetooth has its own antenna */
#define BT_COEXIST_PROTOCOL_FLAG_SEPARATE_ANT 2
/* Coexistence is enabled, Bluetooth shares WiFi antenna */
#define BT_COEXIST_PROTOCOL_FLAG_SHARE_ANT 4
/* Coexistence is enabled, use only BT_ACTIVE signal */
#define BT_COEXIST_PROTOCOL_FLAG_BT_ACTIVE_ONLY 0
/* Coexistence is enabled, use both BT_ACTIVE and BT_PRIORITY signals */
#define BT_COEXIST_PROTOCOL_FLAG_BT_ACTIVE_PRIORITY 1
/* DUAL_ANT_CONFIG_xx values for dual antenna config,
field sdk_phy_info_t.dual_ant_config
(Not really clear how this feature works, if at all.)
*/
#define DUAL_ANT_CONFIG_NONE 0
/* antenna diversity for WiFi, use GPIO0 + U0RXD (?) */
#define DUAL_ANT_CONFIG_DUAL 1
/* TX/RX switch for external PA & LNA: GPIO 0 high, GPIO 3 low during TX */
#define DUAL_ANT_CONFIG_TX_GPIO0_HIGH_GPIO3_LOW
/* TX/RX switch for external PA & LNA: GPIO 0 low, GPIO 3 high during TX */
#define DUAL_ANT_CONFIG_TX_GPIO0_LOW_GPIO3_HIGH
/* CRYSTAL_SLEEP_xx values used for sdk_phy_info_t.crystal_sleep
*/
#define CRYSTAL_SLEEP_OFF 0
#define CRYSTAL_SLEEP_ON 1
#define CRYSTAL_SLEEP_GPIO16 2
#define CRYSTAL_SLEEP_GPIO2 3
/* RF Stage 0 & 1 attenuation constants. Use for sdk_phy_info_t.lp_atten_stage01
@note These values have been tested and are confirmed to work as
expected by measuring RSSI w/ rt73 USB adapter in monitor mode
(some values also checked on spectrum analyzer) - provided
low_power_en is set then the signal is attenuated as per this
setting.
(It may look like LP_ATTEN_STAGE01_11_5DB is out of order, but
according to monitor mode captures this is the correct ordering of
these constants.)
Setting the numeric values in between these constants appears to
also attenuate the signal, but not necessarily by the amount you'd
expect.
*/
#define LP_ATTEN_STAGE01_0DB 0x0f /* 0dB */
#define LP_ATTEN_STAGE01_2_5DB 0x0e /* -2.5dB */
#define LP_ATTEN_STAGE01_6DB 0x0d /* -6dB */
#define LP_ATTEN_STAGE01_8_5DB 0x09 /* -8.5dB */
#define LP_ATTEN_STAGE01_11_5DB 0x0c /* -11.5dB */
#define LP_ATTEN_STAGE01_14DB 0x08 /* -14dB */
#define LP_ATTEN_STAGE01_17_5DB 0x04 /* -17.5dB */
#define LP_ATTEN_STAGE01_23DB 0x00 /* -23dB */
/* Constant for sdk_phy_info_t.pa_vdd */
#define PA_VDD_MEASURE_VCC 0xFF
/* Bitmask flags for sdk_phy_info_t.freq_correct_mode */
/* Set this flag to disable frequency offset correction */
#define FREQ_CORRECT_DISABLE 0
/* Set this flag to enable frequency offset correction */
#define FREQ_CORRECT_ENABLE BIT(0)
/* Set = Baseband PLL frequency is 160MHz (can only apply +ve offset)
* Unset = Baseband PLL frequency is 168MHz (can apply +ve/-ve offset */
#define FREQ_CORRECT_BB_160M BIT(1)
/* Set = use force_freq_offset field to correct, Unset = automatically
measure & correct offset
*/
#define FREQ_CORRECT_FORCE BIT(2)
/* RF_CAL_MODE_xx fields used for sdk_phy_info_t.rf_cal_mode
*/
/* Use saved RF CAL data from flash, only. RF init takes 2ms. */
#define RF_CAL_MODE_SAVED 0
/* Calibrate TX power control only, use saved RF CAL data for others.
RF init takes 20ms. */
#define RF_CAL_MODE_TXPOWER_ONLY 1
/* Unclear if/how this mode is different to 2? */
#define RF_CAL_MODE_SAVED_2 2
/* Run full RF CAL routine. RF init takes approx 200ms. */
#define RF_CAL_MODE_FULL 3
/* Data structure that maps to the phy_info configuration block */
typedef struct __attribute__((packed)) {
uint8_t _reserved00[0x05]; /* 0x00 - 0x04 */
/* This "version" field was set to 5 in the SDK phy_info,
and the original SDK startup code checks it is 5 and then loads
default PHY configuration otherwise.
esp-open-rtos will load phy_info from get_default_phy_info() if
the value stored in flash has a different value to the value
returned in get_default_phy_info(). This means you can
increment the version return by get_default_phy_info() (to any
value but 0xFF), and know that the new defaults will replace
any older stored values.
@notes It's not clear whether this is actually a version field
(the other 24 bytes here have equally arbitrary numbers in
them.) Changing the "version" to other values does not seem to
effect WiFi performance at all, neither does zeroing out the
first 5 reserved bytes in _reserved00. However zeroing bytes in
the _reserved06 region will break WiFi entirely.
*/
uint8_t version; /* 0x05 */
int8_t _reserved06[0x14]; /* 0x06 - 0x19 */
/* spur_freq = spur_freq_primary / spur_freq_divisor */
uint8_t spur_freq_primary; /* 0x1a */
uint8_t spur_freq_divisor; /* 0x1b */
/* Bitmask to enable spur_freq for each channel
Appears to be a big endian short word?
*/
uint8_t spur_freq_en_h; /* 0x1c */
uint8_t spur_freq_en_l; /* 0x1d */
uint8_t _reserved1e[4]; /* 0x1e - 0x21 */
/* Each value is a target power level.
Units are 1/4 dBm ie value 64 = 16dBm.
SDK defaults to using these transmit powers:
20.5dBm, 19.5dBm, 18.5dBm, 17dBm, 16dBm, 14dBm
@note Adjusting these values is confirmed to reduce
transmit power accordingly.
*/
uint8_t target_power[6]; /* 0x22 - 0x27 */
/* Maps 8 MCS (modulation & coding schemes) types for 802.11b, g &
* n to a target_power level index (0-5), set above.
This mapping of MCS slot to MCS type is derived from the
spreadsheet and also a table sent by Espressif, but is untested
and may be SDK version dependendent (especially any 802.11n
rates). However the general relationship is confirmed to hold
(higher MCS index = higher bit rate).
MCS 0: 1Mbps/2Mbps/5.5Mbps/11Mbps (802.11b) / 6Mbps/9Mbps (802.11g)
default target_power 0 (default 20.5dBm)
(see also pwr_ind_11b_en)
MCS 1: 12Mbps (802.11g)
default target_power 0 (default 20.5dBm)
MCS 2: 18Mbps (802.11g)
default target_power 1 (19.5dBm)
MCS 3: 24Mbps (802.11g)
default target_power 1 (19.5dBm)
MCS 4: 36Mbps (802.11g)
default target_power 2 (18.5dBm)
MCS 5: 48Mbps (802.11g)
default target_power 3 (17dBm)
MCS 6: 54Mbps (802.11g)
default target_power 4 (16dBm)
MCS 7: 65Mbps (802.11n) - unclear if ever used?
default target_power 5 (14dBm)
*/
uint8_t target_power_index_mcs[8]; /* 0x28 - 0x2f */
/* One of CRYSTAL_FREQ_40M / CRYSTAL_FREQ_26M / CRYSTAL_FREQ_24M
The crystal configured here is the input to the PLL setting
calculations which are used to derive the CPU & APB peripheral
clock frequency, and probably the WiFi PLLs (unconfirmed.)
*/
uint8_t crystal_freq; /* 0x30 */
uint8_t _unused31; /* 0x31: Possibly high byte of crystal freq? */
/* One of SDIO_CONFIG_AUTO, SDIO_CONFIG_SDIOV1_1, SDIO_CONFIG_SDIOV2_0 */
uint8_t sdio_config; /* 0x32 */
/* BT coexistence pin configuration.
One of BT_COEXIST_CONFIG_NONE, BT_COEXIST_CONFIG_A,
BT_COEXIST_CONFIG_PRESENT, BT_COEXIST_CONFIG_B
*/
uint8_t bt_coexist_config; /* 0x33 */
/* BT coexistence pin protocol.
If no coexistence:
Either BT_COEXIST_PROTOCOL_WIFI_ONLY, or
BT_COEXIST_PROTOCOL_BT_ONLY.
If coexistence:
Combine one of
BT_COEXIST_PROTOCOL_FLAG_SEPARATE_ANT or
BT_COEXIST_PROTOCOL_FLAG_SHARE_ANT
with one of
BT_COEXIST_PROTOCOL_FLAG_BT_ACTIVE_ONLY or
BT_COEXIST_PROTOCOL_FLAG_BT_ACTIVE_BT_PRIORITY
*/
uint8_t bt_coexist_protocol; /* 0x34 */
/* Dual antenna configuration
One of DUAL_ANT_CONFIG_NONE, DUAL_ANT_CONFIG_DUAL,
DUAL_ANT_CONFIG_TX_GPIO0_HIGH_GPIO3_LOW,
DUAL_ANT_CONFIG_TX_GPIO0_LOW_GPIO3_HIGH
*/
uint8_t dual_ant_config; /* 0x35 */
uint8_t _reserved34; /* 0x36 */
/* For sharing crystal clock with other devices:
one of CRYSTAL_SLEEP_OFF, CRYSTAL_SLEEP_ON,
CRYSTAL_SLEEP_GPIO16, CRYSTAL_SLEEP_GPIO2
*/
uint8_t crystal_sleep; /* 0x37 */
uint8_t _unused38[8];
/* spur_freq_2 = spur_freq_2_primary / spur_freq_2_divisor */
uint8_t spur_freq_2_primary; /* 0x40 */
uint8_t spur_freq_2_divisor; /* 0x41 */
/* Bitmask to enable spur_freq_2 for each channel?
Appears to be a big endian short word?
*/
uint8_t spur_freq_2_en_h; /* 0x42 */
uint8_t spur_freq_2_en_l; /* 0x43 */
/* Not really clear what these do */
uint8_t spur_freq_cfg_msb; /* 0x44 */
uint8_t spur_freq_2_cfg_msb; /* 0x45 */
uint16_t spur_freq_3_cfg; /* 0x46 - 0x47 */
uint16_t spur_freq_4_cfg; /* 0x48 - 0x49 */
uint8_t _reserved4a[4]; /* 0x4a - 0x4d */
uint8_t _unused78[15]; /* 0x4e - 0x5c */
/* Flag to enable low power mode */
uint8_t low_power_en; /* 0x5d */
/* Low Power attenuation of RF gain stages 0 & 1
Attenuates transmit power if/when low_power_en is set.
Use one of the constants LP_ATTEN_STAGE01_0DB,
LP_ATTEN_STAGE01_2_5DB, LP_ATTEN_STAGE01_6DB,
LP_ATTEN_STAGE01_8_5DB, LP_ATTEN_STAGE01_11_5DB,
LP_ATTEN_STAGE01_14DB, LP_ATTEN_STAGE01_17_5DB,
LP_ATTEN_STAGE01_23DB.
*/
uint8_t lp_atten_stage01; /* 0x5e */
/* Low Power(?) attenuation of baseband gain
Units are minus 1/4 dB, ie value 4 == -1dB.
Maximum value is 24 (0x18) == -6dB
*/
uint8_t lp_atten_bb; /* 0x5f */
/* I believe this means, when pwr_ind_11b_en == 0 then the 802.11g
MCS 0 level from target_power_index_mcs are used to
determine 802.11b transmit power level.
However, when pwr_ind_11b_en == 1 then the index values in
pwr_ind_11b_0 & pwr_ind_11b_1 are used for 802.11b instead.
This is all unconfirmed, if you can confirm then please update
this comment.
*/
uint8_t pwr_ind_11b_en; /* 0x60 */
/* 802.11b low data rate power index (0~5).
Sets the power level index for operation at 1 & 2Mbps
*/
uint8_t pwr_ind_11b_0; /* 0x61 */
/* 802.11b high data rate power index (0~5)
Sets the power level index for operation at 5.5 & 11Mbps
*/
uint8_t pwr_ind_11b_1; /* 0x62 */
uint8_t _unused63[8]; /* 0x63 - 0x6a */
/* Set the voltage of PA_VDD, which appears to be an internal analog
reference voltage(?)
This field is called vdd33_const in the Arduino phy fields,
and relates to usage of the TOUT pin (ADC pin).
Set to PA_VDD_MEASURE_VCC (0xFF) and leave TOUT (ADC) pin
floating in order to use the ADC to measure the 3.3V input
voltage.
Set to value in the range 18-36 (1.8V to 3.6V) to set a
reference voltage(?) when using TOUT pin as an ADC input. I
think this is the reference voltage used to scale the 0-1V
which is allowed on the pin, in order to get an accurate
reading. So it should be set to a value that matches system
VCC... I think!
*/
uint8_t pa_vdd; /* 0x6b */
/* Disable RF calibration cycle for this many times */
uint8_t disable_rfcal_count; /* 0x6c */
uint8_t _unused6d[3];
/* Flags for frequency correction
A bitmask combination of any of: FREQ_CORRECT_DISABLE,
FREQ_CORRECT_ENABLE, FREQ_CORRECT_BB_160M, FREQ_CORRECT_FORCE
*/
uint8_t freq_correct_mode; /* 0x70 */
/* Force frequency offset adjustment (instead of auto measuring)
units are 1 = 8kHz, full range +/- 1016kHz.
Only used if FREQ_CORRECT_ENABLE and FREQ_CORRECT_FORCE are
set in freq_correct_mode.
Unclear whether setting FREQ_CORRECT_BB_160M (which allows only positive offsets) changes the usable range.
*/
int8_t force_freq_offset; /* 0x71 */
/* Use stored data in flash for RF calibration.
This field was previously called rf_cal_use_flash.
Acceptable values one of RF_CAL_MODE_SAVED, RF_CAL_MODE_TXPOWER_ONLY, RF_CAL_MODE_SAVED_2, RF_CAL_MODE_FULL.
*/
uint8_t rf_cal_mode; /* 0x72 */
uint8_t _unused73[13];
} sdk_phy_info_t;
/* Some sanity check static assertions. These can probably be
removed after this structure has been better tested.
*/
_Static_assert(sizeof(sdk_phy_info_t) == 128, "sdk_phy_info_t is wrong size!");
_Static_assert(offsetof(sdk_phy_info_t, version) == 5, "version at wrong offset");
_Static_assert(offsetof(sdk_phy_info_t, target_power) == 34, "target_power_qdb at wrong offset");
_Static_assert(offsetof(sdk_phy_info_t, bt_coexist_protocol) == 52, "bt_coexist_protocol at wrong offset");
_Static_assert(offsetof(sdk_phy_info_t, spur_freq_2_primary) == 64, "spur_freq_2_primary at wrong offset");
_Static_assert(offsetof(sdk_phy_info_t, lp_atten_stage01) == 94, "lp_atten_stage01 at wrong offset");
_Static_assert(offsetof(sdk_phy_info_t, pa_vdd) == 107, "pa_vdd aka vdd33_const at wrong offset");
_Static_assert(offsetof(sdk_phy_info_t, rf_cal_mode) == 114, "rf_cal_use_flash at wrong offset!");
/* Read the default PHY info into the supplied structure.
This function is weak-aliased to get_sdk_default_phy_info() so you
can replace it with your own if you want to vary the default values
- suggested way to do this is to call get_sdk_default_phy_info()
and then only update the fields you care about.
The default PHY info is used at startup whenever the version field
in the default sdk_phy_info_t does not match the version field
stored in flash. So you can increment the version field to force a
reset to defaults, regardless of what values are in flash.
*/
void get_default_phy_info(sdk_phy_info_t *info);
/* Read the "SDK default" PHY info as used by the Espressif SDK */
void get_sdk_default_phy_info(sdk_phy_info_t *info);
/* Read the PHY info currently stored in the SPI flash SDK configuration sector.
This PHY info is updated by the SDK following RF calibration, etc.
Note that the saved data may be corrupt - read the 'version' field to verify.
*/
void read_saved_phy_info(sdk_phy_info_t *info);
/* Update the saved PHY info in the SPI flash. A reset is necessary to use these values.
Note that the SDK may clobber these values, so it's recommended you reset ASAP after updating them.
*/
void write_saved_phy_info(const sdk_phy_info_t *info);
/* Dump known fields in the phy info structure to stdout,
if 'raw' flag is set then the raw hex values are also dumped.
*/
void dump_phy_info(const sdk_phy_info_t *info, bool raw);
#endif