This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

GATT read requests fail for many characteristics with nRF Connect SDK

Hello everyone,

I hope that you are all doing well during those hard times...

I am writing a code for a nRF52840. The connection is successfully established with a cycling powermeter. Three services are sucessfully discovered, according to the Cycling Power Profile from Bluetooth SIG. Then the characteristics of these profiles are also discovered. Finally, after releasing all the discovery data, I am trying to read the values of the characteristics or subscribe to notifications on some characteristics. 

Subscribing and reading both work fine as long as I am only doing 1 or 2 requests. But as soon as I am trying to read more than two characteristics (or subscribing to one and reading more than 1 characteristic), it crashes and causes a reset of the board : 

Reset logfile

My configuration is the following one : 

- zephyr pointed on tag zephyr-v2.2.0

- nRF Connect SDK pointed on v1.2.0 

I declared the bt_gatt_read_params and bt_gatt_subscribe_params struct statically as global variables : 

// READ, SUBSCRIBE, GATT parameters 
static struct bt_gatt_subscribe_params cp_measurement_subscribe_params = {
	.value = BT_GATT_CCC_NOTIFY
};
static struct bt_gatt_read_params cp_features_read_params = {
	.handle_count = 1,
	.single.offset = 0
};
static struct bt_gatt_read_params cp_sensor_location_read_params = {
	.handle_count = 1,
	.single.offset = 0
};

They are global and filled with parameters from the discovery of services : 

// Cycling power service discovered
void cp_service_found_cb(struct bt_gatt_dm *disc, void *context)
{
	printk("\n[SERVICE] : Cycling Power service 0x1818 discovered succesfully.\n");
	bt_gatt_dm_data_print(disc);

	// Get characteristic for CP Measurement
	const struct bt_gatt_attr* cp_measurement_characteristic = bt_gatt_dm_char_by_uuid(disc, BT_UUID_CP_MEASUREMENT_CHAR);
	if (!cp_measurement_characteristic) {
		printk("Missing CP characteristic for CP Measurement\n");
	}
	const struct bt_gatt_attr* cp_measurement_descriptor = bt_gatt_dm_desc_by_uuid(disc, cp_measurement_characteristic, BT_UUID_CP_MEASUREMENT_CHAR);
	if (!cp_measurement_descriptor) {
		printk("Missing CP descriptor for CP Measurement\n");
	}
	const struct bt_gatt_attr* cp_measurement_gatt_ccc_descriptor = bt_gatt_dm_desc_by_uuid(disc, cp_measurement_characteristic, BT_UUID_GATT_CCC);
	if (!cp_measurement_gatt_ccc_descriptor) {
		printk("Missing GATT CCC descriptor for CP Measurement\n");
	}

	// Fill subscribe params to CP Measurement
	cp_measurement_subscribe_params.notify = &cp_measurement_notify_cb;
	cp_measurement_subscribe_params.value_handle = cp_measurement_descriptor->handle;
	cp_measurement_subscribe_params.ccc_handle = cp_measurement_gatt_ccc_descriptor->handle;

	// Get characteristic for CP Features
	const struct bt_gatt_attr* cp_features_characteristic = bt_gatt_dm_char_by_uuid(disc, BT_UUID_CP_FEATURES_CHAR);
	if (!cp_features_characteristic) {
		printk("Missing CP characteristic for CP Features\n");
	}
	const struct bt_gatt_attr* cp_features_descriptor = bt_gatt_dm_desc_by_uuid(disc, cp_features_characteristic, BT_UUID_CP_FEATURES_CHAR);
	if (!cp_features_descriptor) {
		printk("Missing CP descriptor for CP Features\n");
	}

	// Fill read params CP Features
	cp_features_read_params.func = &cp_features_read_cb;
	cp_features_read_params.single.handle = cp_features_descriptor->handle;

	// Get characteristic for CP Sensor Location
	const struct bt_gatt_attr* cp_sensor_location_characteristic = bt_gatt_dm_char_by_uuid(disc, BT_UUID_CP_SENSOR_LOC_CHAR);
	if (!cp_sensor_location_characteristic) {
		printk("Missing CP characteristic for CP Sensor Location\n");
	}
	const struct bt_gatt_attr* cp_sensor_location_descriptor = bt_gatt_dm_desc_by_uuid(disc, cp_sensor_location_characteristic, BT_UUID_CP_SENSOR_LOC_CHAR);
	if (!cp_sensor_location_descriptor) {
		printk("Missing CP descriptor for CP Sensor Location\n");
	}

	// Fill params read CP Sensor Location
	cp_sensor_location_read_params.func = &cp_sensor_location_read_cb;
	cp_sensor_location_read_params.single.handle = cp_sensor_location_descriptor->handle;

	// Release dicovery data to be able to launch another discovery
	int err = bt_gatt_dm_data_release(disc);
	if (err) {
		printk("Could not release discovery data, err: %d\n", err);
	}
			
	// Now find the Device Information service
	gatt_discover_services(BT_UUID_DEVICE_INFORMATION_SERVICE, &device_info_service_discovery_cb);
}

And finally they are used like that after all the services and characteristics have been discovered : 

// Subscribe to characteristic notifications
int gatt_subscribe_to_notifications(struct bt_gatt_subscribe_params* params)
{
	// Subscribe to characteristic
	int err = bt_gatt_subscribe(conn_cpp_collector, params);
	if (err) {
		printk("Subscribe failed (err %d)\n", err);
	}
	return err;
}

// Read descriptor of a characteristic
int gatt_read_characteristic(struct bt_gatt_read_params* read_params)
{
	// Read it !
	int err = bt_gatt_read(conn_cpp_collector, read_params);
	if(err) {
		printk("Failed to read characteristic, err: %d\n", err);
	}
	return err;
}

// Called after all the characteristics and services have been discovered and found
void get_data()
{
	// Battery service
	gatt_read_characteristic(&battery_level_read_params);

	// Device Information service
	gatt_read_characteristic(&di_man_name_read_params);
	gatt_read_characteristic(&di_model_number_read_params);
	gatt_read_characteristic(&di_hw_rev_read_params);
	gatt_read_characteristic(&di_sw_rev_read_params);

	// CP service
	gatt_subscribe_to_notifications(&cp_measurement_subscribe_params);
	gatt_read_characteristic(&cp_features_read_params);
	gatt_read_characteristic(&cp_sensor_location_read_params);
}

My prj.conf file looks like that : 

#########################################################################################
# Basics
#########################################################################################

# default configuration for the device
CONFIG_NCS_SAMPLES_DEFAULTS=y

# LEDs and buttons
CONFIG_DK_LIBRARY=y

# Enable c new library
CONFIG_NEWLIB_LIBC=y

#########################################################################################
# Memory
#########################################################################################

# nRF52840 HW properties : 1024 kB = 1MB as flash and 256 kB for SRAM
CONFIG_FLASH_SIZE=1024
CONFIG_SRAM_SIZE=256

# Configure memory sizes, values are in byte
CONFIG_MAIN_STACK_SIZE=131072
CONFIG_HEAP_MEM_POOL_SIZE=16384

#########################################################################################
# Bluetooth low energy
#########################################################################################

# Name of the device
CONFIG_BT_DEVICE_NAME="Nordic Cycling Power Collector"

# Connections settings
CONFIG_BT_MAX_CONN=1
CONFIG_BT_MAX_PAIRED=1

# Enable the BLE stack
CONFIG_BT=y
CONFIG_BT_CENTRAL=y
CONFIG_BT_SMP=y

# SCAN module settings 
CONFIG_BT_SCAN=y
CONFIG_BT_SCAN_FILTER_ENABLE=y
CONFIG_BT_SCAN_UUID_CNT=1

# GATT and ATT settings
CONFIG_BT_GATT_CLIENT=y
CONFIG_BT_GATT_DM=y
CONFIG_BT_GATT_POOL=y
CONFIG_BT_GATT_DM_MAX_ATTRS=32
CONFIG_BT_GATT_DM_MAX_MEM_CHUNKS=32
CONFIG_BT_GATT_READ_MULTIPLE=y
CONFIG_BT_GATT_CHRC_POOL_SIZE=16

# Store BLE settings in flash
CONFIG_SETTINGS=y
CONFIG_BT_SETTINGS=y
CONFIG_FLASH=y
CONFIG_NVS=y
CONFIG_FLASH_PAGE_LAYOUT=y
CONFIG_FLASH_MAP=y

#########################################################################################
# Optimizations
#########################################################################################

CONFIG_SIZE_OPTIMIZATIONS=y
CONFIG_SPEED_OPTIMIZATIONS=n
CONFIG_DEBUG_OPTIMIZATIONS=n
CONFIG_NO_OPTIMIZATIONS=n
CONFIG_COMPILER_OPT=""
CONFIG_FLOAT=y

#########################################################################################
# Logging
#########################################################################################

#RTT settings
CONFIG_LOG=y
CONFIG_USE_SEGGER_RTT=y
CONFIG_LOG_IMMEDIATE=n
CONFIG_SEGGER_RTT_BUFFER_SIZE_UP=8192
CONFIG_SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL=y

CONFIG_BT_DEBUG_LOG=y
CONFIG_LOG_MINIMAL=n

CONFIG_BT_LOG_LEVEL_OFF=n
CONFIG_BT_LOG_LEVEL_INF=y
CONFIG_BT_LOG_LEVEL_WRN=y
CONFIG_BT_LOG_LEVEL_ERR=y
CONFIG_BT_LOG_LEVEL_DBG=n

CONFIG_BT_GATT_POOL_LOG_LEVEL_OFF=n
CONFIG_BT_GATT_POOL_LOG_LEVEL_INF=y
CONFIG_BT_GATT_POOL_LOG_LEVEL_WRN=y
CONFIG_BT_GATT_POOL_LOG_LEVEL_ERR=y
CONFIG_BT_GATT_POOL_LOG_LEVEL_DBG=y
CONFIG_BT_GATT_POOL_STATS=n

CONFIG_BT_DEBUG_ATT=n
CONFIG_BT_DEBUG_GATT=n
CONFIG_BT_GATT_DM_DATA_PRINT=y
CONFIG_BT_GATT_DM_LOG_LEVEL_OFF=n
CONFIG_BT_GATT_DM_LOG_LEVEL_INF=y
CONFIG_BT_GATT_DM_LOG_LEVEL_WRN=y
CONFIG_BT_GATT_DM_LOG_LEVEL_ERR=y
CONFIG_BT_GATT_DM_LOG_LEVEL_DBG=y

CONFIG_BT_SCAN_LOG_LEVEL_OFF=y
CONFIG_BT_SCAN_LOG_LEVEL_INF=n
CONFIG_BT_SCAN_LOG_LEVEL_WRN=n
CONFIG_BT_SCAN_LOG_LEVEL_ERR=n
CONFIG_BT_SCAN_LOG_LEVEL_DBG=n

CONFIG_DK_LIBRARY_LOG_LEVEL_OFF=n
CONFIG_DK_LIBRARY_LOG_LEVEL_ERR=y
CONFIG_DK_LIBRARY_LOG_LEVEL_WRN=y
CONFIG_DK_LIBRARY_LOG_LEVEL_INF=y
CONFIG_DK_LIBRARY_LOG_LEVEL_DBG=n

# Debugging options
CONFIG_DEBUG=n
CONFIG_TRACING=n

# enable CPU stats
CONFIG_TRACING_CPU_STATS=n
CONFIG_TRACING_CPU_STATS_LOG=n
CONFIG_TRACING_CPU_STATS_INTERVAL=5000

If needed, I could provide more log files or code.

I hope that I was clear enough and that someone can explain me what I am doing wrong :-)

Cheers,

Sellig

Related