diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.c b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.c index d9ecba277aaed9..e838542d085e67 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.c @@ -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) { @@ -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 @@ -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; @@ -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); @@ -1506,7 +1517,7 @@ 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) @@ -1514,7 +1525,7 @@ 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 @@ -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); @@ -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 @@ -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 @@ -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); @@ -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; } @@ -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; } @@ -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(); @@ -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(); @@ -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) diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.h index bc5d1605302c2e..f1c5e5dd140755 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio.h @@ -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); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_resources.h b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_resources.h index 618e1535839ee0..01a080f1c849d8 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_resources.h +++ b/subsys/bluetooth/controller/ll_sw/nordic/hal/nrf5/radio/radio_nrf5_resources.h @@ -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 diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c index 7bbd7abe6afecb..5d32d0e63cdcbe 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c @@ -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. diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c index 40eac85cb77730..05c9929ed17e50 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_sync.c @@ -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.