emusb-device
SEGGER emUSB-Device for ModusToolbox User Guide

emUSB-Device enables easy integration of USB functionality into an embedded system.Multiple standard classes are provided that allow embedded systems to behave as standard USB devices and communicate with any host like Windows, Linux and Mac systems. Infineon has licensed emUSB-Device from SEGGER and offers it for free to its customers. This middleware library provides emUSB-Device in the form of pre-build libraries.

Features:

  • High performance
  • Can be used with or without an RTOS
  • Easy to use
  • Easy to port
  • No custom USB host driver necessary

Supported USB Device Classes:

  • Audio
  • Legacy Audio V1 device class
  • Bulk communication
  • Smart Card Device Class (CCID)
  • Communication Device Class (CDC)
  • Human Interface Device Class (HID)
  • Mass Storage Device Class (MSD)
  • Media Transfer Protocol Class (MTP)
  • Printer Class
  • Virtual Mass Storage Component (VirtualMSD)
  • Vendor Specific Class (VSC)

Device families supported by the Middleware:

  • CAT1A
  • CAT3

General Description

This manual provides only the basic concepts of emUSB-Device and integration specifics of the emUSB-Device into ModusToolbox flow. For a detail description of the emUSB-Device features, implementation, and APIs, refer to: SEGGER emUSB-Device User Guide & Reference Manual.

Quick Start is available in this API Reference Guide.

emUSB-Device consists of the following layers:

  • The driver for hardware access
  • The emUSB-Device core
  • The USB class driver or the bulk communication component

emUSB-Device core and the USB class drivers are device-independent, while the driver for hardware access is applicable only for one device family. The driver is selected in the USBD_X_Config() function, the template of implementation of USBD_X_Config() is in the export/Config folder.

The drivers for emUSB-Device can support not all available features and may need to be configured in a special manners, refer to the: SEGGER emUSB-Device User Guide & Reference Manual Device driver specifics chapter.

Supported Drivers by the Device family

Device familyDriversPointer to the driver API structure
CAT1A Cypress PSoC 6 driver USB_Driver_Cypress_PSoC6
CAT3 Synopsys DWC2 driver (slave mode)
  • USB_Driver_Infineon_XMC45xx
  • USB_Driver_Infineon_XMC45xx_DynMem
Synopsys DWC2 driver (DMA mode) USB_Driver_Infineon_XMC45xx_DMA

For CAT3 device, the DMA engine of USB IP block does not have access to all SRAM regions. Check Reference Manual for CAT3 device for more information. As a result the memory pool for USB_Driver_Infineon_XMC45xx_DMA driver must be placed only to SRAM region with DMA access. Typically linker script provided with mtb-xmclib-cat3 defines special region - USB_RAM. You can place memory pool to USB_RAM by the next approach: CY_SECTION("USB_RAM") __USED static uint32_t mem_pool[512]. Also it is compulsory to register appropriate callback by USBD_SetCheckAddress(). This callback should check if an address can be used for DMA transfers. You can use the next variables from linker script to determine the borders of the SRAM region: USB_RAM_start, USB_RAM_end. The example of driver configuration is provided in usbd_config.c file.

Note
For the USBD_AddDriver() function description, refer to the: SEGGER emUSB-Device User Guide & Reference Manual.

The emUSB-Device is provided in the form of pre-build libraries. The pre-build library is selected automatically based on configuration of Application project.

The emUSB-device has been already implemented the Target OS Interface for both RTOS and non-RTOS aware environments. The Target OS Interface for RTOS environment is implemented by abstraction-rtos, so this Middleware can be used with any RTOSes supported by abstraction-rtos.

The hardware dependency files are present in export/Config directory, which consist of:

  • One common file responsible for the debug message output
  • Device-specific files for the hardware configuration of each supported device family

Also, the emUSB-Host/Device personality is present in the Device-configurator for simplify routine of configuration clocks and pins for USB IP block operation. The personality is a part of mtb-pdl-cat1 for CAT1A devices and mtb-xmclib-cat3 for CAT3 libraries.

Quick Start

To set up emUSB-Device for mouse and keyboard Human Interface Devices (HID), follow the below-described steps. These code snippets will move the mouse cursor left and right and print the "Hello world" message into the opened text editor. The current snippet is based on SEGGER sample application.

STEP 1: Add the emUSB-Device middleware.

  1. Launch the ModusToolbox Library Manager, click Add Library button and select the emUSB-Device. This step is required only if the ModusToolbox IDE is used. Otherwise, ensure that the emUSB-Device middleware is included in your project.
    Note
    To use the terminal output, add retarget-io middleware from the Library Manager.
    Add the FreeRTOS middleware into the Library Manager if you want to use the FreeRTOS.
  2. Open Makefile of the project. Add USBD_BASE to the COMPONENTS section of the Makefile.
    Note
    Add FREERTOS and RTOS_AWARE to the COMPONENTS section of the Makefile if you want to use FreeRTOS.

STEP 2: Configure pins and clocks for emUSB-Device.

CAT1A Devices:

  1. Launch the ModusToolbox Device Configurator and switch to the Peripherals tab (#1.1).
  2. Enable the USB personality under Communication (#1.2) and select the emUSB-Host/Device personality (#1.3).
  3. Ensure that USB mode is Device (#1.4) and the Clock is connected to CLK_HF3 (#1.5).
  4. Switch to the System tab (#2.1).

    Note
    The clocking system can be different between devices.
  5. Check the IMO clock is enabled (#2.2). Select Trim with the USB.
  6. If your device supports more than one PLL, select one. Enable the selected PLL and set a frequency of 48 MHz (#2.3).
    Note
    Select the enabled source clock with accuracy +/-0.25% into the PATH_MUX section of the selected PLL (#2.4).
  7. Select the CLK_HF3 USB clock (#2.5). Assign the source clock to the CLK_PATH connected to the configured previously PLL.
  8. Select the CLK_HF0 USB clock (#2.6). Assign the source clock to the CLK_PATH connected to the PLL with the clock accuracy +/-0.25%.
    Note
    You can use the PLL selected for CLK_HF3 or choose another one as it shown into the example (#2.7)
  9. If the Power personality is enabled, the System Idle Power Mode must be Active or CPU sleep.
  10. Select File->Save to generate initialization code.

CAT3 Devices:

  1. Launch the ModusToolbox Device Configurator Tool and switch to the Peripherals tab (#1.1).
  2. Enable the USB personality under Communication (#1.2).
  3. Select the USB mode as Device (#1.3).
  4. If you want to create a non-RTOS emUSB application, you should configure the emUSB OS Timer personality by selecting CCU4 source (#1.4) and configure the CCU4 Slice as the emUSB OS Timer personality (#1.5). Check the CCU for OS checkbox (#1.6) and select the appropriate emUSB OS Timer CCU Resource (#1.7).
  5. Follow the instructions in the bottom window to set up the clock source for USB. The USB clock source configuration must look like the configuration on the image below.
    Note
    You can also use System PLL instead USB PLL as a source.
    Recommended: set the highest frequency of System PLL Clock -> CPU Clock for proper work of USB functionality.
  6. Select File->Save to generate initialization code.

STEP 3: Write the code in main.c.

  1. Include headers to get access to the emUSB-Device functions and retarget-io.
    #include <ctype.h>
    #include "cybsp.h"
    #include "cy_retarget_io.h"
    /* Include emUSB-Device headers */
    #include "USB.h"
    #include "USB_HID.h"
    Note
    Include the following headers if you want to use FreeRTOS:
    /* Include FreeRTOS headers */
    #include "FreeRTOS.h"
    #include "task.h"
  2. Add a structure prototype with the information about emUSB-Device.
    static const USB_DEVICE_INFO device_info = {
    0x8765, /* VendorId */
    0x1116, /* ProductId. Should be unique for this sample */
    "Vendor", /* VendorName */
    "HID mouse/keyboard sample", /* ProductName */
    "12345678" /* SerialNumber */
    };
  3. Create a structure prototype for the keyboard data.
    typedef struct {
    uint16_t key_code;
    char key_char;
    } code_to_desc_t;
  4. Initialize the table of the keyboard keys code and the keys descriptions.
    static const code_to_desc_t key_code_to_string_table[] = {
    { 0x04, 'a'},
    { 0x05, 'b'},
    { 0x06, 'c'},
    { 0x07, 'd'},
    { 0x08, 'e'},
    { 0x09, 'f'},
    { 0x0A, 'g'},
    { 0x0B, 'h'},
    { 0x0C, 'i'},
    { 0x0D, 'j'},
    { 0x0E, 'k'},
    { 0x0F, 'l'},
    { 0x10, 'm'},
    { 0x11, 'n'},
    { 0x12, 'o'},
    { 0x13, 'p'},
    { 0x14, 'q'},
    { 0x15, 'r'},
    { 0x16, 's'},
    { 0x17, 't'},
    { 0x18, 'u'},
    { 0x19, 'v'},
    { 0x1A, 'w'},
    { 0x1B, 'x'},
    { 0x1C, 'y'},
    { 0x1D, 'z'},
    { 0x1E, '1'},
    { 0x1F, '2'},
    { 0x20, '3'},
    { 0x21, '4'},
    { 0x22, '5'},
    { 0x23, '6'},
    { 0x24, '7'},
    { 0x25, '8'},
    { 0x26, '9'},
    { 0x27, '0'},
    { 0x2C, ' '},
    { 0x37, '.'}
    };
  5. Add the keyboard and mouse HID reports. These reports are generated according to HID spec and HID Usage Tables specification.
    const uint8_t hid_report_keyboard[] =
    {
    USB_HID_GLOBAL_USAGE_PAGE + 1,
    USB_HID_USAGE_PAGE_GENERIC_DESKTOP,
    USB_HID_LOCAL_USAGE + 1,
    USB_HID_USAGE_KEYBOARD,
    USB_HID_MAIN_COLLECTION + 1,
    USB_HID_COLLECTION_APPLICATION,
    USB_HID_GLOBAL_USAGE_PAGE + 1,
    7,
    USB_HID_LOCAL_USAGE_MINIMUM + 1,
    224,
    USB_HID_LOCAL_USAGE_MAXIMUM + 1,
    231,
    USB_HID_GLOBAL_LOGICAL_MINIMUM + 1,
    0,
    USB_HID_GLOBAL_LOGICAL_MAXIMUM + 1,
    1,
    USB_HID_GLOBAL_REPORT_SIZE + 1,
    1,
    USB_HID_GLOBAL_REPORT_COUNT + 1,
    8,
    USB_HID_MAIN_INPUT + 1,
    USB_HID_VARIABLE,
    USB_HID_MAIN_INPUT + 1,
    1,
    USB_HID_LOCAL_USAGE_MINIMUM + 1,
    0,
    USB_HID_LOCAL_USAGE_MAXIMUM + 1,
    101,
    USB_HID_GLOBAL_LOGICAL_MINIMUM + 1,
    0,
    USB_HID_GLOBAL_LOGICAL_MAXIMUM + 1,
    101,
    USB_HID_GLOBAL_REPORT_SIZE + 1,
    8,
    USB_HID_GLOBAL_REPORT_COUNT + 1,
    6,
    USB_HID_MAIN_INPUT + 1,
    0,
    USB_HID_GLOBAL_USAGE_PAGE + 1,
    USB_HID_USAGE_PAGE_LEDS,
    USB_HID_LOCAL_USAGE_MINIMUM + 1,
    1,
    USB_HID_LOCAL_USAGE_MAXIMUM + 1,
    5,
    USB_HID_GLOBAL_LOGICAL_MINIMUM + 1,
    0,
    USB_HID_GLOBAL_LOGICAL_MAXIMUM + 1,
    1,
    USB_HID_GLOBAL_REPORT_SIZE + 1,
    1,
    USB_HID_GLOBAL_REPORT_COUNT + 1,
    5,
    USB_HID_MAIN_OUTPUT + 1,
    2,
    USB_HID_GLOBAL_REPORT_COUNT + 1,
    3,
    USB_HID_MAIN_OUTPUT + 1,
    1,
    USB_HID_MAIN_ENDCOLLECTION
    };
    const uint8_t hid_report_mouse[] =
    {
    USB_HID_GLOBAL_USAGE_PAGE + 1,
    USB_HID_USAGE_PAGE_GENERIC_DESKTOP,
    USB_HID_LOCAL_USAGE + 1,
    USB_HID_USAGE_MOUSE,
    USB_HID_MAIN_COLLECTION + 1,
    USB_HID_COLLECTION_APPLICATION,
    USB_HID_LOCAL_USAGE + 1,
    USB_HID_USAGE_POINTER,
    USB_HID_MAIN_COLLECTION + 1,
    USB_HID_COLLECTION_PHYSICAL,
    USB_HID_GLOBAL_USAGE_PAGE + 1,
    USB_HID_USAGE_PAGE_BUTTON,
    USB_HID_LOCAL_USAGE_MINIMUM + 1,
    1,
    USB_HID_LOCAL_USAGE_MAXIMUM + 1,
    3,
    USB_HID_GLOBAL_LOGICAL_MINIMUM + 1,
    0,
    USB_HID_GLOBAL_LOGICAL_MAXIMUM + 1,
    1,
    USB_HID_GLOBAL_REPORT_COUNT + 1,
    3,
    USB_HID_GLOBAL_REPORT_SIZE + 1,
    1,
    USB_HID_MAIN_INPUT + 1,
    USB_HID_VARIABLE, /* 3 button bits */
    USB_HID_GLOBAL_REPORT_COUNT + 1,
    1,
    USB_HID_GLOBAL_REPORT_SIZE + 1,
    5,
    USB_HID_MAIN_INPUT + 1,
    USB_HID_CONSTANT, /* 5 bit padding */
    USB_HID_GLOBAL_USAGE_PAGE + 1,
    USB_HID_USAGE_PAGE_GENERIC_DESKTOP,
    USB_HID_LOCAL_USAGE + 1,
    USB_HID_USAGE_X,
    USB_HID_LOCAL_USAGE + 1,
    USB_HID_USAGE_Y,
    USB_HID_GLOBAL_LOGICAL_MINIMUM + 1,
    (unsigned char)-127,
    USB_HID_GLOBAL_LOGICAL_MAXIMUM + 1,
    127,
    USB_HID_GLOBAL_REPORT_SIZE + 1,
    8,
    USB_HID_GLOBAL_REPORT_COUNT + 1,
    2,
    USB_HID_MAIN_INPUT + 1,
    USB_HID_VARIABLE | USB_HID_RELATIVE,
    USB_HID_MAIN_ENDCOLLECTION,
    USB_HID_MAIN_ENDCOLLECTION
    };
  6. Add the functions for adding the keyboard and the mouse to the USB stack.
    /*******************************************************************************
    * Function Name: add_keyboard
    ********************************************************************************
    *
    * Adds the HID keyboard device to the USB stack.
    *
    * \return Keyboard handler
    *
    *******************************************************************************/
    static USB_HID_HANDLE add_keyboard(void)
    {
    USB_HID_INIT_DATA init_data;
    USB_ADD_EP_INFO ep_int_in;
    USB_HID_HANDLE keyboard_handler;
    /* Sets the init_data elements with 0 */
    memset(&init_data, 0, sizeof(init_data));
    /* Sets the flags of the not-used state */
    ep_int_in.Flags = 0;
    /* Sets the IN-direction (Device to Host) */
    ep_int_in.InDir = USB_DIR_IN;
    /* Sets the interval of 8 ms (125 us * 64) */
    ep_int_in.Interval = 64;
    /* Sets the maximum packet size (64 for Interrupt) */
    ep_int_in.MaxPacketSize = USB_HS_INT_MAX_PACKET_SIZE;
    /* Sets the endpoint type as Interrupt */
    ep_int_in.TransferType = USB_TRANSFER_TYPE_INT;
    /* Initializes the endpoint handle data */
    init_data.EPIn = USBD_AddEPEx(&ep_int_in, NULL, 0);
    /* Gets the pointer to a report mouse descriptor */
    init_data.pReport = hid_report_keyboard;
    /* Initializes the size of the HID report descriptor */
    init_data.NumBytesReport = sizeof(hid_report_keyboard);
    /* Adds an HID keyboard device to the USB interface */
    keyboard_handler = USBD_HID_Add(&init_data);
    return keyboard_handler;
    }
    /*******************************************************************************
    * Function Name: add_mouse
    ********************************************************************************
    *
    * Adds the HID mouse device to the USB stack.
    *
    * \return Mouse handler
    *
    *******************************************************************************/
    static USB_HID_HANDLE add_mouse(void)
    {
    USB_HID_INIT_DATA init_data;
    USB_ADD_EP_INFO ep_int_in;
    USB_HID_HANDLE mouse_handler;
    /* Sets the init_data elements to 0 value */
    memset(&init_data, 0, sizeof(init_data));
    /* Sets the flags of the not-used state */
    ep_int_in.Flags = 0;
    /* Sets the IN-direction (Device to Host) */
    ep_int_in.InDir = USB_DIR_IN;
    /* Sets the interval of 8 ms (125 us * 64) */
    ep_int_in.Interval = 64;
    /* Sets the maximum packet size (64 for Interrupt) */
    ep_int_in.MaxPacketSize = USB_HS_INT_MAX_PACKET_SIZE;
    /* Sets the endpoint type as Interrupt */
    ep_int_in.TransferType = USB_TRANSFER_TYPE_INT;
    /* Initializes the endpoint handle data */
    init_data.EPIn = USBD_AddEPEx(&ep_int_in, NULL, 0);
    /* Gets the pointer to a report mouse descriptor */
    init_data.pReport = hid_report_mouse;
    /* Initializes the size of the HID report descriptor */
    init_data.NumBytesReport = sizeof(hid_report_mouse);
    /* Adds an HID mouse device to the USB interface */
    mouse_handler = USBD_HID_Add(&init_data);
    return mouse_handler;
    }
  7. Add the function for writing the keyboard data to the host.
    /*******************************************************************************
    * Function Name: keyboard_send_text
    ********************************************************************************
    *
    * Writes the keyboard data to the host.
    *
    * \param keyboard_handler The HID keyboard device handler.
    * \param keyboard_text The text data to send to the host.
    *
    *******************************************************************************/
    static void keyboard_send_text(USB_HID_HANDLE keyboard_handler, const char* keyboard_text)
    {
    uint8_t char_arr[8];
    char char_temp;
    uint32_t i;
    uint32_t j;
    uint32_t key_code_to_string_table_size;
    key_code_to_string_table_size = ((sizeof(key_code_to_string_table)) / (sizeof(key_code_to_string_table[0])));
    /* Sets all char_arr elements with 0 */
    memset(char_arr, 0, sizeof(char_arr));
    for (i = 0; keyboard_text[i] != 0; i++)
    {
    /* A character is uppercase if its hex value is less than 0x61 ('a')
    * and greater or equal to 0x41 ('A'), therefore we set the LeftShiftUp
    * bit for those characters
    */
    if (keyboard_text[i] < 0x61 && keyboard_text[i] >= 0x41)
    {
    /* Disables LeftShiftUp */
    char_arr[0] = (1 << 1);
    /* Converts the character to lowercase */
    char_temp = tolower((int)keyboard_text[i]);
    }
    else
    {
    char_temp = keyboard_text[i];
    }
    for (j = 0; j < key_code_to_string_table_size; j++)
    {
    if (key_code_to_string_table[j].key_char == char_temp)
    {
    /* Gets the character code */
    char_arr[2] = key_code_to_string_table[j].key_code;
    }
    }
    /* Writes data to the host */
    USBD_HID_Write(keyboard_handler, /* The HID instance */
    &char_arr[0], /* The pointer to the data array to send */
    8u, /* The number of bytes to send */
    0); /* The Timeout in milliseconds */
    /* Sets all char_arr elements with 0 */
    memset(char_arr, 0, sizeof(char_arr));
    /* Send a 0 field packet to tell the host that the key has been released */
    USBD_HID_Write(keyboard_handler, /* The HID instance */
    &char_arr[0], /* The pointer to the data array to send */
    8u, /* The number of bytes to send */
    0); /* The Timeout in milliseconds */
    /* The delay is 50 milliseconds */
    USB_OS_Delay(50);
    }
    }
  8. Add the function for writing the mouse movements data to the host.
    /*******************************************************************************
    * Function Name: mouse_moves
    ********************************************************************************
    *
    * Writes the mouse movements data to the host.
    *
    * \param mouse_handler The HID mouse device handler.
    * \param mouse_move gets data about the mouse movement.
    *
    *******************************************************************************/
    static void mouse_moves(USB_HID_HANDLE mouse_handler, int8_t mouse_move)
    {
    uint8_t move_arr[3];
    /* Sets all move_arr elements with 0 */
    memset(move_arr, 0, sizeof(move_arr));
    /* Gets the mouse movement value */
    move_arr[1] = (uint8_t)mouse_move;
    /* Writes data to the host */
    USBD_HID_Write(mouse_handler, /* The HID instance */
    &move_arr[0], /* The pointer to the data array to send */
    3u, /* The number of bytes to send */
    0); /* The Timeout in milliseconds */
    USB_OS_Delay(1000);
    }
  9. Initialize retarget-io to use the debug UART port:

    For CAT1A devices:

    static void retarget_io_init(void)
    {
    /* Configures the retarget_io pins */
    cy_rslt_t result;
    result = cy_retarget_io_init(CYBSP_DEBUG_UART_TX, CYBSP_DEBUG_UART_RX, CY_RETARGET_IO_BAUDRATE);
    if (CY_RSLT_SUCCESS != result)
    {
    CY_ASSERT(0);
    }
    }

    For CAT3 devices:

    static void retarget_io_init(void)
    {
    /* Configures the retarget_io pins */
    cy_rslt_t result;
    result = cy_retarget_io_init(CYBSP_DEBUG_UART_HW);
    if (CY_RSLT_SUCCESS != result)
    {
    XMC_ASSERT(0, "cy_retarget_io_init returns error status");
    }
    }
  10. Create the main_task() function
    /*******************************************************************************
    * Function Name: main_task
    ********************************************************************************
    *
    * Initializes the emUSB-Device stack.
    *
    * \param arg is not used in this function but required for using FreeRTOS.
    *
    *******************************************************************************/
    void main_task(void* arg)
    {
    (void)arg;
    retarget_io_init();
    /* Mouse movement values */
    int8_t mouse_move_left = -75;
    int8_t mouse_move_right = 75;
    /* The output text from the keyboard */
    const char* keyboard_text = "Hello world! ";
    USB_HID_HANDLE mouse_handler;
    USB_HID_HANDLE keyboard_handler;
    /* Initialization of emUSB-Device */
    USBD_Init();
    /* Adds the HID keyboard device to the USB stack */
    keyboard_handler = add_keyboard();
    /* Adds the HID mouse device to the USB stack */
    mouse_handler = add_mouse();
    /* Sets information used during the device enumeration */
    USBD_SetDeviceInfo(&device_info);
    /* Starts emUSB-Device */
    USBD_Start();
    while (1)
    {
    /* Waits for configuration */
    while ((USBD_GetState() & (USB_STAT_CONFIGURED | USB_STAT_SUSPENDED)) != USB_STAT_CONFIGURED)
    {
    /* Do something to indicate waiting for configuration */
    }
    /* Moves the mouse cursor left and right */
    mouse_moves(mouse_handler, mouse_move_left);
    mouse_moves(mouse_handler, mouse_move_right);
    /* Prints the text */
    keyboard_send_text(keyboard_handler, keyboard_text);
    }
    }
  11. Call main_task():

    For non-RTOS environments:

    Call the main_task() into the main() function.

    main_task(NULL);

    For RTOS environments:

    Create a FreeRTOS task with main_task() using xTaskCreate and start the task scheduler instead of calling main_task():

    /* Creates a FreeRTOS task of the main_task() function */
    xTaskCreate(main_task, "main_task", 500U, NULL, configMAX_PRIORITIES - 6, NULL);
    vTaskStartScheduler();
    Warning
    Typically, the default interrupt priority-configuration from the usbd_config.c file will work with the default FreeRTOS config file. For a malfunction USB project, ensure that the USB interrupt priority is aligned with MAX_API_CALL_INTERRUPT_PRIORITY. See Using emUSB-Device in an RTOS Environment.

STEP 4: Check the emUSB-Device workability.

  1. Build and program your project.
  2. Connect the USB-Device connector to the PC host.
  3. Observe the mouse cursor move and print the "Hello world" message into the text editor.

Configuration Considerations

This section explains the details of the emUSB-Device configuration.

Hardware-dependent Configuration

The hardware resources (Pins, clocks, interrupts) required for USB must be configured before the start of USB operation before calling USBD_Init() or in USBD_X_Config(). Interrupts must be configured in the USBD_X_Config() function. Also, USBD_X_EnableInterrupt() and USBD_X_DisableInterrupt() must be implemented when the USBD_OS_USE_USBD_X_INTERRUPT compile time option is enabled.

The implementation template of USBD_X_Config(), USBD_X_EnableInterrupt() and USBD_X_DisableInterrupt() is provided for each device category in the Config directory under COMPONENT_CATx. This template is automatically copied into your project when middleware is added to project. This template does not include the configuration of clock and pins required for USB operation.

For details on Hardware Dependent Configuration, refer to the - SEGGER emUSB-Device User Guide & Reference Manual.

USB Pins Configuration

CAT1A Devices Family

The D+ and D- pins must be configured for USB operation. The emUSB-Host/Device personality in the Device Configurator allows for easy configuration of configuration of the pins. Otherwise, the pins can be configured manually by PDL APIs.

The following snippet initializes GPIO pins for USB operation by mtb-pdl-cat1 APIs.

Cy_GPIO_Pin_FastInit(USBDP_PORT, USBDP_PIN, CY_GPIO_DM_ANALOG, 0U, USBDP_GPIO);
Cy_GPIO_Pin_FastInit(USBDM_PORT, USBDM_PIN, CY_GPIO_DM_ANALOG, 0U, USBDM_GPIO);

CAT3 Devices Family

The D+/D- pins are dedicated and do not require configuration.

USB Clock Configuration

The USB 2.0 specification defines the required bit rate accuracy for the device in section 7.1.11. Ensure that the clock sources for USB meet the requirements.

The emUSB-Host/Device personality in the Device Configurator allows for easy configuration of the clocks for USB operation and also check if the clocks meet the requirements. Otherwise, the clocks can be configured manually by PDL/HAL APIs for CAT1A and by XMCLIB for CAT3.

CAT1A Devices Family

The USB device requires two clocks for operation:

  • Clock the main clock at 48 MHz. Typically, the main clock is CLK_HF3 output signal, but refer to the device datasheet to identify the clock source for USB for a specific device.
  • Clock the Clock (Bus Reset) at 100 kHz. Typically, Clock (Bus Reset) is connected to CLK_PERI through peripheral clock dividers but refer to the device datasheet to identify the Clock (Bus Reset) source for USB for a specific device.

Both these clocks must be configured with the defined bit rate accuracy per USB 2.0 specification.

Note
Ensure that the clock sources for USB meet the requirements.

CAT3 Devices Family

The USB Device requires two clocks for operation:

  • The USB Phy Clock output must be configured at 48 MHz frequency with required bit rate accuracy according to the USB 2.0 specification.
  • The second USB clock is connected to CPU clock. The CPU clock should be set to highest frequency as possible according to application design. If the CPU clock will have too low frequency the some of USB functionality won't work properly. For more details, refer to the Reference Manual of your CAT3 device.
Note
If the USB must operate during Deep Sleep, keep both clocks enabled.

USB Interrupt Configuration

The interrupt is mandatory for the emUSB-Device Middleware operation. The interrupt priority selection is a part of Application level - the interrupt priority selected in the template files is not suitable for real project. For USB recommended setting the interrupt priority as high as possible.

CAT1A Devices Family

emUSB-Device uses only one interrupt source from the three available in the IP USB block - usb_interrupt_med_IRQn. The emUSB-Device code can be executed on CM4 and CM0+ cores. For CM0+, the interrupt source of the USB IP block can be connected to one of CM0+ IRQs. Refer to the device datasheet and SysInt (System Interrupt) Driver documentation to find the available IRQs for CM0+.

  • The following code snippet shows the interrupt configuration for both CM4 and CM0+ cores.
    /* Define the interrupt source */
    #if (COMPONENT_CM0P)
    /* The number of CM0+ interrupt vectors is different for different devices,
    * so, change the following macro for your selected device.
    */
    #define USBD_INTERRUPT_NUM (NvicMux7_IRQn)
    #else
    #define USBD_INTERRUPT_NUM (usb_interrupt_med_IRQn)
    #endif /* #if (COMPONENT_CM0P) */
    /* Define the interrupt priority */
    #define USBD_ISR_PRIO (3U)
    /* Register this function as a callback in USBD_SetISREnableFunc(). */
    static void enable_isr(USB_ISR_HANDLER * pfISRHandler)
    {
    /* Install interrupt service routine */
    cy_rslt_t result;
    result = cyhal_system_set_isr(USBD_INTERRUPT_NUM, usb_interrupt_med_IRQn, USBD_ISR_PRIO, pfISRHandler);
    CY_ASSERT(CY_RSLT_SUCCESS == result);
    (void) result; /* To avoid the compiler warning in Release mode */
    NVIC_EnableIRQ(USBD_INTERRUPT_NUM);
    }
Note
The number of CM0+ interrupt vectors is different for different devices, so, this code snippet may not be suitable for all devices.

CAT3 Devices Family

CAT3 devices have only one interrupt source in the IP USB block - USB0_0_IRQn.

  • The following code snippet shows the interrupt configuration for CAT3 devices:
    /* Define interrupt priority. In case of FreeRTOS ensure that
    * configMAX_SYSCALL_INTERRUPT_PRIORITY in FreeRTOSConfig.h is
    * configured in accordance to XMC4xxx interrupts configuration
    */
    #define USBD_ISR_PRIO (63U)
    static USB_ISR_HANDLER * p_usb_isr_handler;
    /*********************************************************************
    *
    * USB0_0_IRQHandler
    * Function description
    * USB IRQ Handler
    *
    */
    void USB0_0_IRQHandler(void)
    {
    (p_usb_isr_handler)();
    }
    /* Register this function as a callback in USBD_SetISREnableFunc(). */
    static void enable_isr(USB_ISR_HANDLER * pfISRHandler)
    {
    p_usb_isr_handler = pfISRHandler;
    NVIC_SetPriority(USB0_0_IRQn, USBD_ISR_PRIO);
    NVIC_EnableIRQ(USB0_0_IRQn);
    }

CAT3 Specific Configuration

Some of CAT3 devices features, which affect the USB functionality are implemented outside of USB IP block and can not be configured inside emUSB-Device middleware. These features include: enable/disable power to the USB IP block, enable/disable reset state for the USB IP block and enable/disable the pull-up resistor. All mentioned features can be configured by SCU driver from mtb-xmclib-cat3.

Additional USB configuration steps for CAT3 devices:

  1. Enable the power for USB by using XMC_SCU_POWER_EnableUsb().
  2. De-assert Reset from USB controller by calling XMC_SCU_RESET_DeassertPeripheralReset(XMC_SCU_PERIPHERAL_RESET_USB0) for executing the USB functionality.
  3. Create the callback function which enable USB weak pull-up resistor by XMC_SCU_PCU_EnableUsbPullUp() as it shown in the following code snippet.
    /*********************************************************************
    *
    * hw_attach
    * Function description
    * Enable USB weak pull-up at PADN state
    *
    */
    static void hw_attach(void)
    {
    XMC_SCU_PCU_EnableUsbPullUp();
    }
    The described callback is registers into USBD_SetAttachFunc().
    Note
    It is recommended to enable pull-up only inside a callback registered by USBD_SetAttachFunc().
    Those steps are already implemented in usbd_config.c for CAT3 devices. You can use this file as reference.

Debug Message Output

The debug builds of emUSB-Device allow using the debug message outputs. The template implementation of the message output functions is in export/Config/usbd_config_io.c file. This file is automatically copied into the ModusToolbox project when emUSB-Device middleware is added for the first time by the Library manager. Otherwise, copy this file manually. By default, retarget-io is used for the message output, but message outputs can be redefined to any suitable output way. To disable the default message outputs, set USBD_DISABLE_STANDARD_OUTPUT=1 in the DEFINES variable in the application project Makefile. To provide a custom output method in addition to setting a variable add corresponding API under the #if (USBD_DISABLE_STANDARD_OUTPUT == 1U) condition inside the _puts() function.

For details on Hardware Debug Message Output, refer to the - SEGGER emUSB-Device User Guide & Reference Manual Debugging chapter.

Note
The retarget-io middleware must be configured outside of the emUSB-Device middleware for the message output. Refer to the retarget-io Quick Start.
The retarget-io does not send the debug message from the interrupt in RTOS aware environments. These messages are ignored. But some of them can be critical for debugging. For this case recommended to use other message output method to print all messages.

Low Power Support

The USB Host can initiate Suspend condition on the USB bus to reduce power consumption of the connected device. emUSB-Device can identify Suspend condition in a few ways. For example: calling USBD_GetState() through a specific time interval (typically 1 ms), by the callback function registered in USBD_RegisterSCHook() or by the other ways supported in the emUSB-Device stack. When Suspend condition is identified, the suspended device must limits the current consumption from VBUS to 0.5 mA. Therefore, put the device into Low-power mode to consume less current. emUSB-Device does not change the microcontroller Power mode by itself. It is the application responsibility to reduce power consumption to meet the requirements. Also, it is the application responsibility to prepare emUSB-Device for low-power mode and detect Resume condition. The preparation of the emUSB-Device middleware for low-power mode and detection of Resume condition differ among devices. Pay attention for the following explanation for the required devices.

Refer to the - SEGGER emUSB-Device User Guide & Reference Manual Low power mode chapter for additional information about the behavior of emUSB-Device in low-power mode.

Typically, the microcontroller enters Deep Sleep or similar mode to achieve the required current consumption, but other approaches are also possible if they exist. The next table shows the recommended low-power modes for Suspend state for each supported device:

Device familyRecommended low-power mode
CAT1A Deep Sleep
CAT3 Deep Sleep
Note
After a wake-up from low-power modes in which USB IP block cannot operate, the emUSB-Device must be re-initialized (Except Deep Sleep mode for CAT1A device).

CAT1A Devices Family

The USB IP block operates in Active and Sleep mode without any limitations, but in Deep Sleep, the USB IP block is disabled.

Note
No need to call USBD_DeInit() or USBD_Stop() before entering low-power mode and USBD_Init() or USBD_Start() after wake up contrary to described in SEGGER emUSB-Device User Guide & Reference Manual Low power mode chapter. If they are called, emUSB-Device does not return from Deep Sleep to the previous state after a wake up. The USB Host will probably identify some sets of events like disconnecting the old device and connecting a new device.

emUSB-Device has two additional functions only for CAT1A devices, which take part in detecting Suspend condition and restoring emUSB-Device after Deep Sleep - USB_DRIVER_Cypress_PSoC6_SysTick() and USB_DRIVER_Cypress_PSoC6_Resume(). The application must call USB_DRIVER_Cypress_PSoC6_SysTick() every millisecond in order to get suspend events handled. The USB_DRIVER_Cypress_PSoC6_Resume() function must be called after waking up from Deep Sleep low-power mode. For details, about these functions refer to the SEGGER emUSB-Device User Guide & Reference Manual PSoC6 driver chapter.

Note
After waking up from Deep Sleep, USBD_GetState() can returns the Suspend status for some time. Wait up to 10 milliseconds and then check the USB status with USBD_GetState() because USB_DRIVER_Cypress_PSoC6_SysTick() requires some time for identifying the Resume condition.

The USB IP block is disabled during Deep Sleep mode, so, additional configuration of the D+ pins is required. Configure the falling edge interrupt on the D+ pin (before entering Deep Sleep) to exit low-power mode when the Host drivers resume. The interrupt on the D+ pin wakes up the device from low-power mode when the Host drivers resume. The interrupt is allowed only when emUSB-Device is in Suspended state and the microcontroller in Deep Sleep mode to prevent frequent triggering of GPIO interrupt and loading CPU.

/* Interrupt mask for D+ pin */
#define GPIO_DP_INT_MASK (1U)
/* Configuration structure for D+ pin interrupt */
static cy_stc_sysint_t dp_pin_interrupt_cfg =
{
.intrSrc = ioss_interrupts_gpio_14_IRQn,
.intrPriority = 0U,
};
/* Interrupt handler for D+ pin */
void dp_pin_isr(void)
{
/* Check if an interrupt on the D+ pin was generated */
if (Cy_GPIO_GetInterruptStatusMasked(USBDP_PORT, USBDP_PIN))
{
/* Clear D+ interrupt flag */
Cy_GPIO_ClearInterrupt(USBDP_PORT, USBDP_PIN);
}
}
/* Initialize and configure an interrupt for the D+ pin to detect Resume condition */
void init_dp_interrupt(void)
{
/* Initialize an interrupt on the D+ pin to detect Resume condition */
if (CY_RSLT_SUCCESS != Cy_SysInt_Init(&dp_pin_interrupt_cfg, &dp_pin_isr))
{
/* Insert error handler */
CY_ASSERT(0);
}
/* Set up generation of an interrupt on the falling edge */
Cy_GPIO_SetInterruptEdge(USBDP_PORT, USBDP_PIN, CY_GPIO_INTR_FALLING);
Cy_GPIO_SetInterruptMask(USBDP_PORT, USBDP_PIN, GPIO_DP_INT_MASK);
}
Note
For a non-RTOS environment, disable the default timer for measuring the tick count (set USBD_NORTOS_TICKCNT_ENABLE macro to 0 in Makefile) and provide a specific implementation. For details, see Using emUSB-Device in an RTOS Environment

The next code snippets show preparing/restoring emUSB-Device before/after Deep Sleep.

/* Enable interrupt for D+ pins before entering Deep Sleep
* for detecting Resume condition on USB Bus
*/
void enable_dp_interrupt(void)
{
/* Clear D+ interrupt flag */
Cy_GPIO_ClearInterrupt(USBDP_PORT, USBDP_PIN);
/* Clear any pending interrupt */
NVIC_ClearPendingIRQ(dp_pin_interrupt_cfg.intrSrc);
/* Enable the D+ interrupt */
NVIC_EnableIRQ(dp_pin_interrupt_cfg.intrSrc);
}
/* Prepare emUSB-Device after wake-up from Deep Sleep
* for further operation
*/
void prepare_emusb_after_lpm(void)
{
/* Disable the D+ interrupt */
NVIC_DisableIRQ(dp_pin_interrupt_cfg.intrSrc);
/* Resume emUSB-Device */
USB_DRIVER_Cypress_PSoC6_Resume();
/* Wait up to 10 milliseconds for updating emUSB-Device state */
USB_OS_Delay(10);
}

CAT3 Devices Family

The USB IP block can operate in Active, Sleep, and Deep Sleep mode. For Sleep and Deep Sleep modes, the USB IP block clocking must remain active. This means that USB Phy Clock and System Clock must be enabled during low-power modes. After detecting Resume condition, the CAT3 device exits Deep Sleep mode (The USB interrupt wake-up microcontroller) and enters Active power mode.

If Suspend condition is detected, the device goes to Deep Sleep mode but the USB remains enabled. Example of configuration CAT3 device with enabled USB during Deep Sleep mode:

XMC_SCU_CLOCK_SetDeepSleepConfig(XMC_SCU_CLOCK_DEEPSLEEP_MODE_CONFIG_ENABLE_USB);
XMC_SCU_POWER_WaitForInterrupt(XMC_SCU_POWER_MODE_DEEPSLEEP, false);
Note
You can disable/enable the clock sources in Deep Sleep power mode by adding the appropriate clock source into XMC_SCU_CLOCK_SetDeepSleepConfig().

emUSB-Device in RTOS environment

Typically, RTOS decide to go to Idle state when no active tasks remain active. Often, the transition into Idle condition is accompanied by entering the microcontroller in one of low-power modes (Depends on RTOS configuration). But the USB device must provide correct responses to all events on the USB bus. The preventing mechanism must be implemented, which does not allow the microcontroller to enter low-power mode when emUSB-Device is not in Suspended state. For example, for FreeRTOS, a custom implementation of vApplicationSleep() must be provided.

Link Power Management (LPM)

emUSB-Device supports the Link Power Management feature like the configuration BESL (Best Effort Service Latency) value and reports on LPM transition on USB lines (L0 <--> L1).

To enable LPM:

  1. Call the USBD_UseV210() function in USBD_X_Config().
  2. (optional) Set the recommended BESL values by USBD_SetBESLValues().
  3. Register the callback, which reports on the LPM state transition by USBD_SetOnLPMChange().
  4. Define the behavior of the device on LPM request from the Host by USBD_SetLPMResponse() (reject or acknowledge the LPM request). Call USBD_SetLPMResponse() after USBD_Start(), otherwise, the response configuration may be lost.

Based on the received BESL value, the application can determine the level of the power optimization and select appropriate low-power modes. The behavior of the USB IP block during low-power modes for each device described in Low Power Support.

Note
For the CAT1A device, USB_DRIVER_Cypress_PSoC6_SysTick() must be called every millisecond and USB_DRIVER_Cypress_PSoC6_Resume() after a wake-up from Deep Sleep as well as for Suspend functionality.

For more information about LPM, refer to "USB 2.0 Link Power Management Addendum" and "Errata for USB 2.0 ECN: Link Power Management (LPM) - 7/2007" from usb.org.

Note
CAT3 devices do not support LPM features.

Only PDL APIs support

By default, emUSB-Device requires HAL APIs for operation. However, when HAL APIs cannot be used in the application, the USBD_USE_PDL option is available. With this macro set to 1, the emUSB-Device middleware will use PDL APIs instead of HAL APIs. When USBD_USE_PDL=1, the application must disable the standard debug output (USBD_DISABLE_STANDARD_OUTPUT=1) and, in a non-RTOS environment, provide the custom implementation for USB_OS_GetTickCnt() function (USBD_NORTOS_TICKCNT_ENABLE=0). The USBD_USE_PDL macro must be set in the DEFINES variable in the application project Makefile.

Note
This section is applicable only for CAT1A devices.

Picking an emUSB-Device Library Variant

The Middleware provides emUSB-Device as pre-build libraries. The pre-build libraries are selected automatically based on configurations of Makefile configurations. The table below shows the availability of the configuration options.

ConfigurationOptionsMake Variable
Device family CAT1A, CAT3 DEVICE_COMPONENTS
Build configuration Debug, Release CONFIG
Core
  • CM0P, CM4 for CAT1A;
  • CM4 for CAT3;
CORE
Floating point hardfp, softfp VFP_SELECT
Toolchain GCC_ARM, IAR, ARM TOOLCHAIN
Warning
CAT3 device family supports only GCC_ARM compiler
Note
Typically, the device family and core are selected in BSP Makefile.
CM0P supports only softfp.

Pre-build libraries configuration

Some of the parameters/features of emUSB-Device are configured by the compile-time options (like the number of the interface that supports the ISO transfer, etc) during generation of pre-build libraries and cannot change in run-time. Header file USBD_ConfDefaults.h under the USBD directory contains the common compile time options used during pre-build libraries creation. Similarly, USBD_Conf.h under each COMPONENT_<Device family>/CONFIG_< Build configuration> directory contains the compile time options specific to the set of library variants. The compile time options defined in USBD_Conf.h have a higher priority than in USBD_ConfDefaults.h. Most of the compile time options are defined in these two header files but some are not visible like the macro, which define the number of interfaces. This section describes the compile time options not defined in USBD_Conf.h and USBD_ConfDefaults.h.

This table shows the number of supported interfaces for each class between the device families.

USB ClassCAT1ACAT3
Audio 1 1
Legacy Audio 1 1
Bulk 4 3
CCID 1 1
CDC 2 2
HID 2 2
MSD 1 1
MTP 1 1
Printer 1 1
VirtualMSD 1 1
VSC Limited by USB_MAX_NUM_IF Limited by USB_MAX_NUM_IF Limited by USB_MAX_NUM_IF
Note
The MSD and MTP classes support the connection to up-to-four logical/storage units.

Using emUSB-Device in an RTOS Environment

The emUSB-device has been already implemented the Target OS Interface for both RTOS and non-RTOS aware environments. Selecting the OS layer implementation is automatic based on the RTOS_AWARE component. To inform the emUSB-Device that an RTOS environment is being used, set the RTOS_AWARE component (COMPONENTS+=RTOS_AWARE).

For the RTOS environment, the OS layer uses the abstraction-rtos library, and as a result, the emUSB-Device can be used with RTOSes supported by the abstraction-rtos library.

Specific implementation of Target OS Interface:

  • USB_OS_DecRI() and USB_OS_IncDI() have only alternate implementation because the USBD_OS_USE_USBD_X_INTERRUPT compile time option is enabled. Alternate implementation is more effective compared to the standard one because it allows disabling/enabling USB interrupts only before entering/exiting the critical section for emUSB-device.
  • The emUSB-Device middleware calls some functions of the OS layer from the USB interrupt. As a result, the USB interrupt priority must be aligned with the RTOS configuration. For example, for FreeRTOS, the USB interrupt must have a lower or equal priority to the MAX_API_CALL_INTERRUPT_PRIORITY macro.
  • For non-RTOS environments: For CAT1A devices: USB_OS_GetTickCnt() configures one instance of the timer by Timer (Timer/Counter) Driver of HAL library for returning the current system time in milliseconds. The timer is started by initializing the emUSB-Device middleware.

    To use USB_OS_GetTickCnt() with CAT3 devices:

    1. Enable emUSB OS Timer personality in the Device Configurator->Peripherals->Digital->CCU4 section:
    2. Select the Device mode of emUSB personality. Select the CCU4 configured as emUSB OS Timer from the drop down list of "CCU for OS" section of emUSB personality.
      USB_OS_GetTickCnt() configures the 1 millisecond timer using CCU4 driver reserved by emUSB OS Timer personality. The interrupt priority of reserved CCU4 is 63.

    USB_OS_GetTickCnt() own implementation can be provided due to:

    • The optimization of handling the ISR routine (the timer generates an interrupt every 1 millisecond);
    • Providing more reliable implementation (the timer value reloads every 49 days, 17 hours, 2 mins, 47.296 seconds);
    • The optimization of the HW resources usage (one instance of the TCPWM counter or similar HW resources, which can be used by Timer (Timer/Counter) Driver);

    To do that, set the USBD_NORTOS_TICKCNT_ENABLE macro value to zero in Makefile file.

    Note
    For CAT1A devices: The own implementation of USB_OS_GetTickCnt() must be provided if the application uses the transit into Deep Sleep or Hibernate low-power modes.
  • For Free-RTOS, USB tasks priority must be lower than the priority of RTOS daemon tasks (also known as timer service tasks). The RTOS daemon task priority is defined in configTIMER_TASK_PRIORITY.

For details on Target OS Interface, refer to the - SEGGER emUSB-Device User Guide & Reference Manual Target OS Interface chapter.

emUSB-Device Package Structure

The Middleware structure:

  • export/Config: Contains sample configuration files for hardware-specific configuration.
  • OS: Contains the OS layer implementation.
  • USBD: Contains a set of pre-build emUSB-Device libraries for different configurations of user applications (Device family, Build configuration, Core, Floating point, Toolchain), and a set of header files.
  • tool: Contains the tool for code generation (Audio class only).
  • docs: Contains the API Reference Guide, SEGGER-provided emUSB-Device User Guide & Reference Manual and other supporting documentation.

Changelog

Note that the emUSB-Device Middleware by Infineon and emUSB-Device stack by Segger have different versions

VersionChangesReason for Change
1.3.0 Added support of Smart Card Device Class (CCID) Extending the supported features for emUSB-Device middleware
Added new Audio class with extended features like compatibility to USB Audio version 2 device class, explicit feedback and others. The legacy Audio class is not recommended to use in new applications. Extending the supported features for emUSB-Device middleware
Updated the emUSB-Device stack to 3.62.0 New version is available
Added the new compile time option to allow use emUSB-Device without HAL library. For details, refer to the Only PDL APIs support. Extending the supported features for emUSB-Device middleware
The maximum number of alternative interfaces are increased from 2 to 4 for all supported device families (See the USB_MAX_NUM_ALT_IF macro in the USB_Conf.h file).
Minor documentation updates
1.2.0 Provided support for CAT3 devices.
Updated the emUSB-Device stack to 3.60.1 New version is available
Added a new section in the documentation Pre-build libraries configuration
Minors improvements in OS layer
1.1.0 Updated the emUSB-Device stack to 3.58.0 New version is available
Added support of Audio class Extending the supported features for emUSB-Device middleware
The OS layer uses abstraction-rtos APIs instead of FreeRTOS. This means that emUSB-Device can be used with RTOS supported by abstraction-rtos including FreeRTOS Extend the number of supported RTOS
The next compile time options were updated for CAT1A devices:
  • The maximum numbers of DATA Endpoints increased from 7 -> 8 (See the USB_NUM_EPS macro in the USB_Conf.h file),
    Note
    USB_NUM_EPS define number data endpoints + 1 control endpoint
  • The maximum numbers of Bulk interface increased from 1 -> 4
  • The maximum number of interface association descriptors increased 3 -> 4 (See the USB_MAX_NUM_IAD macro in the USB_Conf.h file).
  • The maximum number of Microsoft OS descriptors increased from 3 -> 4 (See the USB_MAX_NUM_MS_DESC macro in the USB_Conf.h file).
Extending the supported features for CAT1A devices
Added remote wake-up functionality for CAT1A devices Extending the supported features for CAT1A devices
Updated the implementation of Debug Message Output. The usbd_config_io.c file became more friendly for updating and a USBD_DISABLE_STANDARD_OUTPUT macro was added. For details, refer to Debug Message Output Improved the usability of Debug Message Output
Added a new section in the documentation Link Power Management (LPM)
Minor documentation updates
1.0.1 Updating the LICENSE file
1.0.0 Initial release of emUSB-Device stack 3.52.2