Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

RAM requirements per central link?

Hello,

I have an application that is meant to be used mainly as a peripheral. I'm now exploring options to expand functionality via 3rd-party accessories. For this, I need to use the central role.

My question is how much RAM should an extra concurrent central link require? As far as I can see now, testing simply by adding extra links at compile time, each extra link needs 3792 bytes of RAM.

I'm wondering if this is like the absolute minimum RAM requirement or what can I do to reduce it otherwise. My peripheral role is fairly complex (10 services and around 70 characteristics). I don't know if some of this complexity is carried over to the central role, or if each central link is completely independent of each other. In the case where my peripheral application is affecting the RAM requirements of future central links, what can I do to isolate them?

I would like to support up to 8 concurrent accessories. Their implementation in my device would be very simple, most likely a single service and characteristic per accessory. 

I am using an NRF52832 with SDK 15.0. Allocating almost 24 KB of RAM to support 8 central links will leave my application without memory. I know I can reduce the number of concurrent links to 3 or so, but I want to know if it's possible to reduce the requirements for a single link.

Parents
  • HI Andy, 

    I did a quick test with the ble_app_multilink_central example in SDK v15.0.0 where I set the NRF_SDH_BLE_TOTAL_LINK_COUNT and NRF_SDH_BLE_CENTRAL_LINK_COUNT to 1  and then added more centrals one by one. 

    I got the following app_ram_start address from sd_ble_enable

    Central Link Count           Application RAM Start Address

           1                                           0x200021F8

           2                                           0x20002758

           3                                           0x2000CB8

          4                                           0x20003218

    Each additional central increased the RAM start address by 0x560 bytes, i.e. 1376 bytes. Are you the default configuration, i.e. calling  nrf_sdh_ble_default_cfg_set() prior to nrf_sdh_ble_enable() or have you modified it?

    Best regards

    Bjørn 

  • Hi Bjorn,

    Good to know that the RAM requirements can be lower!

    My initialization method looks like this:

    void ble_stack_init(void) {
    	ret_code_t err_code;
    
    	// Initialize the SoftDevice handler module.
    	err_code = nrf_sdh_enable_request();
    	APP_ERROR_CHECK(err_code);
    
    	// Fetch the start address of the application RAM.
    	uint32_t ram_start = 0;
    	err_code = nrf_sdh_ble_app_ram_start_get(&ram_start);
    	APP_ERROR_CHECK(err_code);
    
    	// Overwrite some of the default configurations for the BLE stack.
    	ble_cfg_t ble_cfg;
    
    	memset(&ble_cfg, 0, sizeof(ble_cfg));
    	ble_cfg.common_cfg.vs_uuid_cfg.vs_uuid_count = CUSTOM_UUID_COUNT;
    
    	err_code = sd_ble_cfg_set(BLE_COMMON_CFG_VS_UUID, &ble_cfg, ram_start);
    	APP_ERROR_CHECK(err_code);
    
    	memset(&ble_cfg, 0, sizeof(ble_cfg));
    	// TODO: change this value if you get the NRF_ERROR_NO_MEM
    	// If you change the size, you need to change the RAM settings in the linker file
    	ble_cfg.gatts_cfg.attr_tab_size.attr_tab_size = BLE_GATTS_ATTR_TAB_SIZE_DEFAULT + BLE_GATTS_ATTR_TAB_SIZE_MIN + 0x1100;
    	err_code = sd_ble_cfg_set(BLE_GATTS_CFG_ATTR_TAB_SIZE, &ble_cfg, ram_start);
    	APP_ERROR_CHECK(err_code);
    
    	// Configure the maximum number of connections.
    	memset(&ble_cfg, 0, sizeof(ble_cfg));
    	ble_cfg.gap_cfg.role_count_cfg.periph_role_count  = NRF_SDH_BLE_PERIPHERAL_LINK_COUNT;
    	ble_cfg.gap_cfg.role_count_cfg.central_role_count = NRF_SDH_BLE_CENTRAL_LINK_COUNT;
    	ble_cfg.gap_cfg.role_count_cfg.central_sec_count  = NRF_SDH_BLE_CENTRAL_LINK_COUNT;
    	err_code = sd_ble_cfg_set(BLE_GAP_CFG_ROLE_COUNT, &ble_cfg, ram_start);
    	APP_ERROR_CHECK(err_code);
    
    	// Configure the maximum ATT MTU.
    	memset(&ble_cfg, 0x00, sizeof(ble_cfg));
    	ble_cfg.conn_cfg.params.gatt_conn_cfg.att_mtu = NRF_SDH_BLE_GATT_MAX_MTU_SIZE;
    	ble_cfg.conn_cfg.conn_cfg_tag                 = APP_BLE_CONN_CFG_TAG;
    	err_code = sd_ble_cfg_set(BLE_CONN_CFG_GATT, &ble_cfg, ram_start);
    	APP_ERROR_CHECK(err_code);
    
    	memset(&ble_cfg, 0, sizeof(ble_cfg));
    	ble_cfg.conn_cfg.params.gap_conn_cfg.conn_count     = NRF_BLE_LINK_COUNT;
    	ble_cfg.conn_cfg.params.gap_conn_cfg.event_length   = NRF_SDH_BLE_GAP_EVENT_LENGTH;
    	ble_cfg.conn_cfg.conn_cfg_tag                       = APP_BLE_CONN_CFG_TAG;
    	err_code = sd_ble_cfg_set(BLE_CONN_CFG_GAP, &ble_cfg, ram_start);
    	APP_ERROR_CHECK(err_code);
    
    	// Enable BLE stack.
    	err_code = nrf_sdh_ble_enable(&ram_start);
    	APP_ERROR_CHECK(err_code);
    
    	// Register a handler for BLE events.
    	NRF_SDH_BLE_OBSERVER(m_ble_observer, APP_BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
    }

  • I increased the ATTR TAB SIZE because I need more RAM allocated to the SoftDevice for it to handle the 70 characteristics. If I understand what you're saying, each additional role will be created with enough RAM to handle 70 characteristics as well?

    Is there any way to isolate this? Did I maybe misunderstand the ATTR TAB SIZE attribute and I need to give the RAM for my characteristics elsewhere?

  • HI Andy, 

    it appears that I was mistaken, the Attribute table size does not increase the RAM required for additional connections, its the ATT MTU Size, Write Command Queue and HVN Queue that increase the RAM usage for each additional connection. 

    What is your ATT MTU size? If I set it to 247( the maximum size our SDs allow) then I get a similar RAM increase per connection as you have observed, i.e. 0x1238 per connection added. 

    Best regards

    Bjørn

  • I am setting it to 247. Is it possible somehow to have an MTU of 23 for the central roles? I need a high throughput for my peripheral, but my accessories (central links) have a very low priority which I can handle with a small MTU and long connection intervals.

  • Yes, you can create two different SoftDevice configurations, one for the peripheral role and for the central role. 

    You use sd_ble_cfg_set to set the configuration and the ble_cfg.conn_cfg.conn_cfg_tag field to determine which configuration number that is being set. So for configuration number 1, you can set the ATT MTU to 247 and the peripheral role count to 1. For the seconds configuration, number 2, you can set the ATT  MTU to 23 and the central role count to 8. 

    When you connect to the peripherals using the central role you pass the configuration number in the sd_ble_gap_connect call, i.e. 

    sd_ble_gap_connect(ble_gap_addr_t const *p_peer_addr, ble_gap_scan_params_t const *p_scan_params, ble_gap_conn_params_t const *p_conn_params, uint8_t conn_cfg_tag));

  • That's great! Thanks for your support as always :) I'll implement that and report back when I get some results. I'll mark the question as answered then.

Reply Children
  • Happy to help! Let me know if you run into any issues. 

  • Hi Bjorn,

    So I implemented what you mentioned and it seems to be working nicely :) I could reduce the RAM requirements for each additional central link to 1628 bytes.

    However, I ran into issues when connecting to another peripheral using the central role. These issues are specific to the nrf_ble_gatt module. I run into errors because the module is trying to use a larger MTU and a longer data length than what I have allocated memory for.

    The first issue I have is that the module tries to set an MTU of 247 for my central connections. This is because the module initializes the desired MTU to the MAX MTU SIZE definition in sdk_config.h. This is an easy fix because I can just call nrf_ble_gatt_att_mtu_central_set and override the setting.

    The second issue I have is that the module also tries to set the data length to 251. There aren't separate peripheral/central data lengths. So if I call nrf_ble_gatt_data_length_set to set it to 23 for my central links, this value would be set also for future peripheral connections. I think there should be separate settings just like for the MTU. Consider this a feature request :)

    Anyway, do you have any suggestions on how to tackle this issue?

  • So I actually went away and implemented the two separate data lengths and it works now :) I hope this change can be included in a future SDK!

  • HI Andy, 

    happy to hear that you managed to solve the data length issue with multiple roles. I will add this as a feature request in our internal development database. 

    Best regards
    Bjørn 

Related