Problem with data receive on nRF5340

Hello,


I want to send data from peripheral devices to central device. My peripheral device code is based on "ble_peripheral_uart" sample and my central device code is based on "Multi NUS" sample.

https://devzone.nordicsemi.com/guides/nrf-connect-sdk-guides/b/software/posts/enter-the-multi-nus-a-simple-wireless-uart-network

https://github.com/NordicMatt/multi-NUS


I am checking difference between timestamps in every data packet (timestamp is from peripheral device, so it is from the sending moment).

When I connect peripheral device with nRF Connect app on android phone everything is OK. Difference between timestamps are 8ms sometimes 9ms.
But when I connect peripheral device to Multi NUS there is problem. Every 5th data packet have bigger difference in timestamp.
Interesting is it, that average difference between data frames is about 12 ms. It doesn't matter if peripheral device is sending data every 8ms or every 10ms average is 12ms, because in 8ms case difference between 4th timestamp and 5th timestamp is bigger than in 10ms case.

Annother interesting thing is it, that when I connect second peripheral device to Multi NUS it's not worse, but this problem happens for two devices.


I am sending data (17 Bytes) every 8ms, but I have problem with receiving it with Multi NUS application.

Below is picture presenting what is in my data:







Below are my codes changes snippets:

Peripheral UART:

// Peripheral UART (code snippets - changes)

...

// --------------======================-----------------------========================--------------------=====================---------------------

struct bt_conn *my_conn = NULL;


void on_le_param_updated(struct bt_conn *conn, uint16_t interval, uint16_t latency, uint16_t timeout)
{
    double connection_interval = interval*1.25;         // in ms
    uint16_t supervision_timeout = timeout*10;          // in ms
    LOG_INF("Connection parameters updated: interval %.2f ms, latency %d intervals, timeout %d ms", connection_interval, latency, supervision_timeout);
}



/* STEP 7.1 - Define the function to update the connection's PHY */
static void update_phy(struct bt_conn *conn) // Preferowany PHY
{
    int err;
    const struct bt_conn_le_phy_param preferred_phy = {
        .options = BT_CONN_LE_PHY_OPT_NONE,
        .pref_rx_phy = BT_GAP_LE_PHY_2M,
        .pref_tx_phy = BT_GAP_LE_PHY_2M,
		// .pref_rx_phy = BT_GAP_LE_PHY_CODED,
        // .pref_tx_phy = BT_GAP_LE_PHY_CODED,
    };
    err = bt_conn_le_phy_update(conn, &preferred_phy);
    if (err) {
        LOG_ERR("bt_conn_le_phy_update() returned %d", err);
    }
}


/* STEP 8.1 - Write a callback function to inform about updates in the PHY */
void on_le_phy_updated(struct bt_conn *conn, struct bt_conn_le_phy_info *param)
{
    // PHY Updated
    if (param->tx_phy == BT_CONN_LE_TX_POWER_PHY_1M) {
        LOG_INF("PHY updated. New PHY: 1M");
    }
    else if (param->tx_phy == BT_CONN_LE_TX_POWER_PHY_2M) {
        LOG_INF("PHY updated. New PHY: 2M");
    }
    else if (param->tx_phy == BT_CONN_LE_TX_POWER_PHY_CODED_S8) {
        LOG_INF("PHY updated. New PHY: Long Range");
    }
}

// --------------======================-----------------------========================--------------------=====================---------------------

...

static void connected(struct bt_conn *conn, uint8_t err)
{
	char addr[BT_ADDR_LE_STR_LEN];

	if (err) {
		LOG_ERR("Connection failed (err %u)", err);
		return;
	}

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
	LOG_INF("Connected %s", addr);

		// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	my_conn = bt_conn_ref(conn);
	// dk_set_led(CONNECTION_STATUS_LED, 1);
	/* STEP 1.1 - Declare a structure to store the connection parameters */
	struct bt_conn_info info;
	err = bt_conn_get_info(conn, &info);
	if (err) {
		LOG_ERR("bt_conn_get_info() returned %d", err);
		return;
	}
	/* STEP 7.2 - Update the PHY mode */
	update_phy(my_conn);
	// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	current_conn = bt_conn_ref(conn);

	dk_set_led_on(CON_STATUS_LED);
	is_conn = true; /////////////////////////////////////////////////////////////////

	LOG_INF("BLE address: %s\n", addr);
	LOG_WRN("BLE address: %s\n", addr);
	LOG_ERR("BLE address: %s\n", addr);
	printk("BLE address: %s\n", addr);

}


static void disconnected(struct bt_conn *conn, uint8_t reason)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	LOG_INF("Disconnected: %s (reason %u)", addr, reason);

	if (auth_conn) {
		bt_conn_unref(auth_conn);
		auth_conn = NULL;
	}

	if (current_conn) {
		bt_conn_unref(current_conn);
		current_conn = NULL;
		dk_set_led_off(CON_STATUS_LED);
		is_conn = false; /////////////////////////////////////////////////////////////////
	}

	// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	bt_conn_unref(my_conn);
	// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

}


#ifdef CONFIG_BT_NUS_SECURITY_ENABLED
static void security_changed(struct bt_conn *conn, bt_security_t level,
			     enum bt_security_err err)
{
	char addr[BT_ADDR_LE_STR_LEN];

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	if (!err) {
		LOG_INF("Security changed: %s level %u", addr, level);
	} else {
		LOG_WRN("Security failed: %s level %u err %d", addr,
			level, err);
	}
}
#endif

BT_CONN_CB_DEFINE(conn_callbacks) = {
	.connected    = connected,
	.disconnected = disconnected,

	.le_param_updated       = on_le_param_updated,
	/* STEP 8.3 - Add the callback for PHY mode updates */
	.le_phy_updated         = on_le_phy_updated,
#ifdef CONFIG_BT_NUS_SECURITY_ENABLED
	.security_changed = security_changed,
#endif
};



...

uint8_t data_send_table[] = {0xFF, 0xAA, 0xBB, 0xCC, 0x00, 0x00, 0x22, 0x33, 0x00, 0x00, 0x55, 0x5A, 0xAA, 0xBB, 0x00, 0x00, 0x01};


void update_data_send_table(uint32_t variable) {
    data_send_table[0] = (variable >> 24) & 0xFF;
    data_send_table[1] = (variable >> 16) & 0xFF;
    data_send_table[2] = (variable >> 8) & 0xFF;
    data_send_table[3] = variable & 0xFF;
}

void update_data_send_table_iter_counter(uint32_t iter_counter) {
    data_send_table[10] = (iter_counter >> 24) & 0xFF;
    data_send_table[11] = (iter_counter >> 16) & 0xFF;
    data_send_table[12] = (iter_counter >> 8) & 0xFF;
    data_send_table[13] = iter_counter & 0xFF;
}

void update_data_send_table_iter_counter_TEST(uint32_t iter_counter) {
    data_send_table[6] = (iter_counter >> 24) & 0xFF;
    data_send_table[7] = (iter_counter >> 16) & 0xFF;
    data_send_table[8] = (iter_counter >> 8) & 0xFF;
    data_send_table[9] = iter_counter & 0xFF;
}


void print_data_send_table() {
    for (int i = 0; i < sizeof(data_send_table); i++) {
        printf("0x%02X ", data_send_table[i]);
    }
    printf("\n");
}


...

int main(void)
{
	...
}

...


void ble_write_NUM_thread(void){
	k_sem_take(&ble_init_ok, K_FOREVER);

	for (;;) {


		timer_state = k_uptime_get();

		update_data_send_table(timer_state);			// timer state

		update_data_send_table_iter_counter(iter_counter);

		uint8_t *iter_counter_t_d = data_send_table;

		uint16_t size_t_d = sizeof(data_send_table);


LOG_WRN(":%u;\n", iter_counter);
		if (bt_nus_send(my_conn, iter_counter_t_d, size_t_d)) {
			LOG_WRN("Failed to send --TEST-- data over BLE connection");
		}


		iter_counter++;
	
//		k_msleep(10);
		k_msleep(8);

	}
}


K_THREAD_DEFINE(ble_write_NUM_thread_id, STACKSIZE, ble_write_NUM_thread, NULL, NULL, NULL, 1, 0, 0);




Multi NUS:

// Multi NUS (code snippets - changes)


...

// --------------======================-----------------------========================--------------------=====================---------------------

struct bt_conn *my_conn = NULL;


void on_le_param_updated(struct bt_conn *conn, uint16_t interval, uint16_t latency, uint16_t timeout)
{
    double connection_interval = interval*1.25;         // in ms
    uint16_t supervision_timeout = timeout*10;          // in ms
    LOG_INF("Connection parameters updated: interval %.2f ms, latency %d intervals, timeout %d ms", connection_interval, latency, supervision_timeout);
}



/* STEP 7.1 - Define the function to update the connection's PHY */
static void update_phy(struct bt_conn *conn) // Preferowany PHY
{
    int err;
    const struct bt_conn_le_phy_param preferred_phy = {
        .options = BT_CONN_LE_PHY_OPT_NONE,
        .pref_rx_phy = BT_GAP_LE_PHY_2M,
        .pref_tx_phy = BT_GAP_LE_PHY_2M,
		// .pref_rx_phy = BT_GAP_LE_PHY_CODED,
        // .pref_tx_phy = BT_GAP_LE_PHY_CODED,
    };
    err = bt_conn_le_phy_update(conn, &preferred_phy);
    if (err) {
        LOG_ERR("bt_conn_le_phy_update() returned %d", err);
    }
}


/* STEP 8.1 - Write a callback function to inform about updates in the PHY */
void on_le_phy_updated(struct bt_conn *conn, struct bt_conn_le_phy_info *param)
{
    // PHY Updated
    if (param->tx_phy == BT_CONN_LE_TX_POWER_PHY_1M) {
        LOG_INF("PHY updated. New PHY: 1M");
    }
    else if (param->tx_phy == BT_CONN_LE_TX_POWER_PHY_2M) {
        LOG_INF("PHY updated. New PHY: 2M");
    }
    else if (param->tx_phy == BT_CONN_LE_TX_POWER_PHY_CODED_S8) {
        LOG_INF("PHY updated. New PHY: Long Range");
    }
}

// --------------======================-----------------------========================--------------------=====================---------------------


...


	uint32_t timer_state = 0;
	uint32_t timer_recv_data = 0;
static uint8_t ble_data_received(struct bt_nus_client *nus,const uint8_t *const data, uint16_t len)
{
	int err;
	char text_buffer[64];
	// char text_buffer[32];
	char temp_buffer[16];

	for (uint16_t pos = 0; pos != len;) {
		struct uart_data_t *tx = k_malloc(sizeof(*tx));

		if (!tx) {
			LOG_WRN("Not able to allocate UART send data buffer");
			return BT_GATT_ITER_CONTINUE;
		}

		/* Keep the last byte of TX buffer for potential LF char. */
		size_t tx_data_size = sizeof(tx->data) - 1;

		if ((len - pos) > tx_data_size) {
			tx->len = tx_data_size;
		} else {
			tx->len = (len - pos);
		}

//		memcpy(tx->data, &data[pos], tx->len);

		pos += tx->len;

		/* Append the LF character when the CR character triggered
		 * transmission from the peer.
		 */
		if ((pos == len) && (data[len - 1] == '\r')) {
			tx->data[tx->len] = '\n';
			tx->len++;
		}

		/*	Routed messages. See the comments above. 
		*	Check for *, if there's a star, send it over to the multi-nus send function
		*/
		if (( data[0] == '*') || (routedMessage == true) ) {
			multi_nus_send(tx);
		}

//  //  // -------------------------------------------------------------------------------------------------------------------------------
			timer_recv_data = k_uptime_get();
			timer_state = k_uptime_get();
			uint32_t prev = timer_state;
		LOG_INF("Received data: ");
		for (int i = 0; i < len; i++) {
//			printk("%02X ", data[i]);
///*
			if(i == 0) {
				snprintf(text_buffer, sizeof(text_buffer), "%02X", data[i]); // Writes a number in hexadecimal format
			}
			else {
				snprintf(temp_buffer, sizeof(temp_buffer), "%02X", data[i]); // Writes a number in hexadecimal format
				strcat(text_buffer, temp_buffer);
			}

		}
//		printk("\n");

//		strcat(text_buffer, ";\r\n");
		strcat(text_buffer, ";"); 

		char tmp_index[16];
		snprintf(tmp_index, sizeof(tmp_index), "%d", bt_conn_get_dst(nus->conn));
		strcat(text_buffer, tmp_index); 
		strcat(text_buffer, "\r\n");

//		printk("text_buffer = %s\n", text_buffer);
		printk("\n\tTimer_recv_data: %u \t %s\n", timer_recv_data, text_buffer);

			timer_state = k_uptime_get();
			uint32_t difference_pars = timer_state - prev;
			printk("\tParsing data time: %u ms\n", difference_pars);
				uint32_t prev_do_uart = timer_state;
		uint16_t txt_buff_size = strlen(text_buffer);

		tx->len = txt_buff_size;
		memcpy(tx->data, text_buffer, tx->len);


//  //  // -------------------------------------------------------------------------------------------------------------------------------

		err = uart_tx(uart, tx->data, tx->len, SYS_FOREVER_MS);
		if (err) {
			k_fifo_put(&fifo_uart_tx_data, tx);
		}
				timer_state = k_uptime_get();
				uint32_t to_uart_difference = timer_state - prev_do_uart;
				printk("\t\t UART data send time: %u ms\n", to_uart_difference);
	}

	return BT_GATT_ITER_CONTINUE;
}


...



static void connected(struct bt_conn *conn, uint8_t conn_err)
{
	char addr[BT_ADDR_LE_STR_LEN];
	int err;
/*	struct bt_nus_client_init_param init = {
		.cb = {
			.received = ble_data_received,
			.sent = ble_data_sent,
		}
	};
*/
	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	if (conn_err) {
		LOG_INF("Failed to connect to %s (%d)", addr,conn_err);

		if (default_conn == conn) {
			bt_conn_unref(default_conn);
			default_conn = NULL;

			err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);
			if (err) {
				LOG_ERR("Scanning failed to start (err %d)",
					err);
			}
		}

		return;
	}

	LOG_INF("Connected: %s", addr);

	// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	my_conn = bt_conn_ref(conn);
	// dk_set_led(CONNECTION_STATUS_LED, 1);
	/* STEP 1.1 - Declare a structure to store the connection parameters */
	struct bt_conn_info info;
	err = bt_conn_get_info(conn, &info);
	if (err) {
		LOG_ERR("bt_conn_get_info() returned %d", err);
		return;
	}
	/* STEP 7.2 - Update the PHY mode */
	update_phy(my_conn);
	// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	/*Allocate memory for this connection using the connection context library. For reference,
	this code was taken from hids.c
	*/
	struct bt_nus_client *nus_client =bt_conn_ctx_alloc(&conns_ctx_lib, conn);

	if (!nus_client) {
		LOG_WRN("There is no free memory to "
			"allocate the connection context");
	}
	
	struct bt_nus_client_init_param init = {
		.cb = {
			.received = ble_data_received,
			.sent = ble_data_sent,
		}
	};

	memset(nus_client, 0, bt_conn_ctx_block_size_get(&conns_ctx_lib));

	err = bt_nus_client_init(nus_client, &init);

	bt_conn_ctx_release(&conns_ctx_lib, (void *)nus_client);
	
	if (err) {
		LOG_ERR("NUS Client initialization failed (err %d)", err);
	}else{
		LOG_INF("NUS Client module initialized");
	}

	gatt_discover(conn);

	/*Stop scanning during the discovery*/
	err = bt_scan_stop();
	if ((!err) && (err != -EALREADY)) {
		LOG_ERR("Stop LE scan failed (err %d)", err);
	}

	LOG_INF("BLE address: %s\n", addr);
	LOG_WRN("BLE address: %s\n", addr);
	LOG_ERR("BLE address: %s\n", addr);
	printk("BLE address: %s\n", addr);

}

static void disconnected(struct bt_conn *conn, uint8_t reason)
{
	char addr[BT_ADDR_LE_STR_LEN];
	int err;

	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

	LOG_INF("Disconnected: %s (reason %u)", addr,reason);

	err = bt_conn_ctx_free(&conns_ctx_lib, conn);

	if (err) {
		LOG_WRN("The memory was not allocated for the context of this "
			"connection.");
	}

	bt_conn_unref(conn);
	default_conn = NULL;

	// err = bt_scan_start(BT_SCAN_TYPE_SCAN_ACTIVE);
	// if (err) {
	// 	LOG_ERR("Scanning failed to start (err %d)",
	// 		err);
	// }

	// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	bt_conn_unref(my_conn);
	// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

}


...

static struct bt_conn_cb conn_callbacks = {
	.connected = connected,
	.disconnected = disconnected,
//	.security_changed = security_changed
	.security_changed = security_changed,

	.le_param_updated       = on_le_param_updated,
	/* STEP 8.3 - Add the callback for PHY mode updates */
	.le_phy_updated         = on_le_phy_updated,
};

...





Below is log from UART (from Multi NUS device)

COM11_2024_10_22.17.47.05.386.txt
and python program to analyze it (you have to change 'path_for_file' variable and log name to "data")
import binascii
from collections import defaultdict

def is_hex(s):
    try:
        int(s, 16)
        return True
    except ValueError:
        return False

# Function to process the lines and perform the subtraction for timestamps
def process_timestamps(lines):
    results = []
    for i in range(len(lines) - 1):
        # Extract the 8 hex digits from each line
        hex1 = lines[i][:8]
        hex2 = lines[i + 1][:8]
        
        # Convert hex to integers
        int1 = int(hex1, 16)
        int2 = int(hex2, 16)
        
        # Perform the subtraction
        diff = int2 - int1
        
        # Convert the difference to decimal and hex
        diff_decimal = diff
        diff_hex = format(diff, 'x').upper()
        
        # Format the result string
        result = f"{hex1} - {hex2}   =   {diff_decimal}   =   {diff_hex}"
        results.append(result)
    
    return results

# Function to process the lines and perform the subtraction for increments
def process_increments(lines):
    results = []
    for i in range(len(lines) - 1):
        # Extract the 8 hex digits from each line
        
        hx_check = lines[i][20:28]
        if is_hex(hx_check):
            hex1 = lines[i][20:28]
        else:
            hex1 = "0"
        
        hx_check = lines[i + 1][20:28]
        if is_hex(hx_check):
            hex2 = lines[i + 1][20:28]
        else:
            hex2 = "1"
        
        # Convert hex to integers
        int1 = int(hex1, 16)
        int2 = int(hex2, 16)
        
        # Perform the subtraction
        diff = int2 - int1
        
        # Convert the difference to decimal and hex
        diff_decimal = diff
        diff_hex = format(diff, 'x').upper()
        
        # Format the result string
        result = f"{hex1} - {hex2}   =   {diff_decimal}   =   {diff_hex}"
        results.append(result)
    
    return results

# Function to calculate summary statistics
def calculate_summary(lines, x):
    summary_results = []
    
    # Difference between the 10th frame and the 5th from the end
    if len(lines) >= 15:
        hex_10th_timestamp = lines[9][:8]
        hex_5th_from_end_timestamp = lines[-5][:8]
        
        hex_10th_increment = lines[9][20:28]
        hex_5th_from_end_increment = lines[-5][20:28]
        
        timestamp_diff_decimal = int(hex_5th_from_end_timestamp, 16) - int(hex_10th_timestamp, 16)
        increment_diff_decimal = int(hex_5th_from_end_increment, 16) - int(hex_10th_increment, 16)
        
        summary_results.append(f"Difference between 10th frame and 5th from end (timestamp): {timestamp_diff_decimal}")
        summary_results.append(f"Difference between 10th frame and 5th from end (increment): {increment_diff_decimal}")
    
    # Check if increments go sequentially and count mismatches
    mismatches_count = 0
    for i in range(len(lines) - 1):
        increment_current = int(lines[i][20:28], 16)
        increment_next = int(lines[i + 1][20:28], 16)
        
        if increment_next != increment_current + 1:
            mismatches_count += 1
    
    summary_results.append(f"Number of mismatches in increments: {mismatches_count}")
    
    # Calculate average difference in timestamps
    total_diff_timestamps = sum(int(lines[i + 1][:8], 16) - int(lines[i][:8], 16) for i in range(len(lines) - 1))
    avg_diff_timestamps = total_diff_timestamps / (len(lines) - 1)
    
    summary_results.append(f"Average difference in timestamps: {avg_diff_timestamps}")
    
    # Count cases where timestamp difference is greater than x and calculate percentage
    count_greater_than_x = sum(1 for i in range(len(lines) - 1) if (int(lines[i + 1][:8], 16) - int(lines[i][:8], 16)) > x)
    percentage_greater_than_x = (count_greater_than_x / (len(lines) - 1)) * 100
    
    summary_results.append(f"Number of cases where timestamp difference is greater than {x}: {count_greater_than_x}")
    summary_results.append(f"Percentage of cases where timestamp difference is greater than {x}: {percentage_greater_than_x:.2f}%")
    
    # Total number of frames received
    total_frames_received = len(lines)
    
    summary_results.append(f"Total number of frames received: {total_frames_received}")
    
    return summary_results

# Main function to handle file reading and processing
def main():
    input_file = 'data.txt'
    path_for_files = 'D://YOUR//PATH//'
    input_file = path_for_files + input_file
    malformed_packet = 0

    try:
        with open(input_file, 'r') as file:
            lines = file.readlines()
    except FileNotFoundError:
        print("Input file not found")
        return

    # Group lines by device ID
    device_logs = defaultdict(list)
    for line in lines:
        if line.strip() == "":
            continue
        
        # if len(line.strip().split(';')[0]) == 34 and len(line.strip().split(';')[1]) == 9 and ';' in line:
        if ';' in line and len(line.strip().split(';')[0]) == 34 and len(line.strip().split(';')[1]) == 9:
            try:
                data, device_id = line.strip().split(';')
                device_logs[device_id].append(data)
            except ValueError:
                print(f"Malformed line: {line.strip()}")
                malformed_packet += 1
        else:
            print(f"Malformed line: {line.strip()}")
            malformed_packet += 1

    # Process each device's logs separately
    # x_value = 1000  # Example value for x
    # x_value = 10 # 10ms
    # x_value = 11 # 
    x_value = 9 
    
    for device_id, device_lines in device_logs.items():
        # Process timestamps and increments
        timestamp_results = process_timestamps(device_lines)
        increment_results = process_increments(device_lines)
        
        # Write timestamp results to file
        with open(f'{path_for_files}results_timestamp_difference{device_id}.txt', 'w') as file:
            file.write(f'\tFor device ID: {device_id}\n')
            for result in timestamp_results:
                file.write(result + '\n')
        
        # Write increment results to file
        with open(f'{path_for_files}results_counter_difference_{device_id}.txt', 'w') as file:
            file.write(f'\tFor device ID: {device_id}\n')
            for result in increment_results:
                file.write(result + '\n')
        
        # Calculate summary statistics
        summary_results = calculate_summary(device_lines, x_value)
        
        # Write summary results to file
        with open(f'{path_for_files}results_summary_{device_id}.txt', 'w') as file:
            file.write(f'\tFor device ID: {device_id}\n')
            for result in summary_results:
                file.write(result + '\n')

    print("Processing complete. Results have been written to respective files for each device.")
    print(f"Number of malformed packets: {malformed_packet}")

if __name__ == "__main__":
    main()



Below therare is example outputs from analyzer program (10ms case and 8ms case)
Output from different logs 

    10ms case:
    
00B00FAE - 00B00FB9   =   11   =   B
00B00FB9 - 00B00FC3   =   10   =   A
00B00FC3 - 00B00FCD   =   10   =   A
00B00FCD - 00B00FD7   =   10   =   A
00B00FD7 - 00B00FEA   =   19   =   13
00B00FEA - 00B00FF5   =   11   =   B
00B00FF5 - 00B00FFF   =   10   =   A
00B00FFF - 00B01009   =   10   =   A
00B01009 - 00B01013   =   10   =   A
00B01013 - 00B01026   =   19   =   13
00B01026 - 00B01031   =   11   =   B
00B01031 - 00B0103B   =   10   =   A
00B0103B - 00B01045   =   10   =   A
00B01045 - 00B0104F   =   10   =   A
00B0104F - 00B01062   =   19   =   13
00B01062 - 00B0106D   =   11   =   B
00B0106D - 00B01077   =   10   =   A
00B01077 - 00B01081   =   10   =   A
00B01081 - 00B0108B   =   10   =   A
00B0108B - 00B0109E   =   19   =   13
00B0109E - 00B010A9   =   11   =   B
00B010A9 - 00B010B3   =   10   =   A
00B010B3 - 00B010BD   =   10   =   A
00B010BD - 00B010C7   =   10   =   A
00B010C7 - 00B010DA   =   19   =   13
00B010DA - 00B010E5   =   11   =   B
00B010E5 - 00B010EF   =   10   =   A
00B010EF - 00B010F9   =   10   =   A
00B010F9 - 00B01103   =   10   =   A
00B01103 - 00B01116   =   19   =   13
00B01116 - 00B01121   =   11   =   B
00B01121 - 00B0112B   =   10   =   A
00B0112B - 00B01135   =   10   =   A
00B01135 - 00B0113F   =   10   =   A
00B0113F - 00B01152   =   19   =   13
00B01152 - 00B0115D   =   11   =   B
00B0115D - 00B01167   =   10   =   A
00B01167 - 00B01171   =   10   =   A
00B01171 - 00B0117B   =   10   =   A
00B0117B - 00B0118E   =   19   =   13
00B0118E - 00B01199   =   11   =   B
00B01199 - 00B011A3   =   10   =   A
00B011A3 - 00B011AD   =   10   =   A
00B011AD - 00B011B7   =   10   =   A
00B011B7 - 00B011CA   =   19   =   13
00B011CA - 00B011D5   =   11   =   B
00B011D5 - 00B011DF   =   10   =   A
00B011DF - 00B011E9   =   10   =   A
00B011E9 - 00B011F3   =   10   =   A
00B011F3 - 00B01206   =   19   =   13
00B01206 - 00B01211   =   11   =   B
00B01211 - 00B0121B   =   10   =   A
00B0121B - 00B01225   =   10   =   A
00B01225 - 00B0122F   =   10   =   A
00B0122F - 00B01242   =   19   =   13
00B01242 - 00B0124D   =   11   =   B
00B0124D - 00B01257   =   10   =   A
00B01257 - 00B01261   =   10   =   A
00B01261 - 00B0126B   =   10   =   A
00B0126B - 00B0127E   =   19   =   13
00B0127E - 00B01289   =   11   =   B
00B01289 - 00B01293   =   10   =   A
00B01293 - 00B0129D   =   10   =   A
00B0129D - 00B012A7   =   10   =   A
00B012A7 - 00B012BA   =   19   =   13
00B012BA - 00B012C5   =   11   =   B
00B012C5 - 00B012CF   =   10   =   A
00B012CF - 00B012D9   =   10   =   A
00B012D9 - 00B012E3   =   10   =   A
00B012E3 - 00B012F6   =   19   =   13
00B012F6 - 00B01301   =   11   =   B
00B01301 - 00B0130B   =   10   =   A
00B0130B - 00B01315   =   10   =   A
00B01315 - 00B0131F   =   10   =   A
00B0131F - 00B01332   =   19   =   13
00B01332 - 00B0133D   =   11   =   B
00B0133D - 00B01347   =   10   =   A
00B01347 - 00B01351   =   10   =   A
00B01351 - 00B0135B   =   10   =   A
00B0135B - 00B0136E   =   19   =   13
00B0136E - 00B01379   =   11   =   B
00B01379 - 00B01383   =   10   =   A
00B01383 - 00B0138D   =   10   =   A
00B0138D - 00B01397   =   10   =   A
00B01397 - 00B013AA   =   19   =   13
00B013AA - 00B013B5   =   11   =   B
00B013B5 - 00B013BF   =   10   =   A
00B013BF - 00B013C9   =   10   =   A
00B013C9 - 00B013D3   =   10   =   A
00B013D3 - 00B013E6   =   19   =   13
00B013E6 - 00B013F1   =   11   =   B
00B013F1 - 00B013FB   =   10   =   A
00B013FB - 00B01405   =   10   =   A
00B01405 - 00B0140F   =   10   =   A
00B0140F - 00B01422   =   19   =   13
00B01422 - 00B0142D   =   11   =   B
00B0142D - 00B01437   =   10   =   A
00B01437 - 00B01441   =   10   =   A
00B01441 - 00B0144B   =   10   =   A
00B0144B - 00B0145E   =   19   =   13
00B0145E - 00B01469   =   11   =   B
00B01469 - 00B01473   =   10   =   A
00B01473 - 00B0147D   =   10   =   A
00B0147D - 00B01487   =   10   =   A
00B01487 - 00B0149A   =   19   =   13
00B0149A - 00B014A5   =   11   =   B
00B014A5 - 00B014AF   =   10   =   A
00B014AF - 00B014B9   =   10   =   A
00B014B9 - 00B014C3   =   10   =   A
00B014C3 - 00B014D6   =   19   =   13






    8ms case:
    
01548F1F - 01548F3B   =   28   =   1C
01548F3B - 01548F43   =   8   =   8
01548F43 - 01548F4B   =   8   =   8
01548F4B - 01548F54   =   9   =   9
01548F54 - 01548F5C   =   8   =   8
01548F5C - 01548F77   =   27   =   1B
01548F77 - 01548F7F   =   8   =   8
01548F7F - 01548F87   =   8   =   8
01548F87 - 01548F90   =   9   =   9
01548F90 - 01548F98   =   8   =   8
01548F98 - 01548FB3   =   27   =   1B
01548FB3 - 01548FBB   =   8   =   8
01548FBB - 01548FC3   =   8   =   8
01548FC3 - 01548FCC   =   9   =   9
01548FCC - 01548FD4   =   8   =   8
01548FD4 - 01548FEF   =   27   =   1B
01548FEF - 01548FF7   =   8   =   8
01548FF7 - 01548FFF   =   8   =   8
01548FFF - 01549008   =   9   =   9
01549008 - 01549010   =   8   =   8
01549010 - 0154902B   =   27   =   1B
0154902B - 01549033   =   8   =   8
01549033 - 0154903B   =   8   =   8
0154903B - 01549044   =   9   =   9
01549044 - 0154904C   =   8   =   8
0154904C - 01549067   =   27   =   1B
01549067 - 0154906F   =   8   =   8
0154906F - 01549077   =   8   =   8
01549077 - 01549080   =   9   =   9
01549080 - 01549088   =   8   =   8
01549088 - 015490A3   =   27   =   1B
015490A3 - 015490AB   =   8   =   8
015490AB - 015490B3   =   8   =   8
015490B3 - 015490BC   =   9   =   9
015490BC - 015490C4   =   8   =   8
015490C4 - 015490DF   =   27   =   1B
015490DF - 015490E7   =   8   =   8
015490E7 - 015490EF   =   8   =   8
015490EF - 015490F8   =   9   =   9
015490F8 - 01549100   =   8   =   8
01549100 - 0154911B   =   27   =   1B
0154911B - 01549123   =   8   =   8
01549123 - 0154912B   =   8   =   8
0154912B - 01549134   =   9   =   9
01549134 - 0154913C   =   8   =   8
0154913C - 01549157   =   27   =   1B
01549157 - 0154915F   =   8   =   8
0154915F - 01549167   =   8   =   8
01549167 - 01549170   =   9   =   9
01549170 - 01549178   =   8   =   8
01549178 - 0154919A   =   34   =   22
0154919A - 015491A2   =   8   =   8
015491A2 - 015491AB   =   9   =   9
015491AB - 015491B3   =   8   =   8
015491B3 - 015491D6   =   35   =   23
015491D6 - 015491DE   =   8   =   8
015491DE - 015491E7   =   9   =   9
015491E7 - 015491EF   =   8   =   8
015491EF - 0154920B   =   28   =   1C
0154920B - 01549213   =   8   =   8
01549213 - 0154921B   =   8   =   8
0154921B - 01549224   =   9   =   9
01549224 - 0154922C   =   8   =   8
0154922C - 01549247   =   27   =   1B
01549247 - 0154924F   =   8   =   8
0154924F - 01549257   =   8   =   8
01549257 - 01549260   =   9   =   9
01549260 - 01549268   =   8   =   8
01549268 - 01549283   =   27   =   1B
01549283 - 0154928B   =   8   =   8
0154928B - 01549293   =   8   =   8
01549293 - 0154929C   =   9   =   9
0154929C - 015492A4   =   8   =   8
015492A4 - 015492BF   =   27   =   1B
015492BF - 015492C7   =   8   =   8
015492C7 - 015492CF   =   8   =   8
015492CF - 015492D8   =   9   =   9
015492D8 - 015492E0   =   8   =   8
015492E0 - 015492FB   =   27   =   1B
015492FB - 01549303   =   8   =   8
01549303 - 0154930B   =   8   =   8
0154930B - 01549314   =   9   =   9
01549314 - 0154931C   =   8   =   8
0154931C - 01549337   =   27   =   1B
01549337 - 0154933F   =   8   =   8
0154933F - 01549347   =   8   =   8
01549347 - 01549350   =   9   =   9
01549350 - 01549358   =   8   =   8
01549358 - 01549373   =   27   =   1B
01549373 - 0154937B   =   8   =   8
0154937B - 01549383   =   8   =   8
01549383 - 0154938C   =   9   =   9
0154938C - 01549394   =   8   =   8
01549394 - 015493AF   =   27   =   1B
015493AF - 015493B7   =   8   =   8
015493B7 - 015493BF   =   8   =   8
015493BF - 015493C8   =   9   =   9
015493C8 - 015493D0   =   8   =   8
015493D0 - 015493EB   =   27   =   1B
015493EB - 015493F3   =   8   =   8
015493F3 - 015493FB   =   8   =   8
015493FB - 01549404   =   9   =   9
01549404 - 0154940C   =   8   =   8
0154940C - 01549427   =   27   =   1B


    






Can you help me resolve this problem?

Best Regards

Parents
  • Hi,

    As this works with a phone as central but not the nRF I suspect there may be somethign scheduling related (assuming you test with the same ammount of peripherals). What are the connection parmaeters? Does it help if you set a shorter default event length with CONFIG_BT_CTLR_SDC_MAX_CONN_EVENT_LEN_DEFAULT=2500 (or similar)? 

  • Hi,

    I add this line [CONFIG_BT_CTLR_SDC_MAX_CONN_EVENT_LEN_DEFAULT=2500] (I tried also with different parameters: 10, 2500 and 1000000) but result is the same.
    I tested it in 2 cases:
    - when I added this line only to Multi NUS
    - and when I added this line to both Multi NUS and Peripheral devices
    and nothing changed.



    Below are my config files:

    Peripheral UART:
    prj.conf

    #
    # Copyright (c) 2018 Nordic Semiconductor
    #
    # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
    #
    
    # Enable the UART driver
    CONFIG_UART_ASYNC_API=y
    CONFIG_NRFX_UARTE0=y
    CONFIG_SERIAL=y
    
    CONFIG_GPIO=y
    
    # Make sure printk is printing to the UART console
    CONFIG_CONSOLE=y
    CONFIG_UART_CONSOLE=y
    
    CONFIG_HEAP_MEM_POOL_SIZE=2048
    
    CONFIG_BT=y
    CONFIG_BT_PERIPHERAL=y
    CONFIG_BT_DEVICE_NAME="Nordic_UART_Service"
    CONFIG_BT_MAX_CONN=1
    CONFIG_BT_MAX_PAIRED=1
    
    # Enable the NUS service
    CONFIG_BT_NUS=y
    
    # Enable bonding
    CONFIG_BT_SETTINGS=y
    CONFIG_FLASH=y
    CONFIG_FLASH_PAGE_LAYOUT=y
    CONFIG_FLASH_MAP=y
    CONFIG_NVS=y
    CONFIG_SETTINGS=y
    
    # Enable DK LED and Buttons library
    CONFIG_DK_LIBRARY=y
    
    # This example requires more stack
    CONFIG_MAIN_STACK_SIZE=1152
    CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
    
    # Config logger
    CONFIG_LOG=y
    CONFIG_USE_SEGGER_RTT=y
    CONFIG_LOG_BACKEND_RTT=y
    CONFIG_LOG_BACKEND_UART=n
    CONFIG_LOG_PRINTK=n
    
    CONFIG_ASSERT=y
    
    
    CONFIG_NRFX_TIMER1=y
    CONFIG_NRFX_TIMER2=y
    
    CONFIG_PRINTK=y
    
    CONFIG_PINCTRL=y
    
    
    
    CONFIG_FPU=y
    
    
    CONFIG_BT_GATT_CLIENT=y
    
    
    CONFIG_BT_PERIPHERAL_PREF_MIN_INT=6
    CONFIG_BT_PERIPHERAL_PREF_MAX_INT=6
    CONFIG_BT_PERIPHERAL_PREF_LATENCY=0
    
    CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=y
    
    CONFIG_BT_USER_PHY_UPDATE=y
    
    
    CONFIG_BT_USER_DATA_LEN_UPDATE=y    # enabling the data length extension
    
    



    prj_minimal.conf
    #
    # Copyright (c) 2021 Nordic Semiconductor
    #
    # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
    #
    
    # Enable the UART driver
    CONFIG_UART_ASYNC_API=y
    CONFIG_NRFX_UARTE0=y
    CONFIG_SERIAL=y
    
    CONFIG_HEAP_MEM_POOL_SIZE=2048
    
    CONFIG_BT=y
    CONFIG_BT_PERIPHERAL=y
    CONFIG_BT_DEVICE_NAME="Nordic_UART_Service"
    CONFIG_BT_DEVICE_APPEARANCE=833
    CONFIG_BT_MAX_CONN=1
    CONFIG_BT_MAX_PAIRED=1
    
    # Enable the NUS service
    CONFIG_BT_NUS=y
    
    # Enable bonding
    CONFIG_BT_SETTINGS=y
    CONFIG_FLASH=y
    CONFIG_FLASH_PAGE_LAYOUT=y
    CONFIG_FLASH_MAP=y
    CONFIG_NVS=y
    CONFIG_SETTINGS=y
    
    # Enable DK LED and Buttons library
    CONFIG_DK_LIBRARY=y
    
    # Drivers and peripherals
    CONFIG_I2C=n
    CONFIG_WATCHDOG=n
    CONFIG_SPI=n
    CONFIG_GPIO=n
    
    # Power management
    
    # Interrupts
    CONFIG_DYNAMIC_INTERRUPTS=n
    CONFIG_IRQ_OFFLOAD=n
    
    # Memory protection
    CONFIG_THREAD_STACK_INFO=n
    CONFIG_THREAD_CUSTOM_DATA=n
    # CONFIG_FPU=n
    
    # Boot
    CONFIG_BOOT_BANNER=n
    CONFIG_BOOT_DELAY=0
    
    # Console
    CONFIG_CONSOLE=n
    CONFIG_UART_CONSOLE=n
    CONFIG_STDOUT_CONSOLE=n
    CONFIG_PRINTK=n
    CONFIG_EARLY_CONSOLE=n
    
    # Build
    CONFIG_SIZE_OPTIMIZATIONS=y
    
    # ARM
    CONFIG_ARM_MPU=n
    
    # In order to correctly tune the stack sizes for the threads the following
    # Configurations can enabled to print the current use:
    #CONFIG_THREAD_NAME=y
    #CONFIG_THREAD_ANALYZER=y
    #CONFIG_THREAD_ANALYZER_AUTO=y
    #CONFIG_THREAD_ANALYZER_RUN_UNLOCKED=y
    #CONFIG_THREAD_ANALYZER_USE_PRINTK=y
    #CONFIG_CONSOLE=y
    #CONFIG_UART_CONSOLE=y
    #CONFIG_SERIAL=y
    #CONFIG_PRINTK=y
    
    # Example output of thread analyzer
    #SDC RX              : unused 800 usage 224 / 1024 (21 %)
    #BT ECC              : unused 216 usage 888 / 1104 (80 %)
    #BT RX               : unused 1736 usage 464 / 2200 (21 %)
    #BT TX               : unused 1008 usage 528 / 1536 (34 %)
    #ble_write_thread_id : unused 688 usage 336 / 1024 (32 %)
    #sysworkq            : unused 1912 usage 136 / 2048 (6 %)
    #MPSL signal         : unused 928 usage 96 / 1024 (9 %)
    #idle 00             : unused 224 usage 96 / 320 (30 %)
    #main                : unused 568 usage 456 / 1024 (44 %)
    CONFIG_BT_RX_STACK_SIZE=1024
    CONFIG_BT_HCI_TX_STACK_SIZE_WITH_PROMPT=y
    CONFIG_BT_HCI_TX_STACK_SIZE=640
    CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=1536
    CONFIG_MPSL_WORK_STACK_SIZE=256
    CONFIG_MAIN_STACK_SIZE=864
    CONFIG_IDLE_STACK_SIZE=128
    CONFIG_ISR_STACK_SIZE=1024
    CONFIG_BT_NUS_THREAD_STACK_SIZE=512
    
    # Disable features not needed
    CONFIG_TIMESLICING=n
    CONFIG_MINIMAL_LIBC_MALLOC=n
    CONFIG_LOG=n
    CONFIG_ASSERT=n
    
    # Disable Bluetooth features not needed
    CONFIG_BT_DEBUG_NONE=y
    CONFIG_BT_ASSERT=n
    CONFIG_BT_DATA_LEN_UPDATE=n
    CONFIG_BT_PHY_UPDATE=n
    CONFIG_BT_GATT_CACHING=n
    CONFIG_BT_GATT_SERVICE_CHANGED=n
    CONFIG_BT_GAP_PERIPHERAL_PREF_PARAMS=n
    CONFIG_BT_SETTINGS_CCC_LAZY_LOADING=y
    CONFIG_BT_HCI_VS_EXT=n
    
    # Disable Bluetooth controller features not needed
    CONFIG_BT_CTLR_PRIVACY=n
    CONFIG_BT_CTLR_PHY_2M=n
    
    # Reduce Bluetooth buffers
    CONFIG_BT_BUF_EVT_DISCARDABLE_COUNT=1
    CONFIG_BT_BUF_EVT_DISCARDABLE_SIZE=43
    CONFIG_BT_BUF_EVT_RX_COUNT=2
    
    CONFIG_BT_CONN_TX_MAX=2
    CONFIG_BT_L2CAP_TX_BUF_COUNT=2
    CONFIG_BT_BUF_ACL_TX_COUNT=3
    CONFIG_BT_BUF_ACL_TX_SIZE=27
    
    
    CONFIG_HW_ID_LIBRARY_SOURCE_DEVICE_ID=y
    
    
    
    CONFIG_LOG=y
    
    CONFIG_NRFX_TIMER1=y
    CONFIG_NRFX_TIMER2=y
    
    CONFIG_PRINTK=y
    
    CONFIG_PINCTRL=y
    
    
    
    CONFIG_FPU=y
    
    
    CONFIG_BT_GATT_CLIENT=y
    
    
    CONFIG_BT_PERIPHERAL_PREF_MIN_INT=6
    CONFIG_BT_PERIPHERAL_PREF_MAX_INT=6
    CONFIG_BT_PERIPHERAL_PREF_LATENCY=0
    
    CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=y
    
    CONFIG_BT_USER_PHY_UPDATE=y
    
    
    CONFIG_BT_USER_DATA_LEN_UPDATE=y    # enabling the data length extension
    



    prj_cdc.conf
    #
    # Copyright (c) 2021 Nordic Semiconductor
    #
    # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
    #
    
    # Enable the UART driver
    CONFIG_UART_LINE_CTRL=y
    CONFIG_UART_INTERRUPT_DRIVEN=y
    CONFIG_BT_NUS_UART_ASYNC_ADAPTER=y
    CONFIG_USB_DEVICE_STACK=y
    CONFIG_USB_DEVICE_REMOTE_WAKEUP=n
    CONFIG_USB_CDC_ACM=y
    CONFIG_USB_CDC_ACM_LOG_LEVEL_OFF=y
    
    # Disable the UARTE0 enabled in default project configuration
    CONFIG_NRFX_UARTE0=n
    CONFIG_UART_NRFX=n
    
    
    
    CONFIG_LOG=y
    
    CONFIG_NRFX_TIMER1=y
    CONFIG_NRFX_TIMER2=y
    
    CONFIG_PRINTK=y
    
    CONFIG_PINCTRL=y
    
    
    
    CONFIG_FPU=y
    
    
    CONFIG_BT_GATT_CLIENT=y
    
    
    CONFIG_BT_PERIPHERAL_PREF_MIN_INT=6
    CONFIG_BT_PERIPHERAL_PREF_MAX_INT=6
    CONFIG_BT_PERIPHERAL_PREF_LATENCY=0
    
    CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=y
    
    CONFIG_BT_USER_PHY_UPDATE=y
    
    
    CONFIG_BT_USER_DATA_LEN_UPDATE=y    # enabling the data length extension
    
    





    Multi NUS:
    prj.conf
    #
    # Copyright (c) 2018 Nordic Semiconductor
    #
    # SPDX-License-Identifier: LicenseRef-BSD-5-Clause-Nordic
    #
    
    # Enable the UART driver
    CONFIG_UART_ASYNC_API=y
    CONFIG_NRFX_UARTE0=y
    CONFIG_SERIAL=y
    CONFIG_CONSOLE=y
    CONFIG_UART_CONSOLE=y
    
    # Enable the BLE stack with GATT Client configuration
    CONFIG_BT=y
    CONFIG_BT_CENTRAL=y
    CONFIG_BT_SMP=y
    CONFIG_BT_GATT_CLIENT=y
    CONFIG_BT_MAX_CONN=20
    CONFIG_BT_MAX_PAIRED=20
    CONFIG_BT_CONN_CTX=y
    
    # Enable the BLE modules from NCS
    CONFIG_BT_NUS_CLIENT=y
    CONFIG_BT_SCAN=y
    CONFIG_BT_SCAN_FILTER_ENABLE=y
    CONFIG_BT_SCAN_UUID_CNT=1
    CONFIG_BT_GATT_DM=y
    CONFIG_HEAP_MEM_POOL_SIZE=2048
    
    # This example requires more workqueue stack
    CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048
    
    # Enable bonding
    CONFIG_BT_SETTINGS=y
    CONFIG_FLASH=y
    CONFIG_FLASH_PAGE_LAYOUT=y
    CONFIG_FLASH_MAP=y
    CONFIG_NVS=y
    CONFIG_SETTINGS=y
    
    # Config logger
    CONFIG_LOG=y
    CONFIG_USE_SEGGER_RTT=y
    CONFIG_LOG_BACKEND_RTT=y
    CONFIG_LOG_BACKEND_UART=n
    CONFIG_LOG_PRINTK=y
    
    CONFIG_ASSERT=y
    
    
    CONFIG_FPU=y
    
    
    CONFIG_BT_PERIPHERAL_PREF_MIN_INT=6
    CONFIG_BT_PERIPHERAL_PREF_MAX_INT=6
    CONFIG_BT_PERIPHERAL_PREF_LATENCY=0
    
    CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=y
    
    CONFIG_BT_USER_PHY_UPDATE=y
    
    
    CONFIG_BT_USER_DATA_LEN_UPDATE=y    # enabling the data length extension
    
    
    






  • Hi,

    I am not able to fully understand what is going on there. What are the actuall connection parameters that are used on the connections? Can you make a sniffer trace that shows everyting starting with the connection both with a phone as central and the nRF as central (as that behaves as you expect)? (you may only be able to sniff one of the connections if you use nRF Sniffer, but focusing on one of the connections should be OK as at least then we can see what is happening on the link that may cause the delays you are seeing).

  • Hi,

    I'm not sure that this is what you want, but below are screenshoots from j-link with connection parameters. I also send configuration files in one of previous posts.


    from device with modified ble_central_uart program:







    from device with modified Multi NUS program:











    Below are logs from receiving device. One is from modified ble_central_uart program (and it is OK), second one is from modified Multi NUS program (and it is NOT OK).

    log from modified ble_central_uart program:

    COM23_2024_10_29.17.57.18.478.txt


    log from modified Multi NUS program

    COM11_2024_10_29.17.52.34.361.txt



    If you analize this logs with python script (that I send before)  you will see the difference and what is wrong with Multi NUS app.
                                                [ Remember to change Path in script and log name ]


    Problem with Multi NUS: every fifth packet has a bigger timestamp than it should have - (timestamp is in data packet and is from peripheral device, so it looks like it takes longer for the peripheral device to send every fifth data packet, but when peripheral device is sending data to ble_central_uart or to the phone everything is OK).


    That's how it look like after script analysis (this is the analysis of the above logs):

    difference between timestamps in subsequent data packets:

    ble_central_uart (left image)                                      Multi NUS (right image)
                        

    summary:

    ble_central_uart


    Multi NUS




    So as you see every fifth pachet has much bigger timestamp and average difference between timestamps of subsequent data packets in ble_central_uart case is about 8ms but in Multi NUS case is about 12ms (in the ideal case it should be equal to 8ms). It is worth mentioning that ble_central_uart and Multi NUS are only receiving data and both were connected to the same device that sends data (of course not in the same time).

    So there is something wrong with Multi NUS sample.

  • Hi,

    Thank you for the information. I was not clear enoguh, but what I think we need is to look at the traffic on air. Can you make a sniffer trace of both cases so that we can compare? You can use the nRF sniffer for that. I hope we will understand more from that.

    PS: The Multi NUS project you refer to is not an official sample, and while can be usefull to demonstrate a central with multiple concurrent connections,  you will need to adapt it to your needs.

  • Hi,

    Below are wireshark files.


    Multi NUS:

    Multi_NUS_Wireshark.pcapng

    Multi_NUS_Wireshark__2.pcapng



    central_uart

    central_uart_Wireshark.pcapng



    In Central_uart case you don't see incoming packets (but transmission between devices is OK).


  • Hi,

    The last trace is short and encrypted and does not show much, but looking at Multi_NUS_Wireshark__2.pcapng I notice that every 5 packets are delayed (looking at the delta) and then the subsequent packet has the more data field set, as there is more buffered data. So this points to scheduling not being ideal for your use case. iMost likely what you want is short "slots" for each connection so that you can exchagne packets with little delay? Refering to Advanced Central connection timing, this means that you need to configure a short event length (but long enough to fit the longest packet you intend to send). This can be configured with CONFIG_BT_CTLR_SDC_MAX_CONN_EVENT_LEN_DEFAULT.

Reply Children
  • Hi,

    You previously suggested me to use CONFIG_BT_CTLR_SDC_MAX_CONN_EVENT_LEN_DEFAULT , and I wrote then that result was the same.

    Now I noticed that this is not defined in build.


    I also tried with:

    CONFIG_BT_LL_SOFTDEVICE=y
    CONFIG_BT_CTLR=y

    But it isn't work

    Is there any configuration that needs to be added to make it work?

  • Where did you make this change? This config is relevant on the controller side, so the network core application (hci_ipc/hci_rpmsg depending on SDK version).

  • I changed it in prj.conf file.

    I also tried it on nRF52840 and it is in build (I tried it with different values but problem still occurs).

  • I was searching for problematic code in Multi NUS, so I copied code fragments from Multi NUS project to ble_peripheral_uart sample (which were modified as I described above). So I add BT_CONN_CTX_DEF(conns, CONFIG_BT_MAX_CONN, sizeof(struct bt_nus_client)); line to ble_peripheral_uart and I replaced uart_initgatt_discoverconnecteddisconnected functions in ble_peripheral_uart by their versions from Multi NUS project.

    In this point transmission was OK. But when I replaced discovery_complete function, the ble_peripheral_uart project was working like multi NUS, so it was possible to connect to multiple devices, but there was also a problem with transmission.

    The discovery_complete function (from Multi NUS file) gives the ability to connect multiple devices, but it also causes a delay of every fifth frame in the transmission.


    Is it possible to modify this function to eliminate the transmission problem and retain the ability to connect with multiple devices?

    PS: I don't need to connect with 20 devices, I only need to be able to connect with (up to) 3 devices in the same time (with data transmission in both directions).

  • Hi,

    I am not sure I understood this experiment. The unofficial Multi NUS sample is a central, and it needs BT_CONN_CTX_DEF etc to keep track of the multiple connections. And ble_peripheral_uart is a peripheral (and single link before potential modifications). 

    Could there be other things that cause problems with the scheduling? Which scan parameters are you using? The controller needs to fit both scanning and connections in, so an alternative could be to reduce the scan window and scan frequency and see if that changes aything. That can be done by populating a bt_le_scan_param struct that you refer to in the bt_scan_init_param struct you pass to scan_init() on the central side (see this post on that). 

Related