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

use Uart sample to TX/RX long data > 20 bytes ?

Hello,

Two issues want to ask, after tried the BLE_NUS example code. From other posts, still does not exist clear solution (example, pictures) ? Sure has an application note, document guide for such problems.

  1. TX character ,received data from client (MCP) want to support get more data > 20 bytes . I tried to use the "Request(queued) write" property for the TX characteristic but still only get data bytes less than 20 bytes ? FW code should be fine (from the sample of ble_app_hrs---LongWrite) , could be the Android or MCP problem ?

  2. RX character, send data to client (MCP), want to support send more data > 20 bytes. I tried to add "Read" property in addition to the notify property of RX characteristic.

It seems the sd_ble_gatts_value_set() will split data to multiple chunk automatically, but it require manual to read data by MCP or APP. I still prefer to use the notify method, but has big problem if many data need to send. Getting the error code 0x3004, and BLE reset(error) because I am transmitting data too quickly ? I tried to use the TX_COMPLETE event to control the in/out data flow but still fail. Here is my test code for the problem:

static volatile bool tx_buffer_is_free=true;                                                         void uart_event_handle(app_uart_evt_t * p_event) {
static uint8_t data_array[BLE_MAX_DATA_LEN];
static uint8_t index = 0;
uint32_t       err_code;

switch (p_event->evt_type)
{
    case APP_UART_DATA_READY:
        if (tx_buffer_is_free)
		UNUSED_VARIABLE(app_uart_get(&data_array[index]));
    else
		break;
        index++;
        // for test each byte notify
        //if ((data_array[index - 1] == '\n') || (index >= (BLE_MAX_DATA_LEN))) 
        {
           
            tx_buffer_is_free=false;
            err_code = ble_nus_string_send(&m_nus, data_array, index);
            if (err_code != NRF_ERROR_INVALID_STATE)
            {
                APP_ERROR_CHECK(err_code);
            }
            if (err_code == NRF_SUCCESS)
                  tx_buffer_is_free=true;

            index = 0;
        }
        break;

    case APP_UART_COMMUNICATION_ERROR:
        APP_ERROR_HANDLER(p_event->data.error_communication);
        break;

    case APP_UART_FIFO_ERROR:
        APP_ERROR_HANDLER(p_event->data.error_code);
        break;

    default:
        break;
}  }   

 static void on_ble_evt(ble_evt_t * p_ble_evt) {
	
uint32_t                         err_code;

switch (p_ble_evt->header.evt_id)
{
	case BLE_EVT_TX_COMPLETE:
		tx_buffer_is_free=true;
		break;
         .......
        .......
}}

When I sent more than 8 bytes of data in one time from Uart console, BLE_NUS will reset. below 8 is ok.

What's the right way to handle such problem (sent as many bytes through notification) over ble_nus ?

Appreciate any response , thanks.

Parents
  • FormerMember
    0 FormerMember

    1) For regular write operations, it is easier and faster to use write commands than queued writes. The purpose of queued writes is the following:

    This is normally not a function that you want to use, especially if high bandwidth is crucial in your application. Here's the explanation of this feature from the Core v4.2 specification:

    The purpose of queued writes is to queue up writes of values of multiple attributes in a first-in first-out queue and then execute the write on all of them in a single atomic operation.

    This function is aimed towards altering several attributes in a "big bang" update, like disabling/enabling all notifications in an application. Think synchronous motor applications, where you can get a signal to turn off all motors with the same event instead of waiting for several events and handling this start/stop in the application state machine.

    A queued write operation on-air consists of two commands:

    • prepare write

    • execute write

    The central will do a given number of "prepare write" command over-air, and finally "execute write".

    Underneath the hood, this has more overhead compared to manually segmenting your buffer into 20-byte chunks and sending them like a normal write command.

    Each "prepare write" will consist of a header with opcode/handle/value offset, which reduces your overall throughput.

    For a regular write command, the maximum amount of data is 20 bytes, and for the prepare write (queued write) it is 18 bytes ( Bluetooth core specification v.4.2, vol 3, part F, chapter 3.4.5.3 and 3.4.6.1). I would therefore recommend you to use regular write commands instead of queued writes.

    2) As defined in the Bluetooth core specification v.4.2, vol 3, part F, chapter 3.4.7.1, the maximum amount of data per notification is 20 bytes. The fastest way to transmit notifications is to loop over sd_ble_gatts_hvx(..) as long as it doesn't return any error. It may be useful to take a look at this post as well regarding BLE_EVT_TX_COMPLETE.

    The reason for the reset can be that there is an error handled by APP_ERROR_HANDLER. I would recommend you to run the chip in debug mode and put a breakpoint where the chip receives the data from the UART and see if you can find the source of the error. I would also recommend you to take a look at this thread regarding chip is resetting.

    Update 24.06.16: It should not be any difference between using BLE_GATTS_VLOC_STACK or BLE_GATTS_VLOC_USER.

    When using queued writes, all the data is transferred with a set of prepare write requests, but the data is not available to the application before the event BLE_EVT_USER_MEM_RELEASE. At the event BLE_EVT_USER_MEM_RELEASE, all the transferred data is available to the application at the same time. With that in mind, the introduction in the core specification makes a little more sense(?): The purpose of queued writes is to queue up writes of values of multiple attributes in a first-in first-out queue and then execute the write on all of them in a single atomic operation.

    After the event BLE_EVT_USER_MEM_RELEASE, the data is available in the memory block provided in sd_ble_user_mem_reply(..)

    Update 21.06.16:

    1) Could you try an unmodified version of ble_app_hrs--LongWrite and check if you receive all the data the data that you send? When I do it here, I receive all the data. Do you have an extra nRF51-DK or nRF51 Dongle? If so, could you use the sniffer to track what is being transferred over the air? And upload the sniffer trace here?

    The sniffer should be used with Wireshark, and it works best with version 1.10, not one of the newer versions. Wireshark can be downloaded here:

    When the queued write occurs it should look similar to this: image description

    2) Which function returns NRF_ERROR_NO_MEM?

    3) It should work fine to loop over sd_ble_gatts_hvx(..) and still receive UART events, as long as the context where sd_ble_gatts_hvx(..) is being called has lower priority than the UART events. This example on github shows how to transfer data fast, in data_send(). The example was made for an old version of the SDK. However, the principle will still be the same.

  • FormerMember
    0 FormerMember in reply to FormerMember

    I have updated the answer to answer your questions.

Reply Children
No Data
Related