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

hard fault in examples/peripheral/usbd_ble_uart when MTU is exceeded

I'm using the example examples/peripheral/usbd_ble_uart on a nRF42840 USB dongle (pca10059).

As client (central) I'm using nrfconnect on an Android phone.

Connecting to the peripheral and sending data onto the UART RX channel works fine, as long as data length doesn't exceed the maximum MTU (hardcoded to 64bytes in the example).

Example output:

<info> nrf_ble_gatt: Requesting to update ATT MTU to 64 bytes on connection 0x0.
<info> app: BLE NUS connected
<info> app: Data len is set to 0x3D(61)
<info> app: CDC ACM unavailable, data received: 123456789012345678901234567890123456789012345678901234567890

If I exceed that 64bytes limit, though, the device hard faults with:

<error> app: ERROR 7 [NRF_ERROR_INVALID_PARAM] at ../../../main.c:481
PC at: 0x00031F33
<error> app: End of error report

While this is probably to be expected(?), I'm missing a hint how to do it right.

By right I mean:

best case) how to still be able to receive that data (e.g. as multiple packets each not exceeding the MTU)

worst case) discard data and/or disconnect from the central or alike, but stay operational for the next connection request

..but not hard fault.

Thanks!

Parents
  • Hello,

    I quickly tested this by passing NRF_SDH_BLE_GATT_MAX_MTU_SIZE to nrf_ble_gatt_att_mtu_periph_set() instead of the harcoded "64" value, then wrote >64 bytes to the RX characteristic, but this did not trigger the invalid param error.

    The log you posted says the error occured at line 481 in your main.c file, could you check what function you have at this line? Also, are you testing with SDK v16.0.0?

  • Thanks for the fast reply!

    I totally missed version info:

    nRF5 SDK v16.0.0
    SoftDevice: s140_nrf52_7.0.1_softdevice

    main.c is unmodified, hence like 481 is:

            case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
            {
                ble_gatts_evt_rw_authorize_request_t  req;
                ble_gatts_rw_authorize_reply_params_t auth_reply;
    
                req = p_ble_evt->evt.gatts_evt.params.authorize_request;
    
                if (req.type != BLE_GATTS_AUTHORIZE_TYPE_INVALID)
                {
                    if ((req.request.write.op == BLE_GATTS_OP_PREP_WRITE_REQ)     ||
                        (req.request.write.op == BLE_GATTS_OP_EXEC_WRITE_REQ_NOW) ||
                        (req.request.write.op == BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL))
                    {
                        if (req.type == BLE_GATTS_AUTHORIZE_TYPE_WRITE)
                        {
                            auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
                        }
                        else
                        {
                            auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_READ;
                        }
                        auth_reply.params.write.gatt_status = APP_FEATURE_NOT_SUPPORTED;
                        err_code = sd_ble_gatts_rw_authorize_reply(p_ble_evt->evt.gatts_evt.conn_handle,
                                                                   &auth_reply);
                        APP_ERROR_CHECK(err_code); // <<<<--------------------
                    }
                }
            } break; // BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST

    There was no pca1005*9* target for this example though, so I ad to create one - including a sdk_config.h

    Since you're saying this is not supposed to be normal, I guess it's either the Makefile or the sdk_config.h

    Do you have any pointer/hint which option it might be? Otherwise I'll try again deriving from the pca10056 target, modifying it step by step to have it running on pca10059 with as little difference to pca10056 as possible.

Reply
  • Thanks for the fast reply!

    I totally missed version info:

    nRF5 SDK v16.0.0
    SoftDevice: s140_nrf52_7.0.1_softdevice

    main.c is unmodified, hence like 481 is:

            case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
            {
                ble_gatts_evt_rw_authorize_request_t  req;
                ble_gatts_rw_authorize_reply_params_t auth_reply;
    
                req = p_ble_evt->evt.gatts_evt.params.authorize_request;
    
                if (req.type != BLE_GATTS_AUTHORIZE_TYPE_INVALID)
                {
                    if ((req.request.write.op == BLE_GATTS_OP_PREP_WRITE_REQ)     ||
                        (req.request.write.op == BLE_GATTS_OP_EXEC_WRITE_REQ_NOW) ||
                        (req.request.write.op == BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL))
                    {
                        if (req.type == BLE_GATTS_AUTHORIZE_TYPE_WRITE)
                        {
                            auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
                        }
                        else
                        {
                            auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_READ;
                        }
                        auth_reply.params.write.gatt_status = APP_FEATURE_NOT_SUPPORTED;
                        err_code = sd_ble_gatts_rw_authorize_reply(p_ble_evt->evt.gatts_evt.conn_handle,
                                                                   &auth_reply);
                        APP_ERROR_CHECK(err_code); // <<<<--------------------
                    }
                }
            } break; // BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST

    There was no pca1005*9* target for this example though, so I ad to create one - including a sdk_config.h

    Since you're saying this is not supposed to be normal, I guess it's either the Makefile or the sdk_config.h

    Do you have any pointer/hint which option it might be? Otherwise I'll try again deriving from the pca10056 target, modifying it step by step to have it running on pca10059 with as little difference to pca10056 as possible.

Children
  • Ah, I see the problem now. The client attempts to perform a "long write" (GATTS Queued Writes: Stack handled, one or more attributes require authorization) when the write length exceeds ATT_MTU-3 bytes, but long writes are not supported by the peripheral and it tries to reject the request by replying with the APP_FEATURE_NOT_SUPPORTED status code.

    There is a bug in the example that it is not passing the correct arguments to sd_ble_gatts_rw_authorize_reply(). I suspect it because 'auth_reply' is not initialized to zero. Please try to set it to zero and see if you get the same result.

            case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
            {
                ble_gatts_evt_rw_authorize_request_t  req;
                ble_gatts_rw_authorize_reply_params_t auth_reply = {0}; // <-- initialize to 0
    
                req = p_ble_evt->evt.gatts_evt.params.authorize_request;
    
                if (req.type != BLE_GATTS_AUTHORIZE_TYPE_INVALID)
                {
                ...

    You may also increase the max MTU size by changing the nrf_ble_gatt_att_mtu_periph_set(&m_gatt, 64); call to nrf_ble_gatt_att_mtu_periph_set(&m_gatt, NRF_SDH_BLE_GATT_MAX_MTU_SIZE);

  • Thanks for looking into this!

    I'm afraid, though, zero'ing `auth_reply` before use doesn't appear to make a difference.

  • as a side note: i started "from scratch" - meaning, taking the sdk_config.h file from the pca10056 target and only enabled logging. Still behaving the same (as in: hard fault'ing)

  • Please try with the code posted below. I changed the implementation so it replies with BLE_GATT_STATUS_SUCCESS when it gets a BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL request. Same as we do in the Queued Writes module.

            case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
            {
                ble_gatts_evt_rw_authorize_request_t  req;
                ble_gatts_rw_authorize_reply_params_t auth_reply = {0};
    
                req = p_ble_evt->evt.gatts_evt.params.authorize_request;
    
                if (req.type != BLE_GATTS_AUTHORIZE_TYPE_INVALID)
                {
                    if ((req.request.write.op == BLE_GATTS_OP_PREP_WRITE_REQ)     ||
                        (req.request.write.op == BLE_GATTS_OP_EXEC_WRITE_REQ_NOW) ||
                        (req.request.write.op == BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL))
                    {
                        if (req.type == BLE_GATTS_AUTHORIZE_TYPE_WRITE)
                        {
                            auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
                        }
                        else
                        {
                            auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_READ;
                        }
    
                        auth_reply.params.write.gatt_status = APP_FEATURE_NOT_SUPPORTED;
    
                        if (req.request.write.op == BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL)
                        {
                            auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
                        }
    
                        err_code = sd_ble_gatts_rw_authorize_reply(p_ble_evt->evt.gatts_evt.conn_handle,
                                                                   &auth_reply);
                        APP_ERROR_CHECK(err_code);
                    }
                }
            } break; // BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST

Related