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

UART stalling on central based on NUS example

Hi,

I am creating a central device with some similar services and code as the NUS example in the SDK. I posted with an issue here I was having earlier but I am writing this as a followup question. Basically, in my function that takes the data sent from the peripheral device to the central device and sends it over UART stalls after running for a while. In the code below, it stalls in the do{}while loop I think because it's app_uart_put keeps returning NRF_ERROR_NO_MEM. If I take the while loop out it seems to run but it starts losing data. Any suggestions on what I can do to stop the NRF_ERROR_NO_MEM error. From looking at the code, it looks like the buffers are filling up and not clearing. Should I try to increase the buffer size (currently 2048) more or is the problem more with the code in the function?

For reference, I'm trying to send about 20000 bytes per second to the central from the peripheral. Code for both is below. Also, I am using SDK version 15.3.0 on the 52480 DK.

static void ble_emg_chars_received_uart_print(uint8_t * p_data, uint16_t data_len)
{
    ret_code_t ret_val;

    //NRF_LOG_DEBUG("Receiving data.");
    //NRF_LOG_HEXDUMP_DEBUG(p_data, data_len);

    for (uint32_t i = 0; i < data_len; i++)
    {
        do {
              ret_val = app_uart_put(p_data[i]);
              if ((ret_val != NRF_SUCCESS) && (ret_val != NRF_ERROR_NO_MEM))
              {
                  APP_ERROR_CHECK(ret_val);
              }
        } while (ret_val == NRF_ERROR_NO_MEM || ret_val == NRF_ERROR_BUSY);
    }
}

Central

ble_app_cust.zip

Peripheral

ble_app_cust_p.zip

  • Hi Michael

    What is the baudrate of your UART?

    Have you scoped the UART lines to see if the data is being output on the UART as expected?

    It should be possible for the client on the central side to disable notification on the NUS service once the buffers reach a certain point, which would hold back the data updates from the peripheral side. Then you can re-enable the services again once the UART buffers clear to allow the peripheral to send more data. 

    Best regards
    Torbjørn

  • I'm currently using a baud rate of 230400. I just tried upping the baud rate to 460800. When I increased baudrate, it seemed to stop stalling but there seems to be some sort of data loss or data corruption due to switching of the byte order of data. I pasted an example I copied where this occurs below showing what should be the byte order at the start and then it flips. All of the values should be less than 2048 because they are values from the ADC.

    I noticed in the defines for the baudrate it gives an actual baudrate next to it. Should I be using this baudrate on my terminal program?

    #define UART_BAUDRATE_BAUDRATE_Baud460800 (0x075F7000UL) /*!< 460800 baud (actual rate: 470588) */

    . . .

    b'\xf0\xff'

    -16

    b'\xf0\xff'

    -16

    b'\xff\xf2'

    -3329

    b'\xff\xf2'

    -3329

    b'\xff\xf4'

    -2817

    . . .

  • Hi Michael

    One tip when using UART is to request the external HF clock at all times, to ensure that the baudrate is as accurate as possible. You could try to set your terminal to the actual baudrate as well, but this shouldn't really be necessary as the deviation from the intended baudrate is very small (using the internal HF clock by comparison can lead to drift of 5% or more). 

    I assume a single lost byte would lead to the byte order being flipped, since the only thing you are sending over the UART is the 16-bit ADC samples?

    Best regards
    Torbjørn

  • Hi,

    I assume a single lost byte would lead to the byte order being flipped, since the only thing you are sending over the UART is the 16-bit ADC samples?

    This is correct even a single byte loss would flip the order since I am just sending 16bit ADC values that I get from the peripheral. 

    int main(void)
    {
        ret_code_t       err_code;
        log_init();
        timer_init();
        leds_init();
        uart_init();
        power_management_init();
        ble_stack_init();
        gatt_init();
        db_discovery_init();
        ble_emg_service_init();
    
        err_code = sd_clock_hfclk_request();
        APP_ERROR_CHECK(err_code);
        uint32_t p_is_running = 0;
        while (!p_is_running)
        {
            sd_clock_hfclk_is_running(&p_is_running);
        }
    
        NRF_LOG_INFO("BLE EMG.");
    
        scan_start();
    
        bsp_board_led_on(CENTRAL_SCANNING_LED);
    
        for (;;)
        {
            idle_state_handle();
        }
    }

    I tried requesting the HF clock and I didn't see much of a difference (data still flipping). Can you take a look at this portion to see if I am requesting in the correct way that you were referring to?

    Thanks,

    Michael 

  • Hi Michael

    The code you sent looks fine, yes. Assuming the while loop ends the external HF clock should be running continuously. 

    Maybe you could try to send an empty 'sync byte' of sorts at the start of every sample?

    You should have enough UART throughput for it if you are sending 20000 bytes of data pr second, and it should make it easier to spot what is happening. 

    Best regards
    Torbjørn

Related