notify value callback for simple client produces MPU fault

I'm creating a simple service and client application with two nRF52840 DKs that resembles the central_hr_codes nrf sample, but instead it's a custom service and characteristic that the client subscribes to. 

I'm having trouble on the client side, specifically in the notify value callback as defined in the bt_gatt_subscribe_params struct. 

I've successfully connected, discovered, and subscribed to my custom characteristic. But when the notify_process callback is called, I get a BUS fault when the program tries to call the actual notify callback in main. Similar to line 23 in the on_hrs_measurement_notify function below. 

static uint8_t on_hrs_measurement_notify(struct bt_conn *conn,
					 struct bt_gatt_subscribe_params *params,
					 const void *data, uint16_t length)
{
	int err;
	struct bt_hrs_client *hrs_c;
	struct bt_hrs_client_measurement hr_measurement;

	hrs_c = CONTAINER_OF(params, struct bt_hrs_client, measurement_char.notify_params);

	if (!data) {
		atomic_clear_bit(&hrs_c->state, HRS_MEASUREMENT_NOTIFY_ENABLED);
		LOG_DBG("[UNSUBSCRIBE] from Heart Rate Measurement characterictic");

		return BT_GATT_ITER_STOP;
	}

	LOG_HEXDUMP_DBG(data, length, "[NOTIFICATION] Heart Rate Measurement: ");

	err = hrs_measurement_data_parse(&hr_measurement, data, length);

	if (hrs_c->measurement_char.notify_cb) {
		hrs_c->measurement_char.notify_cb(hrs_c, &hr_measurement, err);
	}

	return BT_GATT_ITER_CONTINUE;
}

Obviously I'm implementing this incorrectly. Here's my client objects defined (paging client).

typedef void (*bt_pag_notify_cb)(struct bt_pag_client *pag,
				 uint8_t page_alert);

struct bt_page_alert_charcteristic {

	struct bt_gatt_subscribe_params notify_params;
	
	/** Notify callback. */
	bt_pag_notify_cb notify_cb;

	/** Properties of the service. */
	uint8_t properties;

	uint16_t ccc_handle;
	
    /** handle of the page alert value*/
	uint16_t val_handle;
    
};

/** @brief Paging Client instance. */
//TODO add property that IDs which device sent the page alert
struct bt_pag_client {

	/** Connection handle. */
	struct bt_conn *conn;
	
	struct bt_page_alert_charcteristic page_chrc;
	
	
	/** Notification supported. */
	bool notify;
};

This is my implementation of the notify value callback.

static uint8_t notify_process(struct bt_conn *conn, struct bt_gatt_subscribe_params *params, const void *data, uint16_t length)
{
	//test byte to forward to main when notified
	uint8_t byte = 0x01;
	struct bt_pag_client *pag_c;
	

	pag_c = CONTAINER_OF(params, struct bt_pag_client, page_chrc.notify_cb);
	
	//Parse the data

	if (pag_c->page_chrc.notify_cb) {
		pag_c->page_chrc.notify_cb(pag_c, byte);
	}

	return BT_GATT_ITER_CONTINUE;
}

Where line 13 above is causing this error

E: ***** BUS FAULT *****
E:   Instruction bus error
E: r0/a1:  0xffffffe5  r1/a2:  0x00000001  r2/a3:  0x00000000
E: r3/a4:  0x9920003c r12/ip:  0x2000261c r14/lr:  0x0004bab3
E:  xpsr:  0x20000000
E: Faulting instruction address (r15/pc): 0x9920003c
E: >>> ZEPHYR FATAL ERROR 0: CPU exception on CPU 0
E: Current thread: 0x20001ce0 (BT RX)

After a lot of trouble shooting I'm still at a loss. I've tried increasing the BT_RX stack size to 8192 and eliminating the arguments passed to the notify callback. When no arguments are passed, I get an MPU fault in the same thread. 

Any help would be appreciated!

Thanks

Sam

  • Hello,

    Seeing that your R15(Program counter) says 0x9920003c, it would suggest that it is trying to run some sort of function located at this address. Since the nRF52840 has 1MB flash, it only goes from 0x00000000 to 0x00100000, so it looks like you have a bad pointer somewhere.

    It is a bit difficult to tell only from your snippets, but perhaps you can try to comment out this line:

    hrs_c->measurement_char.notify_cb(hrs_c, &hr_measurement, err);

    (only for debugging purposes, of course). Do you still get the hard fault? If not, try to either debug or print the address of this callback to the log. Is it the same value that is printed on R15 in your log?

    Also, stepping through these callbacks may be a good idea. You may need to reset from time to time, to do some digging on what function that is called that causes the issue.

    If you are stuck, is this something that you can reproduce on a DK? If so, can you please upload the project so that I can have a look?

    Best regards,

    Edvin

  • Hi Edvin, 

    I have already done what you suggested. It is definitively this line of code that is causing the error:

    pag_c->page_chrc.notify_cb(pag_c, byte);

    I know this because I've commented it out, the error does not happen, but my notification callback does not trigger as it does with the hrs_client. I only posted the hrs_client code snippet to demonstrate that I'm following the hrs_client implementation to achieve a notification callback when a characteristic the client has subscribed to has changed. I'm asking what the correct implementation is. 

    I'm already testing this on two nRF52840 DKs. 

  • Hello,

    Ok, that means that it is either this callback itself, or something inside that callback that is causing your issues. 

    SRall said:
    I'm asking what the correct implementation is.

    Well, I can't tell what's wrong without seeing your project. The correct implementation is the hrs_client sample. Or the other client examples, such as the central_uart sample. 

    So, try to comment out the content inside notify_cb(), and just add a line of logging or something to see that it is called correctly, or if that is your bad pointer. (The address of the callback is set incorrectly). 

    Or, upload your central and peripheral samples, and I can have a look.

    BR,
    Edvin

  • I think the problem is the latter of which you have described, that the address of the callback is set incorrectly. I'm unsure of what my mistake is though. Here is my central and peripheral projects - there is some additional code but it's still fairly minimal. 

    2867.Central.zip

    Peripheral.zip

  • Can you please share how you set up your build configurations on both the central and peripheral? I am struggling to build the samples. 

    Until then, does the log (printk) print any errors before it faults? e.g. "Subscribe failed (err %d)\n"?

    You need to debug (I can't do it until I can build), and see if you can figure out where the callback pointer is changed. Is it correct when it is originally being set?

    BR,

    Edvin

Related