Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bluetooth: Controller: Fix radio_tmr_start_us for single timer use #83393

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 67 additions & 13 deletions subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.c
Original file line number Diff line number Diff line change
Expand Up @@ -611,8 +611,15 @@ uint32_t radio_is_address(void)
}

#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER)
static uint32_t last_pdu_end_latency_us;
static uint32_t last_pdu_end_us;

static void last_pdu_end_us_init(uint32_t latency_us)
{
last_pdu_end_latency_us = latency_us;
last_pdu_end_us = 0U;
}

uint32_t radio_is_done(void)
{
if (NRF_RADIO->NRF_RADIO_TRX_END_EVENT != 0) {
Expand Down Expand Up @@ -1388,7 +1395,11 @@ void radio_tmr_tifs_set(uint32_t tifs)

uint32_t radio_tmr_start(uint8_t trx, uint32_t ticks_start, uint32_t remainder)
{
uint32_t remainder_us;

/* Convert jitter to positive offset remainder in microseconds */
hal_ticker_remove_jitter(&ticks_start, &remainder);
remainder_us = remainder;

#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER)
/* When using single timer for software tIFS switching, ensure that
Expand All @@ -1401,18 +1412,18 @@ uint32_t radio_tmr_start(uint8_t trx, uint32_t ticks_start, uint32_t remainder)
uint32_t latency_ticks;
uint32_t latency_us;

latency_us = MAX(remainder, HAL_RADIO_ISR_LATENCY_MAX_US) - remainder;
latency_us = MAX(remainder_us, HAL_RADIO_ISR_LATENCY_MAX_US) - remainder_us;
latency_ticks = HAL_TICKER_US_TO_TICKS(latency_us);
ticks_start -= latency_ticks;
remainder += latency_us;
#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */
remainder_us += latency_us;
#endif /* CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */

nrf_timer_task_trigger(EVENT_TIMER, NRF_TIMER_TASK_CLEAR);
EVENT_TIMER->MODE = 0;
EVENT_TIMER->PRESCALER = HAL_EVENT_TIMER_PRESCALER_VALUE;
EVENT_TIMER->BITMODE = 2; /* 24 - bit */

nrf_timer_cc_set(EVENT_TIMER, HAL_EVENT_TIMER_TRX_CC_OFFSET, remainder);
nrf_timer_cc_set(EVENT_TIMER, HAL_EVENT_TIMER_TRX_CC_OFFSET, remainder_us);

#if defined(CONFIG_BT_CTLR_NRF_GRTC)
uint32_t cntr_l, cntr_h, cntr_h_overflow, stale;
Expand Down Expand Up @@ -1479,7 +1490,7 @@ uint32_t radio_tmr_start(uint8_t trx, uint32_t ticks_start, uint32_t remainder)

#if !defined(CONFIG_BT_CTLR_TIFS_HW)
#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER)
last_pdu_end_us = 0U;
last_pdu_end_us_init(latency_us);

#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */
nrf_timer_task_trigger(SW_SWITCH_TIMER, NRF_TIMER_TASK_CLEAR);
Expand All @@ -1506,15 +1517,15 @@ uint32_t radio_tmr_start(uint8_t trx, uint32_t ticks_start, uint32_t remainder)
#endif /* CONFIG_BT_CTLR_PHY_CODED && CONFIG_HAS_HW_NRF_RADIO_BLE_CODED */
#endif /* !CONFIG_BT_CTLR_TIFS_HW */

return remainder;
return remainder_us;
}

uint32_t radio_tmr_start_tick(uint8_t trx, uint32_t ticks_start)
{
uint32_t remainder_us;

/* Setup compare event with min. 1 us offset */
remainder_us = 1;
remainder_us = 1U;

#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER)
/* When using single timer for software tIFS switching, ensure that
Expand All @@ -1531,7 +1542,7 @@ uint32_t radio_tmr_start_tick(uint8_t trx, uint32_t ticks_start)
latency_ticks = HAL_TICKER_US_TO_TICKS(latency_us);
ticks_start -= latency_ticks;
remainder_us += latency_us;
#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */
#endif /* CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */

nrf_timer_task_trigger(EVENT_TIMER, NRF_TIMER_TASK_STOP);
nrf_timer_task_trigger(EVENT_TIMER, NRF_TIMER_TASK_CLEAR);
Expand Down Expand Up @@ -1603,7 +1614,7 @@ uint32_t radio_tmr_start_tick(uint8_t trx, uint32_t ticks_start)

#if !defined(CONFIG_BT_CTLR_TIFS_HW)
#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER)
last_pdu_end_us = 0U;
last_pdu_end_us_init(latency_us);
#endif /* CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */
#if defined(CONFIG_SOC_COMPATIBLE_NRF53X) || defined(CONFIG_SOC_COMPATIBLE_NRF54LX)
/* NOTE: Timer clear DPPI configuration is needed only for nRF53
Expand All @@ -1630,7 +1641,11 @@ uint32_t radio_tmr_start_us(uint8_t trx, uint32_t start_us)

#if !defined(CONFIG_BT_CTLR_TIFS_HW)
#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER)
last_pdu_end_us = 0U;
/* As timer is reset on every radio end, remove the accumulated
* last_pdu_end_us in the given start_us.
*/

start_us -= last_pdu_end_us;
#endif /* CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */
#if defined(CONFIG_SOC_COMPATIBLE_NRF53X) || defined(CONFIG_SOC_COMPATIBLE_NRF54LX)
/* NOTE: Timer clear DPPI configuration is needed only for nRF53
Expand Down Expand Up @@ -1672,7 +1687,7 @@ uint32_t radio_tmr_start_us(uint8_t trx, uint32_t start_us)

latency_us = MAX(actual_us, HAL_RADIO_ISR_LATENCY_MAX_US) - actual_us;
actual_us += latency_us;
#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */
#endif /* CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */

nrf_timer_event_clear(EVENT_TIMER, HAL_EVENT_TIMER_TRX_EVENT);
nrf_timer_cc_set(EVENT_TIMER, HAL_EVENT_TIMER_TRX_CC_OFFSET, actual_us);
Expand All @@ -1684,6 +1699,10 @@ uint32_t radio_tmr_start_us(uint8_t trx, uint32_t start_us)
} while ((now_us > start_us) &&
(EVENT_TIMER->EVENTS_COMPARE[HAL_EVENT_TIMER_TRX_CC_OFFSET] == 0U));

#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER)
actual_us += last_pdu_end_us;
#endif /* CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */

return actual_us;
}

Expand All @@ -1697,9 +1716,27 @@ uint32_t radio_tmr_start_now(uint8_t trx)
nrf_timer_task_trigger(EVENT_TIMER, HAL_EVENT_TIMER_SAMPLE_TASK);
start_us = EVENT_TIMER->CC[HAL_EVENT_TIMER_SAMPLE_CC_OFFSET];

#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER)
/* As timer is reset on every radio end, add the accumulated
* last_pdu_end_us to the captured current time.
*/

start_us += last_pdu_end_us;
#endif /* CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */

/* Setup radio start at current time */
start_us = radio_tmr_start_us(trx, start_us);

#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER)
/* Remove the single timer start latency used to mitigate use of too
* small compare register value. Thus, start_us returned be always
* the value corresponding to the captured radio ready timestamp.
* This is used in the calculation of aux_offset in subsequent
* ADV_EXT_IND PDUs.
*/
start_us -= last_pdu_end_latency_us;
#endif /* CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */

return start_us;
}

Expand Down Expand Up @@ -1740,9 +1777,9 @@ void radio_tmr_stop(void)
#endif /* CONFIG_SOC_COMPATIBLE_NRF54LX */
}

void radio_tmr_hcto_configure(uint32_t hcto)
void radio_tmr_hcto_configure(uint32_t hcto_us)
{
nrf_timer_cc_set(EVENT_TIMER, HAL_EVENT_TIMER_HCTO_CC_OFFSET, hcto);
nrf_timer_cc_set(EVENT_TIMER, HAL_EVENT_TIMER_HCTO_CC_OFFSET, hcto_us);

hal_radio_recv_timeout_cancel_ppi_config();
hal_radio_disable_on_hcto_ppi_config();
Expand All @@ -1751,6 +1788,19 @@ void radio_tmr_hcto_configure(uint32_t hcto)
BIT(HAL_RADIO_DISABLE_ON_HCTO_PPI));
}

void radio_tmr_hcto_configure_abs(uint32_t hcto_from_start_us)
{
#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER)
/* As timer is reset on every radio end, remove the accumulated
* last_pdu_end_us in the given hcto_us.
*/

hcto_from_start_us -= last_pdu_end_us;
#endif /* CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */

radio_tmr_hcto_configure(hcto_from_start_us);
}

void radio_tmr_aa_capture(void)
{
hal_radio_ready_time_capture_ppi_config();
Expand Down Expand Up @@ -1825,7 +1875,11 @@ uint32_t radio_tmr_end_get(void)

uint32_t radio_tmr_tifs_base_get(void)
{
#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER)
return 0U;
#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */
return radio_tmr_end_get();
#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */
}

#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,8 @@ uint32_t radio_tmr_start_us(uint8_t trx, uint32_t us);
uint32_t radio_tmr_start_now(uint8_t trx);
uint32_t radio_tmr_start_get(void);
void radio_tmr_stop(void);
void radio_tmr_hcto_configure(uint32_t hcto);
void radio_tmr_hcto_configure(uint32_t hcto_us);
void radio_tmr_hcto_configure_abs(uint32_t hcto_from_start_us);
void radio_tmr_aa_capture(void);
uint32_t radio_tmr_aa_get(void);
void radio_tmr_aa_save(uint32_t aa);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,12 @@
/* Radio ISR Latency to be considered with single timer used so that the PPI/
* DPPI is disabled in time when the timer is cleared on radio end, so that
* the timer compare should not trigger TXEN/RXEN immediately on radio end.
* This value will be used as minimum turnaround time in setting up Rx to Tx
* using radio_tmr_start_us under single timer use.
* The value of 80 us is used considering 150 us TIFS minus the maximum rx
* chain delay ~30 us, and minus the radio ramp up delay ~40 us.
*/
#define HAL_RADIO_ISR_LATENCY_MAX_US 150U
#define HAL_RADIO_ISR_LATENCY_MAX_US 80U

#if defined(CONFIG_BT_CTLR_PHY_CODED)
#define SW_SWITCH_TIMER_EVTS_COMP_BASE 3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ void lll_scan_aux_isr_aux_setup(void *param)
hcto += window_size_us;
hcto += radio_rx_chain_delay_get(phy_aux, PHY_FLAGS_S8);
hcto += addr_us_get(phy_aux);
radio_tmr_hcto_configure(hcto);
radio_tmr_hcto_configure_abs(hcto);

/* capture end of Rx-ed PDU, extended scan to schedule auxiliary
* channel chaining, create connection or to create periodic sync.
Expand Down
2 changes: 1 addition & 1 deletion subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c
Original file line number Diff line number Diff line change
Expand Up @@ -757,7 +757,7 @@ static void isr_aux_setup(void *param)
hcto += window_size_us;
hcto += radio_rx_chain_delay_get(phy_aux, PHY_FLAGS_S8);
hcto += addr_us_get(phy_aux);
radio_tmr_hcto_configure(hcto);
radio_tmr_hcto_configure_abs(hcto);

/* capture end of Rx-ed PDU, extended scan to schedule auxiliary
* channel chaining, create connection or to create periodic sync.
Expand Down
Loading