Bluetooth will force the next data packet transmission to wait until after the 7.5ms connection interval.

We are using the NRF5340 with a Bluetooth transparent transmission example routine. We have set the connection interval to 7.5ms and the transmission timing to 3ms (sending a 242-byte dummy data packet). We observed that Bluetooth can send data packets normally within the 7.5ms interval, but after sending the second data packet, Bluetooth forces the next transmission to wait until after the 7.5ms connection interval, which causes blockage on the transmitting end.
Currently, we have configured the connection event extension with CONFIG_BT_USER_DATA_LEN_UPDATE=y, CONFIG_BT_CTLR_DATA_LENGTH_MAX=251, and the GAP event interval with CONFIG_BT_CTLR_SDC_MAX_CONN_EVENT_LEN_DEFAULT=7500.
Are we missing any key configurations such as the "Connection event length extension" found in nRF52840, like setting opt.common_opt.conn_evt_evt.enable=true; err_code=sd_ble_opt_set(BLE_COMMON_OPT_CONN_EVT_EVT, &opt);? Or are there any existing configurations that need to be enabled in the main function?
Parents
  • Check .config file in build/zephyr, the default only has 3 TX buffers enabled:  CONFIG_BT_BUF_ACL_TX_COUNT=3

    That won't do for high throughput, try to increase to 10. Careful: Must be in sync with the net core firmware config IIRC. Note that this will increase RAM footprint on both cores.

  • bro,What does it mean by "must be synchronized with the network core firmware configuration, IIRC"? Is it referring to the prj.conf of ipc_radio or the main function? I wonder if it could be the CONFIG_IPC_RADIO_LOG_LEVEL in the main function of ipc_radio?

  • Take another look at the throughput sample. There is stuff in both prj.conf AND sysbuild/ipc_radio/prj.conf files.

  • Thanks bro

    I have checked the throughput sample repeatedly, and all the key configurations have been referenced. Here are all my current configurations and the main function for your reference.

    /*
     * 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 <zephyr/bluetooth/bluetooth.h>
    #include <zephyr/bluetooth/uuid.h>
    #include <zephyr/bluetooth/gatt.h>
    #include <zephyr/bluetooth/hci.h>
    
    #include <bluetooth/services/nus.h>
    
    #include <dk_buttons_and_leds.h>
    
    #include <zephyr/settings/settings.h>
    
    #include <stdio.h>
    #include <string.h>
    
    #include <zephyr/logging/log.h>
    
    #include <zephyr/drivers/gpio.h>
    #include<zephyr/sys/printk.h>
    #include<zephyr/drivers/clock_control.h>
    #include<zephyr/drivers/clock_control/nrf_clock_control.h>
    
    #define LOG_MODULE_NAME peripheral_uart
    LOG_MODULE_REGISTER(LOG_MODULE_NAME);
    
    #define STACKSIZE CONFIG_BT_NUS_THREAD_STACK_SIZE
    #define PRIORITY 7
    
    #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(50)
    #define UART_WAIT_FOR_RX CONFIG_BT_NUS_UART_RX_WAIT_TIME
    
    // #define RX_THREAD_PRIORITY -1  // 高于默认
    // #define RX_THREAD_STACK_SIZE 1024
    // #define RX_QUEUE_MAX_ITEMS 20  // 根据数据率调整队列深度
    // #define RX_DATA_SIZE 251       // 匹配 DLE 最大 PDU 大小(242 字节 + 开销)
    // // 数据缓冲区结构
    // struct rx_data {
    //     uint8_t buffer[RX_DATA_SIZE]; // 存储接收的 BLE 数据
    //     size_t len;                   // 数据长度
    // };
    // K_MSGQ_DEFINE(rx_queue, RX_DATA_SIZE, RX_QUEUE_MAX_ITEMS, 4); // 消息队列,4字节对齐
    // void rx_thread_func(void *p1, void *p2, void *p3) {
    // 	// struct rx_data data;
    //     // while (1) {
    //     //     // 从 bt_recv() 或 UART/BLE 队列读取并处理数据
    //     //     if (k_msgq_get(&rx_queue, &data, K_NO_WAIT) == 0) {
    //     //         // 快速处理或转发数据,避免阻塞
    //     //     }
    //     //     k_yield();  // 让出 CPU
    //     // }
    // }
    // static K_THREAD_DEFINE(rx_thread_id, RX_THREAD_STACK_SIZE, rx_thread_func, NULL, NULL, NULL, RX_THREAD_PRIORITY, 0, 0);
    
    
    
    static uint8_t ble_ADC[250];
    static uint8_t ble_Tx[250];
    //static uint8_t ble_Tx1[250];
    static uint16_t bag=0;
    static uint16_t LASTbag=0;
    //static int8_t counter=0;
    static struct k_timer adc_timer;  // 定时器实例
    static void adc_timer_handler(struct k_timer *timer_id);  // 前向声明
    static struct k_work adc_work ;
    
    #define LED0_NODE DT_ALIAS(led0)
    static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios);
    
    static void exchange_func(struct bt_conn *conn, uint8_t att_err, struct bt_gatt_exchange_params *params);
    
    #define BLE_NUS_THROUGHPUT_MAX
    #define BLE_NUS_THROUGHPUT_TEST
    
    #if defined(BLE_NUS_THROUGHPUT_MAX)
    static K_SEM_DEFINE(nus_connection_sem,0,1);
    static const char*phy2str(uint8_t phy)
    {
    	switch (phy)
    	{
    	case 0:return"NO packets";
    		
    	case BT_GAP_LE_PHY_1M:return"LE 1M";
    	case BT_GAP_LE_PHY_2M:return"LE 2M";
    	case BT_GAP_LE_PHY_CODED:return "LE Coded";
    	default: return "Unknown";
    		
    	}
    }
    #endif
    
    static K_SEM_DEFINE(ble_init_ok, 0, 1);
    
    static struct bt_conn *current_conn;
    static struct bt_conn *auth_conn;
    static struct k_work adv_work;
    
    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[UART_BUF_SIZE];
    	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),
    };
    
    #ifdef CONFIG_UART_ASYNC_ADAPTER
    UART_ASYNC_ADAPTER_INST_DEFINE(async_adapter);
    #else
    #define async_adapter NULL
    #endif
    
    
    static void ADC_update(void)
    {
        //生成假数据(忽略ADS1299,模拟24字节/采样)
        for (uint8_t i = 0; i < 242; i++) {
            //ble_ADC[counter * 24+ i + 2] = i;  // 假数据:每个通道固定值i(0-23),偏移2字节包头
    		ble_ADC[i+2]=i;
        }
        //counter++;  // 递增计数器
    
        //if (counter == 10) {  // 累积10次(240字节 + 包头/序列号 = 242字节)
            // 复制到发送缓冲
            for (uint16_t i = 0; i < 242; i++) {
                ble_Tx[i] = ble_ADC[i];
            }
            ble_Tx[1] = (uint8_t)bag++;  // 设置序列号(低8位),递增
            if (bag > 0xFF) bag = 0;     // 循环0-255
    
            // 确保连续性(类似THI_update逻辑)
            if (LASTbag != (ble_Tx[1] - 1)) {
                ble_Tx[1] = (uint8_t)(LASTbag + 1);
            }
            LASTbag = ble_Tx[1];
           // 发送通过NUS(Zephyr API)
    		//bt_nus_send(NULL, ble_Tx, 242);
    
    		gpio_pin_toggle_dt(&led);
    	
    	    int err = bt_nus_send(NULL, ble_Tx, 242);
            if (err) {
                printk("Failed to send: %d\n", err);  // 调试:错误如 -ENOMEM (资源不足,重试机制可加)
            } else {
                printk("Sent packet %d (242 bytes)\n", LASTbag);  // 性能监控
             }
    
          // counter = 0;  // 重置计数器
        //}
    
        // 简单延时模拟采样间隔(可选,Zephyr中定时器已控制周期)
       //k_sleep(K_MSEC(1));  // 替换空循环,1ms稳定
    }
    static void adc_timer_handler(struct k_timer *timer_id)
    {
        ARG_UNUSED(timer_id);  // 避免未用警告
        //ADC_update();  // 调用更新函数
    	k_work_submit(&adc_work);
    }
    
    static void adc_work_handler(struct k_work *work)
    {
       ARG_UNUSED(work);
       ADC_update();
    }
    // static void uart_cb(const struct device *dev, struct uart_event *evt, void *user_data)
    // {
    // 	ARG_UNUSED(dev);
    
    //    // static uint8_t*current_buf;
    // 	static bool buf_release;
    
    // 	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[0]);
    // 			aborted_buf = NULL;
    // 			aborted_len = 0;
    // 		} else {
    // 			buf = CONTAINER_OF(evt->data.tx.buf, struct uart_data_t,
    // 					   data[0]);
    // 		}
    
    // 		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[0]);
    // 		buf->len += evt->data.rx.len;
    
    // 		buf_release=false;
    
    // 		if (disable_req) {
    // 			return;
    // 		}
    
    // 		if ((evt->data.rx.buf[buf->len - 1] == '\n') ||
    // 		    (evt->data.rx.buf[buf->len - 1] == '\r')) {
    // 			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[0]);
    
    // 		if (buf->len > 0) {
    // 			k_fifo_put(&fifo_uart_rx_data, buf);
    // 		} 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((void *)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;
    
    // 	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_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) {
    // 		k_free(rx);
    // 		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 sample\r\n");
    
    // 		if ((pos < 0) || (pos >= sizeof(tx->data))) {
    // 			k_free(rx);
    // 			k_free(tx);
    // 			LOG_ERR("snprintf returned %d", pos);
    // 			return -ENOMEM;
    // 		}
    
    // 		tx->len = pos;
    // 	} else {
    // 		k_free(rx);
    // 		return -ENOMEM;
    // 	}
    
    // 	err = uart_tx(uart, tx->data, tx->len, SYS_FOREVER_MS);
    // 	if (err) {
    // 		k_free(rx);
    // 		k_free(tx);
    // 		LOG_ERR("Cannot display welcome message (err: %d)", err);
    // 		return err;
    // 	}
    
    // 	err = uart_rx_enable(uart, rx->data, sizeof(rx->data), UART_WAIT_FOR_RX);
    // 	if (err) {
    // 		LOG_ERR("Cannot enable uart reception (err: %d)", err);
    // 		/* Free the rx buffer only because the tx buffer will be handled in the callback */
    // 		k_free(rx);
    // 	}
    
    // 	return err;
    // }
    
    static void adv_work_handler(struct k_work *work)
    {
    	int err = bt_le_adv_start(BT_LE_ADV_CONN_FAST_2, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd));
    
    	if (err) {
    		LOG_ERR("Advertising failed to start (err %d)", err);
    		return;
    	}
    
    	LOG_INF("Advertising successfully started");
    }
    
    static void advertising_start(void)
    {
    	k_work_submit(&adv_work);
    }
    
    static void update_data_length(struct bt_conn *conn)
    {
        int err;
        struct bt_conn_le_data_len_param my_data_len = {
            .tx_max_len = BT_GAP_DATA_LEN_MAX,
            .tx_max_time = BT_GAP_DATA_TIME_MAX,
        };
        err = bt_conn_le_data_len_update(conn, &my_data_len);
        if (err) {
            LOG_ERR("data_len_update failed (err %d)", err);
        }
    }
    static struct bt_gatt_exchange_params exchange_params;
    static void update_mtu(struct bt_conn *conn)
    {
        int err;
        exchange_params.func = exchange_func;
    
        err = bt_gatt_exchange_mtu(conn, &exchange_params);
        if (err) {
            LOG_ERR("bt_gatt_exchange_mtu failed (err %d)", err);
        }
    }
    static void exchange_func(struct bt_conn *conn, uint8_t att_err,
    			  struct bt_gatt_exchange_params *params)
    {
    	LOG_INF("MTU exchange %s", att_err == 0 ? "successful" : "failed");
        if (!att_err) {
            uint16_t payload_mtu = bt_gatt_get_mtu(conn) - 3;   // 3 bytes used for Attribute headers.
            LOG_INF("New MTU: %d bytes", payload_mtu);
        }
    }
    void on_le_data_len_updated(struct bt_conn *conn, struct bt_conn_le_data_len_info *info)
    {
        uint16_t tx_len     = info->tx_max_len; 
        uint16_t tx_time    = info->tx_max_time;
        uint16_t rx_len     = info->rx_max_len;
        uint16_t rx_time    = info->rx_max_time;
        LOG_INF("Data length updated. Length %d/%d bytes, time %d/%d us", tx_len, rx_len, tx_time, rx_time);
    }
    // static void mtu_exchange_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_exchange_params *params)
    // {
    //     if (err) {
    //         printk("MTU exchange failed (err %u)\n", err);
    //     } else {
    //         size_t mtu_size = bt_gatt_get_mtu(conn);
    //         printk("MTU exchange successful, negotiated MTU: %zu\n", mtu_size);
    //         // 期望 mtu_size = 247(如果 central 支持 >= 247)
    //     }
    // }
    
    // // 定义 MTU 交换参数
    // static struct bt_gatt_exchange_params mtu_params = {
    //     .func = mtu_exchange_cb,
    // };
    // static struct bt_conn*current_conn=NULL;
    static void connected(struct bt_conn *conn, uint8_t err)
    {
    	char addr[BT_ADDR_LE_STR_LEN];
    
    	if (err) {
    		LOG_ERR("Connection failed, err 0x%02x %s", err, bt_hci_err_to_str(err));
    		return;
    	}
    	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    	LOG_INF("Connected %s", addr);
    
    	// 先发起 MTU 交换,并检查返回值
        // int ret = bt_gatt_exchange_mtu(conn, &mtu_params);
        // if (ret) {
        //     printk("MTU exchange request failed (err %d)\n", ret);
        //     if (ret == -EALREADY) {
        //         // 已交换过,直接获取当前 MTU
        //         size_t mtu_size = bt_gatt_get_mtu(conn);
        //         printk("MTU already exchanged, current MTU: %zu\n", mtu_size);
        //     } else {
        //         // 其他错误处理,例如重试或日志
        //         // 可根据需要添加重试逻辑:atomic_clear_bit(conn->flags, BT_CONN_ATT_MTU_EXCHANGED); 然后重试(调试用,非推荐)
        //     }
        // }
        
         struct bt_le_conn_param param={
            .interval_min=0x0006,
    		.interval_max=0x0006,
    		.latency=0x0000,
    		.timeout=0x00C8,
    	 };
    	 bt_conn_le_param_update(conn,&param);
    
    	 struct bt_conn_le_phy_param phy_param ={
            .pref_tx_phy=BT_GAP_LE_PHY_2M,
    		.pref_rx_phy=BT_GAP_LE_PHY_2M,
    		.options=0
    	 };
    	 bt_conn_le_phy_update(conn,&phy_param);
    
    
    	current_conn = bt_conn_ref(conn);
    	if (!current_conn) {
            printk("Failed to reference connection");
            return;
        }
        printk("Connection referenced successfully");
    //    k_work_delayable_init(&param_update_work,param_update_work_handler);
    //    k_work_schedule(&param_update_work,K_MSEC(300));
    	//k_timer_start(&adc_timer,K_MSEC(1000),K_MSEC(1000));
    	dk_set_led_on(CON_STATUS_LED);
    	#if defined(BLE_NUS_THROUGHPUT_MAX)
    	k_sem_give(&nus_connection_sem);
    	#endif
    	//uint16_t mtu;
    	//bt_gatt_exchange_mtu(conn,&mtu_params);
    	//size_t mtu_size=bt_gatt_get_mtu(conn);
    	k_sleep(K_MSEC(1000));  // Delay added to avoid link layer collisions.
        update_data_length(conn);
        update_mtu(conn);
    	//update_phy(conn);
    }
    
    
    // static void param_update_work_handler(struct k_work *work) {
    //     // 请求数据长度扩展
    //     bt_conn_le_data_len_update(current_conn, BT_LE_DATA_LEN_PARAM(BT_LE_DATA_LEN_PARAM_MAX));
    
    //     // 请求 PHY 更新(2Mbps)
    //     bt_conn_le_phy_update(current_conn, BT_CONN_LE_PHY_PARAM_2M);
    
    // }
    
    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 0x%02x %s", addr, reason, bt_hci_err_to_str(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);
    	}
    }
    
    // static struct bt_conn_cb conn_callbacks = {
    //        .connected=connected,
    // 	   .disconnected=disconnected,
    // };
    // bt_conn_cb_register(&conn_callbacks);
    
    static void recycled_cb(void)
    {
    	LOG_INF("Connection object available from previous conn. Disconnect is complete!");
    	advertising_start();
    }
    
    #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 %s", addr, level, err,
    			bt_security_err_to_str(err));
    	}
    }
    #endif
    
    #if defined(BLE_NUS_THROUGHPUT_MAX)
    
    static bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param)
    {		
    	LOG_INF("Connection parameters update request received.");
    	LOG_INF("Minimum interval: %d, Maximum interval: %d",
    	       param->interval_min, param->interval_max);
    	LOG_INF("Latency: %d, Timeout: %d", param->latency, param->timeout);
    
    	return true;
    }
    
    static void le_param_updated(struct bt_conn *conn, uint16_t interval,
    			     uint16_t latency, uint16_t timeout)
    {
    	LOG_INF("Connection parameters updated."
    	       " interval: %d, latency: %d, timeout: %d",
    	       interval, latency, timeout);
    }
    
    static void le_phy_updated(struct bt_conn *conn,
    			   struct bt_conn_le_phy_info *param)
    {
    	LOG_INF("LE PHY updated: TX PHY %s, RX PHY %s",
    	       phy2str(param->tx_phy), phy2str(param->rx_phy));
    }
    
    static void le_data_length_updated(struct bt_conn *conn,
    				   struct bt_conn_le_data_len_info *info)
    {
    	LOG_INF("LE data len updated: TX (len: %d time: %d)"
    	       " RX (len: %d time: %d)", info->tx_max_len,
    	       info->tx_max_time, info->rx_max_len, info->rx_max_time);
    
    }
    
    #endif
    
    BT_CONN_CB_DEFINE(conn_callbacks) = {
    	.connected        = connected,
    	.disconnected     = disconnected,
    	.recycled         = recycled_cb,
    	.le_data_len_updated    = on_le_data_len_updated,
    
    #if defined(BLE_NUS_THROUGHPUT_MAX)
    .le_param_req = le_param_req,
        .le_param_updated = le_param_updated,
        .le_phy_updated = le_phy_updated,
        .le_data_len_updated = le_data_length_updated,
    #endif
    
    #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);
    
    	if (IS_ENABLED(CONFIG_SOC_SERIES_NRF54HX) || IS_ENABLED(CONFIG_SOC_SERIES_NRF54LX)) {
    		LOG_INF("Press Button 0 to confirm, Button 1 to reject.");
    	} else {
    		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 %s", addr, reason,
    		bt_security_err_to_str(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;
    static struct bt_conn_auth_info_cb conn_auth_info_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);
    	}
    }
    
    int 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) {
    			LOG_ERR("Failed to register authorization callbacks. (err: %d)", err);
    			return 0;
    		}
    
    		err = bt_conn_auth_info_cb_register(&conn_auth_info_callbacks);
    		if (err) {
    			LOG_ERR("Failed to register authorization info callbacks. (err: %d)", err);
    			return 0;
    		}
    	}
    
    	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 0;
    	}
    
    	k_work_init(&adv_work, adv_work_handler);
    
        k_work_init(&adc_work,adc_work_handler);
        k_timer_init(&adc_timer,adc_timer_handler,NULL);
    	k_timer_start(&adc_timer,K_MSEC(3),K_MSEC(3));
    
    	advertising_start();
         
    	int ret;
    	  //bool led_state = true;
       if (!gpio_is_ready_dt(&led)) {
    		return 0;
    	}
    
    	ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
    	if (ret < 0) {
    		return 0;
    	}
    	
        
        ble_ADC[0]=0x64;
        
        //int ble_Tx1[250];
    	// for(uint16_t i=0;i<242;i++)
        //    ble_Tx1[i]=i;
        // ble_Tx1[1]=(uint16_t)bag++;
    	// if (bag>0xFF) bag=0;
    	//k_sleep(K_MSEC(1000));  // Delay added to avoid link layer collisions.
        
    
    
    
    	for (;;) {
    		dk_set_led(RUN_STATUS_LED, (++blink_status) % 2);
    		//bt_nus_send(NULL, ble_Tx, 8);
    		k_sleep(K_MSEC(RUN_LED_BLINK_INTERVAL));
    	}
    }
    
    
    
    void ble_write_thread(void)
    {
    	/* Don't go any further until BLE is initialized */
    	k_sem_take(&ble_init_ok, K_FOREVER);
    	struct uart_data_t nus_data = {
    		.len = 0,
    	};
    
    	for (;;) {
    		/* Wait indefinitely for data to be sent over bluetooth */
    		struct uart_data_t *buf = k_fifo_get(&fifo_uart_rx_data,
    						     K_FOREVER);
    
    		int plen = MIN(sizeof(nus_data.data) - nus_data.len, buf->len);
    		int loc = 0;
    
    		while (plen > 0) {
    			memcpy(&nus_data.data[nus_data.len], &buf->data[loc], plen);
    			nus_data.len += plen;
    			loc += plen;
    
    			if (nus_data.len >= sizeof(nus_data.data) ||
    			   (nus_data.data[nus_data.len - 1] == '\n') ||
    			   (nus_data.data[nus_data.len - 1] == '\r')) {
    				if (bt_nus_send(NULL, nus_data.data, nus_data.len)) {
    					LOG_WRN("Failed to send data over BLE connection");
    				}
    				nus_data.len = 0;
    			}
    
    			plen = MIN(sizeof(nus_data.data), buf->len - loc);
    		}
    
    		k_free(buf);
    	}
    }
    
    // K_THREAD_DEFINE(ble_write_thread_id, STACKSIZE, ble_write_thread, NULL, NULL,
    // 		NULL, PRIORITY, 0, 0);
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    

    8345.prj.conf8345.prj.conf

  • Sorry, it seems I sent two copies of the ipc_radio/prj.conf files by mistake. This one is the prj.conf for the application core's peripheral_uart.2251.prj.conf

  • Interestingly, when my timer K_MSEC() is set to 4 and the connection interval is set to 7.5ms, data packets do not queue (error code-12), but the rate is 3.8ms, which does not meet our target of 3ms. When K_MSEC() is set to 4 and the connection interval is 15ms, data packets start to queue (approximately 2 out of every 5 packets are queued). When K_MSEC() is set to 3 and the connection interval is 7.5ms, data packets also queue (roughly 1 out of every 3 packets is queued). If K_MSEC() is set to 3 and the connection interval is 15ms, even more data packets will queue.
    This seems very much like a blockage at the TX (transmit) end. Regrettably, however, adjusting the value of CONFIG_BT_BUF_ACL_TX_COUNT does not result in any observable changes.
  • Hi,

    I tried to replicate your reported issue using peripheral_uart sample in NCS v3.1.0 but I was not successful. I suggest that you provide your code samples as requested in your second ticket, so that they could be looked into.

    Best regards,
    Dejan

Reply Children
No Data
Related