Bluetooth: controller: implement sw-switch with the event timer

This commit contributes the implementation of the sw-switch for
tIFS in nRF5 Radio using the EVENT_TIMER instead of a dedicated
TIMER instance. A Kconfig configuration is added so the user can
select whether to use the EVENT_TIMER for the tIFS switch or use
a dedicated TIMER instance.

Signed-off-by: Ioannis Glaropoulos <Ioannis.Glaropoulos@nordicsemi.no>
Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
This commit is contained in:
Ioannis Glaropoulos 2018-01-31 14:02:19 +01:00 committed by Carles Cufí
commit 2764084561
5 changed files with 97 additions and 2 deletions

View file

@ -358,6 +358,19 @@ config BT_CTLR_TIFS_HW
help
Enable use of hardware accelerated tIFS Trx switching.
config BT_CTLR_SW_SWITCH_SINGLE_TIMER
bool "Single TIMER tIFS Trx SW switching"
depends on (!BT_CTLR_TIFS_HW) && SOC_SERIES_NRF52X
help
Implement the tIFS Trx SW switch with the same TIMER
instance, as the one used for BLE event timing. Requires
SW switching be enabled. Using a single TIMER:
(+) frees up one TIMER instance
(+) removes jitter for HCTO implementation
(-) introduces drifting to the absolute time inside BLE
events, that increases linearly with the number of
packets exchanged in the event.
if BT_CONN
config BT_CTLR_FAST_ENC

View file

@ -30,7 +30,6 @@
#error "Platform not defined."
#endif
static radio_isr_fp sfp_radio_isr;
void isr_radio(void)
@ -301,10 +300,29 @@ u32_t radio_is_ready(void)
return (NRF_RADIO->EVENTS_READY != 0);
}
#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER)
static u32_t last_pdu_end_us;
u32_t radio_is_done(void)
{
if (NRF_RADIO->EVENTS_END != 0) {
/* On packet END event increment last packet end time value.
* Note: this depends on the function being called exactly once
* in the ISR function.
*/
last_pdu_end_us += EVENT_TIMER->CC[2];
return 1;
} else {
return 0;
}
}
#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */
u32_t radio_is_done(void)
{
return (NRF_RADIO->EVENTS_END != 0);
}
#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */
u32_t radio_has_disabled(void)
{
@ -509,6 +527,13 @@ static void sw_switch(u8_t dir, u8_t phy_curr, u8_t flags_curr, u8_t phy_next,
NRF_PPI_regw_sideeffects();
#endif
#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER)
/* Since the event timer is cleared on END, we
* always need to capture the PDU END time-stamp.
*/
radio_tmr_end_capture();
#endif /* CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */
sw_tifs_toggle += 1;
sw_tifs_toggle &= 1;
}
@ -706,6 +731,10 @@ u32_t radio_tmr_start(u8_t trx, u32_t ticks_start, u32_t remainder)
#endif
#if !defined(CONFIG_BT_CTLR_TIFS_HW)
#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER)
last_pdu_end_us = 0;
#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */
SW_SWITCH_TIMER->TASKS_CLEAR = 1;
SW_SWITCH_TIMER->MODE = 0;
SW_SWITCH_TIMER->PRESCALER = 4;
@ -715,6 +744,7 @@ u32_t radio_tmr_start(u8_t trx, u32_t ticks_start, u32_t remainder)
NRF_TIMER_regw_sideeffects_TASKS_CLEAR(SW_SWITCH_TIMER_NBR);
NRF_TIMER_regw_sideeffects_TASKS_START(SW_SWITCH_TIMER_NBR);
#endif
#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */
HAL_SW_SWITCH_TIMER_CLEAR_PPI_REGISTER_EVT =
HAL_SW_SWITCH_TIMER_CLEAR_PPI_EVT;
@ -890,6 +920,7 @@ void radio_tmr_end_capture(void)
HAL_RADIO_END_TIME_CAPTURE_PPI_REGISTER_TASK =
HAL_RADIO_END_TIME_CAPTURE_PPI_TASK;
NRF_PPI->CHENSET = HAL_RADIO_END_TIME_CAPTURE_PPI_ENABLE;
#if defined(CONFIG_BOARD_NRFXX_NWTSIM)
NRF_PPI_regw_sideeffects();
#endif
@ -897,7 +928,11 @@ void radio_tmr_end_capture(void)
u32_t radio_tmr_end_get(void)
{
#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER)
return last_pdu_end_us;
#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */
return EVENT_TIMER->CC[2];
#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */
}
u32_t radio_tmr_tifs_base_get(void)

View file

@ -181,13 +181,25 @@
#endif /* !CONFIG_BT_CTLR_RADIO_ENABLE_FAST */
#if !defined(CONFIG_BT_CTLR_TIFS_HW)
#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER)
#undef EVENT_TIMER
#define EVENT_TIMER NRF_TIMER4
#define SW_SWITCH_TIMER EVENT_TIMER
#define SW_SWITCH_TIMER_EVTS_COMP_BASE 4
#if defined(CONFIG_BOARD_NRFXX_NWTSIM)
#define SW_SWITCH_TIMER_NBR 4
#endif /* CONFIG_BOARD_NRFXX_NWTSIM */
#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */
#define SW_SWITCH_TIMER NRF_TIMER1
#define SW_SWITCH_TIMER_EVTS_COMP_BASE 0
#if defined(CONFIG_BOARD_NRFXX_NWTSIM)
#define SW_SWITCH_TIMER_NBR 1
#endif /* CONFIG_BOARD_NRFXX_NWTSIM */
#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */
#define SW_SWITCH_TIMER_EVTS_COMP_BASE 0
#define SW_SWITCH_TIMER_TASK_GROUP_BASE 0
#endif /* !CONFIG_BT_CTLR_TIFS_HW */

View file

@ -338,9 +338,21 @@
#endif /* !CONFIG_BT_CTLR_RADIO_ENABLE_FAST */
#if !defined(CONFIG_BT_CTLR_TIFS_HW)
#if defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER)
#undef EVENT_TIMER
#define EVENT_TIMER NRF_TIMER4
#define SW_SWITCH_TIMER EVENT_TIMER
#define SW_SWITCH_TIMER_EVTS_COMP_BASE 3
#define SW_SWITCH_TIMER_EVTS_COMP_S2_BASE 5
#undef HAL_EVENT_TIMER_SAMPLE_CC_OFFSET
#define HAL_EVENT_TIMER_SAMPLE_CC_OFFSET 2
#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */
#define SW_SWITCH_TIMER NRF_TIMER1
#define SW_SWITCH_TIMER_EVTS_COMP_BASE 0
#define SW_SWITCH_TIMER_EVTS_COMP_S2_BASE 2
#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */
#define SW_SWITCH_TIMER_TASK_GROUP_BASE 0
#endif /* !CONFIG_BT_CTLR_TIFS_HW */

View file

@ -214,20 +214,43 @@ static inline void hal_radio_enable_on_tick_ppi_config_and_enable(u8_t trx)
#if !defined(CONFIG_BT_CTLR_TIFS_HW)
/* PPI setup used for SW-based auto-switching during TIFS. */
#if !defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER)
/* Clear SW-switch timer on packet end:
* wire the RADIO EVENTS_END event to SW_SWITCH_TIMER TASKS_CLEAR task.
*
* Note: this PPI is not needed if we use a single TIMER instance in radio.c
*/
#define HAL_SW_SWITCH_TIMER_CLEAR_PPI 7
#define HAL_SW_SWITCH_TIMER_CLEAR_PPI_ENABLE \
((PPI_CHENSET_CH7_Set << PPI_CHENSET_CH7_Pos) & PPI_CHENSET_CH7_Msk)
#define HAL_SW_SWITCH_TIMER_CLEAR_PPI_DISABLE \
((PPI_CHENCLR_CH7_Clear << PPI_CHENCLR_CH7_Pos) & PPI_CHENCLR_CH7_Msk)
#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */
/* Clear event timer (sw-switch timer) on Radio end:
* wire the RADIO EVENTS_END event to the
* EVENT_TIMER TASKS_CLEAR task.
*
* Note: in nRF52X PPI 5 is forked for both capturing and clearing timer
* on RADIO EVENTS_END.
*/
#define HAL_SW_SWITCH_TIMER_CLEAR_PPI 5
#define HAL_SW_SWITCH_TIMER_CLEAR_PPI_ENABLE \
((PPI_CHENSET_CH5_Set << PPI_CHENSET_CH5_Pos) & PPI_CHENSET_CH5_Msk)
#define HAL_SW_SWITCH_TIMER_CLEAR_PPI_DISABLE \
((PPI_CHENCLR_CH5_Clear << PPI_CHENCLR_CH5_Pos) & PPI_CHENCLR_CH5_Msk)
#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */
#define HAL_SW_SWITCH_TIMER_CLEAR_PPI_REGISTER_EVT \
NRF_PPI->CH[HAL_SW_SWITCH_TIMER_CLEAR_PPI].EEP
#define HAL_SW_SWITCH_TIMER_CLEAR_PPI_EVT \
((u32_t)&(NRF_RADIO->EVENTS_END))
#if !defined(CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER)
#define HAL_SW_SWITCH_TIMER_CLEAR_PPI_REGISTER_TASK \
NRF_PPI->CH[HAL_SW_SWITCH_TIMER_CLEAR_PPI].TEP
#else /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */
#define HAL_SW_SWITCH_TIMER_CLEAR_PPI_REGISTER_TASK \
NRF_PPI->FORK[HAL_SW_SWITCH_TIMER_CLEAR_PPI].TEP
#endif /* !CONFIG_BT_CTLR_SW_SWITCH_SINGLE_TIMER */
#define HAL_SW_SWITCH_TIMER_CLEAR_PPI_TASK \
((u32_t)&(SW_SWITCH_TIMER->TASKS_CLEAR))