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
}
