Skip to content

Commit 634177e

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 361759c commit 634177e

File tree

4 files changed

+195
-8
lines changed

4 files changed

+195
-8
lines changed

subsys/bluetooth/controller/Kconfig.ll_sw_split

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,17 @@ 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 as a best effort. This means advertising train can be
184+
preempted by other event at any time.
185+
175186
config BT_CTLR_ADV_DATA_BUF_MAX
176187
int "Advertising Data Maximum Buffers"
177188
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: 177 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,28 @@
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_IFS (EVENT_MAFS_US)
46+
#endif
47+
4348
static int init_reset(void);
4449
static int prepare_cb(struct lll_prepare_param *p);
4550
static void isr_done(void *param);
51+
#if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
52+
static void isr_tx(void *param);
53+
static void pdu_b2b_update(struct lll_adv_sync *lll, struct pdu_adv *pdu);
54+
static void pdu_b2b_aux_ptr_update(struct pdu_adv *pdu, uint8_t phy,
55+
uint8_t flags, uint8_t chan_idx,
56+
uint32_t tifs);
57+
#endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK */
4658

4759
int lll_adv_sync_init(void)
4860
{
@@ -160,6 +172,15 @@ static int prepare_cb(struct lll_prepare_param *p)
160172
pdu = lll_adv_sync_data_latest_get(lll, &extra_data, &upd);
161173
LL_ASSERT(pdu);
162174

175+
#if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
176+
if (upd) {
177+
/* AuxPtr offsets for b2b TX are fixed for given chain so we can
178+
* calculate them here in advance.
179+
*/
180+
pdu_b2b_update(lll, pdu);
181+
}
182+
#endif
183+
163184
#if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
164185
if (extra_data) {
165186
df_cfg = (struct lll_df_adv_cfg *)extra_data;
@@ -174,17 +195,29 @@ static int prepare_cb(struct lll_prepare_param *p)
174195

175196
radio_pkt_tx_set(pdu);
176197

177-
/* TODO: chaining */
178-
radio_isr_set(lll_isr_done, lll);
179-
radio_isr_set(isr_done, lll);
198+
#if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
199+
if (pdu->adv_ext_ind.ext_hdr_len && pdu->adv_ext_ind.ext_hdr.aux_ptr) {
200+
lll->last_pdu = pdu;
180201

202+
radio_isr_set(isr_tx, lll);
203+
radio_tmr_tifs_set(ADV_SYNC_PDU_B2B_IFS);
204+
radio_switch_complete_and_b2b_tx(phy_s, 0, phy_s, 0);
205+
#else
206+
if (0) {
207+
#endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK */
208+
} else {
209+
/* There should be no AuxPtr without piggyback enabled */
210+
LL_ASSERT(!pdu->adv_ext_ind.ext_hdr.aux_ptr);
211+
212+
radio_isr_set(isr_done, lll);
181213
#if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
182-
if (df_cfg) {
183-
radio_switch_complete_and_phy_end_disable();
184-
} else
214+
if (df_cfg) {
215+
radio_switch_complete_and_phy_end_disable();
216+
} else
185217
#endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
186-
{
187-
radio_switch_complete_and_disable();
218+
{
219+
radio_switch_complete_and_disable();
220+
}
188221
}
189222

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

0 commit comments

Comments
 (0)