Skip to content

Commit 9ef7145

Browse files
nimble/phy/nrf: Add support for PA/LNA on nRF52xxx
This adds support for PA/LNA on nRF52 phy. PA/LNA is controlled using PPI CH6 (enable) and CH7 (disable). At the moment no separate timestamp is used to enable PA/LNA in advance, it's simply enabled just after ramp-up. This should be fine for front-end modules with short switch on time like SKY66112 (<800ns).
1 parent 05538bc commit 9ef7145

File tree

1 file changed

+122
-22
lines changed

1 file changed

+122
-22
lines changed

nimble/drivers/nrf52/src/ble_phy.c

Lines changed: 122 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "controller/ble_phy.h"
3030
#include "controller/ble_phy_trace.h"
3131
#include "controller/ble_ll.h"
32+
#include "controller/ble_ll_plna.h"
3233
#include "nrfx.h"
3334
#if MYNEWT
3435
#include "mcu/nrf52_clock.h"
@@ -49,9 +50,11 @@
4950
* using PPI somewhere else.
5051
*
5152
* Pre-programmed channels: CH20, CH21, CH23, CH25, CH31
52-
* Regular channels: CH4, CH5 and optionally CH17, CH18, CH19
53+
* Regular channels: CH4, CH5 and optionally CH6, CH7, CH17, CH18, CH19
5354
* - CH4 = cancel wfr timer on address match
5455
* - CH5 = disable radio on wfr timer expiry
56+
* - CH6 = PA/LNA control (enable)
57+
* - CH7 = PA/LNA control (disable)
5558
* - CH17 = (optional) gpio debug for radio ramp-up
5659
* - CH18 = (optional) gpio debug for wfr timer RX enabled
5760
* - CH19 = (optional) gpio debug for wfr timer radio disabled
@@ -277,6 +280,27 @@ struct nrf_ccm_data
277280
struct nrf_ccm_data g_nrf_ccm_data;
278281
#endif
279282

283+
static int g_ble_phy_gpiote_idx;
284+
285+
#if MYNEWT_VAL(BLE_LL_PA) || MYNEWT_VAL(BLE_LL_LNA)
286+
287+
#define PLNA_SINGLE_GPIO \
288+
(!MYNEWT_VAL(BLE_LL_PA) || !MYNEWT_VAL(BLE_LL_LNA) || \
289+
(MYNEWT_VAL(BLE_LL_PA_GPIO) == MYNEWT_VAL(BLE_LL_LNA_GPIO)))
290+
291+
#if PLNA_SINGLE_GPIO
292+
static uint8_t plna_idx;
293+
#else
294+
#if MYNEWT_VAL(BLE_LL_PA)
295+
static uint8_t plna_pa_idx;
296+
#endif
297+
#if MYNEWT_VAL(BLE_LL_LNA)
298+
static uint8_t plna_lna_idx;
299+
#endif
300+
#endif
301+
302+
#endif
303+
280304
static void
281305
ble_phy_apply_errata_102_106_107(void)
282306
{
@@ -400,6 +424,36 @@ ble_phy_mode_set(uint8_t tx_phy_mode, uint8_t rx_phy_mode)
400424
}
401425
#endif
402426

427+
static void
428+
ble_phy_plna_enable_pa(void)
429+
{
430+
#if MYNEWT_VAL(BLE_LL_PA)
431+
ble_ll_plna_pa_enable();
432+
433+
#if !PLNA_SINGLE_GPIO
434+
NRF_PPI->CH[6].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_SET[plna_pa_idx]);
435+
NRF_PPI->CH[7].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_CLR[plna_pa_idx]);
436+
#endif
437+
438+
NRF_PPI->CHENSET = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk;
439+
#endif
440+
}
441+
442+
static void
443+
ble_phy_plna_enable_lna(void)
444+
{
445+
#if MYNEWT_VAL(BLE_LL_LNA)
446+
ble_ll_plna_lna_enable();
447+
448+
#if !PLNA_SINGLE_GPIO
449+
NRF_PPI->CH[6].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_SET[plna_lna_idx]);
450+
NRF_PPI->CH[7].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_CLR[plna_lna_idx]);
451+
#endif
452+
453+
NRF_PPI->CHENSET = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk;
454+
#endif
455+
}
456+
403457
int
404458
ble_phy_get_cur_phy(void)
405459
{
@@ -925,6 +979,8 @@ ble_phy_tx_end_isr(void)
925979
NRF_TIMER0->CC[0] = rx_time;
926980
NRF_TIMER0->EVENTS_COMPARE[0] = 0;
927981
NRF_PPI->CHENSET = PPI_CHEN_CH21_Msk;
982+
983+
ble_phy_plna_enable_lna();
928984
} else {
929985
/*
930986
* XXX: not sure we need to stop the timer here all the time. Or that
@@ -1053,6 +1109,8 @@ ble_phy_rx_end_isr(void)
10531109
NRF_TIMER0->EVENTS_COMPARE[0] = 0;
10541110
NRF_PPI->CHENSET = PPI_CHEN_CH20_Msk;
10551111

1112+
ble_phy_plna_enable_pa();
1113+
10561114
/*
10571115
* XXX: Hack warning!
10581116
*
@@ -1255,13 +1313,21 @@ ble_phy_isr(void)
12551313

12561314
switch (g_ble_phy_data.phy_state) {
12571315
case BLE_PHY_STATE_RX:
1316+
#if MYNEWT_VAL(BLE_LL_LNA)
1317+
NRF_PPI->CHENCLR = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk;
1318+
ble_ll_plna_lna_disable();
1319+
#endif
12581320
if (g_ble_phy_data.phy_rx_started) {
12591321
ble_phy_rx_end_isr();
12601322
} else {
12611323
ble_ll_wfr_timer_exp(NULL);
12621324
}
12631325
break;
12641326
case BLE_PHY_STATE_TX:
1327+
#if MYNEWT_VAL(BLE_LL_PA)
1328+
NRF_PPI->CHENCLR = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk;
1329+
ble_ll_plna_pa_disable();
1330+
#endif
12651331
ble_phy_tx_end_isr();
12661332
break;
12671333
default:
@@ -1278,13 +1344,17 @@ ble_phy_isr(void)
12781344
}
12791345

12801346
#if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0 || \
1281-
MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0 || \
1282-
MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0
1283-
static inline void
1284-
ble_phy_dbg_time_setup_gpiote(int index, int pin)
1347+
MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0 || \
1348+
MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0 || \
1349+
MYNEWT_VAL(BLE_LL_PA) || \
1350+
MYNEWT_VAL(BLE_LL_LNA)
1351+
static int
1352+
ble_phy_gpiote_configure(int pin)
12851353
{
12861354
NRF_GPIO_Type *port;
12871355

1356+
g_ble_phy_gpiote_idx--;
1357+
12881358
#if NRF52840_XXAA
12891359
port = pin > 31 ? NRF_P1 : NRF_P0;
12901360
pin &= 0x1f;
@@ -1296,21 +1366,25 @@ ble_phy_dbg_time_setup_gpiote(int index, int pin)
12961366
port->DIRSET = (1 << pin);
12971367
port->OUTCLR = (1 << pin);
12981368

1299-
NRF_GPIOTE->CONFIG[index] =
1369+
NRF_GPIOTE->CONFIG[g_ble_phy_gpiote_idx] =
13001370
(GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) |
13011371
((pin & 0x1F) << GPIOTE_CONFIG_PSEL_Pos) |
13021372
#if NRF52840_XXAA
13031373
((port == NRF_P1) << GPIOTE_CONFIG_PORT_Pos);
13041374
#else
13051375
0;
13061376
#endif
1377+
1378+
BLE_LL_ASSERT(g_ble_phy_gpiote_idx >= 0);
1379+
1380+
return g_ble_phy_gpiote_idx;
13071381
}
13081382
#endif
13091383

13101384
static void
13111385
ble_phy_dbg_time_setup(void)
13121386
{
1313-
int gpiote_idx __attribute__((unused)) = 8;
1387+
int idx __attribute__((unused));
13141388

13151389
/*
13161390
* We setup GPIOTE starting from last configuration index to minimize risk
@@ -1319,44 +1393,41 @@ ble_phy_dbg_time_setup(void)
13191393
*/
13201394

13211395
#if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0
1322-
ble_phy_dbg_time_setup_gpiote(--gpiote_idx,
1323-
MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN));
1396+
idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN));
13241397

13251398
NRF_PPI->CH[17].EEP = (uint32_t)&(NRF_RADIO->EVENTS_READY);
1326-
NRF_PPI->CH[17].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[gpiote_idx]);
1399+
NRF_PPI->CH[17].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx]);
13271400
NRF_PPI->CHENSET = PPI_CHEN_CH17_Msk;
13281401

13291402
/* CH[20] and PPI CH[21] are on to trigger TASKS_TXEN or TASKS_RXEN */
1330-
NRF_PPI->FORK[20].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[gpiote_idx]);
1331-
NRF_PPI->FORK[21].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[gpiote_idx]);
1403+
NRF_PPI->FORK[20].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[idx]);
1404+
NRF_PPI->FORK[21].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[idx]);
13321405
#endif
13331406

13341407
#if MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0
1335-
ble_phy_dbg_time_setup_gpiote(--gpiote_idx,
1336-
MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN));
1408+
idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN));
13371409

13381410
/* CH[26] and CH[27] are always on for EVENT_ADDRESS and EVENT_END */
1339-
NRF_PPI->FORK[26].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[gpiote_idx]);
1340-
NRF_PPI->FORK[27].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[gpiote_idx]);
1411+
NRF_PPI->FORK[26].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[idx]);
1412+
NRF_PPI->FORK[27].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx]);
13411413
#endif
13421414

13431415
#if MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0
1344-
ble_phy_dbg_time_setup_gpiote(--gpiote_idx,
1345-
MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN));
1416+
idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN));
13461417

13471418
#if NRF52840_XXAA
13481419
NRF_PPI->CH[18].EEP = (uint32_t)&(NRF_RADIO->EVENTS_RXREADY);
13491420
#else
13501421
NRF_PPI->CH[18].EEP = (uint32_t)&(NRF_RADIO->EVENTS_READY);
13511422
#endif
1352-
NRF_PPI->CH[18].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[gpiote_idx]);
1423+
NRF_PPI->CH[18].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[idx]);
13531424
NRF_PPI->CH[19].EEP = (uint32_t)&(NRF_RADIO->EVENTS_DISABLED);
1354-
NRF_PPI->CH[19].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[gpiote_idx]);
1425+
NRF_PPI->CH[19].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx]);
13551426
NRF_PPI->CHENSET = PPI_CHEN_CH18_Msk | PPI_CHEN_CH19_Msk;
13561427

13571428
/* CH[4] and CH[5] are always on for wfr */
1358-
NRF_PPI->FORK[4].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[gpiote_idx]);
1359-
NRF_PPI->FORK[5].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[gpiote_idx]);
1429+
NRF_PPI->FORK[4].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx]);
1430+
NRF_PPI->FORK[5].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx]);
13601431
#endif
13611432
}
13621433

@@ -1372,6 +1443,8 @@ ble_phy_init(void)
13721443
{
13731444
int rc;
13741445

1446+
g_ble_phy_gpiote_idx = 8;
1447+
13751448
/* Default phy to use is 1M */
13761449
g_ble_phy_data.phy_cur_phy_mode = BLE_PHY_MODE_1M;
13771450
g_ble_phy_data.phy_tx_phy_mode = BLE_PHY_MODE_1M;
@@ -1455,6 +1528,27 @@ ble_phy_init(void)
14551528
NRF_PPI->CH[5].EEP = (uint32_t)&(NRF_TIMER0->EVENTS_COMPARE[3]);
14561529
NRF_PPI->CH[5].TEP = (uint32_t)&(NRF_RADIO->TASKS_DISABLE);
14571530

1531+
#if MYNEWT_VAL(BLE_LL_PA) || MYNEWT_VAL(BLE_LL_LNA)
1532+
#if PLNA_SINGLE_GPIO
1533+
plna_idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_LL_PA_GPIO));
1534+
NRF_PPI->CH[6].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_SET[plna_idx]);
1535+
NRF_PPI->CH[7].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_CLR[plna_idx]);
1536+
#else
1537+
#if MYNEWT_VAL(BLE_LL_PA)
1538+
plna_pa_idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_LL_PA_GPIO));
1539+
NRF_GPIOTE->TASKS_CLR[plna_pa_idx] = 1;
1540+
#endif
1541+
#if MYNEWT_VAL(BLE_LL_LNA)
1542+
plna_lna_idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_LL_LNA_GPIO));
1543+
NRF_GPIOTE->TASKS_CLR[plna_lna_idx] = 1;
1544+
#endif
1545+
#endif
1546+
1547+
NRF_PPI->CH[6].EEP = (uint32_t)&(NRF_RADIO->EVENTS_READY);
1548+
NRF_PPI->CH[7].EEP = (uint32_t)&(NRF_RADIO->EVENTS_DISABLED);
1549+
NRF_PPI->CHENCLR = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk;
1550+
#endif
1551+
14581552
/* Set isr in vector table and enable interrupt */
14591553
#ifndef RIOT_VERSION
14601554
NVIC_SetPriority(RADIO_IRQn, 0);
@@ -1617,7 +1711,10 @@ ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs)
16171711
/* Enable PPI to automatically start TXEN */
16181712
NRF_PPI->CHENSET = PPI_CHEN_CH20_Msk;
16191713
rc = 0;
1714+
1715+
ble_phy_plna_enable_pa();
16201716
}
1717+
16211718
return rc;
16221719
}
16231720

@@ -1662,6 +1759,8 @@ ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs)
16621759
/* Enable PPI to automatically start RXEN */
16631760
NRF_PPI->CHENSET = PPI_CHEN_CH21_Msk;
16641761

1762+
ble_phy_plna_enable_lna();
1763+
16651764
/* Start rx */
16661765
rc = ble_phy_rx();
16671766

@@ -1959,6 +2058,7 @@ ble_phy_disable_irq_and_ppi(void)
19592058
NRF_PPI->CHENCLR = PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk | PPI_CHEN_CH20_Msk |
19602059
PPI_CHEN_CH21_Msk | PPI_CHEN_CH23_Msk |
19612060
PPI_CHEN_CH25_Msk | PPI_CHEN_CH31_Msk;
2061+
NRF_PPI->CHENCLR = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk;
19622062
NVIC_ClearPendingIRQ(RADIO_IRQn);
19632063
g_ble_phy_data.phy_state = BLE_PHY_STATE_IDLE;
19642064
}

0 commit comments

Comments
 (0)