Bluetooth: Controller: 1 ms connection

1 ms connection interval support.

Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
This commit is contained in:
Vinayak Kariappa Chettimada 2019-01-23 23:36:52 +05:30 committed by Fabio Baltieri
commit abfe5f17a9
10 changed files with 215 additions and 42 deletions

View file

@ -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

View file

@ -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)

View file

@ -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);

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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)
{

View file

@ -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);
}

View file

@ -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 =

View file

@ -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;

View file

@ -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 */
/**