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

nrf52832 work in nus CENTRAL at SDK17.0 how to Improve Bluetooth communication data rate,Through ble_nus_c_string_send?

hi guys, 

now i have 2 pieces 52832 boards; A(PERIPHERAL) and B(CENTRAL); both run the nus service.

B(CENTRAL)--->A(PERIPHERAL) Through ble_nus_c_string_send();

and A(PERIPHERAL)--->B(CENTRAL) use ble_nus_data_send();

B(CENTRAL)--->A(PERIPHERAL) the data transfor is slow,(when i use phone connect to --->A(PERIPHERAL)and send data via nus is good )

the cfg is

uint32_t ble_nus_c_string_send(ble_nus_c_t * p_ble_nus_c, uint8_t * p_string, uint16_t length)
{
VERIFY_PARAM_NOT_NULL(p_ble_nus_c);

nrf_ble_gq_req_t write_req;

memset(&write_req, 0, sizeof(nrf_ble_gq_req_t));

if (length > BLE_NUS_MAX_DATA_LEN)
{
NRF_LOG_WARNING("Content too long.");
return NRF_ERROR_INVALID_PARAM;
}
if (p_ble_nus_c->conn_handle == BLE_CONN_HANDLE_INVALID)
{
NRF_LOG_WARNING("Connection handle invalid.");
return NRF_ERROR_INVALID_STATE;
}

write_req.type = NRF_BLE_GQ_REQ_GATTC_WRITE;
write_req.error_handler.cb = gatt_error_handler;
write_req.error_handler.p_ctx = p_ble_nus_c;
write_req.params.gattc_write.handle = p_ble_nus_c->handles.nus_rx_handle;
write_req.params.gattc_write.len = length;
write_req.params.gattc_write.offset = 0;
write_req.params.gattc_write.p_value = p_string;
write_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_CMD;//BLE_GATT_OP_WRITE_CMD BLE_GATT_OP_WRITE_REQ
write_req.params.gattc_write.flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE;

return nrf_ble_gq_item_add(p_ble_nus_c->p_gatt_queue, &write_req, p_ble_nus_c->conn_handle);
}

#define NRF_SDH_BLE_GAP_DATA_LENGTH 107

#define NRF_SDH_BLE_CENTRAL_LINK_COUNT 1

#define NRF_SDH_BLE_GAP_EVENT_LENGTH 24

#define NRF_SDH_BLE_GATT_MAX_MTU_SIZE 103

i want to send 200bytes via ble_nus_c_string_send() and get the event :BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE,

case BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE:

                                        BLE_LOG("send count=%04d",p_ble_evt->evt.gattc_evt.params.write_cmd_tx_complete.count);

break;

send count =0001;It's one every time.

Is my operation correct?

how to use evt BLE_GATTC_EVT_WRITE_RSP and BLE_GATTC_EVT_WRITE_CMD_TX_COMPLETE?and BLE_GATT_OP_WRITE_CMD BLE_GATT_OP_WRITE_REQ?

to Improve Bluetooth communication data rate?

thanks

Parents
  • Hello,

    You don't need to wait for the TX_COMPLETE event before you send more data. 

    Actually, there are a couple of things I want to mention here:

    1. If you want to send a lot of data fast from the central to the peripheral, I suggest that you use the old implementation of ble_nus_c_string_send(), that doesn't use the nrf_ble_gq_item_add(), but the softdevice call for sending data directly. The reason for this is that the gq has a different way of sending the return value for this call. It will return NRF_SUCCESS, but if the queue tries to send too much, it will throw an error in a different event handler, which I don't find very useful. 

    So if you look in SDK15.3.0, the implementation of ble_nus_c_string_send is a bit different from what it is in SDK16 and SDK17:

    uint32_t ble_nus_c_string_send(ble_nus_c_t * p_ble_nus_c, uint8_t * p_string, uint16_t length)
    {
        VERIFY_PARAM_NOT_NULL(p_ble_nus_c);
    
        if (length > BLE_NUS_MAX_DATA_LEN)
        {
            NRF_LOG_WARNING("Content too long.");
            return NRF_ERROR_INVALID_PARAM;
        }
        if (p_ble_nus_c->conn_handle == BLE_CONN_HANDLE_INVALID)
        {
            NRF_LOG_WARNING("Connection handle invalid.");
            return NRF_ERROR_INVALID_STATE;
        }
    
        ble_gattc_write_params_t const write_params =
        {
            .write_op = BLE_GATT_OP_WRITE_CMD,
            .flags    = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE,
            .handle   = p_ble_nus_c->handles.nus_rx_handle,
            .offset   = 0,
            .len      = length,
            .p_value  = p_string
        };
    
        return sd_ble_gattc_write(p_ble_nus_c->conn_handle, &write_params);
    }

    As you can see, it uses sd_ble_gattc_write() directly, instead of keeping the data in a separate middle layer queue. What I usually do is to add this as a separate function called ble_nus_c_string_send_old() in the ble_nus_c.c file, and then replace ble_nus_c_sting_send() calls in main.c with ble_nus_c_string_send_old().

    2. The advantage of using this older implementation is that you can queue several packets faster. Initially, you don't need to wait for the TX_COMPLETE event, but you can keep queuing several packets using ble_nus_c_string_send_old(). As long as ble_nus_c_string_send_old() returns NRF_SUCCESS, you are guaranteed that this packet will be sent sooner or later (and in the order they were queued). When ble_nus_c_string_send_old() returns NRF_ERROR_RESOURCES, this means that the internal queue in the softdevice is full, and the last packet you tried to queue is not queued. Then you should wait for the next TX_COMPLETE event, which means that at least one packet was ACKed. At this point, you can continue to queue packets until it returns NRF_ERROR_RESOURCES again. 

     

    send count =0001;It's one every time.

     Yes. I believe this is the way it works. I believe it was intended to give one event with different write_cmd_tx_complete.count, but instead you get one event per ACKed packet. 

    Best regards,

    Edvin

Reply
  • Hello,

    You don't need to wait for the TX_COMPLETE event before you send more data. 

    Actually, there are a couple of things I want to mention here:

    1. If you want to send a lot of data fast from the central to the peripheral, I suggest that you use the old implementation of ble_nus_c_string_send(), that doesn't use the nrf_ble_gq_item_add(), but the softdevice call for sending data directly. The reason for this is that the gq has a different way of sending the return value for this call. It will return NRF_SUCCESS, but if the queue tries to send too much, it will throw an error in a different event handler, which I don't find very useful. 

    So if you look in SDK15.3.0, the implementation of ble_nus_c_string_send is a bit different from what it is in SDK16 and SDK17:

    uint32_t ble_nus_c_string_send(ble_nus_c_t * p_ble_nus_c, uint8_t * p_string, uint16_t length)
    {
        VERIFY_PARAM_NOT_NULL(p_ble_nus_c);
    
        if (length > BLE_NUS_MAX_DATA_LEN)
        {
            NRF_LOG_WARNING("Content too long.");
            return NRF_ERROR_INVALID_PARAM;
        }
        if (p_ble_nus_c->conn_handle == BLE_CONN_HANDLE_INVALID)
        {
            NRF_LOG_WARNING("Connection handle invalid.");
            return NRF_ERROR_INVALID_STATE;
        }
    
        ble_gattc_write_params_t const write_params =
        {
            .write_op = BLE_GATT_OP_WRITE_CMD,
            .flags    = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE,
            .handle   = p_ble_nus_c->handles.nus_rx_handle,
            .offset   = 0,
            .len      = length,
            .p_value  = p_string
        };
    
        return sd_ble_gattc_write(p_ble_nus_c->conn_handle, &write_params);
    }

    As you can see, it uses sd_ble_gattc_write() directly, instead of keeping the data in a separate middle layer queue. What I usually do is to add this as a separate function called ble_nus_c_string_send_old() in the ble_nus_c.c file, and then replace ble_nus_c_sting_send() calls in main.c with ble_nus_c_string_send_old().

    2. The advantage of using this older implementation is that you can queue several packets faster. Initially, you don't need to wait for the TX_COMPLETE event, but you can keep queuing several packets using ble_nus_c_string_send_old(). As long as ble_nus_c_string_send_old() returns NRF_SUCCESS, you are guaranteed that this packet will be sent sooner or later (and in the order they were queued). When ble_nus_c_string_send_old() returns NRF_ERROR_RESOURCES, this means that the internal queue in the softdevice is full, and the last packet you tried to queue is not queued. Then you should wait for the next TX_COMPLETE event, which means that at least one packet was ACKed. At this point, you can continue to queue packets until it returns NRF_ERROR_RESOURCES again. 

     

    send count =0001;It's one every time.

     Yes. I believe this is the way it works. I believe it was intended to give one event with different write_cmd_tx_complete.count, but instead you get one event per ACKed packet. 

    Best regards,

    Edvin

Children
Related