mirror of
https://github.com/espressif/esp-nimble.git
synced 2026-08-26 03:39:59 +00:00
nimble/ll: Add support for tunable FEM gain and fix compensation
This allows to implement dynamic FEM PA and LNA gains and fixes
some issues with power compensation from host.
g_ble_ll_tx_power and advsm->tx_power now hold rounded host compensated
values. If FEM is used expected PHY tx power is altered by FEM PA gain
(static or dynamic) before being set.
LL operates on PHY (or FEM) power levels and compensate those when
reporting to host via HCI.
As per spec (clarified in errata):
Radiative Tx power level = Tx power level at RF transceiver output +
RF_TX_Path_Compensation_Value
Rx power level at RF transceiver input = Rx power level at antenna +
RF_RX_Path_Compensation_Value
This commit is contained in:
@@ -30,12 +30,25 @@ extern "C" {
|
||||
void ble_ll_fem_pa_init(void);
|
||||
void ble_ll_fem_pa_enable(void);
|
||||
void ble_ll_fem_pa_disable(void);
|
||||
#if MYNEWT_VAL(BLE_LL_FEM_PA_GAIN_TUNABLE)
|
||||
/* Configures FEM to selected TX power and returns expected PHY TX power */
|
||||
int ble_ll_fem_pa_tx_power_set(int tx_power);
|
||||
|
||||
/* returns rounded FEM TX power */
|
||||
int ble_ll_fem_pa_tx_power_round(int tx_power);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MYNEWT_VAL(BLE_LL_FEM_LNA)
|
||||
void ble_ll_fem_lna_init(void);
|
||||
void ble_ll_fem_lna_enable(void);
|
||||
void ble_ll_fem_lna_disable(void);
|
||||
|
||||
#if MYNEWT_VAL(BLE_LL_FEM_LNA_GAIN_TUNABLE)
|
||||
/* Return current value of FEM LNA RX gain (in dBm) */
|
||||
int ble_ll_fem_lna_rx_gain(void);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if MYNEWT_VAL(BLE_LL_FEM_ANTENNA)
|
||||
|
||||
@@ -65,7 +65,8 @@
|
||||
* right thing to do.
|
||||
*/
|
||||
|
||||
int8_t g_ble_ll_tx_power = MYNEWT_VAL(BLE_LL_TX_PWR_DBM);
|
||||
/* This is TX power on PHY (or FEM PA if enabled) */
|
||||
int8_t g_ble_ll_tx_power;
|
||||
int8_t g_ble_ll_tx_power_compensation;
|
||||
int8_t g_ble_ll_rx_power_compensation;
|
||||
|
||||
@@ -1350,8 +1351,8 @@ ble_ll_task(void *arg)
|
||||
ble_phy_init();
|
||||
|
||||
/* Set output power to default */
|
||||
g_ble_ll_tx_power = ble_phy_tx_power_round(MYNEWT_VAL(BLE_LL_TX_PWR_DBM));
|
||||
ble_phy_tx_power_set(g_ble_ll_tx_power);
|
||||
g_ble_ll_tx_power = ble_ll_tx_power_round(MYNEWT_VAL(BLE_LL_TX_PWR_DBM));
|
||||
ble_ll_tx_power_set(g_ble_ll_tx_power);
|
||||
|
||||
/* Tell the host that we are ready to receive packets */
|
||||
ble_ll_hci_send_noop();
|
||||
@@ -1597,8 +1598,8 @@ ble_ll_reset(void)
|
||||
g_ble_ll_rx_power_compensation = 0;
|
||||
|
||||
/* Set output power to default */
|
||||
g_ble_ll_tx_power = ble_phy_tx_power_round(MYNEWT_VAL(BLE_LL_TX_PWR_DBM));
|
||||
ble_phy_tx_power_set(g_ble_ll_tx_power);
|
||||
g_ble_ll_tx_power = ble_ll_tx_power_round(MYNEWT_VAL(BLE_LL_TX_PWR_DBM));
|
||||
ble_ll_tx_power_set(g_ble_ll_tx_power);
|
||||
|
||||
/* FLush all packets from Link layer queues */
|
||||
ble_ll_flush_pkt_queue(&g_ble_ll_data.ll_tx_pkt_q);
|
||||
@@ -1987,3 +1988,37 @@ ble_transport_ll_init(void)
|
||||
{
|
||||
ble_ll_init();
|
||||
}
|
||||
|
||||
int
|
||||
ble_ll_tx_power_round(int tx_power)
|
||||
{
|
||||
#if MYNEWT_VAL(BLE_LL_FEM_PA)
|
||||
#if MYNEWT_VAL(BLE_LL_FEM_PA_GAIN_TUNABLE)
|
||||
tx_power = ble_ll_fem_pa_tx_power_round(tx_power);
|
||||
#else
|
||||
tx_power = ble_phy_tx_power_round(tx_power);
|
||||
tx_power += MYNEWT_VAL(BLE_LL_FEM_PA_GAIN);
|
||||
#endif
|
||||
#else
|
||||
tx_power = ble_phy_tx_power_round(tx_power);
|
||||
#endif
|
||||
|
||||
return tx_power;
|
||||
}
|
||||
|
||||
void
|
||||
ble_ll_tx_power_set(int tx_power)
|
||||
{
|
||||
#if MYNEWT_VAL(BLE_LL_FEM_PA)
|
||||
#if MYNEWT_VAL(BLE_LL_FEM_PA_GAIN_TUNABLE)
|
||||
/* TODO should rounding be in assert only? or just skip it and assume
|
||||
* power is already rounded?
|
||||
*/
|
||||
tx_power = ble_ll_fem_pa_tx_power_round(tx_power);
|
||||
tx_power = ble_ll_fem_pa_tx_power_set(tx_power);
|
||||
#else
|
||||
tx_power -= MYNEWT_VAL(BLE_LL_FEM_PA_GAIN);
|
||||
#endif
|
||||
#endif
|
||||
ble_phy_tx_power_set(tx_power);
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ struct ble_ll_adv_sm
|
||||
uint8_t adv_chan;
|
||||
uint8_t adv_pdu_len;
|
||||
int8_t adv_rpa_index;
|
||||
int8_t adv_txpwr;
|
||||
int8_t tx_power;
|
||||
uint16_t flags;
|
||||
uint16_t props;
|
||||
uint32_t adv_itvl_usecs;
|
||||
@@ -802,7 +802,7 @@ ble_ll_adv_aux_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte)
|
||||
#endif
|
||||
|
||||
if (aux->ext_hdr_flags & (1 << BLE_LL_EXT_ADV_TX_POWER_BIT)) {
|
||||
dptr[0] = advsm->adv_txpwr + g_ble_ll_tx_power_compensation;
|
||||
dptr[0] = advsm->tx_power + g_ble_ll_tx_power_compensation;
|
||||
dptr += BLE_LL_EXT_ADV_TX_POWER_SIZE;
|
||||
}
|
||||
|
||||
@@ -879,7 +879,7 @@ ble_ll_adv_aux_scannable_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_b
|
||||
if (advsm->props & BLE_HCI_LE_SET_EXT_ADV_PROP_INC_TX_PWR) {
|
||||
*ext_hdr_len += BLE_LL_EXT_ADV_TX_POWER_SIZE;
|
||||
*ext_hdr |= (1 << BLE_LL_EXT_ADV_TX_POWER_BIT);
|
||||
dptr[0] = advsm->adv_txpwr + g_ble_ll_tx_power_compensation;
|
||||
dptr[0] = advsm->tx_power + g_ble_ll_tx_power_compensation;
|
||||
dptr += BLE_LL_EXT_ADV_TX_POWER_SIZE;
|
||||
}
|
||||
|
||||
@@ -1029,8 +1029,8 @@ ble_ll_adv_tx_done(void *arg)
|
||||
{
|
||||
struct ble_ll_adv_sm *advsm;
|
||||
|
||||
/* reset power to max after advertising */
|
||||
ble_phy_tx_power_set(g_ble_ll_tx_power);
|
||||
/* reset power to default after advertising */
|
||||
ble_ll_tx_power_set(g_ble_ll_tx_power);
|
||||
|
||||
advsm = (struct ble_ll_adv_sm *)arg;
|
||||
|
||||
@@ -1111,7 +1111,7 @@ ble_ll_adv_tx_start_cb(struct ble_ll_sched_item *sch)
|
||||
}
|
||||
|
||||
/* Set the power */
|
||||
ble_phy_tx_power_set(advsm->adv_txpwr);
|
||||
ble_ll_tx_power_set(advsm->tx_power);
|
||||
|
||||
/* Set channel */
|
||||
rc = ble_phy_setchan(advsm->adv_chan, BLE_ACCESS_ADDR_ADV, BLE_LL_CRCINIT_ADV);
|
||||
@@ -1255,7 +1255,7 @@ ble_ll_adv_secondary_tx_start_cb(struct ble_ll_sched_item *sch)
|
||||
ble_ll_adv_active_chanset_set_sec(advsm);
|
||||
|
||||
/* Set the power */
|
||||
ble_phy_tx_power_set(advsm->adv_txpwr);
|
||||
ble_ll_tx_power_set(advsm->tx_power);
|
||||
|
||||
/* Set channel */
|
||||
aux = AUX_CURRENT(advsm);
|
||||
@@ -1740,7 +1740,7 @@ ble_ll_adv_halt(void)
|
||||
|
||||
ble_ll_trace_u32(BLE_LL_TRACE_ID_ADV_HALT, advsm->adv_instance);
|
||||
|
||||
ble_phy_tx_power_set(g_ble_ll_tx_power);
|
||||
ble_ll_tx_power_set(g_ble_ll_tx_power);
|
||||
|
||||
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV)
|
||||
if (advsm->flags & BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING) {
|
||||
@@ -1858,7 +1858,7 @@ ble_ll_adv_set_adv_params(const uint8_t *cmdbuf, uint8_t len)
|
||||
return BLE_ERR_INV_HCI_CMD_PARMS;
|
||||
}
|
||||
|
||||
advsm->adv_txpwr = g_ble_ll_tx_power;
|
||||
advsm->tx_power = ble_ll_tx_power_round(g_ble_ll_tx_power - g_ble_ll_tx_power_compensation);
|
||||
|
||||
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
|
||||
if (cmd->own_addr_type > BLE_HCI_ADV_OWN_ADDR_RANDOM) {
|
||||
@@ -2157,7 +2157,7 @@ ble_ll_adv_sync_pdu_make(uint8_t *dptr, void *pducb_arg, uint8_t *hdr_byte)
|
||||
}
|
||||
|
||||
if (sync->ext_hdr_flags & (1 << BLE_LL_EXT_ADV_TX_POWER_BIT)) {
|
||||
dptr[0] = advsm->adv_txpwr + g_ble_ll_tx_power_compensation;
|
||||
dptr[0] = advsm->tx_power + g_ble_ll_tx_power_compensation;
|
||||
dptr += BLE_LL_EXT_ADV_TX_POWER_SIZE;
|
||||
}
|
||||
|
||||
@@ -2232,7 +2232,7 @@ ble_ll_adv_sync_tx_start_cb(struct ble_ll_sched_item *sch)
|
||||
ble_ll_adv_flags_set(advsm, BLE_LL_ADV_SM_FLAG_PERIODIC_SYNC_SENDING);
|
||||
|
||||
/* Set the power */
|
||||
ble_phy_tx_power_set(advsm->adv_txpwr);
|
||||
ble_phy_tx_power_set(advsm->tx_power);
|
||||
|
||||
/* Set channel */
|
||||
sync = SYNC_CURRENT(advsm);
|
||||
@@ -3526,9 +3526,9 @@ ble_ll_adv_ext_set_param(const uint8_t *cmdbuf, uint8_t len,
|
||||
|
||||
if (cmd->tx_power == 127) {
|
||||
/* no preference */
|
||||
advsm->adv_txpwr = g_ble_ll_tx_power;
|
||||
advsm->tx_power = ble_ll_tx_power_round(g_ble_ll_tx_power - g_ble_ll_tx_power_compensation);
|
||||
} else {
|
||||
advsm->adv_txpwr = ble_phy_tx_power_round(cmd->tx_power);
|
||||
advsm->tx_power = ble_ll_tx_power_round(cmd->tx_power - g_ble_ll_tx_power_compensation);
|
||||
}
|
||||
|
||||
/* we can always store as those are validated and used only when needed */
|
||||
@@ -3564,7 +3564,7 @@ ble_ll_adv_ext_set_param(const uint8_t *cmdbuf, uint8_t len,
|
||||
|
||||
done:
|
||||
/* Update TX power */
|
||||
rsp->tx_power = rc ? 0 : advsm->adv_txpwr;
|
||||
rsp->tx_power = rc ? 0 : (advsm->tx_power + g_ble_ll_tx_power_compensation);
|
||||
|
||||
*rsplen = sizeof(*rsp);
|
||||
return rc;
|
||||
|
||||
@@ -3490,7 +3490,7 @@ ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr)
|
||||
#endif
|
||||
|
||||
/* Update RSSI */
|
||||
connsm->conn_rssi = hdr->rxinfo.rssi + g_ble_ll_rx_power_compensation;
|
||||
connsm->conn_rssi = hdr->rxinfo.rssi - ble_ll_rx_gain();
|
||||
|
||||
/*
|
||||
* If we are a peripheral, we can only start to use peripheral latency
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "controller/ble_ll_rfmgmt.h"
|
||||
#include "controller/ble_ll_tmr.h"
|
||||
#include "ble_ll_dtm_priv.h"
|
||||
#include "ble_ll_priv.h"
|
||||
|
||||
STATS_SECT_START(ble_ll_dtm_stats)
|
||||
STATS_SECT_ENTRY(rx_count)
|
||||
@@ -243,7 +244,7 @@ ble_ll_dtm_tx_sched_cb(struct ble_ll_sched_item *sch)
|
||||
ble_phy_mode_set(ctx->phy_mode, ctx->phy_mode);
|
||||
#endif
|
||||
ble_phy_set_txend_cb(ble_ll_dtm_tx_done, ctx);
|
||||
ble_phy_tx_power_set(0);
|
||||
ble_ll_tx_power_set(g_ble_ll_tx_power);
|
||||
|
||||
sch->start_time += g_ble_ll_sched_offset_ticks;
|
||||
|
||||
|
||||
@@ -786,8 +786,8 @@ ble_ll_read_tx_power(uint8_t *rspbuf, uint8_t *rsplen)
|
||||
{
|
||||
struct ble_hci_le_rd_transmit_power_rp *rsp = (void *) rspbuf;
|
||||
|
||||
rsp->min_tx_power = ble_phy_tx_power_round(-127);
|
||||
rsp->max_tx_power = ble_phy_tx_power_round(126);
|
||||
rsp->min_tx_power = ble_ll_tx_power_round(-127);
|
||||
rsp->max_tx_power = ble_ll_tx_power_round(126);
|
||||
|
||||
*rsplen = sizeof(*rsp);
|
||||
return BLE_ERR_SUCCESS;
|
||||
|
||||
@@ -124,14 +124,14 @@ ble_ll_hci_vs_set_tx_power(uint16_t ocf, const uint8_t *cmdbuf, uint8_t cmdlen,
|
||||
|
||||
if (cmd->tx_power == 127) {
|
||||
/* restore reset default */
|
||||
g_ble_ll_tx_power = ble_phy_tx_power_round(MYNEWT_VAL(BLE_LL_TX_PWR_DBM));
|
||||
g_ble_ll_tx_power = ble_ll_tx_power_round(MYNEWT_VAL(BLE_LL_TX_PWR_DBM) - g_ble_ll_tx_power_compensation);
|
||||
} else {
|
||||
g_ble_ll_tx_power = ble_phy_tx_power_round(cmd->tx_power);
|
||||
g_ble_ll_tx_power = ble_ll_tx_power_round(cmd->tx_power - g_ble_ll_tx_power_compensation);
|
||||
}
|
||||
|
||||
ble_phy_tx_power_set(g_ble_ll_tx_power);
|
||||
ble_ll_tx_power_set(g_ble_ll_tx_power);
|
||||
|
||||
rsp->tx_power = g_ble_ll_tx_power;
|
||||
rsp->tx_power = g_ble_ll_tx_power + g_ble_ll_tx_power_compensation;
|
||||
*rsplen = sizeof(*rsp);
|
||||
|
||||
return BLE_ERR_SUCCESS;
|
||||
|
||||
@@ -28,6 +28,25 @@ extern int8_t g_ble_ll_tx_power;
|
||||
extern int8_t g_ble_ll_tx_power_compensation;
|
||||
extern int8_t g_ble_ll_rx_power_compensation;
|
||||
|
||||
int ble_ll_tx_power_round(int tx_power);
|
||||
void ble_ll_tx_power_set(int tx_power);
|
||||
|
||||
static inline int
|
||||
ble_ll_rx_gain(void)
|
||||
{
|
||||
int gain = g_ble_ll_rx_power_compensation;
|
||||
|
||||
#if MYNEWT_VAL(BLE_LL_FEM_LNA)
|
||||
#if MYNEWT_VAL(BLE_LL_FEM_LNA_GAIN_TUNABLE)
|
||||
gain += ble_ll_fem_lna_rx_gain();
|
||||
#else
|
||||
gain += MYNEWT_VAL(BLE_LL_FEM_LNA_GAIN);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return gain;
|
||||
}
|
||||
|
||||
#ifdef MYNEWT
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
|
||||
@@ -717,7 +717,7 @@ ble_ll_scan_send_adv_report(uint8_t pdu_type,
|
||||
if (scansm->ext_scanning) {
|
||||
rc = ble_ll_hci_send_legacy_ext_adv_report(evtype,
|
||||
adva, adva_type,
|
||||
hdr->rxinfo.rssi + g_ble_ll_rx_power_compensation,
|
||||
hdr->rxinfo.rssi - ble_ll_rx_gain(),
|
||||
adv_data_len, om,
|
||||
inita, inita_type);
|
||||
goto done;
|
||||
@@ -726,12 +726,12 @@ goto done;
|
||||
|
||||
if (subev == BLE_HCI_LE_SUBEV_DIRECT_ADV_RPT) {
|
||||
rc = ble_ll_hci_send_dir_adv_report(adva, adva_type, inita, inita_type,
|
||||
hdr->rxinfo.rssi + g_ble_ll_rx_power_compensation);
|
||||
hdr->rxinfo.rssi - ble_ll_rx_gain());
|
||||
goto done;
|
||||
}
|
||||
|
||||
rc = ble_ll_hci_send_adv_report(evtype, adva, adva_type,
|
||||
hdr->rxinfo.rssi + g_ble_ll_rx_power_compensation,
|
||||
hdr->rxinfo.rssi - ble_ll_rx_gain(),
|
||||
adv_data_len, om);
|
||||
done:
|
||||
if (!rc && scansm->scan_filt_dups) {
|
||||
|
||||
@@ -409,7 +409,7 @@ ble_ll_hci_ev_update_ext_adv_report_from_ext(struct ble_hci_ev *hci_ev,
|
||||
report->pri_phy = rxinfo->phy;
|
||||
report->sec_phy = 0;
|
||||
report->sid = 0xff;
|
||||
report->rssi = rxhdr->rxinfo.rssi + g_ble_ll_rx_power_compensation;
|
||||
report->rssi = rxhdr->rxinfo.rssi - ble_ll_rx_gain();
|
||||
report->periodic_itvl = 0;
|
||||
report->data_len = 0;
|
||||
|
||||
@@ -530,7 +530,7 @@ ble_ll_hci_ev_send_ext_adv_report(struct os_mbuf *rxpdu,
|
||||
hci_subev = (void *)(*hci_ev)->data;
|
||||
report = hci_subev->reports;
|
||||
|
||||
report->rssi = rxinfo->rssi + g_ble_ll_rx_power_compensation;
|
||||
report->rssi = rxinfo->rssi - ble_ll_rx_gain();
|
||||
|
||||
report->data_len = min(max_data_len, data_len - offset);
|
||||
os_mbuf_copydata(rxpdu, offset, report->data_len, report->data);
|
||||
|
||||
@@ -409,6 +409,15 @@ syscfg.defs:
|
||||
BLE_LL_FEM_PA:
|
||||
description: Enable FEM PA support
|
||||
value: MYNEWT_VAL(BLE_LL_PA)
|
||||
BLE_LL_FEM_PA_GAIN:
|
||||
description: PA fixed TX gain (in dBm).
|
||||
value: 0
|
||||
BLE_LL_FEM_PA_GAIN_TUNABLE:
|
||||
description: >
|
||||
PA TX gain is tunable and not constant. If enabled
|
||||
ble_ll_fem_pa_tx_power_set() and ble_ll_fem_pa_tx_power_round()
|
||||
shall be implemented (see ble_ll_fem.h for details).
|
||||
value: 0
|
||||
BLE_LL_FEM_PA_GPIO:
|
||||
description: >
|
||||
GPIO pin number to control PA. Pin is set to high state when PA
|
||||
@@ -421,6 +430,15 @@ syscfg.defs:
|
||||
BLE_LL_FEM_LNA:
|
||||
description: Enable LNA support
|
||||
value: MYNEWT_VAL(BLE_LL_LNA)
|
||||
BLE_LL_FEM_LNA_GAIN:
|
||||
description: LNA fixed RX gain (in dBm).
|
||||
value: 0
|
||||
BLE_LL_FEM_LNA_GAIN_TUNABLE:
|
||||
description: >
|
||||
LNA RX gain is tunable and not constant. If enabled
|
||||
ble_ll_fem_lna_rx_gain() shall be implemented (see ble_ll_fem.h for
|
||||
details).
|
||||
value: 0
|
||||
BLE_LL_FEM_LNA_GPIO:
|
||||
description: >
|
||||
GPIO pin number to control LNA. Pin is set to high state when LNA
|
||||
|
||||
Reference in New Issue
Block a user