Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs

No memory (error 4) on nrf_sdh.c:391

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.

Parents
  • Hi

    We're somewhat short of staff, so delayed replies must be expected I'm afraid. Thank you for your patience. After discussing this with a colleague, we see that the issue might be that both the BT Mesh stack and the SoftDevice tries to do scanning at the same time. Not sure why this trigs a NO MEM error though to be honest. 

    In order to share the scan packets for the BLE scanner and Bluetooth Mesh RX you need to call the nrf_mesh_rx_cb_set after nrf_mesh_init(). But please note that running the SoftDevice in parallel with the Mesh stack will require timesharing between the BLE and Mesh stack, which will result in worse performance for both stacks. The callback will let both stacks get access to the radio in RX.

    Best regards,

    Simon

  • Thank you, that makes sense. Using this I am able to see advertising packets, however, there is still the problem of not being able to view the scan response data and how do you actually connect to the advertisements? 

    In the infocenter I was just reading this: https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.meshsdk.v5.0.0%2Fmd_doc_user_guide_integrating_mesh_nrf5_sdk.html&cp=8_2_2_7

    and here it says that "If general passive BLE scanning is required (for listening for beacons or other third party activity), hook into the Bluetooth mesh scanner by setting an RX callback with the nrf_mesh_rx_cb_set function. If your application requires active scanning or needs to initiate a connection, the scan parameters should be set as conservatively as possible."

    How would an implementation of active scanning or initiating a connection from the callback nrf_mesh_rx_cb_set look like, since the infocenter did not mention anything about how to do such an implementation and there are no examples

Reply Children
No Data
Related