Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

how to make a reliable consecutive transmission over UART

Hello,

I'm using the following code to communicate my NRF52-DK with pc.

But sometimes the DK transmitting repeat data and sometimes error data is sent(missing 1 byte).

Especially when two peripherals connected.

Can somebody assist me?

NRF_QUEUE_DEF(buffer_t, m_buf_queue, 200, NRF_QUEUE_MODE_NO_OVERFLOW);
NRF_LIBUARTE_ASYNC_DEFINE(libuarte, 0, 2, 2, NRF_LIBUARTE_PERIPHERAL_NOT_USED, 8, 3);

typedef struct {
    uint8_t * p_data;
    uint32_t length;
} buffer_t;

typedef struct {
   int conn;
   uint8_t temp[50];
   uint8_t len;
}RF_Gatt;
static RF_Gatt gatts[2];



void uart_event_handler(void * context, nrf_libuarte_async_evt_t * p_evt)
{
    nrf_libuarte_async_t * p_libuarte = (nrf_libuarte_async_t *)context;
    ret_code_t ret;
    switch (p_evt->type)
    {
        case NRF_LIBUARTE_ASYNC_EVT_TX_DONE:
        {
            if (!nrf_queue_is_empty(&m_buf_queue))
            {
                buffer_t buf;
                ret = nrf_queue_pop(&m_buf_queue, &buf);
                APP_ERROR_CHECK(ret);
                do{
                    ret = nrf_libuarte_async_tx(&libuarte, buf.p_data, buf.length);
                }while(ret == NRF_ERROR_BUSY);
            }
        } break;
        default:
            break;
    }
}


static void lbs_c_evt_handler(ble_lbs_c_t * p_lbs_c, ble_lbs_c_evt_t * p_lbs_c_evt)
{
    switch (p_lbs_c_evt->evt_type)
    {
        case BLE_LBS_C_EVT_DISCOVERY_COMPLETE:
        {
            // same as example code
            // ...
        } break; // BLE_LBS_C_EVT_DISCOVERY_COMPLETE

        case BLE_LBS_C_EVT_BUTTON_NOTIFICATION:
        {
            if (gatts[p_lbs_c_evt->conn_handle].len == 0){
                memcpy(gatts[p_lbs_c_evt->conn_handle].temp, 
                    p_lbs_c_evt->params.button.p_data, 
                    p_lbs_c_evt->params.button.data_len);
                gatts[p_lbs_c_evt->conn_handle].len = p_lbs_c_evt->params.button.data_len;
            } else {
                // Combine packet in temp
                uint8_t data[50];
                int length = gatts[p_lbs_c_evt->conn_handle].len;
                memcpy(data, 
                       gatts[p_lbs_c_evt->conn_handle].temp, 
                       length);
                memcpy(data + length, 
                       p_lbs_c_evt->params.button.p_data, 
                       p_lbs_c_evt->params.button.data_len);
                       
                gatts[p_lbs_c_evt->conn_handle].len = 0;  // set to 0 for next transmission
                
                // convert to ascii for UART 
                static uint8_t text[80] = {0};
                int text_size = 0;
                for (int i = 0 ; i < length + p_lbs_c_evt->params.button.data_len; i++){
                     text_size += sprintf(text+text_size, "%02X", data[i]);
                }
                text_size += sprintf(text+text_size, "\r");
                text_size += sprintf(text+text_size, "\n");
                
                // Send over UART
                ret_code_t err_code = nrf_libuarte_async_tx(&libuarte, text, text_size);//buf.p_data, buf.length);
                if (err_code == NRF_ERROR_BUSY){
                    if (!nrf_queue_is_full(&m_buf_queue)){
                        buffer_t buf;
                        buf.p_data = text;
                        buf.length = (uint8_t)text_size;
                        ret_code_t err_code = nrf_queue_push(&m_buf_queue, &buf);
                        APP_ERROR_CHECK(err_code);
                    }
                }
            }
        } break; // BLE_LBS_C_EVT_BUTTON_NOTIFICATION
        default:
            break;
    }
}

static void lfclk_init(void){
    ret_code_t ret = nrf_drv_clock_init();
    APP_ERROR_CHECK(ret);
  
    nrf_drv_clock_lfclk_request(NULL);
}

static void libuarte_init(void){
    nrf_libuarte_async_config_t nrf_libuarte_async_config = {
            .tx_pin     = TX_PIN_NUMBER,
            .rx_pin     = RX_PIN_NUMBER,
            .cts_pin    = CTS_PIN_NUMBER,
            .rts_pin    = RTS_PIN_NUMBER,
            .baudrate   = NRF_UARTE_BAUDRATE_460800,
            .parity     = NRF_UARTE_PARITY_INCLUDED,
            .hwfc       = NRF_UARTE_HWFC_ENABLED,
            .timeout_us = 500,
            .int_prio   = APP_IRQ_PRIORITY_LOW
    };

    ret_code_t err_code = nrf_libuarte_async_init(&libuarte, &nrf_libuarte_async_config, uart_event_handler, (void *)&libuarte);

    APP_ERROR_CHECK(err_code);

    nrf_libuarte_async_enable(&libuarte);
}

Thank you.

Parents
  • sometimes the DK transmitting repeat data and sometimes error data is sent(missing 1 byte).

    How do you know that the problems are in the DK ... ?

  • Because the problems is getting worse when two peripherals connected.

    peripheral:

    total time 117.73
    total packet 11774
    repeated packet 2
    CRC erorr 0

    peripherals, 

    p1 p2
    total time 53.9 53.58
    total packet 5393 3528
    repeated packet 137 862
    CRC erorr -3 1830

    Receiving side is a PC running Python. It keeps checking inWaiting() and printing out the value.

    I don't think my pc is slower than a DK...

    Here is the testing code.

    import binascii
    
    import serial
    import serial.tools.list_ports as ports
    import time
    import sys
    import threading
    import queue
    
    
    inputQueue = queue.Queue()
    
    
    def receive_thread(com, inputQueue):
        while com:
            if com.inWaiting() > 0:
                line = com.readline()
                hex_str = ""
                for i in range(len(line)):
                    hex_str += chr(line[i])
                print(hex_str)
                
                try:
                    (int(hex_str, 16))     # check CRC 
                    if len(hex_str) == 74: # check string legnth
                        inputQueue.put(hex_str)
                except ValueError:
                    print("ValueError")
    
    
    def convert_data_thread(inputQueue):
        # convert and log data in another thread
        
    
    if __name__ == "__main__":
        port = serial.tools.list_ports.comports()[0].device
    
        com = serial.Serial(port=port,
                            baudrate=460800,
                            parity=serial.PARITY_NONE,
                            stopbits=serial.STOPBITS_ONE,
                            bytesize=serial.EIGHTBITS,
                            rtscts=True,
                            timeout=1)
    
        if com is None:
            print("cannot open serial port")
            sys.exit()
            
        t1 = threading.Thread(target=receive_thread, args=[com, inputQueue])
        t1.daemon = True
        t1.start()
        convert_data_thread(inputQueue)

  • Adding additional BLE peripheral links are in essence just more high priority interrupts that cause more frequent pending of code execution in the application main() and interrupts. I am not sure where to begin to debug here, but adding a counter in the buffer, could make it easier to catch that the same nrf_libuarte_async_tx() was called two times with the same counter. That could be a start to narrow it down?

  • Thank you so much for the suggestions. 

    The problem actually related to the event length.

    Hope this code helps the people with similar questions.

    In sdk_config.h

    #define NRF_SDH_BLE_GAP_EVENT_LENGTH 3

    void conn_evt_len_ext_set(bool status)
    {
        ret_code_t err_code;
        ble_opt_t  opt;
    
        memset(&opt, 0x00, sizeof(opt));
        opt.common_opt.conn_evt_ext.enable = status ? 1 : 0;
    
        err_code = sd_ble_opt_set(BLE_COMMON_OPT_CONN_EVT_EXT, &opt);
        APP_ERROR_CHECK(err_code);
    
        m_test_params.conn_evt_len_ext_enabled = status;
    }
    
    
    int main(void){
        ...
        conn_evt_len_ext_set(true);
    }

Reply
  • Thank you so much for the suggestions. 

    The problem actually related to the event length.

    Hope this code helps the people with similar questions.

    In sdk_config.h

    #define NRF_SDH_BLE_GAP_EVENT_LENGTH 3

    void conn_evt_len_ext_set(bool status)
    {
        ret_code_t err_code;
        ble_opt_t  opt;
    
        memset(&opt, 0x00, sizeof(opt));
        opt.common_opt.conn_evt_ext.enable = status ? 1 : 0;
    
        err_code = sd_ble_opt_set(BLE_COMMON_OPT_CONN_EVT_EXT, &opt);
        APP_ERROR_CHECK(err_code);
    
        m_test_params.conn_evt_len_ext_enabled = status;
    }
    
    
    int main(void){
        ...
        conn_evt_len_ext_set(true);
    }

Children
No Data
Related