Bluetooth Notification Failure - "No ATT Channel for MTU" and "No Buffer Available" Warnings. When i send string data on bluetooth.

I am encountering warnings while attempting to send Bluetooth notifications in my Zephyr-based project. The warnings are preventing successful notification of ECG data. Below are the specifics:

Warnings

  1. W: No ATT channel for MTU 33
  2. W: No buffer available to send notification

Description

I have implemented a GATT service to send notifications for ECG data. While the string data of size 22 and i take array of size 30 can be read using the read callback, notifications are failing with the two warnings listed above.

  • Warning 1: No ATT channel for MTU 33

  • Warning 2: No buffer available to send notification

Project Details

  • Board: nRF52840
  • Zephyr Version: v2.6.1
  • Bluetooth Configuration: Using GATT services to send ECG data notifications.

Configurations in prj.conf
CONFIG_NCS_SAMPLES_DEFAULTS=y

CONFIG_DISABLE_FLASH_PATCH=y
#config basic
CONFIG_PRINTK=y
CONFIG_PWM=y
CONFIG_SHELL=y
CONFIG_LOG=y

#log configuration
CONFIG_MOOV_LOG_DEBUG=y

CONFIG_I2C=y
CONFIG_CBPRINTF_FP_SUPPORT=y

#configuration for LIS2DW12
CONFIG_LIS2DW12=y
CONFIG_LIS2DW12_TRIGGER_GLOBAL_THREAD=y
CONFIG_LIS2DW12_THRESHOLD=y

#configuration for cpu temp
CONFIG_SENSOR=y
CONFIG_ADC=y
CONFIG_SPI=y

#configuration for fuel gauge npm1300
CONFIG_REGULATOR=y
CONFIG_NRF_FUEL_GAUGE=y

#configuration for hw id
CONFIG_HW_ID_LIBRARY=y
CONFIG_HW_ID_LIBRARY_SOURCE_DEVICE_ID=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_BAS=y

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

# Enable bonding
# CONFIG_BT_SETTINGS=y
CONFIG_FLASH=y
CONFIG_FLASH_PAGE_LAYOUT=y
CONFIG_FLASH_MAP=y
CONFIG_NVS=y
CONFIG_MPU_ALLOW_FLASH_WRITE=y
CONFIG_BT_MAX_PAIRED=2

#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
CONFIG_MCUMGR_MGMT_NOTIFICATION_HOOKS=y
CONFIG_MCUMGR_GRP_IMG_STATUS_HOOKS=y

CONFIG_MAIN_STACK_SIZE=3072

#for power management
# Required to disable default behavior of deep sleep on timeout
CONFIG_PM_DEVICE=y
# Optional select RAM retention (nRF52 only)
CONFIG_APP_RETENTION=n
CONFIG_CRC=y
CONFIG_POWEROFF=y

#configurations for date and time
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

Expected Behavior

The client should receive ECG data notifications over Bluetooth successfully.

Actual Behavior

Bluetooth notifications fail with the warnings mentioned above, and no data is transmitted to the client.

Steps Taken

  1. Configured MTU size in prj.conf file as shown above.

Steps to Reproduce

  1. Set up a GATT service that supports notifications on the nRF52840 board.
  2. Attempt to notify clients with ECG data over Bluetooth.

Additional Information

  • I am using Zephyr NCS v2.6.1.
  • The board in use is nRF52840.

Any help or insights into resolving these warnings would be greatly appreciated.

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

/** @file moov_alarm.c
 *  @brief MOOV Alarm Service.
 * 
 *  This file provides APIs related to MOOV Alarm Service.
 */

#include <zephyr/types.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/kernel.h>
#include <zephyr/logging/log.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 "main.h"
#include "vc_ble_bio_data_service.h"


MOOV_MODULE_REGISTER(vc_bds_svc_log,MOOV_LOG_LEVEL);

static bool live_notif_enabled;							/** Flag indicating whether notifications are enabled. */
static bool past_notif_enabled;							/** Flag indicating whether notifications are enabled. */
uint8_t ecg_data_live[30];
uint8_t ecg_data_past[30];
char* get_ecg_data_live;
char* get_ecg_data_past; 
static struct vc_bds_svc_cb bds_svc_cb; 

bool is_ecg_live_enabled(){
	return live_notif_enabled ? true : false;
}


bool is_ecg_past_enabled(){
	return past_notif_enabled ? true : false;
}

/**
 * @brief Callback function for handling configuration change of Client Characteristic Configuration (CCC).
 *
 * This function is called when the CCC configuration changes for USB device service.
 *
 * @param attr Pointer to the attribute structure.
 * @param value New value of the CCC configuration.
 */
static void vc_ecg_data_live_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
{
	live_notif_enabled = (value == BT_GATT_CCC_NOTIFY);

	MOOV_INF("ECG DATA Live Notifications %s", live_notif_enabled ? "enabled" : "disabled");
}

/**
 * @brief Callback function for handling configuration change of Client Characteristic Configuration (CCC).
 *
 * This function is called when the CCC configuration changes for USB device service.
 *
 * @param attr Pointer to the attribute structure.
 * @param value New value of the CCC configuration.
 */
static void vc_ecg_data_past_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
{
	past_notif_enabled = (value == BT_GATT_CCC_NOTIFY);

	MOOV_INF("ECG DATA PAST Notifications %s", past_notif_enabled ? "enabled" : "disabled");
}

/**
 * @brief Read USB device status.
 *
 * This function reads the USB device status characteristic.
 *
 * @param conn Connection object.
 * @param attr Pointer to the attribute structure.
 * @param buf Pointer to the buffer to store the value.
 * @param len Length of the buffer.
 * @param offset Offset.
 *
 * @return ssize_t Length of the data read.
 */
static ssize_t read_ecg_data_live(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
			   uint16_t len, uint16_t offset)
{

	if (bds_svc_cb.ecg_data_live_cb) {
		// Call the application callback function to update the get the current value of the button
		get_ecg_data_live = bds_svc_cb.ecg_data_live_cb();
		snprintf(ecg_data_live, sizeof(ecg_data_live), "%s", get_ecg_data_live);
		return bt_gatt_attr_read(conn, attr, buf, len, offset, ecg_data_live, sizeof(ecg_data_live));
	}

	return 0;
}

/**
 * @brief Read USB device status.
 *
 * This function reads the USB device status characteristic.
 *
 * @param conn Connection object.
 * @param attr Pointer to the attribute structure.
 * @param buf Pointer to the buffer to store the value.
 * @param len Length of the buffer.
 * @param offset Offset.
 *
 * @return ssize_t Length of the data read.
 */
static ssize_t read_ecg_data_past(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
			   uint16_t len, uint16_t offset)
{

	if (bds_svc_cb.ecg_data_live_cb) {
		// Call the application callback function to update the get the current value of the button
		get_ecg_data_past = bds_svc_cb.ecg_data_live_cb();
		snprintf(ecg_data_past, sizeof(ecg_data_past), "%s", get_ecg_data_past);
		return bt_gatt_attr_read(conn, attr, buf, len, offset, ecg_data_past, sizeof(ecg_data_past));
	}

	return 0;
}


BT_GATT_SERVICE_DEFINE(bds_svc,
	BT_GATT_PRIMARY_SERVICE(BT_UUID_BDS_SVC),

	BT_GATT_CHARACTERISTIC(BT_UUID_ECG_DATA_LIVE,
			       BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
			       BT_GATT_PERM_READ, read_ecg_data_live, NULL,
			       &ecg_data_live),
	BT_GATT_CCC(vc_ecg_data_live_ccc_cfg_changed,
		    BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
	
	BT_GATT_CHARACTERISTIC(BT_UUID_ECG_DATA_PAST,
			       BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
			       BT_GATT_PERM_READ, read_ecg_data_past, NULL,
			       &ecg_data_past),
	BT_GATT_CCC(vc_ecg_data_past_ccc_cfg_changed,
		    BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
);

int vc_bds_svc_init(struct vc_bds_svc_cb *callbacks)
{
	if (callbacks) {
		bds_svc_cb.ecg_data_live_cb = callbacks->ecg_data_live_cb;
		bds_svc_cb.ecg_data_past_cb = callbacks->ecg_data_past_cb;
	}

	return 0;
}

// int vc_ecg_send_live_data(char* ecg_data_live_buff)
// {
// 	if (!live_notif_enabled) {
// 		return -EACCES;
// 	}
// 	int rc;

// 	snprintf(ecg_data_live, sizeof(ecg_data_live), "%s", ecg_data_live_buff);
// 	MOOV_INF("%s", ecg_data_live);

// 	rc = bt_gatt_notify(NULL, &bds_svc.attrs[1], &ecg_data_live, sizeof(ecg_data_live));

// 	return rc == -ENOTCONN ? 0 : rc;
// }

static void on_sent(struct bt_conn *conn, void *user_data)
{
	
	MOOV_INF("%s", ecg_data_live);
}

int vc_ecg_send_live_data(char* ecg_data_live_buff)
{
	if (!live_notif_enabled) {
		return -EACCES;
	}
	int rc;

	snprintf(ecg_data_live, sizeof(ecg_data_live), "%s", ecg_data_live_buff);
	MOOV_INF("%s", ecg_data_live);

	struct bt_gatt_notify_params params = {0};
	const struct bt_gatt_attr *attr = &bds_svc.attrs[1];

	params.attr = attr;
	params.data = ecg_data_live;
	params.len = sizeof(ecg_data_live);
	params.func = on_sent;
	
	rc  = bt_gatt_notify_cb(NULL, &params);

	return rc == -ENOTCONN ? 0 : rc;
}

int vc_ecg_send_past_data(char* ecg_data_past_buff)
{
	if (!past_notif_enabled) {
		return -EACCES;
	}
	int rc;

	snprintf(ecg_data_past, sizeof(ecg_data_past), "%s", ecg_data_past_buff);
	MOOV_INF("%s", ecg_data_past);

	rc = bt_gatt_notify(NULL, &bds_svc.attrs[4], &ecg_data_past, sizeof(ecg_data_past));

	return rc == -ENOTCONN ? 0 : rc;
}

Parents
  • The error "No ATT channel for MTU" and "No buffer available to send notification" usually occurs when the Maximum Transmission Unit (MTU) size is not properly configured or the available buffer is insufficient for the data transmission.
    To resolve this issue, you can increase the MTU size and the buffer size in your configuration file (prj.conf). Here are the configuration options you can add or modify:
    CONFIG_BT_BUF_ACL_RX_SIZE=251
    CONFIG_BT_BUF_ACL_TX_SIZE=251
    CONFIG_BT_L2CAP_TX_MTU=247
    This will increase the MTU size to 247 bytes and the buffer size to 251 bytes, which should be sufficient for most data transmissions.
    If you still encounter the error after increasing the MTU and buffer size, you can check the Bluetooth Low Energy Fundamentals course on Nordic Developer Academy, particularly Lesson 3 Exercise 2, which provides detailed steps on how to properly increase the MTU size.
    In addition, you can also monitor the outcome of the ATT MTU negotiation by registering a callback for att mtu updated using the bt_gatt_cb_register() function.
Reply
  • The error "No ATT channel for MTU" and "No buffer available to send notification" usually occurs when the Maximum Transmission Unit (MTU) size is not properly configured or the available buffer is insufficient for the data transmission.
    To resolve this issue, you can increase the MTU size and the buffer size in your configuration file (prj.conf). Here are the configuration options you can add or modify:
    CONFIG_BT_BUF_ACL_RX_SIZE=251
    CONFIG_BT_BUF_ACL_TX_SIZE=251
    CONFIG_BT_L2CAP_TX_MTU=247
    This will increase the MTU size to 247 bytes and the buffer size to 251 bytes, which should be sufficient for most data transmissions.
    If you still encounter the error after increasing the MTU and buffer size, you can check the Bluetooth Low Energy Fundamentals course on Nordic Developer Academy, particularly Lesson 3 Exercise 2, which provides detailed steps on how to properly increase the MTU size.
    In addition, you can also monitor the outcome of the ATT MTU negotiation by registering a callback for att mtu updated using the bt_gatt_cb_register() function.
Children
  • Thanks for help it's working. i just configure in prj.config 

    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

    and implement a code of increase mtu size which is provided at Bluetooth Low Energy Fundamentals course on Nordic Developer Academy, particularly Lesson 3 Exercise 2.
Related