Skip to content

Commit abfe5f1

Browse files
cvinayakfabiobaltieri
authored andcommitted
Bluetooth: Controller: 1 ms connection
1 ms connection interval support. Signed-off-by: Vinayak Kariappa Chettimada <[email protected]>
1 parent e7799d4 commit abfe5f1

File tree

10 files changed

+215
-42
lines changed

10 files changed

+215
-42
lines changed

subsys/bluetooth/controller/Kconfig.ll_sw_split

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1090,6 +1090,19 @@ config BT_CTLR_ALLOW_SAME_PEER_CONN
10901090
WARNING: This option enables behavior that violates the Bluetooth
10911091
specification.
10921092

1093+
config BT_CTLR_CONN_INTERVAL_LOW_LATENCY
1094+
bool "Allow low latency connection intervals"
1095+
help
1096+
Allow low latency connection intervals.
1097+
1098+
config BT_CTLR_EVENT_IFS_LOW_LAT_US
1099+
prompt "Low latency tIFS value in microseconds" if BT_CTLR_CONN_INTERVAL_LOW_LATENCY
1100+
int
1101+
default 52 if BT_CTLR_CONN_INTERVAL_LOW_LATENCY
1102+
default 150
1103+
help
1104+
Set low latency tIFS value.
1105+
10931106
endif # BT_CONN
10941107

10951108
config BT_CTLR_ADV_INDICATION

subsys/bluetooth/controller/ll_sw/lll.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@
1616

1717
#define EVENT_PIPELINE_MAX 7
1818

19-
#define ADV_INT_UNIT_US 625U
20-
#define SCAN_INT_UNIT_US 625U
21-
#define CONN_INT_UNIT_US 1250U
22-
#define ISO_INT_UNIT_US CONN_INT_UNIT_US
23-
#define PERIODIC_INT_UNIT_US CONN_INT_UNIT_US
19+
#define ADV_INT_UNIT_US 625U
20+
#define SCAN_INT_UNIT_US 625U
21+
#define CONN_INT_UNIT_US 1250U
22+
#define ISO_INT_UNIT_US CONN_INT_UNIT_US
23+
#define PERIODIC_INT_UNIT_US CONN_INT_UNIT_US
24+
#define CONN_LOW_LAT_INT_UNIT_US 500U
2425

2526
#define ISO_INTERVAL_TO_US(interval) ((interval) * ISO_INT_UNIT_US)
2627

subsys/bluetooth/controller/ll_sw/lll_conn.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,10 @@ int lll_conn_reset(void);
175175
void lll_conn_flush(uint16_t handle, struct lll_conn *lll);
176176

177177
void lll_conn_prepare_reset(void);
178-
int lll_conn_is_abort_cb(void *next, void *curr, lll_prepare_cb_t *resume_cb);
178+
int lll_conn_central_is_abort_cb(void *next, void *curr,
179+
lll_prepare_cb_t *resume_cb);
180+
int lll_conn_peripheral_is_abort_cb(void *next, void *curr,
181+
lll_prepare_cb_t *resume_cb);
179182
void lll_conn_abort_cb(struct lll_prepare_param *prepare_param, void *param);
180183
void lll_conn_isr_rx(void *param);
181184
void lll_conn_isr_tx(void *param);

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1311,10 +1311,15 @@ static void preempt(void *param)
13111311

13121312
/* Check if current event want to continue */
13131313
err = event.curr.is_abort_cb(ready->prepare_param.param, event.curr.param, &resume_cb);
1314-
if (!err) {
1315-
/* Let preemptor LLL know about the cancelled prepare */
1316-
ready->is_aborted = 1;
1317-
ready->abort_cb(&ready->prepare_param, ready->prepare_param.param);
1314+
if (!err || (err == -EBUSY)) {
1315+
/* Returns -EBUSY when same curr and next state/role, do not
1316+
* abort same curr and next event.
1317+
*/
1318+
if (err != -EBUSY) {
1319+
/* Let preemptor LLL know about the cancelled prepare */
1320+
ready->is_aborted = 1;
1321+
ready->abort_cb(&ready->prepare_param, ready->prepare_param.param);
1322+
}
13181323

13191324
return;
13201325
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ void lll_central_prepare(void *param)
7575
LL_ASSERT(err >= 0);
7676

7777
/* Invoke common pipeline handling of prepare */
78-
err = lll_prepare(lll_is_abort_cb, lll_conn_abort_cb, prepare_cb, 0,
79-
param);
78+
err = lll_prepare(lll_conn_central_is_abort_cb, lll_conn_abort_cb,
79+
prepare_cb, 0, param);
8080
LL_ASSERT(!err || err == -EINPROGRESS);
8181
}
8282

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

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,9 @@ void lll_conn_prepare_reset(void)
157157
#endif /* CONFIG_BT_CTLR_LE_ENC */
158158
}
159159

160-
int lll_conn_is_abort_cb(void *next, void *curr, lll_prepare_cb_t *resume_cb)
160+
#if defined(CONFIG_BT_CENTRAL)
161+
int lll_conn_central_is_abort_cb(void *next, void *curr,
162+
lll_prepare_cb_t *resume_cb)
161163
{
162164
struct lll_conn *lll = curr;
163165

@@ -166,8 +168,38 @@ int lll_conn_is_abort_cb(void *next, void *curr, lll_prepare_cb_t *resume_cb)
166168
return 0;
167169
}
168170

171+
/* Do not be aborted by same event if a single central trx has not been
172+
* exchanged.
173+
*/
174+
if ((next == curr) && (trx_cnt < 1U)) {
175+
return -EBUSY;
176+
}
177+
169178
return -ECANCELED;
170179
}
180+
#endif /* CONFIG_BT_CENTRAL */
181+
182+
#if defined(CONFIG_BT_PERIPHERAL)
183+
int lll_conn_peripheral_is_abort_cb(void *next, void *curr,
184+
lll_prepare_cb_t *resume_cb)
185+
{
186+
struct lll_conn *lll = curr;
187+
188+
/* Do not abort if near supervision timeout */
189+
if (lll->forced) {
190+
return 0;
191+
}
192+
193+
/* Do not be aborted by same event if a single peripheral trx has not
194+
* been exchanged.
195+
*/
196+
if ((next == curr) && (trx_cnt <= 1U)) {
197+
return -EBUSY;
198+
}
199+
200+
return -ECANCELED;
201+
}
202+
#endif /* CONFIG_BT_PERIPHERAL */
171203

172204
void lll_conn_abort_cb(struct lll_prepare_param *prepare_param, void *param)
173205
{

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ void lll_periph_prepare(void *param)
8080
lll = p->param;
8181

8282
/* Invoke common pipeline handling of prepare */
83-
err = lll_prepare(lll_conn_is_abort_cb, lll_conn_abort_cb, prepare_cb,
84-
0U, p);
83+
err = lll_prepare(lll_conn_peripheral_is_abort_cb, lll_conn_abort_cb,
84+
prepare_cb, 0U, param);
8585
LL_ASSERT(!err || err == -EINPROGRESS);
8686
}
8787

subsys/bluetooth/controller/ll_sw/ull_conn.c

Lines changed: 139 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -711,7 +711,13 @@ uint8_t ll_apto_get(uint16_t handle, uint16_t *apto)
711711
return BT_HCI_ERR_UNKNOWN_CONN_ID;
712712
}
713713

714-
*apto = conn->apto_reload * conn->lll.interval * 125U / 1000;
714+
if (conn->lll.interval >= BT_HCI_LE_INTERVAL_MIN) {
715+
*apto = conn->apto_reload * conn->lll.interval *
716+
CONN_INT_UNIT_US / (10U * USEC_PER_MSEC);
717+
} else {
718+
*apto = conn->apto_reload * (conn->lll.interval + 1U) *
719+
CONN_LOW_LAT_INT_UNIT_US / (10U * USEC_PER_MSEC);
720+
}
715721

716722
return 0;
717723
}
@@ -725,9 +731,17 @@ uint8_t ll_apto_set(uint16_t handle, uint16_t apto)
725731
return BT_HCI_ERR_UNKNOWN_CONN_ID;
726732
}
727733

728-
conn->apto_reload = RADIO_CONN_EVENTS(apto * 10U * 1000U,
729-
conn->lll.interval *
730-
CONN_INT_UNIT_US);
734+
if (conn->lll.interval >= BT_HCI_LE_INTERVAL_MIN) {
735+
conn->apto_reload =
736+
RADIO_CONN_EVENTS(apto * 10U * USEC_PER_MSEC,
737+
conn->lll.interval *
738+
CONN_INT_UNIT_US);
739+
} else {
740+
conn->apto_reload =
741+
RADIO_CONN_EVENTS(apto * 10U * USEC_PER_MSEC,
742+
(conn->lll.interval + 1U) *
743+
CONN_LOW_LAT_INT_UNIT_US);
744+
}
731745

732746
return 0;
733747
}
@@ -1061,8 +1075,17 @@ void ull_conn_done(struct node_rx_event_done *done)
10611075
if (0) {
10621076
#if defined(CONFIG_BT_PERIPHERAL)
10631077
} else if (lll->role) {
1064-
ull_drift_ticks_get(done, &ticks_drift_plus,
1065-
&ticks_drift_minus);
1078+
if (!conn->periph.drift_skip) {
1079+
ull_drift_ticks_get(done, &ticks_drift_plus,
1080+
&ticks_drift_minus);
1081+
1082+
if (ticks_drift_plus || ticks_drift_minus) {
1083+
conn->periph.drift_skip =
1084+
ull_ref_get(&conn->ull);
1085+
}
1086+
} else {
1087+
conn->periph.drift_skip--;
1088+
}
10661089

10671090
if (!ull_tx_q_peek(&conn->tx_q)) {
10681091
ull_conn_tx_demux(UINT8_MAX);
@@ -1106,10 +1129,18 @@ void ull_conn_done(struct node_rx_event_done *done)
11061129
else {
11071130
/* Start supervision timeout, if not started already */
11081131
if (!conn->supervision_expire) {
1109-
const uint32_t conn_interval_us = conn->lll.interval * CONN_INT_UNIT_US;
1132+
uint32_t conn_interval_us;
1133+
1134+
if (conn->lll.interval >= BT_HCI_LE_INTERVAL_MIN) {
1135+
conn_interval_us = conn->lll.interval *
1136+
CONN_INT_UNIT_US;
1137+
} else {
1138+
conn_interval_us = (conn->lll.interval + 1U) *
1139+
CONN_LOW_LAT_INT_UNIT_US;
1140+
}
11101141

11111142
conn->supervision_expire = RADIO_CONN_EVENTS(
1112-
(conn->supervision_timeout * 10U * 1000U),
1143+
(conn->supervision_timeout * 10U * USEC_PER_MSEC),
11131144
conn_interval_us);
11141145
}
11151146
}
@@ -2186,17 +2217,22 @@ void ull_conn_update_parameters(struct ll_conn *conn, uint8_t is_cu_proc, uint8_
21862217
uint32_t win_offset_us, uint16_t interval, uint16_t latency,
21872218
uint16_t timeout, uint16_t instant)
21882219
{
2189-
struct lll_conn *lll;
2220+
uint16_t conn_interval_unit_old;
2221+
uint16_t conn_interval_unit_new;
21902222
uint32_t ticks_win_offset = 0U;
2223+
uint16_t conn_interval_old_us;
2224+
uint16_t conn_interval_new_us;
21912225
uint32_t ticks_slot_overhead;
21922226
uint16_t conn_interval_old;
21932227
uint16_t conn_interval_new;
21942228
uint32_t conn_interval_us;
2195-
uint32_t periodic_us;
2196-
uint16_t latency_upd;
2229+
uint32_t ticks_at_expire;
21972230
uint16_t instant_latency;
2231+
uint32_t ready_delay_us;
21982232
uint16_t event_counter;
2199-
uint32_t ticks_at_expire;
2233+
uint32_t periodic_us;
2234+
uint16_t latency_upd;
2235+
struct lll_conn *lll;
22002236

22012237
lll = &conn->lll;
22022238

@@ -2220,16 +2256,89 @@ void ull_conn_update_parameters(struct ll_conn *conn, uint8_t is_cu_proc, uint8_
22202256
}
22212257
#endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
22222258

2259+
#if defined(CONFIG_BT_CTLR_PHY)
2260+
ready_delay_us = lll_radio_tx_ready_delay_get(lll->phy_tx,
2261+
lll->phy_flags);
2262+
#else
2263+
ready_delay_us = lll_radio_tx_ready_delay_get(0U, 0U);
2264+
#endif
2265+
22232266
/* compensate for instant_latency due to laziness */
2224-
conn_interval_old = instant_latency * lll->interval;
2225-
latency_upd = conn_interval_old / interval;
2226-
conn_interval_new = latency_upd * interval;
2227-
if (conn_interval_new > conn_interval_old) {
2228-
ticks_at_expire += HAL_TICKER_US_TO_TICKS((conn_interval_new - conn_interval_old) *
2229-
CONN_INT_UNIT_US);
2267+
if (lll->interval >= BT_HCI_LE_INTERVAL_MIN) {
2268+
conn_interval_old = instant_latency * lll->interval;
2269+
conn_interval_unit_old = CONN_INT_UNIT_US;
22302270
} else {
2231-
ticks_at_expire -= HAL_TICKER_US_TO_TICKS((conn_interval_old - conn_interval_new) *
2232-
CONN_INT_UNIT_US);
2271+
conn_interval_old = instant_latency * (lll->interval + 1U);
2272+
conn_interval_unit_old = CONN_LOW_LAT_INT_UNIT_US;
2273+
}
2274+
2275+
if (interval >= BT_HCI_LE_INTERVAL_MIN) {
2276+
uint16_t max_tx_time;
2277+
uint16_t max_rx_time;
2278+
uint32_t slot_us;
2279+
2280+
conn_interval_new = interval;
2281+
conn_interval_unit_new = CONN_INT_UNIT_US;
2282+
lll->tifs_tx_us = EVENT_IFS_DEFAULT_US;
2283+
lll->tifs_rx_us = EVENT_IFS_DEFAULT_US;
2284+
lll->tifs_hcto_us = EVENT_IFS_DEFAULT_US;
2285+
2286+
#if defined(CONFIG_BT_CTLR_DATA_LENGTH) && \
2287+
defined(CONFIG_BT_CTLR_SLOT_RESERVATION_UPDATE)
2288+
max_tx_time = lll->dle.eff.max_tx_time;
2289+
max_rx_time = lll->dle.eff.max_rx_time;
2290+
2291+
#else /* !CONFIG_BT_CTLR_DATA_LENGTH ||
2292+
* !CONFIG_BT_CTLR_SLOT_RESERVATION_UPDATE
2293+
*/
2294+
max_tx_time = PDU_DC_MAX_US(PDU_DC_PAYLOAD_SIZE_MIN, PHY_1M);
2295+
max_rx_time = PDU_DC_MAX_US(PDU_DC_PAYLOAD_SIZE_MIN, PHY_1M);
2296+
#if defined(CONFIG_BT_CTLR_PHY)
2297+
max_tx_time = MAX(max_tx_time, PDU_DC_MAX_US(PDU_DC_PAYLOAD_SIZE_MIN, lll->phy_tx));
2298+
max_rx_time = MAX(max_rx_time, PDU_DC_MAX_US(PDU_DC_PAYLOAD_SIZE_MIN, lll->phy_rx));
2299+
#endif /* !CONFIG_BT_CTLR_PHY */
2300+
#endif /* !CONFIG_BT_CTLR_DATA_LENGTH ||
2301+
* !CONFIG_BT_CTLR_SLOT_RESERVATION_UPDATE
2302+
*/
2303+
2304+
/* Calculate event time reservation */
2305+
slot_us = max_tx_time + max_rx_time;
2306+
slot_us += lll->tifs_rx_us + (EVENT_CLOCK_JITTER_US << 1);
2307+
slot_us += ready_delay_us;
2308+
2309+
if (IS_ENABLED(CONFIG_BT_CTLR_EVENT_OVERHEAD_RESERVE_MAX) ||
2310+
(lll->role == BT_HCI_ROLE_CENTRAL)) {
2311+
slot_us += EVENT_OVERHEAD_START_US + EVENT_OVERHEAD_END_US;
2312+
}
2313+
2314+
conn->ull.ticks_slot = HAL_TICKER_US_TO_TICKS_CEIL(slot_us);
2315+
2316+
} else {
2317+
conn_interval_new = interval + 1U;
2318+
conn_interval_unit_new = CONN_LOW_LAT_INT_UNIT_US;
2319+
lll->tifs_tx_us = CONFIG_BT_CTLR_EVENT_IFS_LOW_LAT_US;
2320+
lll->tifs_rx_us = CONFIG_BT_CTLR_EVENT_IFS_LOW_LAT_US;
2321+
lll->tifs_hcto_us = CONFIG_BT_CTLR_EVENT_IFS_LOW_LAT_US;
2322+
/* Reserve only the processing overhead, on overlap the
2323+
* is_abort_cb mechanism will ensure to continue the event so
2324+
* as to not loose anchor point sync.
2325+
*/
2326+
conn->ull.ticks_slot =
2327+
HAL_TICKER_US_TO_TICKS_CEIL(EVENT_OVERHEAD_START_US);
2328+
}
2329+
2330+
conn_interval_us = conn_interval_new * conn_interval_unit_new;
2331+
periodic_us = conn_interval_us;
2332+
2333+
conn_interval_old_us = conn_interval_old * conn_interval_unit_old;
2334+
latency_upd = conn_interval_old_us / conn_interval_us;
2335+
conn_interval_new_us = latency_upd * conn_interval_us;
2336+
if (conn_interval_new_us > conn_interval_old_us) {
2337+
ticks_at_expire += HAL_TICKER_US_TO_TICKS(
2338+
conn_interval_new_us - conn_interval_old_us);
2339+
} else {
2340+
ticks_at_expire -= HAL_TICKER_US_TO_TICKS(
2341+
conn_interval_old_us - conn_interval_new_us);
22332342
}
22342343

22352344
lll->latency_prepare += conn->llcp.prep.lazy;
@@ -2238,15 +2347,14 @@ void ull_conn_update_parameters(struct ll_conn *conn, uint8_t is_cu_proc, uint8_
22382347
/* calculate the offset */
22392348
if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) {
22402349
ticks_slot_overhead =
2241-
MAX(conn->ull.ticks_active_to_start, conn->ull.ticks_prepare_to_start);
2350+
MAX(conn->ull.ticks_active_to_start,
2351+
conn->ull.ticks_prepare_to_start);
2352+
22422353
} else {
22432354
ticks_slot_overhead = 0U;
22442355
}
22452356

22462357
/* calculate the window widening and interval */
2247-
conn_interval_us = interval * CONN_INT_UNIT_US;
2248-
periodic_us = conn_interval_us;
2249-
22502358
switch (lll->role) {
22512359
#if defined(CONFIG_BT_PERIPHERAL)
22522360
case BT_HCI_ROLE_PERIPHERAL:
@@ -2333,7 +2441,13 @@ void ull_conn_update_peer_sca(struct ll_conn *conn)
23332441
lll = &conn->lll;
23342442

23352443
/* calculate the window widening and interval */
2336-
conn_interval_us = lll->interval * CONN_INT_UNIT_US;
2444+
if (lll->interval >= BT_HCI_LE_INTERVAL_MIN) {
2445+
conn_interval_us = lll->interval *
2446+
CONN_INT_UNIT_US;
2447+
} else {
2448+
conn_interval_us = (lll->interval + 1U) *
2449+
CONN_LOW_LAT_INT_UNIT_US;
2450+
}
23372451
periodic_us = conn_interval_us;
23382452

23392453
lll->periph.window_widening_periodic_us =

subsys/bluetooth/controller/ll_sw/ull_conn_types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ struct ll_conn {
205205
#endif /* CONFIG_BT_CTLR_CONN_META */
206206
uint8_t latency_cancel:1;
207207
uint8_t sca:3;
208+
uint8_t drift_skip;
208209
uint32_t force;
209210
uint32_t ticks_to_offset;
210211
} periph;

0 commit comments

Comments
 (0)