Peripheral_uart passthrough example not fast enough

I'm looking to set up a UART-BLE passthrough for high data rate transmissions (~7500 bytes/s). I've been looking into the peripheral_uart example script but it can't keep up with the transmission speed. I'm sending a count up to 1000 over the RX pin and seeing about half lost on the BLE output. I haven't been able to identify whether the issue is with the UART or BLE.

BLE output on sending 0-1000:

I've removed all of the code relating to BLE security as this is not necessary. I have increased the size of the UART RX buffer. I tried to increase BLE MTU size to 251 in the project config but this is disallowed as its being overwritten somewhere else. 

Unfortunately for our particular use, case flow control is not an option. 

Peripheral_uart with modifications:

/*
 * Copyright (c) 2018 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
 */

/** @file
 *  @brief Nordic UART Bridge Service (NUS) sample
 */
#include "uart_async_adapter.h"

#include <zephyr/types.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/uart.h>
#include <zephyr/usb/usb_device.h>

#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <soc.h>

#include <sys/printk.h>

#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/hci.h>
#include <zephyr/bluetooth/conn.h>

#include <bluetooth/services/nus.h>

#include <dk_buttons_and_leds.h>

#include <zephyr/settings/settings.h>

#include <stdio.h>

#include <zephyr/logging/log.h>

#define LOG_MODULE_NAME peripheral_uart
LOG_MODULE_REGISTER(LOG_MODULE_NAME);

#define STACKSIZE CONFIG_BT_NUS_THREAD_STACK_SIZE
#define PRIORITY 1

#define DEVICE_NAME CONFIG_BT_DEVICE_NAME
#define DEVICE_NAME_LEN	(sizeof(DEVICE_NAME) - 1)

#define RUN_STATUS_LED DK_LED1
#define RUN_LED_BLINK_INTERVAL 1000

#define CON_STATUS_LED DK_LED2

#define KEY_PASSKEY_ACCEPT DK_BTN1_MSK
#define KEY_PASSKEY_REJECT DK_BTN2_MSK

#define UART_BUF_SIZE CONFIG_BT_NUS_UART_BUFFER_SIZE
#define UART_WAIT_FOR_BUF_DELAY K_MSEC(5)
#define UART_WAIT_FOR_RX 20//PCONFIG_BT_NUS_UART_RX_WAIT_TIME

#define MIN_CONN_INTERVAL 50
#define MAX_CONN_INTERVAL 400

#define MTU_SIZE NRF_SDH_BLE

static K_SEM_DEFINE(ble_init_ok, 0, 1);

static struct bt_conn *current_conn;
static struct bt_conn *auth_conn;

static const struct device *uart = DEVICE_DT_GET(DT_CHOSEN(nordic_nus_uart));
static struct k_work_delayable uart_work;

struct uart_data_t {
	void *fifo_reserved;
	uint8_t data[80];
	uint16_t len;
};

static K_FIFO_DEFINE(fifo_uart_tx_data);
static K_FIFO_DEFINE(fifo_uart_rx_data);

static const struct bt_data ad[] = {
	BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
	BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
};


static const struct bt_data sd[] = {
	BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_NUS_VAL),
};

#if CONFIG_BT_NUS_UART_ASYNC_ADAPTER
UART_ASYNC_ADAPTER_INST_DEFINE(async_adapter);
#else
static const struct device *const async_adapter;
#endif


const struct uart_config uart_cfg = {   //serial communications settings
		.baudrate = 115200,
		.parity = UART_CFG_PARITY_NONE,
		.stop_bits = UART_CFG_STOP_BITS_1,
		.data_bits = UART_CFG_DATA_BITS_8,
		.flow_ctrl = UART_CFG_FLOW_CTRL_NONE
	};



static void uart_cb(const struct device *dev, struct uart_event *evt, void *user_data)
{
	ARG_UNUSED(dev);
	static size_t aborted_len;
	struct uart_data_t *buf;
	static uint8_t *aborted_buf;
	static bool disable_req;
	
	switch (evt->type) {
	case UART_TX_DONE:
		LOG_DBG("UART_TX_DONE");
		if ((evt->data.tx.len == 0) ||
		    (!evt->data.tx.buf)) {
			return;
		}

		if (aborted_buf) {
			buf = CONTAINER_OF(aborted_buf, struct uart_data_t,
					   data);
			aborted_buf = NULL;
			aborted_len = 0;
		} else {
			buf = CONTAINER_OF(evt->data.tx.buf, struct uart_data_t,
					   data);
		}

		k_free(buf);

		buf = k_fifo_get(&fifo_uart_tx_data, K_NO_WAIT);
		if (!buf) {
			return;
		}

		if (uart_tx(uart, buf->data, buf->len, SYS_FOREVER_MS)) {
			LOG_WRN("Failed to send data over UART");
		}

		break;

	case UART_RX_RDY:
		LOG_DBG("UART_RX_RDY");
		buf = CONTAINER_OF(evt->data.rx.buf, struct uart_data_t, data);
		buf->len += evt->data.rx.len;

		if (disable_req) {
			return;
		}

		if ((evt->data.rx.buf[buf->len - 1] == '\n') ||
		    (buf->len == 14)) {
			disable_req = true;
			uart_rx_disable(uart);
		}

		break;

	case UART_RX_DISABLED:
		LOG_DBG("UART_RX_DISABLED");
		disable_req = false;

		buf = k_malloc(sizeof(*buf));
		if (buf) {
			buf->len = 0;
		} else {
			LOG_WRN("Not able to allocate UART receive buffer");
			k_work_reschedule(&uart_work, UART_WAIT_FOR_BUF_DELAY);
			return;
		}

		uart_rx_enable(uart, buf->data, sizeof(buf->data),
			       UART_WAIT_FOR_RX);

		break;

	case UART_RX_BUF_REQUEST:
		LOG_DBG("UART_RX_BUF_REQUEST");
		buf = k_malloc(sizeof(*buf));
		if (buf) {
			buf->len = 0;
			uart_rx_buf_rsp(uart, buf->data, sizeof(buf->data));
		} else {
			LOG_WRN("Not able to allocate UART receive buffer");
		}

		break;

	case UART_RX_BUF_RELEASED:
		LOG_DBG("UART_RX_BUF_RELEASED");
		buf = CONTAINER_OF(evt->data.rx_buf.buf, struct uart_data_t,
				   data);

		if (buf->len > 0) {
			k_fifo_put(&fifo_uart_rx_data, buf);
			//printk("RX data: %s\n", buf->data);
		} else {
			k_free(buf);
		}

		break;

	case UART_TX_ABORTED:
		LOG_DBG("UART_TX_ABORTED");
		if (!aborted_buf) {
			aborted_buf = (uint8_t *)evt->data.tx.buf;
		}

		aborted_len += evt->data.tx.len;
		buf = CONTAINER_OF(aborted_buf, struct uart_data_t,
				   data);

		uart_tx(uart, &buf->data[aborted_len],
			buf->len - aborted_len, SYS_FOREVER_MS);

		break;

	default:
		break;
	}
}

static void uart_work_handler(struct k_work *item)
{
	struct uart_data_t *buf;

	buf = k_malloc(sizeof(*buf));
	if (buf) {
		buf->len = 0;
	} else {
		LOG_WRN("Not able to allocate UART receive buffer");
		k_work_reschedule(&uart_work, UART_WAIT_FOR_BUF_DELAY);
		return;
	}

	uart_rx_enable(uart, buf->data, sizeof(buf->data), UART_WAIT_FOR_RX);
}

static bool uart_test_async_api(const struct device *dev)
{
	const struct uart_driver_api *api =
			(const struct uart_driver_api *)dev->api;

	return (api->callback_set != NULL);
}

static int uart_init(void)
{
	int err;
	int pos;
	struct uart_data_t *rx;
	struct uart_data_t *tx;


	uart_configure(uart, &uart_cfg);


	if (!device_is_ready(uart)) {
		return -ENODEV;
	}

	if (IS_ENABLED(CONFIG_USB_DEVICE_STACK)) {
		err = usb_enable(NULL);
		if (err && (err != -EALREADY)) {
			LOG_ERR("Failed to enable USB");
			return err;
		}
	}

	rx = k_malloc(sizeof(*rx));
	if (rx) {
		rx->len = 0;
	} else {
		return -ENOMEM;
	}

	k_work_init_delayable(&uart_work, uart_work_handler);


	if (IS_ENABLED(CONFIG_BT_NUS_UART_ASYNC_ADAPTER) && !uart_test_async_api(uart)) {
		/* Implement API adapter */
		uart_async_adapter_init(async_adapter, uart);
		uart = async_adapter;
	}

	err = uart_callback_set(uart, uart_cb, NULL);
	if (err) {
		LOG_ERR("Cannot initialize UART callback");
		return err;
	}

	if (IS_ENABLED(CONFIG_UART_LINE_CTRL)) {
		LOG_INF("Wait for DTR");
		while (true) {
			uint32_t dtr = 0;

			uart_line_ctrl_get(uart, UART_LINE_CTRL_DTR, &dtr);
			if (dtr) {
				break;
			}
			/* Give CPU resources to low priority threads. */
			k_sleep(K_MSEC(100));
		}
		LOG_INF("DTR set");
		err = uart_line_ctrl_set(uart, UART_LINE_CTRL_DCD, 1);
		if (err) {
			LOG_WRN("Failed to set DCD, ret code %d", err);
		}
		err = uart_line_ctrl_set(uart, UART_LINE_CTRL_DSR, 1);
		if (err) {
			LOG_WRN("Failed to set DSR, ret code %d", err);
		}
	}

	tx = k_malloc(sizeof(*tx));

	if (tx) {
		pos = snprintf(tx->data, sizeof(tx->data),
			       "Starting Nordic UART service example\r\n");

		if ((pos < 0) || (pos >= sizeof(tx->data))) {
			k_free(tx);
			LOG_ERR("snprintf returned %d", pos);
			return -ENOMEM;
		}

		tx->len = pos;
	} else {
		return -ENOMEM;
	}

	err = uart_tx(uart, tx->data, tx->len, SYS_FOREVER_MS);
	if (err) {
		LOG_ERR("Cannot display welcome message (err: %d)", err);
		return err;
	}

	return uart_rx_enable(uart, rx->data, sizeof(rx->data), UART_WAIT_FOR_RX);
}


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);

	current_conn = bt_conn_ref(conn);

	       //below code is added to increase MTU size as per throughput example
	struct bt_conn_le_data_len_param data_len_param;

	data_len_param.tx_max_len = 200; // byte
	data_len_param.tx_max_time = 3750; // us


}

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);
	}
}

// #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,
// #ifdef CONFIG_BT_NUS_SECURITY_ENABLED
// 	.security_changed = security_changed,
// #endif
};

// #if defined(CONFIG_BT_NUS_SECURITY_ENABLED)
// static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey)
// {
// 	char addr[BT_ADDR_LE_STR_LEN];

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

// 	LOG_INF("Passkey for %s: %06u", addr, passkey);
// }

// static void auth_passkey_confirm(struct bt_conn *conn, unsigned int passkey)
// {
// 	char addr[BT_ADDR_LE_STR_LEN];

// 	auth_conn = bt_conn_ref(conn);

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

// 	LOG_INF("Passkey for %s: %06u", addr, passkey);
// 	LOG_INF("Press Button 1 to confirm, Button 2 to reject.");
// }


// static void auth_cancel(struct bt_conn *conn)
// {
// 	char addr[BT_ADDR_LE_STR_LEN];

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

// 	LOG_INF("Pairing cancelled: %s", addr);
// }


// static void pairing_complete(struct bt_conn *conn, bool bonded)
// {
// 	char addr[BT_ADDR_LE_STR_LEN];

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

// 	LOG_INF("Pairing completed: %s, bonded: %d", addr, bonded);
// }


// static void pairing_failed(struct bt_conn *conn, enum bt_security_err reason)
// {
// 	char addr[BT_ADDR_LE_STR_LEN];

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

// 	LOG_INF("Pairing failed conn: %s, reason %d", addr, reason);
// }


// static struct bt_conn_auth_cb conn_auth_callbacks = {
// 	.passkey_display = auth_passkey_display,
// 	.passkey_confirm = auth_passkey_confirm,
// 	.cancel = auth_cancel,
// };

// static struct bt_conn_auth_info_cb conn_auth_info_callbacks = {
// 	.pairing_complete = pairing_complete,
// 	.pairing_failed = pairing_failed
// };
// #else
// static struct bt_conn_auth_cb conn_auth_callbacks;
// #endif

static void bt_receive_cb(struct bt_conn *conn, const uint8_t *const data,
			  uint16_t len)
{
	int err;
	char addr[BT_ADDR_LE_STR_LEN] = {0};

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

	LOG_INF("Received data from: %s", addr);

	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;
		}

		/* 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++;
		}

		err = uart_tx(uart, tx->data, tx->len, SYS_FOREVER_MS);
		if (err) {
			k_fifo_put(&fifo_uart_tx_data, tx);
		}
	}
}

// static struct bt_nus_cb nus_cb = {
// 	.received = bt_receive_cb,
// };

// void error(void)
// {
// 	dk_set_leds_state(DK_ALL_LEDS_MSK, DK_NO_LEDS_MSK);

// 	while (true) {
// 		/* Spin for ever */
// 		k_sleep(K_MSEC(1000));
// 	}
// }

// #ifdef CONFIG_BT_NUS_SECURITY_ENABLED
// static void num_comp_reply(bool accept)
// {
// 	if (accept) {
// 		bt_conn_auth_passkey_confirm(auth_conn);
// 		LOG_INF("Numeric Match, conn %p", (void *)auth_conn);
// 	} else {
// 		bt_conn_auth_cancel(auth_conn);
// 		LOG_INF("Numeric Reject, conn %p", (void *)auth_conn);
// 	}

// 	bt_conn_unref(auth_conn);
// 	auth_conn = NULL;
// }

// void button_changed(uint32_t button_state, uint32_t has_changed)
// {
// 	uint32_t buttons = button_state & has_changed;

// 	if (auth_conn) {
// 		if (buttons & KEY_PASSKEY_ACCEPT) {
// 			num_comp_reply(true);
// 		}

// 		if (buttons & KEY_PASSKEY_REJECT) {
// 			num_comp_reply(false);
// 		}
// 	}
// }
// #endif /* CONFIG_BT_NUS_SECURITY_ENABLED */

// static void configure_gpio(void)
// {
// 	int err;

// #ifdef CONFIG_BT_NUS_SECURITY_ENABLED
// 	err = dk_buttons_init(button_changed);
// 	if (err) {
// 		LOG_ERR("Cannot init buttons (err: %d)", err);
// 	}
// #endif /* CONFIG_BT_NUS_SECURITY_ENABLED */

// 	err = dk_leds_init();
// 	if (err) {
// 		LOG_ERR("Cannot init LEDs (err: %d)", err);
// 	}
// }

void main(void)
{
	int blink_status = 0;
	int err = 0;

	//configure_gpio();

	err = uart_init();
	if (err) {
		//error();
	}

	// if (IS_ENABLED(CONFIG_BT_NUS_SECURITY_ENABLED)) {
	// 	err = bt_conn_auth_cb_register(&conn_auth_callbacks);
	// 	if (err) {
	// 		printk("Failed to register authorization callbacks.\n");
	// 		return;
	// 	}

	// 	err = bt_conn_auth_info_cb_register(&conn_auth_info_callbacks);
	// 	if (err) {
	// 		printk("Failed to register authorization info callbacks.\n");
	// 		return;
	// 	}
	// }

	err = bt_enable(NULL);
	if (err) {
		//error();
	}

	LOG_INF("Bluetooth initialized");

	k_sem_give(&ble_init_ok);

	if (IS_ENABLED(CONFIG_SETTINGS)) {
		settings_load();
	}

	// err = bt_nus_init(&nus_cb);
	// if (err) {
	// 	LOG_ERR("Failed to initialize UART service (err: %d)", err);
	// 	return;
	// }

	//const struct bt_le_conn_param *param = 
	bt_conn_le_param_update(current_conn, BT_LE_CONN_PARAM(MIN_CONN_INTERVAL, MAX_CONN_INTERVAL, 0,40));



	err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd,
			      ARRAY_SIZE(sd));
	if (err) {
		LOG_ERR("Advertising failed to start (err %d)", err);
		return;
	}
}


void ble_write_thread(void)
{
	/* Don't go any further until BLE is initialized */
	k_sem_take(&ble_init_ok, K_FOREVER);

	for (;;) {
		/* Wait indefinitely for data to be sent over bluetooth */
		struct uart_data_t *buf = k_fifo_get(&fifo_uart_rx_data,
						     K_FOREVER);

		if (bt_nus_send(NULL, buf->data, buf->len)) {
			LOG_WRN("Failed to send data over BLE connection");
		}

		k_free(buf);
	}
}

K_THREAD_DEFINE(ble_write_thread_id, STACKSIZE, ble_write_thread, NULL, NULL,
		NULL, PRIORITY, 0, 0);

minimal .conf file:

#
# 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_PINMUX=n
CONFIG_SPI=n
CONFIG_GPIO=n

# Power management
CONFIG_PM=n

# 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=y
CONFIG_UART_CONSOLE=y
CONFIG_STDOUT_CONSOLE=n
CONFIG_PRINTK=y
CONFIG_EARLY_CONSOLE=n
CONFIG_LOG=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_CTLR_SDC_RX_STACK_SIZE=324
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=512
CONFIG_MPSL_WORK_STACK_SIZE=256
CONFIG_MAIN_STACK_SIZE=640
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_ASSERT=n

# Disable Bluetooth features not needed
CONFIG_BT_DEBUG_NONE=y
CONFIG_BT_ASSERT=n
CONFIG_BT_DATA_LEN_UPDATE=y
CONFIG_BT_PHY_UPDATE=y
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=y

# 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_CTLR_RX_BUFFERS=1
CONFIG_BT_BUF_ACL_TX_COUNT=3
CONFIG_BT_BUF_ACL_TX_SIZE=27
CONFIG_BT_CTLR_DATA_LENGTH_MAX=27

I'm running nRF connect SDK v1.2.0 in VSCode with the nrf52dk built as nrf52810.

Help is much appreciated. 

  • Hi Nathalie

    What is the error message you get when trying to increase the MTU size?

    Have you tried to increase the CONFIG_BT_NUS_UART_BUFFER_SIZE setting?

    Could you try to log the length of the packets sent over BLE to see how long packets you are sending? 
    I am not sure why you are checking if the length equals 14 in the code, this seems a bit short. 

    The peripheral_uart example is not really optimized for speed. I will take a closer look at it next week and see if there is some room for improvement. 
    That said, if you are unable to use flow control there will always be some risk of data loss, if the throughput over BLE is lower than the UART throughput. 

    Best regards
    Torbjørn

  • Hi Torbjørn,

    This is the error: 

    warning: BT_CTLR_DATA_LENGTH_MAX (defined at
    C:/nordicsemi/v2.1.0/nrf\subsys\bluetooth\services\fast_pair/Kconfig.fast_pair:97,
    subsys/bluetooth\controller/Kconfig:380) was assigned the value '251' but got the value '27'. See
    docs.zephyrproject.org/.../kconfig.html and/or look up
    BT_CTLR_DATA_LENGTH_MAX in the menuconfig/guiconfig interface. The Application Development Primer,
    Setting Configuration Values, and Kconfig - Tips and Best Practices sections of the manual might be
    helpful too.

    warning: user value 251 on the int symbol BT_CTLR_DATA_LENGTH_MAX (defined at C:/nordicsemi/v2.1.0/nrf\subsys\bluetooth\services\fast_pair/Kconfig.fast_pair:97, subsys/bluetooth\controller/Kconfig:380) ignored due to being outside the active range ([27, 27]) -- falling back on defaults

    error: Aborting due to Kconfig warnings


    I don't have CONFIG_BT_NUS_UART_BUFFER_SIZE show up as a config option, do I need to import anything for this?

    I'm using 14 as the check because my data is 7 bytes long. Receiving two data points in one packet works better than one, but I'm unable to go up to three because while data is still received on the UART, nothing is received over BLE for a check of 21.

    I am unfortunately unable to use the log as there is not enough SRAM free.

    Do you know of any other examples that would be a better starting point for increased speed?

    Thanks

  • Hi Nathalie

    If you increase CONFIG_BT_BUF_ACL_RX_SIZE as well you should be able to increase the BT_CTLR_DATA_LENGTH_MAX parameter. 

    NathalieH said:
    I don't have CONFIG_BT_NUS_UART_BUFFER_SIZE show up as a config option, do I need to import anything for this?

    CONFIG_BT_NUS_UART_BUFFER_SIZE should be available if you have copied the peripheral_uart example, it is defined by the Kconfig file in the example root folder. 

    NathalieH said:
    I am unfortunately unable to use the log as there is not enough SRAM free.

    You don't have an nRF52DK available for debugging purposes? 

    The nRF52810 doesn't come with it's own DK, and normally the nRF52DK is used. This kit uses the nRF52832, which has more available memory. 

    NathalieH said:
    Do you know of any other examples that would be a better starting point for increased speed?

    In general the best example to start out with if you care about transfer speed is the throughput sample.

    Best regards
    Torbjørn

  • Thanks for the suggestions!

    I ended up writing something from scratch which allowed me to cut out all features not relevant to the application. With this I achieved the required data rate.

  • Hi Nathalie

    Good to hear that you got it working well Slight smile

    I will consider the case resolved then. 

    Best regards
    Torbjørn

Related