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 :
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