I'm using nRF Connect SDK v2.0.2 (in VSCode, w/ the plugin) on nRF52840-DKs.
Following the MPSL Timeslot sample, in the code shown below, I created a non-preemptible thread that periodically requests a single timeslot.
In the mpsl_timeslot_callback()
, the MPSL_TIMESLOT_SIGNAL_START
and MPSL_TIMESLOT_SIGNAL_TIMER0
events occur as expected, but the MPSL_TIMESLOT_SIGNAL_RADIO
case never happens. Why not? How can I make that happen?
#define TIMESLOT_REQUEST_PERIOD_ms (250) // ... /* Timeslot requests */ static mpsl_timeslot_request_t timeslot_request_earliest = { .request_type = MPSL_TIMESLOT_REQ_TYPE_EARLIEST, .params.earliest.hfclk = MPSL_TIMESLOT_HFCLK_CFG_NO_GUARANTEE, //TODO: OK? .params.earliest.priority = MPSL_TIMESLOT_PRIORITY_HIGH, .params.earliest.length_us = TIMESLOT_LENGTH_US, .params.earliest.timeout_us = TIMESLOT_TIMEOUT_US, }; static mpsl_timeslot_signal_return_param_t signal_callback_return_param; // ... static mpsl_timeslot_signal_return_param_t *mpsl_timeslot_callback( mpsl_timeslot_session_id_t session_id, uint32_t signal_type) { (void) session_id; /* unused parameter */ mpsl_timeslot_signal_return_param_t *p_ret_val = NULL; switch (signal_type) { case MPSL_TIMESLOT_SIGNAL_RADIO: { //NB: this doesn't hit... break; } case MPSL_TIMESLOT_SIGNAL_START: { // this hits /* No return action */ signal_callback_return_param.callback_action = MPSL_TIMESLOT_SIGNAL_ACTION_NONE; p_ret_val = &signal_callback_return_param; /* Setup timer to trigger an interrupt (and thus the TIMER0 * signal) before timeslot end. */ nrf_timer_cc_set(NRF_TIMER0, NRF_TIMER_CC_CHANNEL0, TIMER_EXPIRY_US); nrf_timer_int_enable(NRF_TIMER0, NRF_TIMER_INT_COMPARE0_MASK); break; } case MPSL_TIMESLOT_SIGNAL_TIMER0: { // this hits /* Clear event */ nrf_timer_int_disable(NRF_TIMER0, NRF_TIMER_INT_COMPARE0_MASK); nrf_timer_event_clear(NRF_TIMER0, NRF_TIMER_EVENT_COMPARE0); /* Timeslot will be ended */ signal_callback_return_param.callback_action = MPSL_TIMESLOT_SIGNAL_ACTION_NONE; //MPSL_TIMESLOT_SIGNAL_ACTION_END; p_ret_val = &signal_callback_return_param; break; } case MPSL_TIMESLOT_SIGNAL_SESSION_IDLE: break; case MPSL_TIMESLOT_SIGNAL_SESSION_CLOSED: break; // case MPSL_TIMESLOT_SIGNAL_BLOCKED: // case SIGNAL_CODE_BLOCKED_CANCELLED: default: { printk("ERR: unexpected signal: %u\n", signal_type); k_oops(); break; } } return p_ret_val; } /* To ensure thread safe operation, call all MPSL APIs from a non-preemptible * thread. */ static void mpsl_nonpreemptible_thread(void) { // Open timeslot session, and make periodic timeslot request // (every TIMESLOT_REQUEST_PERIOD_ms) int err; /* Initialize to invalid session id */ mpsl_timeslot_session_id_t session_id = 0xFFu; err = mpsl_timeslot_session_open(mpsl_timeslot_callback, &session_id); if (err) { printk("ERR: Timeslot session open error: %d\n", err); k_oops(); } else { while (1) { osDelay(TIMESLOT_REQUEST_PERIOD_ms); err = mpsl_timeslot_request(session_id, ×lot_request_earliest); if (err) { printk("ERR: Timeslot request error: %d\n", err); k_oops(); } } } } K_THREAD_DEFINE(mpsl_nonpreemptible_thread_id, STACKSIZE, mpsl_nonpreemptible_thread, NULL, NULL, NULL, K_PRIO_COOP(MPSL_THREAD_PRIO), 0, 0); void main(void) { // do some BLE stuff... }
Things I tried, which made no difference:
1. I've tried adding
nrf_radio_int_enable(NRF_RADIO, (NRF_RADIO_INT_CCABUSY_MASK | NRF_RADIO_INT_CCAIDLE_MASK));
in main()
, (and I used nrf_radio_int_enable_check()
to ensure it set the bits).
2. I also tried using mpsl_radio_notification_cfg_set()
such as shown below.
// Following comments from // https://github.com/inductivekickback/ncs_ble_esb_demo // which I used as a sample. Unsure if it still applies. /** * An interrupt vector to use with the Radio Notification feature as well as lowering the * priority of the MPSL callback (Zero Latency IRQ workaround). As of NCS v1.6 this doesn't * handle MPSL_TIMESLOT_SIGNAL_TIMER0 signals correctly unless it uses priority MPSL_LOW_PRIO * or higher. */ #define RADIO_IRQN QDEC_IRQn #define RADIO_IRQ_NODELABEL qdec //#define RADIO_IRQN RADIO_IRQn //#define RADIO_IRQ_NODELABEL radio #define RADIO_IRQ_PRIO 4 static void radio_notify_cb(const void *context); static void setup_radio_notification(void) { IRQ_CONNECT(DT_IRQN(DT_NODELABEL(RADIO_IRQ_NODELABEL)), RADIO_IRQ_PRIO, radio_notify_cb, NULL, 0); irq_enable(DT_IRQN(DT_NODELABEL(RADIO_IRQ_NODELABEL))); int32_t err = mpsl_radio_notification_cfg_set(MPSL_RADIO_NOTIFICATION_TYPE_INT_ON_ACTIVE, MPSL_RADIO_NOTIFICATION_DISTANCE_200US, RADIO_IRQN); if (err) { printk("ERR: mpsl_radio_notification_cfg_set() returned %i\n", err); } } static void radio_notify_cb(const void *context) { // this doesn't hit either }