This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Bandwidth configuration for maximum throughput [nRF51]

Hi,

I am trying to achieve the maximum throughput when using the nRF51822.

According to the answer in this link (devzone.nordicsemi.com/.../), operation mode (write command or write request), connection interval (down to 7.5ms for both sides), and # of packets per interval (up to 6) are main factors for the throughput.

In S130_SDS_v2.0.pdf (page 76), I've also found that the maximum throughput can be up to 149.2 kbps.

The setup that I am using is as below.

Central: nRF51 dongle (PCA10031) to PC terminal (Termite 3.2) -Application firmware: ble_app_uart_c_s130_pca10031 (...\Nordic Semiconductor\nRF5_SDK_11.0.0_89a8197\examples\ble_central\ble_app_uart_c\pca10031\s130\arm5_no_packs)

Peripheral: nRF51822 3rd party module with an external MCU (UART communication) -Application firmware: ble_app_uart (...\Nordic Semiconductor\nRF5_SDK_11.0.0_89a8197\examples\ble_peripheral\ble_app_uart\custom\s130\arm5_no_packs)

SDK:nRF5_SDK_11.0.0_89a8197

Softdevice: s130_nrf51_2.0.0_softdevice.hex

IDE: nRFgo Studio for SoftDevice & Keil uVision V5.18.0.0 for Application

To achieve the maximum throughput, first of all, the connection intervals and slave latency are set to 7.5 ms and 0, respectively, for both Central and Periperal as below.

define MIN_CONN_INTERVAL MSEC_TO_UNITS(7.5, UNIT_1_25_MS)
define MAX_CONN_INTERVAL MSEC_TO_UNITS(7.5, UNIT_1_25_MS)
define SLAVE_LATENCY 0

I've checked that the maximum character length was already configured to 20 characters in above application firmwares.

define GATT_MTU_SIZE_DEFAULT 23

define BLE_NUS_MAX_DATA_LEN (GATT_MTU_SIZE_DEFAULT - 3)

Regarding to the operation mode, I've found that the "ble_nus_c_string_send" function uses "write command" in this link (devzone.nordicsemi.com/.../)

For the last factor, which is the bandwidth configuration among low(1), mid(3), and high(6), I've read below two related Q & As.

  1. devzone.nordicsemi.com/.../
  2. devzone.nordicsemi.com/.../

I've tried modifying the firmware of the Central only because by default, connections as a Central will be set to medium bandwidth and connections as a Peripheral will be set to high bandwidth. (11.4 BLE role configuration in S130_SDS_v2.0.pdf (page 38))

Referring to above two Q & As and the message sequence chart of connection bandwidth configuration (infocenter.nordicsemi.com/index.jsp, I've modified "static void ble_stack_init(void)" function in "main.c" because bandwidth configuration is done when enabling the BLE stack and will allow the SoftDevice to allocate memory pools large enough to fit the bandwidth configurations of all connections. (11.4 BLE role configuration in S130_SDS_v2.0.pdf (page 38))

The "softdevice_enable_get_default_config()" function for the default configuration was removed and new configurations for high bandwidth were added.

However, I faced a problem, which is that the Central (nRF 51 dongle) could not start the scan when changing the "conn_bw_counts" to configure the memory pools for high bandwidth by this line. (ble_enable_params.common_enable_params.p_conn_bw_counts = &conn_bw_counts;)

I must have missed some points. Please check below modified "ble_stack_init()" function and let me know how to solve this issue that I faced. Thank you in advance.

Best regards,

YSK

static void ble_stack_init(void)
{
    uint32_t err_code;
		
    nrf_clock_lf_cfg_t clock_lf_cfg = NRF_CLOCK_LFCLKSRC;
    
    // Initialize the SoftDevice handler module. -> sd_softdevice_enable(clock, assertion_handler);
    SOFTDEVICE_HANDLER_INIT(&clock_lf_cfg, NULL); //refer to "softdevice_handler.c"
		
	 	ble_enable_params_t ble_enable_params; //refer to "ble.h"
    
	  memset(&ble_enable_params, 0x00, sizeof(ble_enable_params));
		
  	//Configure the memory pools available for application packets
	  ble_conn_bw_counts_t conn_bw_counts = {
	   	  .tx_counts = {.high_count = 1, .mid_count = 0, .low_count = 0},
				.rx_counts = {.high_count = 1, .mid_count = 0, .low_count = 0}
		};
			
		//Configure conn_bw_counts in enable_params (along with others) 
	  ble_enable_params.common_enable_params.p_conn_bw_counts = &conn_bw_counts;
		ble_enable_params.common_enable_params.vs_uuid_count = 1;
		ble_enable_params.gatts_enable_params.attr_tab_size = BLE_GATTS_ATTR_TAB_SIZE_DEFAULT;
		ble_enable_params.gatts_enable_params.service_changed = 0;
		ble_enable_params.gap_enable_params.periph_conn_count = PERIPHERAL_LINK_COUNT; //PERIPHERAL_LINK_COUNT   0   < Number of peripheral links used by the application. When changing this number remember to adjust the RAM settings
		ble_enable_params.gap_enable_params.central_conn_count = CENTRAL_LINK_COUNT; //CENTRAL_LINK_COUNT      1  < Number of central links used by the application. When changing this number remember to adjust the RAM settings
		ble_enable_params.gap_enable_params.central_sec_count = 1;
		
    //Check the ram settings against the used number of links
    CHECK_RAM_START_ADDR(CENTRAL_LINK_COUNT,PERIPHERAL_LINK_COUNT);
		
		//Enable BLE stack.
    err_code = softdevice_enable(&ble_enable_params); //err_code = sd_ble_enable(p_ble_enable_params, &app_ram_base);
		APP_ERROR_CHECK(err_code);
	 
		//Configure the bandwidth for each connection 
    ble_opt_t ble_opt; //refer to "ble.h"
  		
	  memset(&ble_opt, 0x00, sizeof(ble_opt));
		ble_opt.common_opt.conn_bw.conn_bw.conn_bw_tx = BLE_CONN_BW_HIGH; //< Connection bandwidth configuration for transmission, see @ref BLE_CONN_BWS.
	  ble_opt.common_opt.conn_bw.conn_bw.conn_bw_rx = BLE_CONN_BW_HIGH;  //< Connection bandwidth configuration for reception, see @ref BLE_CONN_BWS.
	  ble_opt.common_opt.conn_bw.role = BLE_GAP_ROLE_CENTRAL; //#define BLE_GAP_ROLE_CENTRAL     0x2     Central Role. 
		
		err_code = sd_ble_opt_set(BLE_COMMON_OPT_CONN_BW, &ble_opt);
		APP_ERROR_CHECK(err_code);
		
    // Register with the SoftDevice handler module for BLE events.
    err_code = softdevice_ble_evt_handler_set(ble_evt_dispatch);
    APP_ERROR_CHECK(err_code);
}

[Updated on July 26 2016]

This attachment is the complete project. (updated on July 27 2016 with the revision of the IRAM1 start address and size)

ble_app_uart_c.zip

If I understand correctly, in the "softdevice_enable()" of the "softdevice_handler.c", the "app_ram_base" is set to the starting memory address of the application RAM ("app_ram_base = ram_start;"), which is the IRAM1(0x20001CE0) obtained directly from the linker by the below. defined ( __CC_ARM ) extern uint32_t Image$$RW_IRAM1$$Base; const volatile uint32_t ram_start = (uint32_t) &Image$$RW_IRAM1$$Base;

[Updated on July 27 2016]

Thank you very much for your testing.

When I used the debugger before changing the IRAM1 address that you commented, I found that the “sd_req_ram_start” is 0x20001CE0 in the “sd_check_ram_start()” of the “softdevice_handler.c” file as a below figure.

image description

In the “softdevice_handler.h”, I could see that the “sd_req_ram_start” is determined by the “app_ram_start_addr” from the “app_ram_base.h” file depending on the link numbers of centrals and peripherals and the bandwidth. As below, currently the “MID_BW” is used.

define CHECK_RAM_START_ADDR_INTERN(CENTRAL_LINK_COUNT, PERIPHERAL_LINK_COUNT)
do{
uint32_t app_ram_start_addr = APP_RAM_BASE_CENTRAL_LINKS_##CENTRAL_LINK_COUNT##PERIPH_LINKS##PERIPHERAL_LINK_COUNT##_SEC_COUNT_0_MID_BW;
err_code = sd_check_ram_start(app_ram_start_addr);
APP_ERROR_CHECK(err_code);
} while (0)

I wonder why there is no “app_ram_base” for “HIGH_BW” in the “app_ram_base.h” file. Should I change “uint32_t app_ram_start_addr = APP_RAM_BASE_CENTRAL_LINKS_##CENTRAL_LINK_COUNT##PERIPH_LINKS##PERIPHERAL_LINK_COUNT##_SEC_COUNT_0_MID_BW; \” to “uint32_t app_ram_start_addr = 0x20001F80”?

The “ram_start” is determined by the IRAM1 start address as you mentioned.

In the “softdevice_enable()” of the “softdevice_handler.c” file, “app_ram_base” is also 0x20001CE0 by the line 464 (app_ram_base = ram_start;) as below. This is different with what you obtained (0x20001F80).

image description

Probably I should’ve modified something to obtain the 0x20001F80 that you mentioned.

Please let me know how you got 0x20001F80 as the “app_ram_base”.

Thank you in advance.

[Updated on July 27 2016]

Thank you very much for your comment.

After the "sd_ble_enable()", I could see same values that you got.

image description

Thank you again.

  • Have you changed the memory settings in your project? What do you mean could not start the scan? Do you get an error? Have you tried to use the debugger? Could you upload your complete project so I can't test it, instead of this code snippet?

  • Hi,

    Thank you for the reply.

    Yes, I've changed the memory setting in "Options for Target 'nrf51422_xxac_s130". In "Read/Wirte Memory Areas" section, the "Start" and "Size" of IRAM1 are 0x20001CE0 and 0x6320, respectively. I refered to the "#define APP_RAM_BASE_CENTRAL_LINKS_1_PERIPH_LINKS_0_SEC_COUNT_0_MID_BW 0x20001ce0" in "app_ram_base.h" file. (There is no option for "HIGH_BW".)

    Regarding to the debugging, I defined the "NRF_LOG_USES_RTT=1" in the "C/C++" tab of "Options for Target 'nrf51422_xxac_s130" and add a line, "#include "SEGGER_RTT.h" in "main.c" file. All I could see in the "J-Link RTT viewer V5.12h" is repeated messages, which is the "sd_ble_enable: RAM START at 0x20001CE0". I didn't get any other errors in the J-Link RTT viewer.

    I've tried checking the some parameters after the "ble_stack_init()" in a main function as below, but they were not shown in the J-Link RTT viewer.

    int main(void) { ble_opt_t ble_opt; //refer to "ble.h" ble_enable_params_t ble_enable_params;

    	APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, NULL);
    
    uart_init();
    buttons_leds_init();
    db_discovery_init();
      ble_stack_init();
    
      SEGGER_RTT_printf(0,"tx %d, rx %d, role %d\r\n", ble_opt.common_opt.conn_bw.conn_bw.conn_bw_tx, ble_opt.common_opt.conn_bw.conn_bw.conn_bw_rx, ble_opt.common_opt.conn_bw.role);
    SEGGER_RTT_printf(0,"rx high %d, mid %d, low %d\r\n", ble_enable_params.common_enable_params.p_conn_bw_counts->rx_counts.high_count, ble_enable_params.common_enable_params.p_conn_bw_counts->rx_counts.mid_count, ble_enable_params.common_enable_params.p_conn_bw_counts->rx_counts.mid_count);
      SEGGER_RTT_printf(0,"tx high %d, mid %d, low %d\r\n", ble_enable_params.common_enable_params.p_conn_bw_counts->tx_counts.high_count, ble_enable_params.common_enable_params.p_conn_bw_counts->tx_counts.mid_count, ble_enable_params.common_enable_params.p_conn_bw_counts->tx_counts.mid_count);
      
      nus_c_init();
     // Start scanning for peripherals and initiate connection
    // with devices that advertise NUS UUID.
    scan_start();
    //printf("Scan started\r\n");
    	
    for (;;)
    {
        power_manage();
    }
    

    }

    I've tried uploading the complete project but I don't know how to do that in comments section. Could you tell me how to attach the file here?

    Thank you for your time.

  • I'm guessing that you have provided too little ram for the SoftDevice. You should compare ram_start and app_ram_base in softdevice_enable(). You can use the debugger, just set Optimization Level to 0. You can upload your complete project by editing your question above.

  • I tested your project, if you use the debugger you can see that ram_start is 0x20001CE0, while app_ram_base is 0x20001F80. Set IRAM1 start to 0x20001F80 and size to 0x6080, then it should work.

  • It works like a charm after setting IRAM1 starting point and its size as said.

    But I have a question regarding to the setting of peripheral, which by default is said to use high bandwidth.

    In the function ble_stack_init() of peripheral code, I printf conn_bw_counts and got the following values:

    Tx: Hi 0, Mid 4, Low 0

    Rx: Hi 32, Mid 229, Low 8

    The hight_counts for tx is 0. Why is it so? Is the peripheral not using high bandwidth to transmit?

Related