This is an automated email from the ASF dual-hosted git repository. janc pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git
commit 24c7b00317d4e80e0a02245bb0a9160d6ecfb4e7 Author: Szymon Janc <[email protected]> AuthorDate: Wed Sep 28 22:25:31 2022 +0200 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 --- nimble/controller/include/controller/ble_ll_fem.h | 13 +++++++ nimble/controller/src/ble_ll.c | 45 ++++++++++++++++++++--- nimble/controller/src/ble_ll_adv.c | 28 +++++++------- nimble/controller/src/ble_ll_conn.c | 2 +- nimble/controller/src/ble_ll_dtm.c | 3 +- nimble/controller/src/ble_ll_hci.c | 4 +- nimble/controller/src/ble_ll_hci_vs.c | 8 ++-- nimble/controller/src/ble_ll_priv.h | 19 ++++++++++ nimble/controller/src/ble_ll_scan.c | 6 +-- nimble/controller/src/ble_ll_scan_aux.c | 4 +- nimble/controller/syscfg.yml | 18 +++++++++ 11 files changed, 118 insertions(+), 32 deletions(-) diff --git a/nimble/controller/include/controller/ble_ll_fem.h b/nimble/controller/include/controller/ble_ll_fem.h index d8c6dbec..48cf94c5 100644 --- a/nimble/controller/include/controller/ble_ll_fem.h +++ b/nimble/controller/include/controller/ble_ll_fem.h @@ -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) diff --git a/nimble/controller/src/ble_ll.c b/nimble/controller/src/ble_ll.c index bcd03740..64c4f6e7 100644 --- a/nimble/controller/src/ble_ll.c +++ b/nimble/controller/src/ble_ll.c @@ -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); +} diff --git a/nimble/controller/src/ble_ll_adv.c b/nimble/controller/src/ble_ll_adv.c index 8733e5d8..8d6b6e85 100644 --- a/nimble/controller/src/ble_ll_adv.c +++ b/nimble/controller/src/ble_ll_adv.c @@ -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; diff --git a/nimble/controller/src/ble_ll_conn.c b/nimble/controller/src/ble_ll_conn.c index eeed8b66..2d344e22 100644 --- a/nimble/controller/src/ble_ll_conn.c +++ b/nimble/controller/src/ble_ll_conn.c @@ -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 diff --git a/nimble/controller/src/ble_ll_dtm.c b/nimble/controller/src/ble_ll_dtm.c index 1b41bc2d..2a32ccca 100644 --- a/nimble/controller/src/ble_ll_dtm.c +++ b/nimble/controller/src/ble_ll_dtm.c @@ -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; diff --git a/nimble/controller/src/ble_ll_hci.c b/nimble/controller/src/ble_ll_hci.c index fa3bf66b..79d90e50 100644 --- a/nimble/controller/src/ble_ll_hci.c +++ b/nimble/controller/src/ble_ll_hci.c @@ -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; diff --git a/nimble/controller/src/ble_ll_hci_vs.c b/nimble/controller/src/ble_ll_hci_vs.c index 93ec2e85..d248d213 100644 --- a/nimble/controller/src/ble_ll_hci_vs.c +++ b/nimble/controller/src/ble_ll_hci_vs.c @@ -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; diff --git a/nimble/controller/src/ble_ll_priv.h b/nimble/controller/src/ble_ll_priv.h index c373de20..ccaf9faa 100644 --- a/nimble/controller/src/ble_ll_priv.h +++ b/nimble/controller/src/ble_ll_priv.h @@ -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" diff --git a/nimble/controller/src/ble_ll_scan.c b/nimble/controller/src/ble_ll_scan.c index d9354050..a5b3833b 100644 --- a/nimble/controller/src/ble_ll_scan.c +++ b/nimble/controller/src/ble_ll_scan.c @@ -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) { diff --git a/nimble/controller/src/ble_ll_scan_aux.c b/nimble/controller/src/ble_ll_scan_aux.c index 0800f4af..f7c92d53 100644 --- a/nimble/controller/src/ble_ll_scan_aux.c +++ b/nimble/controller/src/ble_ll_scan_aux.c @@ -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); diff --git a/nimble/controller/syscfg.yml b/nimble/controller/syscfg.yml index 364e9f58..ba750daa 100644 --- a/nimble/controller/syscfg.yml +++ b/nimble/controller/syscfg.yml @@ -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
