This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Hardfault sd_ble_gatts_hvx - Custom Characteristic

I have been struggling with the custom characteristic implementation. I have followed the great tutorial on custom service that is online but there is really no doc or information on the characteristic part of the implementation.

I have tried to follow the AN36 to build my custom characteristic.

But I have getting a Hardfault when trying to send the notification with sd_ble_gatts_hvx.

sd_ble_gatts_hvx does not even return an error code, it places the device directly in hardfault.

My code for the service is below. Any idea why this is happening ?

// Code

#include "nt_service.h"
#include "app_error.h"
#include "ble_srv_common.h"
#include "string.h"
#include "nt_bsp.h"
#include "nordic_common.h"

static void on_connect(ble_nt_t * p_nt, ble_evt_t * p_ble_evt)
{
    p_nt->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
}

static void on_disconnect(ble_nt_t * p_nt, ble_evt_t * p_ble_evt)
{
    UNUSED_PARAMETER(p_ble_evt);
    p_nt->conn_handle = BLE_CONN_HANDLE_INVALID;
}

void ble_nt_on_ble_evt(ble_nt_t * p_nt, ble_evt_t * p_ble_evt)
{
    switch (p_ble_evt->header.evt_id)
    {
        case BLE_GAP_EVT_CONNECTED:
            on_connect(p_nt, p_ble_evt);
            break;
            
        case BLE_GAP_EVT_DISCONNECTED:
            on_disconnect(p_nt, p_ble_evt);
            break;
            
        default:
            // No implementation needed.
            break;
    }
}

static uint32_t acc_char_add(ble_nt_t * p_nt) {
	
		uint32_t err_code;
	
	  ble_gatts_char_md_t char_md;
	  ble_gatts_attr_md_t cccd_md;
    ble_gatts_attr_t    attr_char_value;
    ble_uuid_t          ble_uuid;
    ble_gatts_attr_md_t attr_md;
	
	  memset(&cccd_md, 0, sizeof(cccd_md));
    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);
    cccd_md.vloc = BLE_GATTS_VLOC_STACK;
	
	  memset(&char_md, 0, sizeof(char_md));
    char_md.char_props.read   = 1;
    char_md.char_props.notify = 1;
    char_md.p_char_user_desc  = NULL;
    char_md.p_char_pf         = NULL;
    char_md.p_user_desc_md    = NULL;
    char_md.p_cccd_md         = &cccd_md;
		//char_md.p_cccd_md         = NULL;
    char_md.p_sccd_md         = NULL;
    
    ble_uuid.type = p_nt->uuid_type;
    ble_uuid.uuid = BLE_UUID_NT_ACC_CHAR;
		
		memset(&attr_md, 0, sizeof(attr_md));
    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
    BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm);
		attr_md.read_perm  = attr_md.read_perm;
		attr_md.write_perm = attr_md.write_perm;
    attr_md.vloc       = BLE_GATTS_VLOC_STACK;
    attr_md.rd_auth    = 0;
    attr_md.wr_auth    = 0;
    attr_md.vlen       = 1;
		
		memset(&attr_char_value, 0, sizeof(attr_char_value));
    attr_char_value.p_uuid       = &ble_uuid;
    attr_char_value.p_attr_md    = &attr_md;
    attr_char_value.init_len     = sizeof(uint8_t);
    attr_char_value.init_offs    = 0;
		attr_char_value.max_len      = sizeof(uint8_t);
    attr_char_value.p_value      = NULL;
    
    err_code = sd_ble_gatts_characteristic_add(p_nt->service_handle, &char_md,
                                               &attr_char_value,
                                               &p_nt->acc_char_handles);
		APP_ERROR_CHECK(err_code);
		
		return err_code;
		
}


void nt_service_init(ble_nt_t *p_nt) {
	
	uint8_t err_code;
	ble_uuid_t ble_uuid;
	ble_uuid128_t base_uuid = {BLE_UUID_NT_BASE_UUID};
	
	// Add Service
	err_code = sd_ble_uuid_vs_add(&base_uuid, &p_nt->uuid_type);
	APP_ERROR_CHECK(err_code);
	ble_uuid.type = p_nt->uuid_type;
	ble_uuid.uuid = BLE_UUID_NT_SERVICE;

	
	err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
																				&ble_uuid,
																				&p_nt->service_handle);
	APP_ERROR_CHECK(err_code);
	
	// Add Characteristics
	err_code = acc_char_add(p_nt);
	APP_ERROR_CHECK(err_code);

	
	
}

uint32_t ble_nt_on_acc_change(ble_nt_t * p_nt) {
	
	uint32_t err_code = NRF_SUCCESS;
	
	if (p_nt->conn_handle != BLE_CONN_HANDLE_INVALID) {
    ble_gatts_hvx_params_t params;
		uint8_t data = 10;
	  uint16_t len1 = 1;

    memset(&params, 0, sizeof(params));
		params.handle = p_nt->acc_char_handles.value_handle;
    params.type = BLE_GATT_HVX_NOTIFICATION;
		params.offset = 0;
    params.p_len  = &len1;
    params.p_data = &data;

		err_code = sd_ble_gatts_hvx(p_nt->conn_handle, &params);
		
	}
  return err_code;
}
  • After doing some further investigation, I am calling ble_nt_on_acc_change in a TIMER2 Interrupt and it looks like the sd_ble_gatts_hvx is not liking me calling it from the interrupt.

    I have created another timer with app_timer on the RTC1 and it works fine.

    The issue is that the RTC1 is not precise and is too slow.

    Any hints on why I would not be able to call sd_ble_gatts_hvx in a Timer2 interrupt ?

  • This probably comes up about twice a week in the forums. You can't call SVC calls from an interrupt level higher than the SVC call interrupt level, which is 2. So most likely your TIMER2 is running with APP_PRIORITY_HIGH which is interrupt level 1. Run the timer at APP_PRIORITY_LOW or use another method like an app scheduler to get the SVC call sent from a lower priority interrupt level or thread mode.

  • Thanks. That was it. I set the timer priority to 3 with NVIC_SetPriority(TIMER2_IRQn, 3); and it now works.

Related