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

    I linked you to the rx_cb_set functions as I didn't get the impression you wanted to do connection, and only needed to scan for devices.

    Combining Bluetooth mesh and BLE does need some consideration, since both need access to the same radio. This will be a constraint regardless of which protocols you combine, but for Bluetooth mesh and BLE one advantage is that since they both use the same type of advertising packet, combining Bluetooth mesh with a BLE scanner comes with virtually no overhead. When combining with BLE connections, on the other hand, time spent for the connections will impact the mesh performance.

    For optimal Bluetooth mesh operation, the mesh stack needs access to the radio as much of the time as possible. This is because incoming mesh packets over the advertiser bearer may come in at any time. The larger the fraction of time used in RX, the higher chance of packet reception. When a node is spending less time in RX, you may experience that you need to configure the other nodes in the network to a higher retransmission count, to compensate.

    On the BLE side you can increase the connection interval and slave latency for the connection, in order to use less radio time for BLE. Also, a high supervision timeout will allow for more connection events to be lost without losing the connection.

    For an example of Bluetooth mesh combined with a BLE connection, see the SDK UART coexistence example. While we do not have an nRF5 SDK for Mesh example of coexistence with a BLE central, that example has a BLE peripheral which for the purposes of Bluetooth mesh coexistence with BLE is very similar. The main difference is that with central you are in control of the connection parameters, so you are in a better position to choose parameters that puts a smaller burden on the mesh communication.

    Best regards,

    Simon

Reply
  • Hi

    I linked you to the rx_cb_set functions as I didn't get the impression you wanted to do connection, and only needed to scan for devices.

    Combining Bluetooth mesh and BLE does need some consideration, since both need access to the same radio. This will be a constraint regardless of which protocols you combine, but for Bluetooth mesh and BLE one advantage is that since they both use the same type of advertising packet, combining Bluetooth mesh with a BLE scanner comes with virtually no overhead. When combining with BLE connections, on the other hand, time spent for the connections will impact the mesh performance.

    For optimal Bluetooth mesh operation, the mesh stack needs access to the radio as much of the time as possible. This is because incoming mesh packets over the advertiser bearer may come in at any time. The larger the fraction of time used in RX, the higher chance of packet reception. When a node is spending less time in RX, you may experience that you need to configure the other nodes in the network to a higher retransmission count, to compensate.

    On the BLE side you can increase the connection interval and slave latency for the connection, in order to use less radio time for BLE. Also, a high supervision timeout will allow for more connection events to be lost without losing the connection.

    For an example of Bluetooth mesh combined with a BLE connection, see the SDK UART coexistence example. While we do not have an nRF5 SDK for Mesh example of coexistence with a BLE central, that example has a BLE peripheral which for the purposes of Bluetooth mesh coexistence with BLE is very similar. The main difference is that with central you are in control of the connection parameters, so you are in a better position to choose parameters that puts a smaller burden on the mesh communication.

    Best regards,

    Simon

Children
No Data
Related