BLE characteristic ( Longer than 20 Bytes. ) notification not working. NCS.

Hi There, 

I am currently developing the firmware for a peripheral device using the NRF52840 and NCS V2.0.0. 

At the moment everything is working as expected except for notifying characteristics longer than 20 Bytes. I am aware that the extension of the ATT MTU is possible as I have in the past got this working with the classic SDK however I am still new to NCS.

The following errors occur when I try to send these notifications: Larger than 20 Bytes.

[00:01:06.056,304] <wrn> bt_att: No ATT channel for MTU 26
[00:01:06.057,006] <wrn> bt_gatt: No buffer available to send notification

And the bt_gatt_notify() function returns the value -128. 

The project configuration prj.conf looks like this: 

CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096


CONFIG_BT=y
CONFIG_BT_DEBUG_LOG=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_DEVICE_NAME="NGP-BL"


#BLE Allow connection parameters update.
CONFIG_BT_USER_DATA_LEN_UPDATE=y
CONFIG_BT_GAP_AUTO_UPDATE_CONN_PARAMS=y
CONFIG_BT_PERIPHERAL_PREF_MAX_INT=100
CONFIG_BT_PERIPHERAL_PREF_MIN_INT=100

#BLE Buffering configuration.
CONFIG_BT_ATT_PREPARE_COUNT=20
CONFIG_BT_BUF_ACL_TX_COUNT=20
CONFIG_BT_BUF_ACL_RX_COUNT=20
CONFIG_BT_BUF_ACL_RX_SIZE=251
CONFIG_BT_BUF_ACL_TX_SIZE=251
CONFIG_BT_L2CAP_TX_MTU=247
CONFIG_BT_CTLR_DATA_LENGTH_MAX=251

CONFIG_BT_RX_STACK_SIZE=4096

# Bluetooth PHY selection.
CONFIG_BT_CTLR_PRIVACY=n
CONFIG_BT_USER_PHY_UPDATE=y
CONFIG_BT_CTLR_PHY_2M=y


# BLE Configuration.
CONFIG_BT_DEVICE_NAME_DYNAMIC=y

# Enable power management module
CONFIG_PM=y
# Required to disable default behavior of deep sleep on timeout
CONFIG_PM_DEVICE=y

CONFIG_REBOOT=y

# Peripheral Configuration
CONFIG_GPIO=y
CONFIG_GPIO_AS_PINRESET=y
CONFIG_I2C=y
CONFIG_I2C_NRFX=y
CONFIG_ADC=y
CONFIG_PWM=n
# Native peripheral configuration
CONFIG_NRFX_PWM0=y
CONFIG_NRFX_PPI=y
CONFIG_NRFX_GPIOTE=y
CONFIG_NRFX_TIMER2=y
CONFIG_NRFX_TIMER1=y
CONFIG_NRFX_SAADC=y

# Multiprotocol service layer. 
CONFIG_MPSL=y
CONFIG_RING_BUFFER=y
CONFIG_MPSL_TIMESLOT_SESSION_COUNT=1

# Enable the UART driver
CONFIG_UART_ASYNC_API=y
CONFIG_NRFX_UARTE0=y
CONFIG_SERIAL=y

# Enable console 
CONFIG_CONSOLE=y
# Enable RTT logging.
CONFIG_USE_SEGGER_RTT=y
CONFIG_RTT_CONSOLE=y

# Allow use of sprintf and print
CONFIG_NEWLIB_LIBC=y
CONFIG_NEWLIB_LIBC_FLOAT_PRINTF=y

# Logging subsystem configuration
CONFIG_LOG=y
CONFIG_LOG_MODE_IMMEDIATE=y
# Use this mode for time sensitive logging
# CONFIG_LOG_MODE_DEFERRED=y
# CONFIG_LOG_BUFFER_SIZE=2048 
CONFIG_LOG_BACKEND_SHOW_COLOR=y
CONFIG_LOG_INFO_COLOR_GREEN=y

# Allow system to use internal low frequency RC for Softdevice.
CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y

CONFIG_HEAP_MEM_POOL_SIZE=16384
 

The central device I am using is the nrf52840 USB Dongle, and the Bluetooth Low Energy Standalone V4.0.0, I doubt the configuration on the central device is the issue as I have a couple of different devices which work fine with it notifying characteristics up to 247 bytes long. But based of the classic SDK. 

To my my understanding the following lines define the MTU size however it does not work. 

#BLE Buffering configuration.
CONFIG_BT_ATT_PREPARE_COUNT=20
CONFIG_BT_BUF_ACL_TX_COUNT=20
CONFIG_BT_BUF_ACL_RX_COUNT=20
CONFIG_BT_BUF_ACL_RX_SIZE=251
CONFIG_BT_BUF_ACL_TX_SIZE=251
CONFIG_BT_L2CAP_TX_MTU=247
CONFIG_BT_CTLR_DATA_LENGTH_MAX=251

Any idea as to why this may happen ? 

Secondly, How could I set the value of a particular characteristic ? in the previous SDK versions I would have used the following function: 

sd_ble_gatts_value_set();

Is there a equivalent to this in NCS ? 

Cheers, 

Parents Reply
  • Hi, 

    Thanks for your comment, I got to the same conclusion the MTU in this case is not being updated by the peripheral device. 

    The question is actually around configuring larger MTUs in NCS. 

    Which does not seem to work with this configuration:

    #BLE Buffering configuration.
    CONFIG_BT_ATT_PREPARE_COUNT=20
    CONFIG_BT_BUF_ACL_TX_COUNT=20
    CONFIG_BT_BUF_ACL_RX_COUNT=20
    CONFIG_BT_BUF_ACL_RX_SIZE=251
    CONFIG_BT_BUF_ACL_TX_SIZE=251
    CONFIG_BT_L2CAP_TX_MTU=247
    CONFIG_BT_CTLR_DATA_LENGTH_MAX=251

    Ae you able to provide any insights regarding this ? 

    Ta 

Children
  • The kconfig options are ok. the initial MTU could be small, and won't be updated until MTU exchange is done. suggest to try to call the MTU exchange request from peripheral/central after connection is made. could try on the peripheral side if the central doesn't start this process.

    https://github.com/nrfconnect/sdk-nrf/blob/0ea5deb771513a9ef9ced24844e180e9fe8f9a64/samples/bluetooth/throughput/src/main.c#L148

    this config option required if not added to the project.

    CONFIG_BT_GATT_CLIENT=y

    could verify the current used MTU by calling: bt_gatt_get_mtu();

    Also another side of the connection could refuse the MTU update, please monitor the update callbacks and check if MTU updated successfully. 

  • Thanks for your help, that did the trick, I would also add that apart from having the configuration as above, it is a requirement to call the gatt exchange function on connection, for the config parameters to be applied. 

    static void exchange_func(struct bt_conn *conn, uint8_t att_err,
    			  struct bt_gatt_exchange_params *params){
    
    	struct bt_conn_info info = {0};
    	int err;
    
    	LOG_INF("MTU exchange %s", att_err == 0 ? "successful" : "failed");
    	LOG_INF("MTU size is: %d", bt_gatt_get_mtu(conn));
    
    	err = bt_conn_get_info(conn, &info);
    	if (err) {
    		LOG_ERR("Failed to get connection info %d\n", err);
    		return;
    	}
    
    }
    static void onConnect(struct bt_conn *conn, uint8_t err){
    
    	if (err) {
    		LOG_ERR("Connection failed (err %u)\n", err);
    		return;
    	}
    
    	exchange_params.func	= exchange_func;
    
    	int retCode = bt_gatt_exchange_mtu(conn, &exchange_params);
    
    	if(retCode){
    		LOG_ERR("BT Gatt exchange error -> %d",retCode);
    	}
    
    	LOG_INF("Connected\n");
    
    }

Related