Bluetooth: Controller: 1 ms connection
1 ms connection interval support. Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
This commit is contained in:
parent
e7799d4977
commit
abfe5f17a9
10 changed files with 215 additions and 42 deletions
|
@ -1090,6 +1090,19 @@ config BT_CTLR_ALLOW_SAME_PEER_CONN
|
|||
WARNING: This option enables behavior that violates the Bluetooth
|
||||
specification.
|
||||
|
||||
config BT_CTLR_CONN_INTERVAL_LOW_LATENCY
|
||||
bool "Allow low latency connection intervals"
|
||||
help
|
||||
Allow low latency connection intervals.
|
||||
|
||||
config BT_CTLR_EVENT_IFS_LOW_LAT_US
|
||||
prompt "Low latency tIFS value in microseconds" if BT_CTLR_CONN_INTERVAL_LOW_LATENCY
|
||||
int
|
||||
default 52 if BT_CTLR_CONN_INTERVAL_LOW_LATENCY
|
||||
default 150
|
||||
help
|
||||
Set low latency tIFS value.
|
||||
|
||||
endif # BT_CONN
|
||||
|
||||
config BT_CTLR_ADV_INDICATION
|
||||
|
|
|
@ -16,11 +16,12 @@
|
|||
|
||||
#define EVENT_PIPELINE_MAX 7
|
||||
|
||||
#define ADV_INT_UNIT_US 625U
|
||||
#define SCAN_INT_UNIT_US 625U
|
||||
#define CONN_INT_UNIT_US 1250U
|
||||
#define ISO_INT_UNIT_US CONN_INT_UNIT_US
|
||||
#define PERIODIC_INT_UNIT_US CONN_INT_UNIT_US
|
||||
#define ADV_INT_UNIT_US 625U
|
||||
#define SCAN_INT_UNIT_US 625U
|
||||
#define CONN_INT_UNIT_US 1250U
|
||||
#define ISO_INT_UNIT_US CONN_INT_UNIT_US
|
||||
#define PERIODIC_INT_UNIT_US CONN_INT_UNIT_US
|
||||
#define CONN_LOW_LAT_INT_UNIT_US 500U
|
||||
|
||||
#define ISO_INTERVAL_TO_US(interval) ((interval) * ISO_INT_UNIT_US)
|
||||
|
||||
|
|
|
@ -175,7 +175,10 @@ int lll_conn_reset(void);
|
|||
void lll_conn_flush(uint16_t handle, struct lll_conn *lll);
|
||||
|
||||
void lll_conn_prepare_reset(void);
|
||||
int lll_conn_is_abort_cb(void *next, void *curr, lll_prepare_cb_t *resume_cb);
|
||||
int lll_conn_central_is_abort_cb(void *next, void *curr,
|
||||
lll_prepare_cb_t *resume_cb);
|
||||
int lll_conn_peripheral_is_abort_cb(void *next, void *curr,
|
||||
lll_prepare_cb_t *resume_cb);
|
||||
void lll_conn_abort_cb(struct lll_prepare_param *prepare_param, void *param);
|
||||
void lll_conn_isr_rx(void *param);
|
||||
void lll_conn_isr_tx(void *param);
|
||||
|
|
|
@ -1311,10 +1311,15 @@ preempt_find_preemptor:
|
|||
|
||||
/* Check if current event want to continue */
|
||||
err = event.curr.is_abort_cb(ready->prepare_param.param, event.curr.param, &resume_cb);
|
||||
if (!err) {
|
||||
/* Let preemptor LLL know about the cancelled prepare */
|
||||
ready->is_aborted = 1;
|
||||
ready->abort_cb(&ready->prepare_param, ready->prepare_param.param);
|
||||
if (!err || (err == -EBUSY)) {
|
||||
/* Returns -EBUSY when same curr and next state/role, do not
|
||||
* abort same curr and next event.
|
||||
*/
|
||||
if (err != -EBUSY) {
|
||||
/* Let preemptor LLL know about the cancelled prepare */
|
||||
ready->is_aborted = 1;
|
||||
ready->abort_cb(&ready->prepare_param, ready->prepare_param.param);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -75,8 +75,8 @@ void lll_central_prepare(void *param)
|
|||
LL_ASSERT(err >= 0);
|
||||
|
||||
/* Invoke common pipeline handling of prepare */
|
||||
err = lll_prepare(lll_is_abort_cb, lll_conn_abort_cb, prepare_cb, 0,
|
||||
param);
|
||||
err = lll_prepare(lll_conn_central_is_abort_cb, lll_conn_abort_cb,
|
||||
prepare_cb, 0, param);
|
||||
LL_ASSERT(!err || err == -EINPROGRESS);
|
||||
}
|
||||
|
||||
|
|
|
@ -157,7 +157,9 @@ void lll_conn_prepare_reset(void)
|
|||
#endif /* CONFIG_BT_CTLR_LE_ENC */
|
||||
}
|
||||
|
||||
int lll_conn_is_abort_cb(void *next, void *curr, lll_prepare_cb_t *resume_cb)
|
||||
#if defined(CONFIG_BT_CENTRAL)
|
||||
int lll_conn_central_is_abort_cb(void *next, void *curr,
|
||||
lll_prepare_cb_t *resume_cb)
|
||||
{
|
||||
struct lll_conn *lll = curr;
|
||||
|
||||
|
@ -166,8 +168,38 @@ int lll_conn_is_abort_cb(void *next, void *curr, lll_prepare_cb_t *resume_cb)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Do not be aborted by same event if a single central trx has not been
|
||||
* exchanged.
|
||||
*/
|
||||
if ((next == curr) && (trx_cnt < 1U)) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return -ECANCELED;
|
||||
}
|
||||
#endif /* CONFIG_BT_CENTRAL */
|
||||
|
||||
#if defined(CONFIG_BT_PERIPHERAL)
|
||||
int lll_conn_peripheral_is_abort_cb(void *next, void *curr,
|
||||
lll_prepare_cb_t *resume_cb)
|
||||
{
|
||||
struct lll_conn *lll = curr;
|
||||
|
||||
/* Do not abort if near supervision timeout */
|
||||
if (lll->forced) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Do not be aborted by same event if a single peripheral trx has not
|
||||
* been exchanged.
|
||||
*/
|
||||
if ((next == curr) && (trx_cnt <= 1U)) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
return -ECANCELED;
|
||||
}
|
||||
#endif /* CONFIG_BT_PERIPHERAL */
|
||||
|
||||
void lll_conn_abort_cb(struct lll_prepare_param *prepare_param, void *param)
|
||||
{
|
||||
|
|
|
@ -80,8 +80,8 @@ void lll_periph_prepare(void *param)
|
|||
lll = p->param;
|
||||
|
||||
/* Invoke common pipeline handling of prepare */
|
||||
err = lll_prepare(lll_conn_is_abort_cb, lll_conn_abort_cb, prepare_cb,
|
||||
0U, p);
|
||||
err = lll_prepare(lll_conn_peripheral_is_abort_cb, lll_conn_abort_cb,
|
||||
prepare_cb, 0U, param);
|
||||
LL_ASSERT(!err || err == -EINPROGRESS);
|
||||
}
|
||||
|
||||
|
|
|
@ -711,7 +711,13 @@ uint8_t ll_apto_get(uint16_t handle, uint16_t *apto)
|
|||
return BT_HCI_ERR_UNKNOWN_CONN_ID;
|
||||
}
|
||||
|
||||
*apto = conn->apto_reload * conn->lll.interval * 125U / 1000;
|
||||
if (conn->lll.interval >= BT_HCI_LE_INTERVAL_MIN) {
|
||||
*apto = conn->apto_reload * conn->lll.interval *
|
||||
CONN_INT_UNIT_US / (10U * USEC_PER_MSEC);
|
||||
} else {
|
||||
*apto = conn->apto_reload * (conn->lll.interval + 1U) *
|
||||
CONN_LOW_LAT_INT_UNIT_US / (10U * USEC_PER_MSEC);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -725,9 +731,17 @@ uint8_t ll_apto_set(uint16_t handle, uint16_t apto)
|
|||
return BT_HCI_ERR_UNKNOWN_CONN_ID;
|
||||
}
|
||||
|
||||
conn->apto_reload = RADIO_CONN_EVENTS(apto * 10U * 1000U,
|
||||
conn->lll.interval *
|
||||
CONN_INT_UNIT_US);
|
||||
if (conn->lll.interval >= BT_HCI_LE_INTERVAL_MIN) {
|
||||
conn->apto_reload =
|
||||
RADIO_CONN_EVENTS(apto * 10U * USEC_PER_MSEC,
|
||||
conn->lll.interval *
|
||||
CONN_INT_UNIT_US);
|
||||
} else {
|
||||
conn->apto_reload =
|
||||
RADIO_CONN_EVENTS(apto * 10U * USEC_PER_MSEC,
|
||||
(conn->lll.interval + 1U) *
|
||||
CONN_LOW_LAT_INT_UNIT_US);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1061,8 +1075,17 @@ void ull_conn_done(struct node_rx_event_done *done)
|
|||
if (0) {
|
||||
#if defined(CONFIG_BT_PERIPHERAL)
|
||||
} else if (lll->role) {
|
||||
ull_drift_ticks_get(done, &ticks_drift_plus,
|
||||
&ticks_drift_minus);
|
||||
if (!conn->periph.drift_skip) {
|
||||
ull_drift_ticks_get(done, &ticks_drift_plus,
|
||||
&ticks_drift_minus);
|
||||
|
||||
if (ticks_drift_plus || ticks_drift_minus) {
|
||||
conn->periph.drift_skip =
|
||||
ull_ref_get(&conn->ull);
|
||||
}
|
||||
} else {
|
||||
conn->periph.drift_skip--;
|
||||
}
|
||||
|
||||
if (!ull_tx_q_peek(&conn->tx_q)) {
|
||||
ull_conn_tx_demux(UINT8_MAX);
|
||||
|
@ -1106,10 +1129,18 @@ void ull_conn_done(struct node_rx_event_done *done)
|
|||
else {
|
||||
/* Start supervision timeout, if not started already */
|
||||
if (!conn->supervision_expire) {
|
||||
const uint32_t conn_interval_us = conn->lll.interval * CONN_INT_UNIT_US;
|
||||
uint32_t conn_interval_us;
|
||||
|
||||
if (conn->lll.interval >= BT_HCI_LE_INTERVAL_MIN) {
|
||||
conn_interval_us = conn->lll.interval *
|
||||
CONN_INT_UNIT_US;
|
||||
} else {
|
||||
conn_interval_us = (conn->lll.interval + 1U) *
|
||||
CONN_LOW_LAT_INT_UNIT_US;
|
||||
}
|
||||
|
||||
conn->supervision_expire = RADIO_CONN_EVENTS(
|
||||
(conn->supervision_timeout * 10U * 1000U),
|
||||
(conn->supervision_timeout * 10U * USEC_PER_MSEC),
|
||||
conn_interval_us);
|
||||
}
|
||||
}
|
||||
|
@ -2186,17 +2217,22 @@ void ull_conn_update_parameters(struct ll_conn *conn, uint8_t is_cu_proc, uint8_
|
|||
uint32_t win_offset_us, uint16_t interval, uint16_t latency,
|
||||
uint16_t timeout, uint16_t instant)
|
||||
{
|
||||
struct lll_conn *lll;
|
||||
uint16_t conn_interval_unit_old;
|
||||
uint16_t conn_interval_unit_new;
|
||||
uint32_t ticks_win_offset = 0U;
|
||||
uint16_t conn_interval_old_us;
|
||||
uint16_t conn_interval_new_us;
|
||||
uint32_t ticks_slot_overhead;
|
||||
uint16_t conn_interval_old;
|
||||
uint16_t conn_interval_new;
|
||||
uint32_t conn_interval_us;
|
||||
uint32_t ticks_at_expire;
|
||||
uint16_t instant_latency;
|
||||
uint32_t ready_delay_us;
|
||||
uint16_t event_counter;
|
||||
uint32_t periodic_us;
|
||||
uint16_t latency_upd;
|
||||
uint16_t instant_latency;
|
||||
uint16_t event_counter;
|
||||
uint32_t ticks_at_expire;
|
||||
struct lll_conn *lll;
|
||||
|
||||
lll = &conn->lll;
|
||||
|
||||
|
@ -2220,16 +2256,89 @@ void ull_conn_update_parameters(struct ll_conn *conn, uint8_t is_cu_proc, uint8_
|
|||
}
|
||||
#endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
ready_delay_us = lll_radio_tx_ready_delay_get(lll->phy_tx,
|
||||
lll->phy_flags);
|
||||
#else
|
||||
ready_delay_us = lll_radio_tx_ready_delay_get(0U, 0U);
|
||||
#endif
|
||||
|
||||
/* compensate for instant_latency due to laziness */
|
||||
conn_interval_old = instant_latency * lll->interval;
|
||||
latency_upd = conn_interval_old / interval;
|
||||
conn_interval_new = latency_upd * interval;
|
||||
if (conn_interval_new > conn_interval_old) {
|
||||
ticks_at_expire += HAL_TICKER_US_TO_TICKS((conn_interval_new - conn_interval_old) *
|
||||
CONN_INT_UNIT_US);
|
||||
if (lll->interval >= BT_HCI_LE_INTERVAL_MIN) {
|
||||
conn_interval_old = instant_latency * lll->interval;
|
||||
conn_interval_unit_old = CONN_INT_UNIT_US;
|
||||
} else {
|
||||
ticks_at_expire -= HAL_TICKER_US_TO_TICKS((conn_interval_old - conn_interval_new) *
|
||||
CONN_INT_UNIT_US);
|
||||
conn_interval_old = instant_latency * (lll->interval + 1U);
|
||||
conn_interval_unit_old = CONN_LOW_LAT_INT_UNIT_US;
|
||||
}
|
||||
|
||||
if (interval >= BT_HCI_LE_INTERVAL_MIN) {
|
||||
uint16_t max_tx_time;
|
||||
uint16_t max_rx_time;
|
||||
uint32_t slot_us;
|
||||
|
||||
conn_interval_new = interval;
|
||||
conn_interval_unit_new = CONN_INT_UNIT_US;
|
||||
lll->tifs_tx_us = EVENT_IFS_DEFAULT_US;
|
||||
lll->tifs_rx_us = EVENT_IFS_DEFAULT_US;
|
||||
lll->tifs_hcto_us = EVENT_IFS_DEFAULT_US;
|
||||
|
||||
#if defined(CONFIG_BT_CTLR_DATA_LENGTH) && \
|
||||
defined(CONFIG_BT_CTLR_SLOT_RESERVATION_UPDATE)
|
||||
max_tx_time = lll->dle.eff.max_tx_time;
|
||||
max_rx_time = lll->dle.eff.max_rx_time;
|
||||
|
||||
#else /* !CONFIG_BT_CTLR_DATA_LENGTH ||
|
||||
* !CONFIG_BT_CTLR_SLOT_RESERVATION_UPDATE
|
||||
*/
|
||||
max_tx_time = PDU_DC_MAX_US(PDU_DC_PAYLOAD_SIZE_MIN, PHY_1M);
|
||||
max_rx_time = PDU_DC_MAX_US(PDU_DC_PAYLOAD_SIZE_MIN, PHY_1M);
|
||||
#if defined(CONFIG_BT_CTLR_PHY)
|
||||
max_tx_time = MAX(max_tx_time, PDU_DC_MAX_US(PDU_DC_PAYLOAD_SIZE_MIN, lll->phy_tx));
|
||||
max_rx_time = MAX(max_rx_time, PDU_DC_MAX_US(PDU_DC_PAYLOAD_SIZE_MIN, lll->phy_rx));
|
||||
#endif /* !CONFIG_BT_CTLR_PHY */
|
||||
#endif /* !CONFIG_BT_CTLR_DATA_LENGTH ||
|
||||
* !CONFIG_BT_CTLR_SLOT_RESERVATION_UPDATE
|
||||
*/
|
||||
|
||||
/* Calculate event time reservation */
|
||||
slot_us = max_tx_time + max_rx_time;
|
||||
slot_us += lll->tifs_rx_us + (EVENT_CLOCK_JITTER_US << 1);
|
||||
slot_us += ready_delay_us;
|
||||
|
||||
if (IS_ENABLED(CONFIG_BT_CTLR_EVENT_OVERHEAD_RESERVE_MAX) ||
|
||||
(lll->role == BT_HCI_ROLE_CENTRAL)) {
|
||||
slot_us += EVENT_OVERHEAD_START_US + EVENT_OVERHEAD_END_US;
|
||||
}
|
||||
|
||||
conn->ull.ticks_slot = HAL_TICKER_US_TO_TICKS_CEIL(slot_us);
|
||||
|
||||
} else {
|
||||
conn_interval_new = interval + 1U;
|
||||
conn_interval_unit_new = CONN_LOW_LAT_INT_UNIT_US;
|
||||
lll->tifs_tx_us = CONFIG_BT_CTLR_EVENT_IFS_LOW_LAT_US;
|
||||
lll->tifs_rx_us = CONFIG_BT_CTLR_EVENT_IFS_LOW_LAT_US;
|
||||
lll->tifs_hcto_us = CONFIG_BT_CTLR_EVENT_IFS_LOW_LAT_US;
|
||||
/* Reserve only the processing overhead, on overlap the
|
||||
* is_abort_cb mechanism will ensure to continue the event so
|
||||
* as to not loose anchor point sync.
|
||||
*/
|
||||
conn->ull.ticks_slot =
|
||||
HAL_TICKER_US_TO_TICKS_CEIL(EVENT_OVERHEAD_START_US);
|
||||
}
|
||||
|
||||
conn_interval_us = conn_interval_new * conn_interval_unit_new;
|
||||
periodic_us = conn_interval_us;
|
||||
|
||||
conn_interval_old_us = conn_interval_old * conn_interval_unit_old;
|
||||
latency_upd = conn_interval_old_us / conn_interval_us;
|
||||
conn_interval_new_us = latency_upd * conn_interval_us;
|
||||
if (conn_interval_new_us > conn_interval_old_us) {
|
||||
ticks_at_expire += HAL_TICKER_US_TO_TICKS(
|
||||
conn_interval_new_us - conn_interval_old_us);
|
||||
} else {
|
||||
ticks_at_expire -= HAL_TICKER_US_TO_TICKS(
|
||||
conn_interval_old_us - conn_interval_new_us);
|
||||
}
|
||||
|
||||
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_
|
|||
/* calculate the offset */
|
||||
if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) {
|
||||
ticks_slot_overhead =
|
||||
MAX(conn->ull.ticks_active_to_start, conn->ull.ticks_prepare_to_start);
|
||||
MAX(conn->ull.ticks_active_to_start,
|
||||
conn->ull.ticks_prepare_to_start);
|
||||
|
||||
} else {
|
||||
ticks_slot_overhead = 0U;
|
||||
}
|
||||
|
||||
/* calculate the window widening and interval */
|
||||
conn_interval_us = interval * CONN_INT_UNIT_US;
|
||||
periodic_us = conn_interval_us;
|
||||
|
||||
switch (lll->role) {
|
||||
#if defined(CONFIG_BT_PERIPHERAL)
|
||||
case BT_HCI_ROLE_PERIPHERAL:
|
||||
|
@ -2333,7 +2441,13 @@ void ull_conn_update_peer_sca(struct ll_conn *conn)
|
|||
lll = &conn->lll;
|
||||
|
||||
/* calculate the window widening and interval */
|
||||
conn_interval_us = lll->interval * CONN_INT_UNIT_US;
|
||||
if (lll->interval >= BT_HCI_LE_INTERVAL_MIN) {
|
||||
conn_interval_us = lll->interval *
|
||||
CONN_INT_UNIT_US;
|
||||
} else {
|
||||
conn_interval_us = (lll->interval + 1U) *
|
||||
CONN_LOW_LAT_INT_UNIT_US;
|
||||
}
|
||||
periodic_us = conn_interval_us;
|
||||
|
||||
lll->periph.window_widening_periodic_us =
|
||||
|
|
|
@ -205,6 +205,7 @@ struct ll_conn {
|
|||
#endif /* CONFIG_BT_CTLR_CONN_META */
|
||||
uint8_t latency_cancel:1;
|
||||
uint8_t sca:3;
|
||||
uint8_t drift_skip;
|
||||
uint32_t force;
|
||||
uint32_t ticks_to_offset;
|
||||
} periph;
|
||||
|
|
|
@ -8,11 +8,15 @@
|
|||
* User CPR Interval
|
||||
*/
|
||||
#if !defined(CONFIG_BT_CTLR_USER_CPR_INTERVAL_MIN)
|
||||
#if defined(CONFIG_BT_CTLR_CONN_INTERVAL_LOW_LATENCY)
|
||||
#define CONN_INTERVAL_MIN(x) (0U)
|
||||
#else /* !CONFIG_BT_CTLR_CONN_INTERVAL_LOW_LATENCY */
|
||||
/* Bluetooth defined CPR Interval Minimum (7.5ms) */
|
||||
#define CONN_INTERVAL_MIN(x) (6)
|
||||
#define CONN_INTERVAL_MIN(x) (6U)
|
||||
#endif /* !CONFIG_BT_CTLR_CONN_INTERVAL_LOW_LATENCY */
|
||||
#else /* CONFIG_BT_CTLR_USER_CPR_INTERVAL_MIN */
|
||||
/* Proprietary user defined CPR Interval Minimum */
|
||||
#define CONN_INTERVAL_MIN(x) (MAX(ull_conn_interval_min_get(x), 1))
|
||||
#define CONN_INTERVAL_MIN(x) (MAX(ull_conn_interval_min_get(x), 1U))
|
||||
#endif /* CONFIG_BT_CTLR_USER_CPR_INTERVAL_MIN */
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue