USBD CDC seems too slow

Hi,

I am trying to make a USB to BLE (central) device with nRF52840. I have removed the end character check from the "usbd_ble_uart" example and used a 50ms timeout instead. However, when sending about 240 bytes of data, the timer reaches the timeout value. It is not expected as I thought the device supports at least USB 2.0, which has 480Mbps or 12Mbps data rate, later I found the device is only capable of much lower speed (https://devzone.nordicsemi.com/f/nordic-q-a/38822/usbd-with-cdc-acm-class-windows-10-maximum-data-rate  CDC ACM binary file transfer (Windows): 215 kB/s (1720 kbit/s). 

Is there any way to improve the transfer rate? As my setup shows much lower speed than given in forums, as it cannot transfer 240 bytes within a 50ms window. Is it possible to get 100kbps with the device working as BLE central as well?

The code is given below:

case APP_USBD_CDC_ACM_USER_EVT_RX_DONE:
        {
            ret_code_t ret;
            //NRF_LOG_INFO("Bytes waiting: %d", app_usbd_cdc_acm_bytes_stored(p_cdc_acm));
            
            nrfx_timer_pause(&m_usb_cdc_timer);
            nrfx_timer_clear(&m_usb_cdc_timer);
            do
            {
                /*Get amount of data transferred*/
                size_t size = app_usbd_cdc_acm_rx_size(p_cdc_acm);
                rx_buffer += size;
                //NRF_LOG_INFO("RX: size: %lu char: %c", size, *rx_buffer);
               
                /* Fetch data until internal buffer is empty */
                ret = app_usbd_cdc_acm_read_any(&m_app_cdc_acm,
                                            rx_buffer,
                                            READ_SIZE);
                
            } while (ret == NRF_SUCCESS);
            
            
            nrfx_timer_resume(&m_usb_cdc_timer);
            break;
        }

Other question is, how to re-assign buffer to "app_usbd_cdc_acm_read_any" function before APP_USBD_CDC_ACM_USER_EVT_RX_DONE event? Because the buffer pointer increments during the "APP_USBD_CDC_ACM_USER_EVT_RX_DONE" event (see the code) which should be set to the beginning of the buffer on timeout event.

Thank you.

Ras

  • Hi Ras

    It should definitely be possible to get higher data throughput than what you are experiencing. 

    To be clear, is the problem receiving data from the USB host, or sending it?
    The code you attach is showing the receiving part. 

    Also, why are you incrementing the rx_buffer before receiving the data?
    In the original example the rx_buffer pointer is pointing to an empty buffer, and there is no need to increment this buffer until after the data has been transferred into it. 

    Best regards
    Torbjørn

  • Hi,

    Thanks for the reply. Yes, I am trying to get higher data rate for receiving part. I didn't show whole code here, the idea is:

    1. The first transfer is setup on APP_USBD_CDC_ACM_USER_EVT_PORT_OPEN event

    case APP_USBD_CDC_ACM_USER_EVT_PORT_OPEN:
            {
                /*Set up the first transfer*/
                ret_code_t ret = app_usbd_cdc_acm_read_any(&m_app_cdc_acm,
                                                       rx_bytes,
                                                       READ_SIZE);
            }

    This is the reason for incrementing rx_buffer pointer as I am trying to setup "app_usbd_cdc_acm_read_any" for next transaction.

    2. For each "APP_USBD_CDC_ACM_USER_EVT_RX_DONE" event, set buffer for next transaction and clear timer. The code is posted in my first post.

    3. On timer timeout event, sends the received data through BLE, and set the buffer pointer for "app_usbd_cdc_acm_read_any" to the beginning.

    static void timer1_event_handler(nrf_timer_event_t event_type, void * p_context)
    {
        // Copy the data and initialize BLE data transmission
        uint16_t len = get_rx_data_len();
        reset_rx_buf_ptr();
        
        memcpy(ble_buffer, rx_buffer, len);
        ble_nus_c_send_data(ble_buffer, len);
        
        /* Set buffer pointer to the beginning */
        ret_code_t ret = app_usbd_cdc_acm_read_any(&m_app_cdc_acm,
                                                       rx_buffer,
                                                       READ_SIZE);
    }

    In my testing, the function call to reset the buffer pointer to the beginning is not working. The next data write to the location set by the step 2.

Related