Skip to content

Commit 25c8a99

Browse files
Bluetooth: controller: Enable back-to-back chaining for periodic adv
This enables chaining ota for periodic advertising. AUX_CHAIN_IND PDUs will be sent automatically if AuxPtr is detected in preceding PDU. AuxPtr offset is always set to achieve minimal required frame spacing, i.e. 300us (T_mafs). AuxPtr in all PDUs in advertising train are updated on enqueue since PDU spacing is already known at that time so we do not need to waste time in LLL. Signed-off-by: Andrzej Kaczmarek <[email protected]>
1 parent f8d18d8 commit 25c8a99

File tree

6 files changed

+205
-12
lines changed

6 files changed

+205
-12
lines changed

subsys/bluetooth/controller/Kconfig.ll_sw_split

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,26 @@ config BT_CTLR_ADV_PDU_LINK
172172
is required to enable advertising data trains (i.e. transmission of
173173
AUX_CHAIN_IND).
174174

175+
config BT_CTLR_ADV_SYNC_PDU_BACK2BACK
176+
bool "Enable back-to-back transmission of periodic advertising trains"
177+
depends on BT_CTLR_ADV_PERIODIC
178+
select BT_CTLR_ADV_PDU_LINK
179+
help
180+
Enables transmission of AUX_CHAIN_IND in periodic advertising train by
181+
sending each AUX_CHAIN_IND one after another back-to-back.
182+
Note, consecutive AUX_CHAIN_IND packets are not scheduled but sent at
183+
a constant offset on a best effort basis. This means advertising train can
184+
be preempted by other event at any time.
185+
186+
config BT_CTLR_ADV_SYNC_PDU_BACK2BACK_AFS
187+
int "AUX Frame Space for back-to-back transmission of periodic advertising trains"
188+
depends on BT_CTLR_ADV_SYNC_PDU_BACK2BACK
189+
default 300
190+
range 300 1000
191+
help
192+
Specific AUX Frame Space to be used for back-to-back transmission of
193+
periodic advertising trains. Time specified in microseconds.
194+
175195
config BT_CTLR_ADV_DATA_BUF_MAX
176196
int "Advertising Data Maximum Buffers"
177197
depends on BT_BROADCASTER

subsys/bluetooth/controller/ll_sw/lll_adv.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ struct lll_adv_sync {
2727
uint32_t ticks_offset;
2828

2929
struct lll_adv_pdu data;
30+
#if defined(CONFIG_BT_CTLR_ADV_PDU_LINK)
31+
struct pdu_adv *last_pdu;
32+
#endif /* CONFIG_BT_CTLR_ADV_PDU_LINK */
3033

3134
#if defined(CONFIG_BT_CTLR_ADV_ISO)
3235
struct lll_adv_iso *iso;

subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_pdu.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ static inline struct pdu_adv *lll_adv_aux_data_curr_get(struct lll_adv_aux *lll)
9191
#if defined(CONFIG_BT_CTLR_ADV_PERIODIC)
9292
int lll_adv_and_extra_data_release(struct lll_adv_pdu *pdu);
9393

94+
#if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
95+
void lll_adv_sync_pdu_b2b_update(struct lll_adv_sync *lll, uint8_t idx);
96+
#endif
97+
9498
struct pdu_adv *lll_adv_pdu_and_extra_data_alloc(struct lll_adv_pdu *pdu,
9599
void **extra_data,
96100
uint8_t *idx);

subsys/bluetooth/controller/ll_sw/nordic/lll/lll_adv_sync.c

Lines changed: 175 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,29 @@
3333
#include "lll_internal.h"
3434
#include "lll_adv_internal.h"
3535
#include "lll_tim_internal.h"
36+
#include "lll_prof_internal.h"
3637
#include "lll_df_internal.h"
3738

3839
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER)
3940
#define LOG_MODULE_NAME bt_ctlr_lll_adv_sync
4041
#include "common/log.h"
4142
#include "hal/debug.h"
4243

44+
#if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
45+
#define ADV_SYNC_PDU_B2B_AFS (CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK_AFS)
46+
#endif
47+
4348
static int init_reset(void);
4449
static int prepare_cb(struct lll_prepare_param *p);
4550
static void abort_cb(struct lll_prepare_param *prepare_param, void *param);
4651
static void isr_done(void *param);
52+
#if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
53+
static void isr_tx(void *param);
54+
static void pdu_b2b_update(struct lll_adv_sync *lll, struct pdu_adv *pdu);
55+
static void pdu_b2b_aux_ptr_update(struct pdu_adv *pdu, uint8_t phy,
56+
uint8_t flags, uint8_t chan_idx,
57+
uint32_t tifs);
58+
#endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK */
4759

4860
int lll_adv_sync_init(void)
4961
{
@@ -148,6 +160,15 @@ static int prepare_cb(struct lll_prepare_param *p)
148160
pdu = lll_adv_sync_data_latest_get(lll, &extra_data, &upd);
149161
LL_ASSERT(pdu);
150162

163+
#if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
164+
if (upd) {
165+
/* AuxPtr offsets for b2b TX are fixed for given chain so we can
166+
* calculate them here in advance.
167+
*/
168+
pdu_b2b_update(lll, pdu);
169+
}
170+
#endif
171+
151172
#if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
152173
if (extra_data) {
153174
df_cfg = (struct lll_df_adv_cfg *)extra_data;
@@ -162,16 +183,26 @@ static int prepare_cb(struct lll_prepare_param *p)
162183

163184
radio_pkt_tx_set(pdu);
164185

165-
/* TODO: chaining */
166-
radio_isr_set(isr_done, lll);
186+
#if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
187+
if (pdu->adv_ext_ind.ext_hdr_len && pdu->adv_ext_ind.ext_hdr.aux_ptr) {
188+
lll->last_pdu = pdu;
167189

190+
radio_isr_set(isr_tx, lll);
191+
radio_tmr_tifs_set(ADV_SYNC_PDU_B2B_AFS);
192+
radio_switch_complete_and_b2b_tx(phy_s, 0, phy_s, 0);
193+
#else
194+
if (0) {
195+
#endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK */
196+
} else {
197+
radio_isr_set(isr_done, lll);
168198
#if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
169-
if (df_cfg) {
170-
radio_switch_complete_and_phy_end_disable();
171-
} else
199+
if (df_cfg) {
200+
radio_switch_complete_and_phy_end_disable();
201+
} else
172202
#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
173-
{
174-
radio_switch_complete_and_disable();
203+
{
204+
radio_switch_complete_and_disable();
205+
}
175206
}
176207

177208
ticks_at_event = p->ticks_at_expire;
@@ -256,3 +287,140 @@ static void isr_done(void *param)
256287
#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
257288
lll_isr_done(lll);
258289
}
290+
291+
#if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
292+
static void isr_tx(void *param)
293+
{
294+
struct lll_adv_sync *lll_sync;
295+
struct pdu_adv *pdu;
296+
struct lll_adv *lll;
297+
uint32_t hcto;
298+
299+
if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) {
300+
lll_prof_latency_capture();
301+
}
302+
303+
/* Clear radio tx status and events */
304+
lll_isr_tx_status_reset();
305+
306+
lll_sync = param;
307+
lll = lll_sync->adv;
308+
309+
/* TODO: do not hardcode to single value */
310+
lll_chan_set(0);
311+
312+
pdu = lll_adv_pdu_linked_next_get(lll_sync->last_pdu);
313+
LL_ASSERT(pdu);
314+
lll_sync->last_pdu = pdu;
315+
316+
/* setup tIFS switching */
317+
if (pdu->adv_ext_ind.ext_hdr_len && pdu->adv_ext_ind.ext_hdr.aux_ptr) {
318+
radio_tmr_tifs_set(ADV_SYNC_PDU_B2B_AFS);
319+
radio_isr_set(isr_tx, lll_sync);
320+
radio_switch_complete_and_b2b_tx(lll->phy_s, 0, lll->phy_s, 0);
321+
} else {
322+
radio_isr_set(lll_isr_done, lll);
323+
#if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
324+
if (lll_sync->cte_started) {
325+
radio_switch_complete_and_phy_end_disable();
326+
} else
327+
#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
328+
{
329+
radio_switch_complete_and_disable();
330+
}
331+
}
332+
333+
radio_pkt_tx_set(pdu);
334+
335+
/* assert if radio packet ptr is not set and radio started rx */
336+
LL_ASSERT(!radio_is_ready());
337+
338+
if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) {
339+
lll_prof_cputime_capture();
340+
}
341+
342+
/* +/- 2us active clock jitter, +1 us hcto compensation */
343+
hcto = radio_tmr_tifs_base_get() + ADV_SYNC_PDU_B2B_AFS + 4 + 1;
344+
hcto += radio_tx_chain_delay_get(lll->phy_s, 1);
345+
hcto += addr_us_get(lll->phy_s);
346+
hcto -= radio_tx_chain_delay_get(lll->phy_s, 0);
347+
radio_tmr_hcto_configure(hcto);
348+
349+
/* capture end of AUX_SYNC_IND/AUX_CHAIN_IND PDU, used for calculating
350+
* next PDU timestamp.
351+
*/
352+
radio_tmr_end_capture();
353+
354+
#if defined(CONFIG_BT_CTLR_GPIO_LNA_PIN)
355+
if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) {
356+
/* PA/LNA enable is overwriting packet end used in ISR
357+
* profiling, hence back it up for later use.
358+
*/
359+
lll_prof_radio_end_backup();
360+
}
361+
362+
radio_gpio_lna_setup();
363+
radio_gpio_pa_lna_enable(radio_tmr_tifs_base_get() +
364+
ADV_SYNC_PDU_B2B_AFS - 4 -
365+
radio_tx_chain_delay_get(lll->phy_s, 0) -
366+
CONFIG_BT_CTLR_GPIO_LNA_OFFSET);
367+
#endif /* CONFIG_BT_CTLR_GPIO_LNA_PIN */
368+
369+
if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) {
370+
lll_prof_send();
371+
}
372+
}
373+
374+
static void pdu_b2b_update(struct lll_adv_sync *lll, struct pdu_adv *pdu)
375+
{
376+
while (pdu) {
377+
pdu_b2b_aux_ptr_update(pdu, lll->adv->phy_s, 0, 0,
378+
ADV_SYNC_PDU_B2B_AFS);
379+
pdu = lll_adv_pdu_linked_next_get(pdu);
380+
}
381+
}
382+
383+
static void pdu_b2b_aux_ptr_update(struct pdu_adv *pdu, uint8_t phy,
384+
uint8_t flags, uint8_t chan_idx,
385+
uint32_t tifs)
386+
{
387+
struct pdu_adv_com_ext_adv *com_hdr;
388+
struct pdu_adv_ext_hdr *hdr;
389+
struct pdu_adv_aux_ptr *aux;
390+
uint32_t offs;
391+
uint8_t *dptr;
392+
393+
com_hdr = &pdu->adv_ext_ind;
394+
hdr = &com_hdr->ext_hdr;
395+
/* Skip flags */
396+
dptr = hdr->data;
397+
398+
if (!com_hdr->ext_hdr_len || !hdr->aux_ptr) {
399+
return;
400+
}
401+
402+
LL_ASSERT(!hdr->adv_addr);
403+
LL_ASSERT(!hdr->tgt_addr);
404+
405+
if (hdr->cte_info) {
406+
dptr++;
407+
}
408+
409+
LL_ASSERT(!hdr->adi);
410+
411+
/* Update AuxPtr */
412+
aux = (void *)dptr;
413+
offs = PKT_AC_US(pdu->len, phy) + tifs;
414+
offs = offs / OFFS_UNIT_30_US;
415+
if ((offs >> 13) != 0) {
416+
aux->offs = offs / (OFFS_UNIT_300_US / OFFS_UNIT_30_US);
417+
aux->offs_units = 1U;
418+
} else {
419+
aux->offs = offs;
420+
aux->offs_units = 0U;
421+
}
422+
aux->chan_idx = chan_idx;
423+
aux->ca = 0;
424+
aux->phy = find_lsb_set(phy) - 1;
425+
}
426+
#endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK */

subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ void lll_scan_prepare_connect_req(struct lll_scan *lll, struct pdu_adv *pdu_tx,
146146

147147
conn_interval_us = (uint32_t)lll_conn->interval * CONN_INT_UNIT_US;
148148
conn_offset_us = radio_tmr_end_get() + EVENT_IFS_US +
149-
PKT_AC_US(sizeof(struct pdu_adv_connect_ind), 0,
149+
PKT_AC_US(sizeof(struct pdu_adv_connect_ind),
150150
phy == PHY_LEGACY ? PHY_1M : phy);
151151

152152
/* Add transmitWindowDelay to default calculated connection offset:

subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -433,11 +433,9 @@ static int isr_rx_pdu(struct lll_scan_aux *lll, uint8_t devmatch_ok,
433433
ull = HDR_LLL2ULL(lll_scan);
434434
if (pdu_end_us > (HAL_TICKER_TICKS_TO_US(ull->ticks_slot) -
435435
EVENT_IFS_US -
436-
PKT_AC_US(aux_connect_req_len, 0,
437-
lll->phy) -
436+
PKT_AC_US(aux_connect_req_len, lll->phy) -
438437
EVENT_IFS_US -
439-
PKT_AC_US(aux_connect_rsp_len, 0,
440-
lll->phy) -
438+
PKT_AC_US(aux_connect_rsp_len, lll->phy) -
441439
EVENT_OVERHEAD_START_US -
442440
EVENT_TICKER_RES_MARGIN_US)) {
443441
return -ETIME;

0 commit comments

Comments
 (0)