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

USB speed issue on nRF52840

Hi,

I'm using a BMD-340 module evaluation kit (Rigado) I modified usbd example and I can transfer data in between host and device. But I have issues with usb speed and I need more help to debug this issue.

The host side is using libusb-1.0, sending 16 X 64  = 1K bytes bulk data from ENDPOINTOUT1  using libusb_bulk_transfer function and after the device receiving 1 KByte data it's sending back the data to the host on ENDPOINTIN1. Data is transferred correctly but the time spent to do just 1 KByte transfer is very long and varying a lot. I measured varying rates from 2 - 100 KBytes/second. I tried various libusb drivers (winUSB, libusb-win32 and libusbK) to see any variation with data rate but didn't see any difference.

I'm  attaching the main.c for convenience.

/**
 * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form, except as embedded into a Nordic
 *    Semiconductor ASA integrated circuit in a product or a software update for
 *    such product, must reproduce the above copyright notice, this list of
 *    conditions and the following disclaimer in the documentation and/or other
 *    materials provided with the distribution.
 *
 * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
 *    contributors may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * 4. This software, with or without modification, must only be used with a
 *    Nordic Semiconductor ASA integrated circuit.
 *
 * 5. Any software provided in binary form under this license must not be reverse
 *    engineered, decompiled, modified and/or disassembled.
 *
 * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include "nrf.h"
#include "nrf_drv_usbd.h"
#include "nrf_drv_clock.h"
#include "nrf_gpio.h"
#include "nrf_delay.h"
#include "nrf_drv_power.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "app_timer.h"
#include "app_error.h"
#include "bsp.h"


#define BTN_DATA_SEND               0
#define BTN_DATA_KEY_RELEASE        (bsp_event_t)(BSP_EVENT_KEY_LAST + 1)

#define RECEIVE_FRAMES              16        // number of usb frames expected from the host
#define SEND_FRAMES                 16        // number of usb frames sent to the host
#define TRANSFER_NUM                16        // number of data transfers for each bulk data of 64 bytes
#define TOTAL_BYTES                 (TRANSFER_NUM*EP1_MAXPACKETSIZE) // total bytes of data that will be transferred to usb device

//#define ENABLE_MY_PRINTS
#define BULK_ENDPOINT               2
#define INTERRUPT_ENDPOINT          3
//#define ISOCHRONOUS_ENDPOINT

/**
 * @brief Button for system OFF request
 *
 * This button would set the request for system OFF.
 */
#define BTN_SYSTEM_OFF BSP_BOARD_BUTTON_1

/**
 * @brief Configuration status LED
 *
 * This LED would blink quickly (5 Hz) when device is not configured
 * or slowly (1 Hz) when configured and working properly.
 */
#define LED_USB_STATUS BSP_BOARD_LED_0
/**
 * @brief Power detect LED
 *
 * The LED is ON when connection is detected on USB port.
 * It is turned off when connection is removed.
 */
#define LED_USB_POWER BSP_BOARD_LED_3

/**
 * @brief Running LED
 *
 * LED that turns on when USB is sending
 */
#define LED_SEND BSP_BOARD_LED_2

/**
 * @brief Active LED
 *
 * LED that turns on when USB is receiving
 */
#define LED_RECEIVE BSP_BOARD_LED_1

/**
 * @brief Enable power USB detection
 *
 * Configure if example supports USB port connection
 */
#ifndef USBD_POWER_DETECTION
#define USBD_POWER_DETECTION true
#endif

/**
 * @brief Startup delay
 *
 * Number of microseconds to start USBD after powering up.
 * Kind of port insert debouncing.
 */
#define STARTUP_DELAY 100


/** Maximum size of the packed transfered by EP0 */
#define EP0_MAXPACKETSIZE NRF_DRV_USBD_EPSIZE

/** Maximum size of the packed transfered by EP1 */
#define EP1_MAXPACKETSIZE NRF_DRV_USBD_EPSIZE

/** Device descriptor */
#define USBD_DEVICE_DESCRIPTOR \
    0x12,                        /* bLength | size of descriptor                                                  */\
    0x01,                        /* bDescriptorType | descriptor type                                             */\
    0x00, 0x02,                  /* bcdUSB | USB spec release (ver 2.0)                                           */\
    0x00,                        /* bDeviceClass ¦ class code (each interface specifies class information)        */\
    0x00,                        /* bDeviceSubClass ¦ device sub-class (must be set to 0 because class code is 0) */\
    0x00,                        /* bDeviceProtocol | device protocol (no class specific protocol)                */\
    EP0_MAXPACKETSIZE,           /* bMaxPacketSize0 | maximum packet size (64 bytes)                              */\
    0x15, 0x19,                  /* vendor ID  (0x1915 Nordic)                                                    */\
    0x0D, 0x52,                  /* product ID (0x520A nRF52 MS device nrf_drv)                                */\
    0x01, 0x01,                  /* bcdDevice | final device release number in BCD Format                         */\
    USBD_STRING_MANUFACTURER_IX, /* iManufacturer | index of manufacturer string                                  */\
    USBD_STRING_PRODUCT_IX,      /* iProduct | index of product string                                            */\
    USBD_STRING_SERIAL_IX,       /* iSerialNumber | Serial Number string                                          */\
    0x01                         /* bNumConfigurations | number of configurations                                 */

/** Configuration descriptor */
#define DEVICE_SELF_POWERED 1
#define REMOTE_WU           0

#define USBD_CONFIG_DESCRIPTOR_SIZE   9
#define USBD_CONFIG_DESCRIPTOR_FULL_SIZE   (USBD_CONFIG_DESCRIPTOR_SIZE + (9 + 7 + 7))
#define USBD_CONFIG_DESCRIPTOR  \
    0x09,         /* bLength | length of descriptor                                             */\
    0x02,         /* bDescriptorType | descriptor type (CONFIGURATION)                          */\
    USBD_CONFIG_DESCRIPTOR_FULL_SIZE, 0x00,    /* wTotalLength | total length of descriptor(s)  */\
    0x01,         /* bNumInterfaces                                                             */\
    0x01,         /* bConfigurationValue                                                        */\
    0x04,         /* index of string Configuration | configuration string index (not supported) */\
    0x80| (((DEVICE_SELF_POWERED) ? 1U:0U)<<6) | (((REMOTE_WU) ? 1U:0U)<<5), /* bmAttributes    */\
    250            /* maximum power in steps of 2mA (500mA)                                       */

#define USBD_INTERFACE0_DESCRIPTOR  \
    0x09,         /* bLength                                                                          */\
    0x04,         /* bDescriptorType | descriptor type (INTERFACE)                                    */\
    0x00,         /* bInterfaceNumber                                                                 */\
    0x00,         /* bAlternateSetting                                                                */\
    0x02,         /* bNumEndpoints | number of endpoints (1)                                          */\
    0x08,         /* bInterfaceClass | interface class (8..defined by USB spec: Mass storage device)  */\
    0x00,         /* bInterfaceSubClass |interface sub-class (0: SCI command set not reported)        */\
    0x00,         /* bInterfaceProtocol | interface protocol )                                        */\
    0x00          /* interface string index (not supported)                                           */

#define USBD_ENDPOINT1OUT_DESCRIPTOR  \
    0x07,         /* bLength | length of descriptor (7 bytes)                                     */\
    0x05,         /* bDescriptorType | descriptor type (ENDPOINT)                                 */\
    0x01,         /* bEndpointAddress | endpoint address (IN endpoint, endpoint 1)                */\
    BULK_ENDPOINT,/* bmAttributes | endpoint attributes                                           */\
    0x40,0x00,    /* bMaxPacketSizeLowByte,bMaxPacketSizeHighByte | maximum packet size(64 bytes) */\
    0x00          /* bInterval | polling interval (10ms)                                          */

#define USBD_ENDPOINT1IN_DESCRIPTOR  \
    0x07,         /* bLength | length of descriptor (7 bytes)                                     */\
    0x05,         /* bDescriptorType | descriptor type (ENDPOINT)                                 */\
    0x81,         /* bEndpointAddress | endpoint address (IN endpoint, endpoint 1)                */\
    BULK_ENDPOINT,/* bmAttributes | endpoint attributes                                           */\
    0x40,0x00,    /* bMaxPacketSizeLowByte,bMaxPacketSizeHighByte | maximum packet size(64 bytes) */\
    0x00          /* bInterval | polling interval (10ms)                                          */

/**
 * String config descriptor
 */
#define USBD_STRING_LANG_IX  0x00
#define USBD_STRING_LANG \
    0x04,         /* length of descriptor                   */\
    0x03,         /* descriptor type                        */\
    0x09,         /*                                        */\
    0x04          /* Supported LangID = 0x0409 (US-English) */

#define USBD_STRING_MANUFACTURER_IX  0x01
#define USBD_STRING_MANUFACTURER \
    42,           /* length of descriptor (? bytes)   */\
    0x03,         /* descriptor type                  */\
    'N', 0x00,    /* Define Unicode String "Nordic Semiconductor  */\
    'o', 0x00, \
    'r', 0x00, \
    'd', 0x00, \
    'i', 0x00, \
    'c', 0x00, \
    ' ', 0x00, \
    'S', 0x00, \
    'e', 0x00, \
    'm', 0x00, \
    'i', 0x00, \
    'c', 0x00, \
    'o', 0x00, \
    'n', 0x00, \
    'd', 0x00, \
    'u', 0x00, \
    'c', 0x00, \
    't', 0x00, \
    'o', 0x00, \
    'r', 0x00

#define USBD_STRING_PRODUCT_IX  0x02
#define USBD_STRING_PRODUCT \
    72,           /* length of descriptor (? bytes)         */\
    0x03,         /* descriptor type                        */\
    'n', 0x00,    /* generic unicode string for all devices */\
    'R', 0x00, \
    'F', 0x00, \
    '5', 0x00, \
    '2', 0x00, \
    ' ', 0x00, \
    'U', 0x00, \
    'S', 0x00, \
    'B', 0x00, \
    ' ', 0x00, \
    'M', 0x00, \
    'Y', 0x00, \
    ' ', 0x00, \
    'd', 0x00, \
    'e', 0x00, \
    'v', 0x00, \
    'i', 0x00, \
    'c', 0x00, \
    'e', 0x00, \
    ' ', 0x00, \
    'o', 0x00, \
    'n', 0x00, \
    ' ', 0x00, \
    'n', 0x00, \
    'r', 0x00, \
    'f', 0x00, \
    '_', 0x00, \
    'd', 0x00, \
    'r', 0x00, \
    'v', 0x00, \
    ' ', 0x00, \
    'D', 0x00, \
    'e', 0x00, \
    'm', 0x00, \
    'o', 0x00, \

#define USBD_STRING_SERIAL_IX  0x00

static const uint8_t get_descriptor_device[] = {
    USBD_DEVICE_DESCRIPTOR
};

static const uint8_t get_descriptor_configuration[] = {
    USBD_CONFIG_DESCRIPTOR,
    USBD_INTERFACE0_DESCRIPTOR,
    USBD_ENDPOINT1IN_DESCRIPTOR,
    USBD_ENDPOINT1OUT_DESCRIPTOR
};
static const uint8_t get_descriptor_string_lang[] = {
    USBD_STRING_LANG
};
static const uint8_t get_descriptor_string_manuf[] = {
    USBD_STRING_MANUFACTURER
};
static const uint8_t get_descriptor_string_prod[] = {
    USBD_STRING_PRODUCT
};

static const uint8_t get_config_resp_configured[]   = {1};
static const uint8_t get_config_resp_unconfigured[] = {0};

static const uint8_t get_status_device_resp_nrwu[] = {
    ((DEVICE_SELF_POWERED) ? 1 : 0), //LSB first: self-powered, no remoteWk
    0
};
static const uint8_t get_status_device_resp_rwu[]  = {
    ((DEVICE_SELF_POWERED) ? 1 : 0) | 2, //LSB first: self-powered, remoteWk
    0
};

static const uint8_t get_status_interface_resp[] = {0, 0};
static const uint8_t get_status_ep_halted_resp[] = {1, 0};
static const uint8_t get_status_ep_active_resp[] = {0, 0};


#define GET_CONFIG_DESC_SIZE    sizeof(get_descriptor_configuration)
#define GET_INTERFACE_DESC_SIZE 9
#define GET_ENDPOINT_DESC_SIZE  7

#define get_descriptor_interface_0 \
    &get_descriptor_configuration[GET_CONFIG_DESC_SIZE]
#define get_descriptor_endpoint_1  \
    &get_descriptor_configuration[GET_CONFIG_DESC_SIZE+GET_INTERFACE_DESC_SIZE]

volatile static int receive_cnt = 0;   // counter for number of received buffers
volatile static int send_cnt = 0;      // counter for number of sent buffers
static uint8_t receive_buffer[EP1_MAXPACKETSIZE];   // data buffer for receiving data
static uint8_t send_buffer[EP1_MAXPACKETSIZE];      // data buffer for sending data
volatile static bool send_flag = 0;
uint16_t txTestData[TOTAL_BYTES / 2];     //test counter data to be sent to the host counts from 0 to 32767
uint8_t  rxTestData[TOTAL_BYTES];         //test counter data to be received from the host which should count from 0 to 32767

/************************Helper function to prepare data**************************************/
static void fillTxBuffer(void)
{
    int i = 0;
    for (i = 0; i < (TOTAL_BYTES / 2); i++)
    {
        txTestData[i] = i;
    }
    printf("First = %d , Last = %d\n", txTestData[0], txTestData[(TOTAL_BYTES / 2 -1)]);

}
static void printTxData(uint16_t *txBuff, int length)
{
    uint8_t *pTxBuff = (uint8_t*)txBuff;
    int i = 0;
    for (i = 0; i < length; i++)
    {
        printf("byte data = %x\n", *(pTxBuff++));
    }
}

/*********************************************************************************************/

/**
 * @brief USB configured flag
 *
 * The flag that is used to mark the fact that USB is configured and ready
 * to transmit data
 */
static volatile bool m_usbd_configured = false;

/**
 * @brief USB suspended
 *
 * The flag that is used to mark the fact that USB is suspended and requires wake up
 * if new data is available.
 *
 * @note This variable is changed from the main loop.
 */
static bool m_usbd_suspended = false;

/**
 * @brief Mark the fact if remote wake up is enabled
 *
 * The internal flag that marks if host enabled the remote wake up functionality in this device.
 */
static
#if REMOTE_WU
    volatile // Disallow optimization only if Remote wakeup is enabled
#endif
bool m_usbd_rwu_enabled = false;

/**
 * @brief The requested suspend state
 *
 * The currently requested suspend state based on the events
 * received from USBD library.
 * If the value here is different than the @ref m_usbd_suspended
 * the state changing would be processed inside main loop.
 */
static volatile bool m_usbd_suspend_state_req = false;

/**
 * @brief System OFF request flag
 *
 * This flag is used in button event processing and marks the fact that
 * system OFF should be activated from main loop.
 */
static volatile bool m_system_off_req = false;


/**
 * @brief Setup all the endpoints for selected configuration
 *
 * Function sets all the endpoints for specific configuration.
 *
 * @note
 * Setting the configuration index 0 means technically disabling the HID interface.
 * Such configuration should be set when device is starting or USB reset is detected.
 *
 * @param index Configuration index
 *
 * @retval NRF_ERROR_INVALID_PARAM Invalid configuration
 * @retval NRF_SUCCESS             Configuration successfully set
 */
static ret_code_t ep_configuration(uint8_t index)
{
    if ( index == 1 )
    {
        nrf_drv_usbd_ep_dtoggle_clear(NRF_DRV_USBD_EPIN1);
        nrf_drv_usbd_ep_stall_clear(NRF_DRV_USBD_EPIN1);
        nrf_drv_usbd_ep_enable(NRF_DRV_USBD_EPIN1);
        nrf_drv_usbd_ep_dtoggle_clear(NRF_DRV_USBD_EPOUT1);
        nrf_drv_usbd_ep_stall_clear(NRF_DRV_USBD_EPOUT1);
        nrf_drv_usbd_ep_enable(NRF_DRV_USBD_EPOUT1);
        m_usbd_configured = true;
        nrf_drv_usbd_setup_clear();
    }
    else if ( index == 0 )
    {
        nrf_drv_usbd_ep_disable(NRF_DRV_USBD_EPIN1);
        nrf_drv_usbd_ep_disable(NRF_DRV_USBD_EPOUT1);
        m_usbd_configured = false;
        nrf_drv_usbd_setup_clear();
    }
    else
    {
        return NRF_ERROR_INVALID_PARAM;
    }
    return NRF_SUCCESS;
}

/**
 * @name Processing setup requests
 *
 * @{
 */
/**
 * @brief Respond on ep 0
 *
 * Auxiliary function for sending respond on endpoint 0
 * @param[in] p_setup Pointer to setup data from current setup request.
 *                    It would be used to calculate the size of data to send.
 * @param[in] p_data  Pointer to the data to send.
 * @param[in] size    Number of bytes to send.
 * @note Data pointed by p_data has to be available till the USBD_EVT_BUFREADY event.
 */
static void respond_setup_data(
    nrf_drv_usbd_setup_t const * const p_setup,
    void const * p_data, size_t size)
{
    /* Check the size against required response size */
    if (size > p_setup->wLength)
    {
        size = p_setup->wLength;
    }
    ret_code_t ret;
    nrf_drv_usbd_transfer_t transfer =
    {
        .p_data = {.tx = p_data},
        .size = size
    };
    ret = nrf_drv_usbd_ep_transfer(NRF_DRV_USBD_EPIN0, &transfer);
    if (ret != NRF_SUCCESS)
    {
        NRF_LOG_ERROR("Transfer starting failed: %d", (uint32_t)ret);
    }
    ASSERT(ret == NRF_SUCCESS);
    UNUSED_VARIABLE(ret);
}


/** React to GetStatus */
static void usbd_setup_GetStatus(nrf_drv_usbd_setup_t const * const p_setup)
{
    switch (p_setup->bmRequestType)
    {
    case 0x80: // Device
        if (((p_setup->wIndex) & 0xff) == 0)
        {
            respond_setup_data(
                p_setup,
                m_usbd_rwu_enabled ? get_status_device_resp_rwu : get_status_device_resp_nrwu,
                sizeof(get_status_device_resp_nrwu));
            return;
        }
        break;
    case 0x81: // Interface
        if (m_usbd_configured) // Respond only if configured
        {
            if (((p_setup->wIndex) & 0xff) == 0) // Only interface 0 supported
            {
                respond_setup_data(
                    p_setup,
                    get_status_interface_resp,
                    sizeof(get_status_interface_resp));
                return;
            }
        }
        break;
    case 0x82: // Endpoint
        if (((p_setup->wIndex) & 0xff) == 0) // Endpoint 0
        {
            respond_setup_data(
                p_setup,
                get_status_ep_active_resp,
                sizeof(get_status_ep_active_resp));
            return;
        }
        if (m_usbd_configured) // Other endpoints responds if configured
        {
            if (((p_setup->wIndex) & 0xff) == NRF_DRV_USBD_EPIN1)
            {
                if (nrf_drv_usbd_ep_stall_check(NRF_DRV_USBD_EPIN1))
                {
                    respond_setup_data(
                        p_setup,
                        get_status_ep_halted_resp,
                        sizeof(get_status_ep_halted_resp));
                    return;
                }
                else
                {
                    respond_setup_data(
                        p_setup,
                        get_status_ep_active_resp,
                        sizeof(get_status_ep_active_resp));
                    return;
                }
            }
        }
        break;
    default:
        break; // Just go to stall
    }
    NRF_LOG_ERROR("Unknown status: 0x%2x", p_setup->bmRequestType);
    nrf_drv_usbd_setup_stall();
}

static void usbd_setup_ClearFeature(nrf_drv_usbd_setup_t const * const p_setup)
{
    if ((p_setup->bmRequestType) == 0x02) // standard request, recipient=endpoint
    {
        if ((p_setup->wValue) == 0)
        {
            if ((p_setup->wIndex) == NRF_DRV_USBD_EPIN1)
            {
                nrf_drv_usbd_ep_stall_clear(NRF_DRV_USBD_EPIN1);
                nrf_drv_usbd_setup_clear();
                return;
            }
        }
    }
    else if ((p_setup->bmRequestType) ==  0x0) // standard request, recipient=device
    {
        if (REMOTE_WU)
        {
            if ((p_setup->wValue) == 1) // Feature Wakeup
            {
                m_usbd_rwu_enabled = false;
                nrf_drv_usbd_setup_clear();
                return;
            }
        }
    }
    NRF_LOG_ERROR("Unknown feature to clear");
    nrf_drv_usbd_setup_stall();
}

static void usbd_setup_SetFeature(nrf_drv_usbd_setup_t const * const p_setup)
{
    if ((p_setup->bmRequestType) == 0x02) // standard request, recipient=endpoint
    {
        if ((p_setup->wValue) == 0) // Feature HALT
        {
            if ((p_setup->wIndex) == NRF_DRV_USBD_EPIN1)
            {
                nrf_drv_usbd_ep_stall(NRF_DRV_USBD_EPIN1);
                nrf_drv_usbd_setup_clear();
                return;
            }
        }
    }
    else if ((p_setup->bmRequestType) ==  0x0) // standard request, recipient=device
    {
        if (REMOTE_WU)
        {
            if ((p_setup->wValue) == 1) // Feature Wakeup
            {
                m_usbd_rwu_enabled = true;
                nrf_drv_usbd_setup_clear();
                return;
            }
        }
    }
    NRF_LOG_ERROR("Unknown feature to set");
    nrf_drv_usbd_setup_stall();
}

static void usbd_setup_GetDescriptor(nrf_drv_usbd_setup_t const * const p_setup)
{
    //determine which descriptor has been asked for
    switch ((p_setup->wValue) >> 8)
    {
    case 1: // Device
        if ((p_setup->bmRequestType) == 0x80)
        {
            respond_setup_data(
                p_setup,
                get_descriptor_device,
                sizeof(get_descriptor_device));
            return;
        }
        break;
    case 2: // Configuration
        if ((p_setup->bmRequestType) == 0x80)
        {
            respond_setup_data(
                p_setup,
                get_descriptor_configuration,
                GET_CONFIG_DESC_SIZE);
            return;
        }
        break;
    case 3: // String
        if ((p_setup->bmRequestType) == 0x80)
        {
            // Select the string
            switch ((p_setup->wValue) & 0xFF)
            {
            case USBD_STRING_LANG_IX:
                respond_setup_data(
                    p_setup,
                    get_descriptor_string_lang,
                    sizeof(get_descriptor_string_lang));
                return;
            case USBD_STRING_MANUFACTURER_IX:
                respond_setup_data(
                    p_setup,
                    get_descriptor_string_manuf,
                    sizeof(get_descriptor_string_manuf));
                return;
            case USBD_STRING_PRODUCT_IX:
                respond_setup_data(p_setup,
                    get_descriptor_string_prod,
                    sizeof(get_descriptor_string_prod));
                return;
            default:
                break;
            }
        }
        break;
    case 4: // Interface
        if ((p_setup->bmRequestType) == 0x80)
        {
            // Which interface?
            if ((((p_setup->wValue) & 0xFF) == 0))
            {
                respond_setup_data(
                    p_setup,
                    get_descriptor_interface_0,
                    GET_INTERFACE_DESC_SIZE);
                return;
            }
        }
        break;
    case 5: // Endpoint
        if ((p_setup->bmRequestType) == 0x80)
        {
            // Which endpoint?
            if (((p_setup->wValue) & 0xFF) == 1)
            {
                respond_setup_data(
                    p_setup,
                    get_descriptor_endpoint_1,
                    GET_ENDPOINT_DESC_SIZE);
                return;
            }
        }
        break;

    default:
        break; // Not supported - go to stall
    }

    NRF_LOG_ERROR("Unknown descriptor requested: 0x%2x, type: 0x%2x or value: 0x%2x",
        p_setup->wValue >> 8,
        p_setup->bmRequestType,
        p_setup->wValue & 0xFF);
    nrf_drv_usbd_setup_stall();
}

static void usbd_setup_GetConfig(nrf_drv_usbd_setup_t const * const p_setup)
{
    if (m_usbd_configured)
    {
        respond_setup_data(
            p_setup,
            get_config_resp_configured,
            sizeof(get_config_resp_configured));
    }
    else
    {
        respond_setup_data(
            p_setup,
            get_config_resp_unconfigured,
            sizeof(get_config_resp_unconfigured));
    }
}

static void usbd_setup_SetConfig(nrf_drv_usbd_setup_t const * const p_setup)
{
    if ((p_setup->bmRequestType) == 0x00)
    {
        // accept only 0 and 1
        if (((p_setup->wIndex) == 0) && ((p_setup->wLength) == 0) &&
            ((p_setup->wValue) <= UINT8_MAX))
        {
            if (NRF_SUCCESS == ep_configuration((uint8_t)(p_setup->wValue)))
            {
                nrf_drv_usbd_setup_clear();
                return;
            }
        }
    }
    NRF_LOG_ERROR("Wrong configuration: Index: 0x%2x, Value: 0x%2x.",
        p_setup->wIndex,
        p_setup->wValue);
    nrf_drv_usbd_setup_stall();
}

static void usbd_setup_SetIdle(nrf_drv_usbd_setup_t const * const p_setup)
{
    if (p_setup->bmRequestType == 0x21)
    {
        //accept any value
        nrf_drv_usbd_setup_clear();
        return;
    }
    NRF_LOG_ERROR("Set Idle wrong type: 0x%2x.", p_setup->bmRequestType);
    nrf_drv_usbd_setup_stall();
}

static void usbd_setup_SetInterface(
    nrf_drv_usbd_setup_t const * const p_setup)
{
    //no alternate setting is supported - STALL always
    NRF_LOG_ERROR("No alternate interfaces supported.");
    nrf_drv_usbd_setup_stall();
}

static void usbd_setup_SetProtocol(
    nrf_drv_usbd_setup_t const * const p_setup)
{
    if (p_setup->bmRequestType == 0x21)
    {
        //accept any value
        nrf_drv_usbd_setup_clear();
        return;
    }
    NRF_LOG_ERROR("Set Protocol wrong type: 0x%2x.", p_setup->bmRequestType);
    nrf_drv_usbd_setup_stall();
}

/** @} */ /* End of processing setup requests functions */


static void usbd_event_handler(nrf_drv_usbd_evt_t const * const p_event)
{
    switch (p_event->type)
    {
    case NRF_DRV_USBD_EVT_SUSPEND:
        NRF_LOG_INFO("SUSPEND state detected");
        m_usbd_suspend_state_req = true;
        break;
    case NRF_DRV_USBD_EVT_RESUME:
        NRF_LOG_INFO("RESUMING from suspend");
        m_usbd_suspend_state_req = false;
        break;
    case NRF_DRV_USBD_EVT_WUREQ:
        NRF_LOG_INFO("RemoteWU initiated");
        m_usbd_suspend_state_req = false;
        break;
    case NRF_DRV_USBD_EVT_RESET:
        {
            ret_code_t ret = ep_configuration(0);
            ASSERT(ret == NRF_SUCCESS);
            UNUSED_VARIABLE(ret);
            m_usbd_suspend_state_req = false;
            break;
        }
    case NRF_DRV_USBD_EVT_SOF:
        {
            static uint32_t cycle = 0;
            ++cycle;
            if ((cycle % (m_usbd_configured ? 500 : 100)) == 0)
            {
                bsp_board_led_invert(LED_USB_STATUS);
            }
            break;
        }
    case NRF_DRV_USBD_EVT_EPTRANSFER:
     	if (NRF_DRV_USBD_EPOUT1 == p_event->data.eptransfer.ep) 
        {
            bsp_board_led_off(LED_RECEIVE);
            static nrf_drv_usbd_transfer_t usb_rx_transfer;
            if (NRF_USBD_EP_WAITING == p_event->data.eptransfer.status) 
            {
                usb_rx_transfer.p_data.rx = &rxTestData[(receive_cnt*EP1_MAXPACKETSIZE)];
                usb_rx_transfer.size = EP1_MAXPACKETSIZE;
                int ret = nrf_drv_usbd_ep_transfer(NRF_DRV_USBD_EPOUT1, &usb_rx_transfer);
            } 
            else if (NRF_USBD_EP_OK == p_event->data.eptransfer.status) 
            {
               /* If errata 154 is present the data transfer is acknowledged by the hardware. */
                if (!nrf_drv_usbd_errata_154())
                {
                    /* Transfer ok - allow status stage */
                    nrf_drv_usbd_setup_clear();
                }
#ifdef  ENABLE_MY_PRINTS               
                size_t size = 0;
                nrf_drv_usbd_ep_status_get(p_event->data.eptransfer.ep, &size);
                printf("Received %d bytes %dth times:\n", size, receive_cnt);
                for (int i = 0; i < size; i++) printf("0x%02X ", rxTestData[i+(receive_cnt*EP1_MAXPACKETSIZE)]);
                printf("\n");
#endif
                receive_cnt++;
                send_flag = 1;
                bsp_board_led_on(LED_RECEIVE);

 
            }
            else if (NRF_USBD_EP_ABORTED == p_event->data.eptransfer.status)
            {
                /* Just ignore */
                NRF_LOG_INFO("Transfer aborted event on EPOUT1");
            }
            else
            {
                NRF_LOG_ERROR("Transfer failed on EPOUT1: %d", p_event->data.eptransfer.status);
                nrf_drv_usbd_setup_stall();
            }
    	}
        else if (NRF_DRV_USBD_EPIN1 == p_event->data.eptransfer.ep) 
        {
            if (NRF_USBD_EP_OK == p_event->data.eptransfer.status) 
            {
                   //* If errata 154 is present the data transfer is acknowledged by the hardware. */
                    if (!nrf_drv_usbd_errata_154())
                    {
                        /* Transfer ok - allow status stage */
                        nrf_drv_usbd_setup_clear();
                    }
                    send_cnt++;
                    
                  //bsp_board_led_off(LED_SEND);

                   send_flag = 0;

            }
            else if (NRF_USBD_EP_ABORTED == p_event->data.eptransfer.status)
            {
                /* Just ignore */
                NRF_LOG_INFO("Transfer aborted event on EPIN1");
            }
            else
            {
                NRF_LOG_ERROR("Transfer failed on EPIN1: %d", p_event->data.eptransfer.status);
                nrf_drv_usbd_setup_stall();
            }
    	}
        if (NRF_DRV_USBD_EPIN0 == p_event->data.eptransfer.ep)
        {
            if (NRF_USBD_EP_OK == p_event->data.eptransfer.status)
            {
                if (!nrf_drv_usbd_errata_154())
                {
                    /* Transfer ok - allow status stage */
                    nrf_drv_usbd_setup_clear();
                }
            }
            else if (NRF_USBD_EP_ABORTED == p_event->data.eptransfer.status)
            {
                /* Just ignore */
                NRF_LOG_INFO("Transfer aborted event on EPIN0");
            }
            else
            {
                NRF_LOG_ERROR("Transfer failed on EPIN0: %d", p_event->data.eptransfer.status);
                nrf_drv_usbd_setup_stall();
            }
        }
        else
        if (NRF_DRV_USBD_EPOUT0 == p_event->data.eptransfer.ep)
        {
            /* NOTE: No EPOUT0 data transfers are used.
             * The code is here as a pattern how to support such a transfer. */
            if (NRF_USBD_EP_OK == p_event->data.eptransfer.status)
            {
                /* NOTE: Data values or size may be tested here to decide if clear or stall.
                 * If errata 154 is present the data transfer is acknowledged by the hardware. */
                if (!nrf_drv_usbd_errata_154())
                {
                    /* Transfer ok - allow status stage */
                    nrf_drv_usbd_setup_clear();
                }
            }
            else if (NRF_USBD_EP_ABORTED == p_event->data.eptransfer.status)
            {
                /* Just ignore */
                NRF_LOG_INFO("Transfer aborted event on EPOUT0");
            }
            else
            {
                NRF_LOG_ERROR("Transfer failed on EPOUT0: %d", p_event->data.eptransfer.status);
                nrf_drv_usbd_setup_stall();
            }
        }
        else
        {
            /* Nothing to do */
        }
        break;
    case NRF_DRV_USBD_EVT_SETUP:
        {
            nrf_drv_usbd_setup_t setup;
            nrf_drv_usbd_setup_get(&setup);
            switch (setup.bmRequest)
            {
            case 0x00: // GetStatus
                usbd_setup_GetStatus(&setup);
                break;
            case 0x01: // CleartFeature
                usbd_setup_ClearFeature(&setup);
                break;
            case 0x03: // SetFeature
                usbd_setup_SetFeature(&setup);
                break;
            case 0x05: // SetAddress
                //nothing to do, handled by hardware; but don't STALL
                break;
            case 0x06: // GetDescriptor
                usbd_setup_GetDescriptor(&setup);
                break;
            case 0x08: // GetConfig
                usbd_setup_GetConfig(&setup);
                break;
            case 0x09: // SetConfig
                usbd_setup_SetConfig(&setup);
                break;
            //HID class
            case 0x0A: // SetIdle
                usbd_setup_SetIdle(&setup);
                break;
            case 0x0B: // SetProtocol or SetInterface
                if (setup.bmRequestType == 0x01) // standard request, recipient=interface
                {
                    usbd_setup_SetInterface(&setup);
                }
                else if (setup.bmRequestType == 0x21) // class request, recipient=interface
                {
                    usbd_setup_SetProtocol(&setup);
                }
                else
                {
                    NRF_LOG_ERROR("Command 0xB. Unknown request: 0x%2x", setup.bmRequestType);
                    nrf_drv_usbd_setup_stall();
                }
                break;
            default:
                NRF_LOG_ERROR("Unknown request: 0x%2x", setup.bmRequest);
                nrf_drv_usbd_setup_stall();
                return;
            }
            break;
        }
    default:
        break;
    }
}


static void power_usb_event_handler(nrf_drv_power_usb_evt_t event)
{
    switch (event)
    {
    case NRF_DRV_POWER_USB_EVT_DETECTED:
        NRF_LOG_INFO("USB power detected");
        if (!nrf_drv_usbd_is_enabled())
        {
            nrf_drv_usbd_enable();
        }
        break;
    case NRF_DRV_POWER_USB_EVT_REMOVED:
        NRF_LOG_INFO("USB power removed");
        m_usbd_configured = false;
        if (nrf_drv_usbd_is_started())
        {
            nrf_drv_usbd_stop();
        }
        if (nrf_drv_usbd_is_enabled())
        {
            nrf_drv_usbd_disable();
        }
        /* Turn OFF LEDs */
        bsp_board_led_off(LED_USB_STATUS);
        bsp_board_led_off(LED_USB_POWER);
        bsp_board_led_on(LED_SEND);     
        bsp_board_led_on(LED_RECEIVE);
        break;
    case NRF_DRV_POWER_USB_EVT_READY:
        NRF_LOG_INFO("USB ready");
        bsp_board_led_on(LED_USB_POWER);
        bsp_board_led_on(LED_SEND);
        bsp_board_led_on(LED_RECEIVE);
        if (!nrf_drv_usbd_is_started())
        {
            nrf_drv_usbd_start(true);
        }
        break;
    default:
        ASSERT(false);
    }
}
static void clock_init(void)
{
    ret_code_t err_code = nrf_drv_clock_init();
    ASSERT((err_code == NRF_SUCCESS) || (err_code == NRF_ERROR_MODULE_ALREADY_INITIALIZED));
    nrfx_clock_hfclk_start();
    nrfx_clock_lfclk_start();

    nrf_drv_clock_hfclk_request(NULL);
    while (!nrf_drv_clock_hfclk_is_running())
    {
        // spin lock
    }
    nrf_drv_clock_lfclk_request(NULL);
    while (!nrf_drv_clock_lfclk_is_running())
    {
        // spin lock
    }
}
static void init_power_clock(void)
{
    ret_code_t ret;
    /* Initializing power and clock */
    APP_ERROR_CHECK(ret);
    ret = nrf_drv_power_init(NULL);
    APP_ERROR_CHECK(ret);
    
    clock_init();
    
    ret = app_timer_init();
    APP_ERROR_CHECK(ret);

    /* Avoid warnings if assertion is disabled */
    UNUSED_VARIABLE(ret);
}

static void bsp_evt_handler(bsp_event_t evt)
{
    switch ((unsigned int)evt)
    {
    case BSP_EVENT_SYSOFF:
    {
        m_system_off_req = true;
        break;
    }
    default:
        return;
    }
}

static void init_bsp(void)
{
    ret_code_t ret;
    ret = bsp_init(BSP_INIT_BUTTONS, bsp_evt_handler);
    APP_ERROR_CHECK(ret);

    ret = bsp_event_to_button_action_assign(
        BTN_SYSTEM_OFF,
        BSP_BUTTON_ACTION_RELEASE,
        BSP_EVENT_SYSOFF);
    APP_ERROR_CHECK(ret);
    ret = bsp_event_to_button_action_assign(BTN_DATA_SEND,
                                            BSP_BUTTON_ACTION_RELEASE,
                                            BTN_DATA_KEY_RELEASE);
    APP_ERROR_CHECK(ret);
    /* Avoid warnings if assertion is disabled */
    UNUSED_VARIABLE(ret);
}


int main(void)
{
    ret_code_t ret, ret_ep;
    UNUSED_RETURN_VALUE(NRF_LOG_INIT(NULL));
    
    init_power_clock();
    //init_bsp();

    NRF_LOG_INFO("USDB example started.");
    if (NRF_DRV_USBD_ERRATA_ENABLE)
    {
        NRF_LOG_INFO("USB errata 104 %s", (uint32_t)(nrf_drv_usbd_errata_104() ? "enabled" : "disabled"));
        NRF_LOG_INFO("USB errata 154 %s", (uint32_t)(nrf_drv_usbd_errata_154() ? "enabled" : "disabled"));
    }


    /* USB work starts right here */
    ret = nrf_drv_usbd_init(usbd_event_handler);
    APP_ERROR_CHECK(ret);

    /* Configure LED and button */
    bsp_board_init(BSP_INIT_LEDS);
    bsp_board_led_on(LED_RECEIVE);
    bsp_board_led_on(LED_SEND);
    
    
    if (USBD_POWER_DETECTION)
    {
        static const nrf_drv_power_usbevt_config_t config =
        {
            .handler = power_usb_event_handler
        };
        ret = nrf_drv_power_usbevt_init(&config);
        APP_ERROR_CHECK(ret);
    }
    else
    {
        NRF_LOG_INFO("No USB power detection enabled\r\nStarting USB now");
        nrf_delay_us(STARTUP_DELAY);
        if (!nrf_drv_usbd_is_enabled())
        {
            nrf_drv_usbd_enable();
            ret = ep_configuration(0);
            APP_ERROR_CHECK(ret);
        }
        /* Wait for regulator power up */
        while (NRF_DRV_POWER_USB_STATE_CONNECTED == nrf_drv_power_usbstatus_get())
        {
            /* Just waiting */
        }

        if (NRF_DRV_POWER_USB_STATE_READY == nrf_drv_power_usbstatus_get())
        {
            if (!nrf_drv_usbd_is_started())
            {
                nrf_drv_usbd_start(true);
            }
        }
        else
        {
            nrf_drv_usbd_disable();
        }
    }

     while (true)
    {

       if (receive_cnt == RECEIVE_FRAMES  && send_cnt < SEND_FRAMES)
       {
           nrf_drv_usbd_transfer_t transfer;
           transfer.p_data.tx = &rxTestData[send_cnt*EP1_MAXPACKETSIZE];
           transfer.size = EP1_MAXPACKETSIZE;
           
           bsp_board_led_off(LED_SEND);
           while(nrf_drv_usbd_ep_is_busy(NRF_DRV_USBD_EPIN1)); 
           ret = nrf_drv_usbd_ep_transfer(NRF_DRV_USBD_EPIN1, &transfer);
           bsp_board_led_on(LED_SEND);

#ifdef ENABLE_MY_PRINTS
           if (ret == NRF_SUCCESS)
           {
              printf("sent %d frames\n", send_cnt);
              printf("Sent %d bytes %dth times:\n", EP1_MAXPACKETSIZE, send_cnt);
              for (uint8_t i = 0; i < transfer.size; i++) printf("0x%02X ", *(rxTestData+(send_cnt*EP1_MAXPACKETSIZE+i)));
              printf("\n");

           }
           else
           {
              printf("ERROR = %d\n", ret);
           }
#endif           
       }
       else if (receive_cnt == RECEIVE_FRAMES  && send_cnt > SEND_FRAMES)
       {
            // led test points are inverted somehow
            bsp_board_led_on(LED_SEND);
            bsp_board_led_on(LED_RECEIVE);
            break;

       }
     
    }

}

I'm measuring the time spent to send and receive data on the usb device toggling LED's and measuring those using a logic analyzer.  

Using LED_SEND to measure time spent on ENDPOINTIN1 and using LED_RECEIVE to measure time on ENDPOINTOUT1. 

My understanding from the nRF52840_PS_v1.0.pdf,  usb has to run with the high frequency clock (which is 64 MHz ?) However even I don't run clock_init function (I comment out clock_init function (line#1052) I don't see any differences with the speed. It varies but it is very slow compared to expected bulk transfer rates.  At this point I don't know how to debug this speed issue further. I'm attaching two captures showing the SEND and RECEIVE times with and without hflck enabled. Can you please help with this?

Thank you and Best Regards,

Asli

Parents
  • Hi Asli

    Would it be an option to use the CDC or MSC USB classes instead?

    We have full examples for this in the SDK, and have tested them to work at speeds of > 200KBytes/sec.

    Best regards
    Torbjørn

  • Hi Torbjorn,

    Actually I'm defining a MSC device with bulk endpoints, modifying the usbd example which should provide the highest usb speed according to my understanding. My goal is evaluate the maximum usb rate available and show that it can reach ~600-700 kB/sec which is needed for our application.

    I went through the SDK examples but not sure how MSC and CDC examples will help me to reach faster speeds. 

    Is it possible to provide the USB speed measurement example (with both PC and device side code) where you can measure >200KBytes/sec? This would be a great help.

    Thanks,

    Asli

  • Hi Asli

    The device side code is just the standard SDK examples. 

    Currently the USB developers are unavailable, but once they are back I will ask if they can share some details on the host configuration when these tests were performed. 

    Best regards
    Torbjørn

  • Hi Asli

    I got the following descriptions for CDC and MSC testing respectively.

    CDC:

    1. Install Tera Term
    2. Flash CDC ACM example (logging and lack of event queue decreases performance), connect to COM
    3. Change speed to highest available (921600)
    4. Send a big file using binary option

    MSC:

    Quick notes how to test MSC transfers

    1. Connect MSC demo to the linux machine or linux virtual machine.
    2. Detect the device using dmesg command

      dmesg
    3. Search for our devices, they would look like this:

     

    [ 5089.681017] sd 6:0:0:0: [sdb] 64 512-byte logical blocks: (32.8 kB/32.0 KiB)
    [ 5089.689992] sd 6:0:0:1: [sdc] 1048576 512-byte logical blocks: (537 MB/512 MiB)

     

    Test read

     

    sdc is a detected device name:

    sudo dd if=/dev/sdc of=/dev/null bs=1M count=32 status=progress

    Test write

    sudo dd if=/dev/zero of=/dev/sdc bs=1M count=32 status=progress

    Real time statistic

     

    The status=progress seems not to work properly with /dev/zero as a source. How to view statistic anyway:

    http://askubuntu.com/questions/215505/how-do-you-monitor-the-progress-of-dd

    Best regards
    Torbjørn

  • Hi Torbjorn,

    Thank you for the update and suggested speed testing. 

    I'll repeat the tests and update the results when I'm done but I'm specifically looking for speed test with  Windows, where the data rate was measured >200 KBytes/sec with Windows as you wrote about earlier in the thread (please check your replies above)

    CDC rate is not high enough for our requirement and the issue I'm observing is the low and varying data rate with Windows as I explained above in the ticket.

    As an additional update, when I run my code with libusb on linux I see ~480 KBytes/sec  and the rate is not varying much as in Windows (with Windows it's varying a lot and the highest rate I get is ~100 KBytes/sec and mostly ~30 - 70 KBytes/sec).  So now I'm wondering whether there is a limitation with Windows no matter I'm using libusb and its drivers? 

    If you can provide the instructions for the speed test with Windows where the rate  is > 200 KBytes/sec that would be very helpful. 

    Thank you and Best Regards,

    Asli

  • Hi again,

    I tested the MSC device speed as instructed. Attached are the images for Write and Read speed.

    I see a high change (drop) in speed as the block and total data sizes are smaller. 

              - Is this speed drop expected and why is it happening?

    Write Test:

    MSC_Write_Speed_Test

    Read Test: 

    MSC_Read_Speed_Test

    I'm working on CDC_ACM speed test in order to evaluate it . I'll update once I have the results but please update with Windows example/instructions with >200 KBytes/sec data rate if available.

    Thank you and Best Regards,

    Asli

  • Hi Asli

    Reviewing the test results again I see that the only test results from Windows was using the CDC class, and the end result was 215 kB/s. 

    This was using the method desribed below, using Tera Term to send a binary file over the virtual comport. 

    Have you tried this test?

    I will try to repeat it myself to see if I can reproduce the issue of variability that you discovered. The original testing done by the USB team doesn't include any note of this. 

    Edit: Another important note is that logging must be disabled and the event queue enabled for optimal performance when running the CDC example. If you can't figure out how just let me know, and I will try to provide more detailed instructions. 

    Best regards
    Torbjørn

Reply
  • Hi Asli

    Reviewing the test results again I see that the only test results from Windows was using the CDC class, and the end result was 215 kB/s. 

    This was using the method desribed below, using Tera Term to send a binary file over the virtual comport. 

    Have you tried this test?

    I will try to repeat it myself to see if I can reproduce the issue of variability that you discovered. The original testing done by the USB team doesn't include any note of this. 

    Edit: Another important note is that logging must be disabled and the event queue enabled for optimal performance when running the CDC example. If you can't figure out how just let me know, and I will try to provide more detailed instructions. 

    Best regards
    Torbjørn

Children
  • Hi Torbjorn,

    I tried CDC_ACM device data speed test and I had the below results. I disabled logging and used the example modifying the tx data and it's size, sent known binary data and 64 bytes each time. I also increased the COM port baud rate to highest. I measured the time on LED_CDC_ACM_TX using  a scope)

    10 frames X 64 bytes => ~242 KBytes/sec

    100 frames X 64 bytes => ~220 KBytes/sec

    500 frames X 64 bytes => ~153 KBytes/sec

    4096 frames X 64 bytes => ~133 KBytes/sec (also measured ~120 KBytes or ~150 KBytes/sec)

    It seems like data rate is slowing down as the consecutive number of frames are higher. Also the data rate for the same number of frames might vary a bit.

    Please let me know your test results and if you have further description about testing if you think above results are unexpected.

    Thanks and Best Regards,

    Asli

  • Hi Asli

    I was able to repeat the test myself. I simply took the CDC_ACM example from SKD v15.2.0 and disabled logging. 

    I am getting a quite consistent data rate of 290-300 KBytes/sec, and if I send a large file the transfer rate seems very consistent throughout the file. 

    I tested it both on my new desktop computer and an older laptop with similar results, running Windows 10 in both cases. 

    Which version of Windows are you using, and are you able to test on another Windows computer to see if there are any differences?

    The developer was unavailable today unfortunately, so I didn't have a chance to discuss your results with him. I will try to get a hold of him tomorrow so I can get his feedback. 

    Best regards
    Torbjørn

  • Hi Torbjorn,

    I've just tested sending a binary file from the host to device using Tera Term 'Send File' with binary option, and I see 290-300 KBytes/sec similar to your test results  on TeraTerm file transfer window when I send a large file. I also measured the LED_CDC_ACM_RX toggling time and the data rate was within the range ~290 KBytes/sec.

    My test results above in the previous reply are for sending data from device to the host which our project will do data transfer mainly on this direction. As I mentioned before I just could measure the LED_CDC_ACM_TX toggling time as a measure of transfer time for the known binary data with various frame numbers. 

    Can you please confirm using LED_CDC_ACM_TX (or RX) toggling duration is roughly good enough to measure the data rate and confirm my device -> host data transfer rate results are as expected with developers?

    Thank you and Best Regards,

    Asli

  • Hi Asli

    The toggling of the LED will indicate a packet sent, that is correct, but measuring a single interval is not really enough as there is quite a bit of jitter from packet to packet. For this to work properly you would have to measure the total time taken over a larger number of transfers, and calculate an average. Maybe that is what you did to get the attached numbers?

    I tried to test the speed from device to host in a slightly different way. I modified the send function of the example to send 64 bytes on each transfer, but still include a counter in the string:

    if(m_send_flag)
    {
    static int frame_counter;
    for(int i = 0; i < 64; i++) m_tx_buffer[i] = '-';

    size_t size = sprintf(m_tx_buffer, "Hello USB CDC FA demo: %u\r\n", frame_counter);

    ret = app_usbd_cdc_acm_write(&m_app_cdc_acm, m_tx_buffer, 64);
    if (ret == NRF_SUCCESS)
    {
    ++frame_counter;
    }
    }

    Then I pressed button 1 on the kit for 30 seconds, and noted in the terminal how many transactions came through. 

    It ended up at 155909 packets of 64 bytes each, averaging out to about 330KB/sec.

    Running the test for a long time doesn't appear to slow down the transfer. 

    Maybe you can share the changes you did to send 10/100/500/4096 frames and I can try it out? 

    Alternatively, copy my changes above and try to repeat my test scenario.

    Best regards
    Torbjørn

  • Hi Torbjorn,

    I repeated your test, sent data to host for about 30 seconds  couple of times and I measure ~140 - 160 KBytes/sec not as high as your test result.

    I also did some measurements checking the number of frames on Tera Term similar to yours and measured the toggling LED_CDC_ACM_TX time but to set number of frames to 100, 500 or another number I did the below.

    I know it's not very accurate but this way I can test the small and exact number of frames. 

     1. I commented out the LED toggling in main.c line#163

                       case APP_USBD_CDC_ACM_USER_EVT_TX_DONE:
                              //bsp_board_led_invert(LED_CDC_ACM_TX);
                       break;

    2. Modified the while loop in  main function code as below:

       ......................................................................................................................

        for (int i = 0; i< 64; i++)
        {
            m_tx_buffer[i] = i;
        }
        static int frame_counter;

       // clear the led (it's opposite because of the LEDS_ACTIVE_STATE 0 in pca10056.h)
        bsp_board_led_on(LED_CDC_ACM_TX); 

        while (true)
        {
            while (app_usbd_event_queue_process())
            {
                /* Nothing to do */
            }

            if(m_send_flag)
            {
                bsp_board_led_off(LED_CDC_ACM_TX); //set the led
                ret = app_usbd_cdc_acm_write(&m_app_cdc_acm, m_tx_buffer, 64);
                if (ret == NRF_SUCCESS)
                {
                    ++frame_counter;
                }
             }

            if (frame_counter == 4096)
           {
               bsp_board_led_on(LED_CDC_ACM_TX);//clear the led
               break;
           }

         nrf_cli_process(&m_cli_uart);

    ............................................................................................................

    3. On Tera Term I save a log (only binary option is checked)

    4. Change the frame number for different data lengths

    I press the button and check the scope to see LED_CDC_ACM_TX go high and low during the transfer of total frame numbers and measure the 'high' time. I also check the Tera Term window to check the total amount of bytes as in the below image and use it for the data rate calculation.

    Please let me know if you can reproduce similar results.

    Best Regards, 

    Asli

Related