Hi. Currently I am been getting NRF_ERROR_NO_MEM on nrf_sdh.c:391. I am using the nrf5 SDK 17.0.2 and the nrf5 SDK for Mesh, working primarily on the nrf52840 DK.
So currently in my program there are many moving parts, which I suspect when put together may be causing this issue, however, I have been struggling to figure out why this error happens.
A little background on the things my program uses: Currently in my program, it is using a limited subset of the Mesh SDK since I only need the Mesh DFU functionality from it as I described here in a previous ticket: Use Mesh DFU but on a non-mesh BLE example. To achieve this, I only initialized a subset of the mesh SDK functions (I will explain in further detail later in my post what I did when I get to showing my code). Additionally, the program is both a BLE Central and BLE peripheral. I also use the app_scheduler library that I guess kind of ties all this together.
Here is the beginning part of my code that I am able to show:
#define APP_SCHED_EVENT_SIZE 12
#define APP_SCHED_QUEUE_SIZE 32
void ble_stack_init(void) {
ERROR_CHECK(nrf_sdh_enable_request());
// Configure the BLE stack using the default settings.
// Fetch the start address of the application RAM.
uint32_t ram_start = 0;
ERROR_CHECK(nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start));
// Enable BLE stack.
ERROR_CHECK(nrf_sdh_ble_enable(&ram_start));
// Register a handler for BLE events.
NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
NRF_SDH_SOC_OBSERVER(mesh_observer, NRF_SDH_BLE_STACK_OBSERVER_PRIO, on_sd_evt, NULL);
}
void gap_params_init(void) {
ble_gap_conn_params_t gap_conn_params;
ble_gap_conn_sec_mode_t sec_mode;
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
ERROR_CHECK(sd_ble_gap_device_name_set(&sec_mode, (const uint8_t *) DEVICE_NAME, strlen(DEVICE_NAME)));
memset(&gap_conn_params, 0, sizeof(gap_conn_params));
gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;
gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;
gap_conn_params.slave_latency = SLAVE_LATENCY;
gap_conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT;
ERROR_CHECK(sd_ble_gap_ppcp_set(&gap_conn_params));
}
void gatt_init(void) {
ERROR_CHECK(nrf_ble_gatt_init(&m_gatt, gatt_evt_handler));
ERROR_CHECK(nrf_ble_gatt_att_mtu_periph_set(&m_gatt, NRF_SDH_BLE_GATT_MAX_MTU_SIZE));
}
void conn_params_init(void) {
ble_conn_params_init_t cp_init;
memset(&cp_init, 0, sizeof(cp_init));
cp_init.p_conn_params = NULL;
cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
cp_init.next_conn_params_update_delay = NEXT_CONN_PARAMS_UPDATE_DELAY;
cp_init.max_conn_params_update_count = MAX_CONN_PARAMS_UPDATE_COUNT;
cp_init.start_on_notify_cccd_handle = BLE_GATT_HANDLE_INVALID;
cp_init.disconnect_on_fail = false;
cp_init.evt_handler = on_conn_params_evt;
cp_init.error_handler = conn_params_error_handler;
ERROR_CHECK(ble_conn_params_init(&cp_init));
}
static nrf_mesh_init_params_t mesh_init_params = {
.irq_priority = NRF_MESH_IRQ_PRIORITY_THREAD,
.lfclksrc = DEV_BOARD_LF_CLK_CFG,
};
static void initialize(void) {
ERROR_CHECK(app_timer_init());
__LOG_INIT(LOG_SRC_APP | LOG_SRC_MEM_MANAGER | LOG_SRC_DFU, LOG_LEVEL_INFO, LOG_CALLBACK_DEFAULT);
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "-------- DevID %08X %08X --------\n", NRF_FICR->DEVICEID[1], NRF_FICR->DEVICEID[0]);
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "------- DevAddr %08X %08X -------\n", NRF_FICR->DEVICEADDR[1], NRF_FICR->DEVICEADDR[0]);
ble_stack_init();
APP_SCHED_INIT(APP_SCHED_EVENT_SIZE, APP_SCHED_QUEUE_SIZE);
gap_params_init();
gatt_init();
ble_central_manager_init(); //Initializes BLE services (I use BLE_NUS service) and advertising module (ble_advertising_init())
ble_peripheral_manager_init(); //Initializes the DB discovery module (ble_db_discovery_init()) and the scanner (nrf_ble_scan_init())
conn_params_init();
uarte_link_init(uart_data_handle);
ERROR_CHECK(nrf_mesh_init(&mesh_init_params)); //I call this directly since I don't need the Access layer or foundation models
dfu_handler_init(); //This function is wrapper for all the code in the Mesh SDK's DFU example
}
static void start(void) {
rtt_input_enable(rtt_debug_util_handler, RTT_INPUT_POLL_PERIOD_MS);
ble_peripheral_manager_start(); //begins advertising (ble_advertising_start(), fast advertising)
ble_central_manager_start(); //begins scanning for the desired peripheral to connect (nrf_ble_scan_start())
__LOG(LOG_SRC_APP, LOG_LEVEL_INFO, m_usage_string);
ERROR_CHECK(nrf_mesh_enable());
}
int main(void) {
#if CONFIG_JLINK_MONITOR_ENABLED
NVIC_SetPriority(DebugMonitor_IRQn, APP_IRQ_PRIORITY_LOW_MID); //for monitor mode debugging
#endif
initialize();
start();
for (;;) {
app_sched_execute();
bool mesh_process_done = nrf_mesh_process();
if (mesh_process_done) {
sd_app_evt_wait();
}
}
}
I call nrf_mesh_init() directly since I only need the DFU portion of the Mesh SDK, I don't think it causes issues with DFU as I tested it on a minimal example from the mesh SDK where I called nrf_mesh_init() directly and did a successful DFU.
So far what I am found is that, if I comment out either one of the following functions, the NRF_ERROR_NO_MEM on nrf_sdh.c:391 is gone:
- ble_central_manager_start(); (which is just a wrapper that calls nrf_ble_scan_start())
- or nrf_mesh_enable(); (if I did deeper further into this function, I can comment out bearer_event_flag_set(m_mesh_be_flag))
However, for obvious reasons, the BLE Central functionality and the Mesh DFU functionality are crucial parts of the program. Is there a reason why this NRF_ERROR_NO_MEM on nrf_sdh.c:391 happens when I use the BLE Central scanning, Mesh stack, and app_scheduler together? I would really like to continue using these three components together.