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

slow ble uart on sdk14.2.0 s132 52832 device

i have 2 setups, one on a pca10040 running sdk 14.2.0 s132 and the other one on a pca10028 clone running sdk12.3.0 s130 with a 51822_xxaa mpu

the ble_uart examples from both sdks got the following equal modifications

replaced uart code with my own (isr support) along with my own queue-ing classes

getting the tx data from my tx fifo and sticking it into the ble_nus_string_send funct is at a 5 ms period handled in main with a max payload of 20 bytes

my firmware queues (tx) up strings to a nexus 7 at a 30 ms period on the 51822 and at a 100 ms period on the 52832 ... yes, the 52832 can not handle a 30 ms data stream period

the periodic data strings start with a length of 1 incremented by one up to a max of 90 chars followed by a decrement by one, and again ... this provides a nice pyramid shape data scroll and any misses are visually easy to spot

the same kind of pyramid data is also sent by the nexus 7 to the ble device ... the max speed seems determined by the capabilities of the nexus 7 and maxes out at 100 ms

the 51822 ble_nus_string_send appears to exhibit err_code returns of NRF_ERROR_BUSY and BLE_ERROR_NO_TX_PACKETS, in which case i repeat the previous data on the next 5 ms ble_nus_string_send period and everything seems fine ... i can live with some data errors on long test lines

the slow problem child seems to be the 52832 s132 based device where the ble_nus_string_send funct returns either NRF_ERROR_BUSY or unknown error 0x13

why do i not get a BLE_ERROR_NO_TX_PACKETS and instead this to me unknown err 0x13 which appears to be some like missing resources or similar

both projects are literally almost the same, except where the s132 vs s130 dictate differences

what's wrong with the, should be faster, cortex-m4 52832 setups

one note on the side :

why is there, this to me significant, code difference in the ble_nus_string_send funct

52832 hvx_params.handle = p_nus->tx_handles.value_handle ;

51822 hvx_params.handle = p_nus->rx_handles.value_handle;

what is it now ... tx or rx ... ble_nus_string_send woudd imply tx to me

any help on the slow s132 based 52832 setup would be highly appreciated

cheers Klaus

  • Hi Klaus,

    Firstly you shouldn't base your re-sending attempts on any timer but simply wait for TX_COMPLETE event. It looks like cosmetics but if you are trying to time-sync your application and BLE stack it indicates that you are missing the core idea of asynchronous operation of BLE stack layers and there might be more problems related to this misconception (now or later).

    Secondly you are comparing heavily modified code. What about to simply go back to basics and compare throughput of unmodified nRF51 DK (PC10028) + S130 V2.0.1 + BLE NUS FW from nRF5 SDK v12.3.0 and nRF52 (PSA10040) + S132 V5.0.0 + BLE NUS FW from nRF5 SDK V14.2.0? Or even better go back and try on nRF52 version with S132 V3.0.0 and BLE NUS FW from the same SDK version as nRF51 (= v12.3.0)?

    Finally to the error codes: if you really get 0x0013 (all 16 bits are significant so make sure you don't kill upper byte by some typecast) then it's NRF_ERROR_TIMEOUT. If you see what is done inside ble_nus_string_send function which you call (whole BLE NUS "library" is provided in source code so you can read it and debug it) then you see that it calls sd_ble_gatts_hvx and returns error code from there. Then you can read all the details in respective SD API header file:

    /**@brief Notify or Indicate an attribute value.
     *
     * @details This function checks for the relevant Client Characteristic Configuration descriptor value to verify that the relevant operation
     *          (notification or indication) has been enabled by the client. It is also able to update the attribute value before issuing the PDU, so that
     *          the application can atomically perform a value update and a server initiated transaction with a single API call.
     *
     * @note    The local attribute value may be updated even if an outgoing packet is not sent to the peer due to an error during execution.
     *          The Attribute Table has been updated if one of the following error codes is returned: @ref NRF_ERROR_INVALID_STATE, @ref NRF_ERROR_BUSY,
     *          @ref NRF_ERROR_FORBIDDEN, @ref BLE_ERROR_GATTS_SYS_ATTR_MISSING and @ref NRF_ERROR_RESOURCES.
     *          The caller can check whether the value has been updated by looking at the contents of *(p_hvx_params->p_len).
     *
     * @note    Only one indication procedure can be ongoing per connection at a time.
     *          If the application tries to indicate an attribute value while another indication procedure is ongoing,
     *          the function call will return @ref NRF_ERROR_BUSY.
     *          A @ref BLE_GATTS_EVT_HVC event will be issued as soon as the confirmation arrives from the peer.
     *
     * @note    The number of Handle Value Notifications that can be queued is configured by @ref ble_gatts_conn_cfg_t::hvn_tx_queue_size
     *          When the queue is full, the function call will return @ref NRF_ERROR_RESOURCES.
     *          A @ref BLE_GATTS_EVT_HVN_TX_COMPLETE event will be issued as soon as the transmission of the notification is complete.
     *
     * @note    The application can keep track of the available queue element count for notifications by following the procedure below:
     *          - Store initial queue element count in a variable.
     *          - Decrement the variable, which stores the currently available queue element count, by one when a call to this function returns @ref NRF_SUCCESS.
     *          - Increment the variable, which stores the current available queue element count, by the count variable in @ref BLE_GATTS_EVT_HVN_TX_COMPLETE event.
     *
     * @events
     * @event{@ref BLE_GATTS_EVT_HVN_TX_COMPLETE, Notification transmission complete.}
     * @event{@ref BLE_GATTS_EVT_HVC, Confirmation received from the peer.}
     * @endevents
     *
     * @mscs
     * @mmsc{@ref BLE_GATTS_HVX_SYS_ATTRS_MISSING_MSC}
     * @mmsc{@ref BLE_GATTS_HVN_MSC}
     * @mmsc{@ref BLE_GATTS_HVI_MSC}
     * @mmsc{@ref BLE_GATTS_HVX_DISABLED_MSC}
     * @endmscs
     *
     * @param[in] conn_handle  Connection handle.
     * @param[in] p_hvx_params Pointer to an HVx parameters structure. If the p_data member contains a non-NULL pointer the attribute value will be updated with
     *                         the contents pointed by it before sending the notification or indication.
     *
     * @retval ::NRF_SUCCESS Successfully queued a notification or indication for transmission, and optionally updated the attribute value.
     * @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
     * @retval ::NRF_ERROR_INVALID_STATE One or more of the following is true:
     *                                   - Invalid Connection State
     *                                   - Notifications and/or indications not enabled in the CCCD
     *                                   - An ATT_MTU exchange is ongoing
     * @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
     * @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
     * @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle(s) supplied. Only attributes added directly by the application are available to notify and indicate.
     * @retval ::BLE_ERROR_GATTS_INVALID_ATTR_TYPE Invalid attribute type(s) supplied, only characteristic values may be notified and indicated.
     * @retval ::NRF_ERROR_NOT_FOUND Attribute not found.
     * @retval ::NRF_ERROR_FORBIDDEN The connection's current security level is lower than the one required by the write permissions of the CCCD associated with this characteristic.
     * @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied.
     * @retval ::NRF_ERROR_BUSY For @ref BLE_GATT_HVX_INDICATION Procedure already in progress. Wait for a @ref BLE_GATTS_EVT_HVC event and retry.
     * @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known value.
     * @retval ::NRF_ERROR_RESOURCES Too many notifications queued.
     *                               Wait for a @ref BLE_GATTS_EVT_HVN_TX_COMPLETE event and retry.
     */
    SVCALL(SD_BLE_GATTS_HVX, uint32_t, sd_ble_gatts_hvx(uint16_t conn_handle, ble_gatts_hvx_params_t const *p_hvx_params));
    

    Knowing that I'm not directly answering your concern I hope these hints will help you to debug your code on lower level. It seems to me that you measure throughput by some indirect events (like how often some packet arrives to some bloody black-box smart phone). Proper way would probably be to measure it on two nRF5x DK boards or measuring it with radio analyzer/BLE sniffer. Then we can clearly see if bandwidth (= number of PDUs per connection interval) and other on-air parameters of LL (e.g. connection interval) are really the same so we are not comparing apples with pears.

  • hi Endnode :

    thanks for your instantaneous reply on new years day ;)

    i'll try to answer your suggestions and would also like to note that my development environment is the latest eclipse oxygen with the arm mcu tool-chain added and in an eclipse managed project running under kubuntu 1604 lts ... i have also tested this development environment and projects on a win 10 install

    in the mean time i changed the 51 references (code) in the sdk v12.3.0 based project to 52 references (code) in a new project and have now 2 version of my uart test code either running on a 51 with s130 or 52 running on s132 sdk v12.3.0 softdevice

    the only differences are in using mpu type relevant sdk files like startup5x, linker script 5x, nrf5x.h ...

    both performances are now identical

    the sdk v14.2.0 52 project has not been touched and is still slow compared to both 51 and 52 based sdk v112.2.0 projects

    one word to my xmt data concept :

    my main loop and all other classes (code) are the same except where the mpu dictates differences and of course the sdk example code parts are taken from the related sdk 12 or sdk 14

    i created my own ble.ccp/h class where those uart example code parts reside

    to make a very simple test case (avoiding lots of callbacks and flags) it appeared easy to provide a variable timer (e.g. 30 ms vs 100 ms) in which the test strings are being created and stuffed into a tx queue ... this simulates a periodic data package creation

    to not overload the nus tx function i opted for a 5 ms timer stuffing it with up to 20 bytes, when available ... as can be seen with the sdk v12.2.0 100 ms data creation timing having no problems of nus tx overruns, but 30 ms will cause lines longer than 80 bytes to overrun occasionally

    i agree that there are more elegant solutions, but for simplicity i thought this might be a good test case

    and now i'm back to the original question, why can the 51 as well as 52 based sdk v12.2.0 versions of my test cases perform equally and provide a let's call it good data throughput for now and show BLE_ERROR_NO_TX_PACKETS errs upon overrun versus error 0x13 on the sdk v14.2.0 52 based test case

    it appears also that this err might be

    components/softdevice/s132/headers/nrf_error.h:#define NRF_ERROR_RESOURCES (NRF_ERROR_BASE_NUM + 19) ///< Not enough resources for operation

    i think the key to it might be in the error code differences

    that's what i was able to come up with in this short period of time

    i did some poking around with wireshark and nrf-sniffer v2.0 beta-1, but as a none ble educated person i couldn't extract any useful information ... the 20 byte data packets seem to come across in 300 us to 1500 us periods

    my intention is to produce my new embedded designs with a single nrf 52832 based mpu using nus as a binary data link to android and desktop based gui control apps and that's about all i want to know about ble for now ... the rest is all my code dealing with the intricacies of the particular embedded hw ... i want to consolidate the mpu for the control functs and the mpu on a ble serial module into one control / ble nus mcu

    while ble is very interesting, it's very hard to afford learning all details when you want to pound out your current design an use ble just as a rx / tx nus link to the outside world

    more later when i have more info and as always ... any help is highly appreciated

    i will not work on it tomorrow since i have to run errands

    cheers Klaus and Happy New Year ;)

  • I've messed up 0x13 and 19, good catch. Now the error message makes more sense! I would search for this particular code on the forum. Also it looks that S130 V2.0.1 and S132 V3.0.0 behave the same while the change comes from upgrade to S132 V5.0.0. Based on different write-ups here on the forum this looks very possible and the solution is typically in proper queuing on APP layer (inside your code) before pushing something blindly into GATT layer (which is what you do now, more or less). But hopefully you will get more detailed explanation from Nordic support or already answered questions...

  • thanks to Petter Myhre :

    your last suggestion of increasing hvn_tx_queue_size to a larger number worked as in the question related to send speed below

    devzone.nordicsemi.com/.../

    i used the code as suggested below with the exception of setting it to 20 instead of 4

    devzone.nordicsemi.com/.../

    here is my code in ble_stack_init

    ret_code_t err_code ;
    
    err_code = nrf_sdh_enable_request () ;
    APP_ERROR_CHECK (err_code) ;
    
    	// Configure the BLE stack using the default settings.
    	// Fetch the start address of the application RAM.
    uint32_t ram_start = 0 ;
    err_code = nrf_sdh_ble_default_cfg_set (APP_BLE_CONN_CFG_TAG, &ram_start) ;
    APP_ERROR_CHECK (err_code) ;
    
    	// Max Packets Per Connection Event
    ble_cfg_t ble_cfg ;
    ::memset (&ble_cfg, 0, sizeof ble_cfg) ;
    ble_cfg.conn_cfg.conn_cfg_tag = CONN_CFG_TAG ;
    ble_cfg.conn_cfg.params.gatts_conn_cfg.hvn_tx_queue_size = 20 ;
    err_code = sd_ble_cfg_set (BLE_CONN_CFG_GATTS, &ble_cfg, ram_start) ;
    APP_ERROR_CHECK (err_code) ;
    
    	// Enable BLE stack.
    err_code = nrf_sdh_ble_enable (&ram_start) ;
    APP_ERROR_CHECK (err_code) ;
    
    	// Register a handler for BLE events.
    NRF_SDH_BLE_OBSERVER (m_ble_observer, APP_BLE_OBSERVER_PRIO, ::Ble_evt_handler, NULL) ;
    

    the inserted code is under the "// Max Packets Per Connection Event" comment

    i also added the following line in add_config.h

    #define NRF_SDH_BLE_GAP_EVENT_LENGTH 30
    

    the data send throughput in ble_nus_string_send -> sd_ble_gatts_hvx is now 120 byte strings in 20 byte chunks at a 45 ms period ... 120 * 22 = 2640 bytes / sec

  • What is CONN_CFG_TAG defined as? I cannot find this in the ble_app_uart example. 

Related