Connectivity board crashes after a few seconds of sending/receiving packets really fast with the following:
<error> app: ERROR 4 [NRF_ERROR_NO_MEM] at ../nrf_sdk/components/serialization/connectivity/ser_conn_handlers.c:172
Why it happens: ser_conn_ble_event_handle calls nrf_sdh_suspend() to stop more incoming events if the scheduler queue is full.
void ser_conn_ble_event_handle(ble_evt_t const * p_ble_evt, void * p_context)
{
uint32_t err_code = NRF_SUCCESS;
/* We can NOT encode and send BLE events here. SoftDevice handler implemented in
* softdevice_handler.c pull all available BLE events at once but we need to reschedule between
* encoding and sending every BLE event because sending a response on received packet has higher
* priority than sending a BLE event. Solution for that is to put BLE events into application
* scheduler queue to be processed at a later time. */
err_code = app_sched_event_put(p_ble_evt, p_ble_evt->header.evt_len,
ser_conn_ble_event_encoder);
APP_ERROR_CHECK(err_code);
uint16_t free_space = app_sched_queue_space_get();
if (!free_space)
{
// Queue is full. Do not pull new events.
nrf_sdh_suspend();
}
}
nrf_sdh_suspend() disables the SD IRQ, but the currently triggered IRQ is still polling for events in a loop (in nrf_sdh_ble_evts_poll), so nrf_sdh_suspend() doesn't guarantee that absolutely no events will come until unsuspending!.
My fix:
- Add a check for nrf_sdh_is_suspended() in nrf_sdh_ble_evts_poll that aborts the loop
- Add sd_nvic_SetPendingIRQ((IRQn_Type)SD_EVT_IRQn); after nrf_sdh_resume() in connectivity firmware's main(). This is needed because the SD IRQ appears to be "edge-triggered" (?) so if you don't read all the events in the IRQ handler, it never triggers again.
I'm not sure if this is the right fix (is it the SDH's responsibility to ensure no events are delivered after suspending?) but it seems to work for me. I'd appreciate if someone from Nordic could confirm the fix looks good, or suggest a better one :)