nRF52840 DK BLE MTU Size Issue: Device Not Discoverable After Reconnect

Hi,

I’m developing a BLE IoT product using the nRF52840 DK, where I need to send a payload of 60 bytes. In a previous response to one of my questions, I was advised to increase the MTU size to handle the larger payload. I implemented the MTU size increase using the code provided, and everything works fine when I connect to the device for the first time.

However, when I disconnect and try to reconnect, the device is no longer visible in the Bluetooth device list. This issue only occurs after the first disconnect. I’m not sure what could be causing the problem.

Has anyone experienced this before or have any suggestions on how to resolve this issue? I'm attaching my code below for reference.

Thanks in advance for your help!

main.c

/*
 * Copyright (c) 2016 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include "main.h"
#include "ff.h"
#include "ffconf.h"
#include "mem.h"
#include "shell.h"
#include "flash_management.h"
#include "TargetPlatform.h"
#include "vc_date_time.h"
#include "vc_ble_bio_data_service.h"

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

LOG_MODULE_REGISTER(main, LOG_LEVEL_DBG);

BUILD_ASSERT(DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_console), zephyr_cdc_acm_uart),
             "Console device is not ACM CDC UART device");

const struct device *const dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_console));

char app_ecg_live[50];
char app_ecg_past[50] = {0};
vcPatchData_t patchData;
int64_t current_date;
int loop = 0;
FATFS fs;
int64_t app_time = 0;
volatile uint32_t available_instance_count = 1;
extern struct tm new_date_time;
uint32_t dtr = 0;

K_MUTEX_DEFINE(test_mutex);
/**
 * @brief Message queue declaration for managing led patterns.
 *
 * This message queue is used to store and manage led patterns.
 */
K_MSGQ_DEFINE(process_ecg_data_queue, sizeof(app_ecg_live), 10, 4);

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

/**
 * @brief Bluetooth advertising parameters.
 *
 * This variable holds the parameters for Bluetooth advertising.
 */
static struct bt_le_adv_param *adv_param = BT_LE_ADV_PARAM(
    (BT_LE_ADV_OPT_CONNECTABLE |
     BT_LE_ADV_OPT_USE_IDENTITY), /* Connectable advertising and use identity address */
    1600,                         /* Min Advertising Interval 1000ms (1600*0.625ms) */
    1601,                         /* Max Advertising Interval 1000.625ms (1601*0.625ms) */
    NULL);                        /* Set to NULL for undirected advertising */

/**
 * @brief Bluetooth advertising data.
 *
 * This variable holds the advertising data for Bluetooth.
 */
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),
};

/**
 * @brief Bluetooth scan response data.
 *
 * This variable holds the scan response data for Bluetooth.
 */
static const struct bt_data sd[] = {
    BT_DATA_BYTES(BT_DATA_UUID16_ALL, BT_UUID_16_ENCODE(BT_UUID_UDS_VAL)),
};

static char *app_ecg_data_live_cb()
{
        return app_ecg_live;
}
static char *app_ecg_data_past_cb()
{
        return app_ecg_live;
}

static struct vc_bds_svc_cb app_vc_bds_callbacks = {
    .ecg_data_live_cb = app_ecg_data_live_cb,
    .ecg_data_past_cb = app_ecg_data_past_cb,
};

static void exchange_func(struct bt_conn *conn, uint8_t att_err,
                          struct bt_gatt_exchange_params *params);
/* STEP 11.2 - Create variable that holds callback for MTU negotiation */
static struct bt_gatt_exchange_params exchange_params;

struct bt_conn *my_conn = NULL;

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(my_conn, &my_data_len);
        if (err)
        {
                LOG_ERR("data_len_update failed (err %d)", err);
        }
}

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

/**
 * @brief Callback function for Bluetooth connection established event.
 *
 * This function is called when a Bluetooth connection is established.
 *
 * @param conn Pointer to the connection structure.
 * @param err Error code indicating the connection status.
 *            0 if connection is successful, non-zero error code otherwise.
 *
 * @return None.
 */
static void on_connected(struct bt_conn *conn, uint8_t err)
{
        if (err)
        {
                LOG_ERR("Connection failed (err %u)", err);
                return;
        }
        LOG_INF("Connected");
        my_conn = bt_conn_ref(conn);
        update_data_length(my_conn);
        update_mtu(my_conn);
}

/**
 * @brief Callback function for Bluetooth connection disconnected event.
 *
 * This function is called when a Bluetooth connection is disconnected.
 *
 * @param conn Pointer to the connection structure.
 * @param reason Disconnection reason code.
 *
 * @return None.
 */
static void on_disconnected(struct bt_conn *conn, uint8_t reason)
{
        LOG_INF("Disconnected (reason %u)", reason);
}

/**
 * @brief Callback function for Bluetooth security changed event.
 *
 * This function is called when Bluetooth security level changes.
 *
 * @param conn Pointer to the connection structure.
 * @param level New security level.
 * @param err Error code indicating the security change status.
 *
 * @return None.
 */
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_INF("Security failed: %s level %u err %d", addr, level,
                        err);
        }
}

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

BT_CONN_CB_DEFINE(conn_callbacks) = {
    .connected = on_connected,
    .disconnected = on_disconnected,
    .security_changed = security_changed,
};

/* Implement callback function for MTU exchange */
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);
        }
}

/**
 * @brief Callback function for displaying passkey during Bluetooth pairing.
 *
 * This function is called to display the passkey during Bluetooth pairing.
 *
 * @param conn Pointer to the connection structure.
 * @param passkey Passkey to be displayed.
 *
 * @return None.
 */
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);
}

/**
 * @brief Callback function for canceling Bluetooth pairing.
 *
 * This function is called to cancel Bluetooth pairing process.
 *
 * @param conn Pointer to the connection structure.
 *
 * @return None.
 */
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);
}

/**
 * @brief Callback function for Bluetooth pairing completion.
 *
 * This function is called when Bluetooth pairing is completed.
 *
 * @param conn Pointer to the connection structure.
 * @param bonded Flag indicating if the device is bonded after pairing.
 *
 * @return None.
 */
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);
}

/**
 * @brief Callback function for Bluetooth pairing failure.
 *
 * This function is called when Bluetooth pairing fails.
 *
 * @param conn Pointer to the connection structure.
 * @param reason Error code indicating the reason for pairing failure.
 *
 * @return None.
 */
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);
}

/**
 * @brief Bluetooth connection authentication callbacks structure.
 *
 * This structure holds callback functions related to Bluetooth connection authentication.
 */
static struct bt_conn_auth_cb conn_auth_callbacks = {
    .passkey_display = auth_passkey_display,
    .cancel = auth_cancel,
    .passkey_display = NULL,
    .passkey_confirm = NULL,
};

/**
 * @brief Bluetooth connection authentication info callbacks structure.
 *
 * This structure holds callback functions related to Bluetooth connection authentication information.
 */
static struct bt_conn_auth_info_cb conn_auth_info_callbacks = {
    .pairing_complete = pairing_complete,
    .pairing_failed = pairing_failed};

int main(void)
{
        /* Initialize sensors */
        sensor_init();

        /* Initialize GPIO and configure GPIOTE */
        gpio_init();

        flash_init();

        vc_set_time(1999999997);

        /*erasing nand flash(mt29)*/

        int err = 0; // Variable to store error codes

        err = bt_conn_auth_cb_register(&conn_auth_callbacks); // Register Bluetooth authorization callbacks
        if (err)
        {
                LOG_ERR("Failed to register authorization callbacks."); // Log error if registration fails
        }

        err = bt_conn_auth_info_cb_register(&conn_auth_info_callbacks); // Register Bluetooth authorization info callbacks
        if (err)
        {
                LOG_ERR("Failed to register authorization info callbacks."); // Log error if registration fails
        }

        err = bt_enable(NULL); // Enable Bluetooth
        if (err)
        {
                LOG_ERR("Bluetooth init failed (err %d)", err); // Log error if Bluetooth initialization fails
        }
        err = vc_bds_svc_init(&app_vc_bds_callbacks); // Initialize USB device
        if (err)
        {
                LOG_ERR("Failed to init usb dev (err:%d)", err); // Log error if initialization fails
        }

        LOG_INF("Bluetooth initialized"); // Log Bluetooth initialization success

        err = bt_le_adv_start(adv_param, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); // Start Bluetooth advertising
        if (err)
        {
                LOG_ERR("Advertising failed to start (err %d)", err); // Log error if advertising fails
        }
}

/**
 * @brief Application LED pattern thread.
 *
 * This thread runs continuously and switches between different LED patterns based on
 * the value of `moov_dev_pattern`. It calls the respective functions for booting, blinking,
 * and circular patterns. After executing a pattern, it waits for a period of 1000 milliseconds.
 */
void process_ecg_data(void)
{
        while (1)
        {
                k_msgq_get(&process_ecg_data_queue, &app_ecg_live, K_FOREVER);
                if (is_ecg_live_enabled())
                {
                        if (   vc_ecg_send_live_data(app_ecg_live))
                        {
                                LOG_ERR("vc_ecg_send_live_data error");
                        }
                }
                else
                {
                        LOG_INF("app_ecg_live:%s", app_ecg_live);
                        k_mutex_lock(&test_mutex, K_FOREVER);
                        int len = strlen(app_ecg_live);
                        app_ecg_live[len  ] = '\n';

                        storingData(app_ecg_live);
                        k_mutex_unlock(&test_mutex);
                }
        }
}

/**
 * @brief Application LED pattern thread.
 *
 * This thread runs continuously and switches between different LED patterns based on
 * the value of `moov_dev_pattern`. It calls the respective functions for booting, blinking,
 * and circular patterns. After executing a pattern, it waits for a period of 1000 milliseconds.
 */
void process_ecg_data_past(void)
{
        char patchData[40];

        while (1)
        {
                if (is_ecg_past_enabled())
		{
                        k_mutex_lock(&test_mutex, K_FOREVER);
                        readFromFile(app_ecg_past);  
                        if (vc_ecg_send_past_data(app_ecg_past))
                        {
                                LOG_ERR("vc_ecg_send_live_data error");
                        }
                        k_mutex_unlock(&test_mutex);
                }
                k_msleep(100);
        }
}

void usb_thread()
{
        if (usb_enable(NULL))
        {
                printk("usb enable failed\n");
                return;
        }
        printk("usb thread started\n");
        while (1)
        {
                if (!dtr)
                {
                        uart_line_ctrl_get(dev, UART_LINE_CTRL_DTR, &dtr);
                        k_sleep(K_MSEC(100));
                }
                else
                {
                        k_sleep(K_SECONDS(1));
                }
        }
}

K_THREAD_DEFINE(write_id, 32768, process_ecg_data, NULL, NULL, NULL, 5, 0, 10000);

K_THREAD_DEFINE(read_id, 32768, process_ecg_data_past, NULL, NULL, NULL, 6, 0, 10000);

K_THREAD_DEFINE(usb_id, 1024, usb_thread, NULL, NULL, NULL, 6, 0, NULL);

prj.conf

CONFIG_LOG=y
CONFIG_PRINTK=y
CONFIG_LOG_MODE_IMMEDIATE=y
CONFIG_CBPRINTF_FP_SUPPORT=y
# CONFIG_LOG_BACKEND_RTT=y


CONFIG_SPI=y
CONFIG_SENSOR=y
CONFIG_PM_DEVICE=y

CONFIG_APPLICATION_DEFINED_SYSCALL=y
CONFIG_MAIN_STACK_SIZE=32768
# CONFIG_FILE_SYSTEM=y


#timer
CONFIG_DATE_TIME=y
CONFIG_DATE_TIME_UPDATE_INTERVAL_SECONDS=0
CONFIG_DATE_TIME_TOO_OLD_SECONDS=0
CONFIG_DATE_TIME_NTP=y
CONFIG_NETWORKING=y
CONFIG_NET_SOCKETS=y


#Enable MCUBOOT bootloader build in the application
CONFIG_BOOTLOADER_MCUBOOT=y
#Set firmware image version
CONFIG_MCUBOOT_IMGTOOL_SIGN_VERSION="1.0.1"
#Include MCUMGR and the dependencies in the build
CONFIG_NCS_SAMPLE_MCUMGR_BT_OTA_DFU=y


#usb
CONFIG_USB_DEVICE_STACK=y
CONFIG_USB_DEVICE_PRODUCT="Zephyr USB console sample"
CONFIG_USB_DEVICE_PID=0x0004
CONFIG_USB_DEVICE_INITIALIZE_AT_BOOT=n
CONFIG_SERIAL=y
CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y
CONFIG_UART_LINE_CTRL=y

#bluetooth configuration
CONFIG_BT=y
CONFIG_BT_SMP=y
CONFIG_BT_SMP_APP_PAIRING_ACCEPT=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_DEVICE_NAME="VC Manoj"

CONFIG_BT_DIS=y
CONFIG_BT_DIS_PNP=y
CONFIG_BT_DIS_MANUF="DotcomIoTLLP"
CONFIG_BT_DIS_PNP_VID_SRC=2
CONFIG_BT_DIS_PNP_VID=0x1915
CONFIG_BT_DIS_PNP_PID=0xEEEB
CONFIG_BT_DIS_PNP_VER=0x0100

#bt Update Data Length and MTU
CONFIG_BT_GATT_CLIENT=y
CONFIG_BT_USER_DATA_LEN_UPDATE=y
CONFIG_BT_CTLR_DATA_LENGTH_MAX=251
CONFIG_BT_BUF_ACL_RX_SIZE=251
CONFIG_BT_BUF_ACL_TX_SIZE=251
CONFIG_BT_L2CAP_TX_MTU=247

Parents
  • Hi, 

    You can start advertising in the disconnect function as in this example

    Regards,
    Amanda H.

  • Thank you for your help!

    I got my solution. I realized I wasn't dereferencing my BLE connection upon disconnection, which caused the issue. Initially, I referenced the BLE connection correctly in the connection callback like this:

    static void on_connected(struct bt_conn *conn, uint8_t err)
    {
    if (err)
    {
    VC_ERR("Connection failed (err %u)", err);
    return;
    }
    VC_DBG("Connected");
    my_conn = bt_conn_ref(conn);
    update_data_length(my_conn);
    update_mtu(my_conn);
    }

    However, I wasn’t dereferencing it in the disconnection callback. Adding the following solved the problem:

    static void on_disconnected(struct bt_conn *conn, uint8_t reason)
    {
    VC_DBG("Disconnected (reason %u)", reason);
    bt_conn_unref(my_conn);
    }

    Thanks again for pointing me in the right direction! i will also try to your solution.


Reply
  • Thank you for your help!

    I got my solution. I realized I wasn't dereferencing my BLE connection upon disconnection, which caused the issue. Initially, I referenced the BLE connection correctly in the connection callback like this:

    static void on_connected(struct bt_conn *conn, uint8_t err)
    {
    if (err)
    {
    VC_ERR("Connection failed (err %u)", err);
    return;
    }
    VC_DBG("Connected");
    my_conn = bt_conn_ref(conn);
    update_data_length(my_conn);
    update_mtu(my_conn);
    }

    However, I wasn’t dereferencing it in the disconnection callback. Adding the following solved the problem:

    static void on_disconnected(struct bt_conn *conn, uint8_t reason)
    {
    VC_DBG("Disconnected (reason %u)", reason);
    bt_conn_unref(my_conn);
    }

    Thanks again for pointing me in the right direction! i will also try to your solution.


Children
Related