This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C123FH6PM: USB composite device: Tx does not work for CDC composite devices started from 3

Part Number: TM4C123FH6PM

Hello!

I am designing a device which is used as a hub, connecting several serial devices to a computer as USB CDC devices. This device uses usblib to create a composite device with required nomber of CDC devices.

It works perfectly with up to 3 devices, but when I am trying to add more devices, I face the following issue: when I receive data from host and my underlying device is sending back some response, it is never received by host.

Debugging the application I see the device structure has iCDCTxState field set to eCDCStateWaitData, and reading usbcdc.c I see this field should be set to eCDCStateIdle by ProcessDataToHost() function, which is called by HandleEndpoints() function, but HandleEndpoints() is called only while receiving from host, but never after ScheduleNextTransmission() is called from USB buffer.

The CDC devices are all initialized in the same way:

    int i;
    for(i = 0; i < nPorts; i++)
    {
        g_sCompDevice.psDevices[i].pvInstance =
                USBDCDCCompositeInit(0, &g_psCDCDevice[i], &g_psCompEntries[i]);
        USBBufferInit(&g_psTxBuffer[i]);
        USBBufferInit(&g_psRxBuffer[i]);
    }
    g_sCompDevice.ui32NumDevices = nPorts;
    pCompInst = USBDCompositeInit(0, (tUSBDCompositeDevice *)&g_sCompDevice, COMPOSITE_DCDC_SIZE * nPorts,
                      g_pucDescriptorData);

The structures are declared as:

extern tUSBBuffer g_psTxBuffer[MAX_SERIAL_DEVICES];
extern tUSBBuffer g_psRxBuffer[MAX_SERIAL_DEVICES];
extern tUSBDCDCDevice g_psCDCDevice[MAX_SERIAL_DEVICES];
extern uint8_t g_pui8USBTxBuffer[];
extern uint8_t g_pui8USBRxBuffer[];
extern uint32_t ControlHandler(void *pvCBData, uint32_t ui32Event,
                               uint32_t ui32MsgValue, void *pvMsgData);
extern uint32_t RxHandlerCDC(void *pvCBData, uint32_t ui32Event,
                              uint32_t ui32MsgValue, void *pvMsgData);
extern uint32_t TxHandlerCDC(void *pvlCBData, uint32_t ui32Event,
                              uint32_t ui32MsgValue, void *pvMsgData);


#define CDC_DEV_STRUCT(n)                           \
        {                                           \
            USB_VID_TI_1CBE,                        \
            USB_PID_SERIAL,                         \
            0,                                      \
            USB_CONF_ATTR_BUS_PWR,                  \
            ControlHandler,                         \
            (void *)&g_psCDCDevice[n],              \
            USBBufferEventCallback,                 \
            (void *)&g_psRxBuffer[n],               \
            USBBufferEventCallback,                 \
            (void *)&g_psTxBuffer[n],               \
            g_pui8StringDescriptorsCDC,             \
            NUM_STRING_DESCRIPTORS                  \
        }

tUSBDCDCDevice g_psCDCDevice[MAX_SERIAL_DEVICES] =
{
 CDC_DEV_STRUCT(0),
 CDC_DEV_STRUCT(1),
 CDC_DEV_STRUCT(2),
 CDC_DEV_STRUCT(3),
 CDC_DEV_STRUCT(4),
 CDC_DEV_STRUCT(5),
 CDC_DEV_STRUCT(6),
 CDC_DEV_STRUCT(7),
 CDC_DEV_STRUCT(8),
 CDC_DEV_STRUCT(9),
 CDC_DEV_STRUCT(10),
 CDC_DEV_STRUCT(11),
 CDC_DEV_STRUCT(12),
 CDC_DEV_STRUCT(13),
 CDC_DEV_STRUCT(14),
 CDC_DEV_STRUCT(15)
};

#define CDC_RX_BUFFER(n)                            \
        {                                           \
            false,                                  \
            RxHandlerCDC,                           \
            (void *)&g_psCDCDevice[n],              \
            USBDCDCPacketRead,                      \
            USBDCDCRxPacketAvailable,               \
            (void *)&g_psCDCDevice[n],              \
            g_ppui8USBRxBuffer[n],                  \
            UART_BUFFER_SIZE,                       \
        }

uint8_t g_ppui8USBRxBuffer[MAX_SERIAL_DEVICES][UART_BUFFER_SIZE];
tUSBBuffer g_psRxBuffer[MAX_SERIAL_DEVICES] =
{
 CDC_RX_BUFFER(0),
 CDC_RX_BUFFER(1),
 CDC_RX_BUFFER(2),
 CDC_RX_BUFFER(3),
 CDC_RX_BUFFER(4),
 CDC_RX_BUFFER(5),
 CDC_RX_BUFFER(6),
 CDC_RX_BUFFER(7),
 CDC_RX_BUFFER(8),
 CDC_RX_BUFFER(9),
 CDC_RX_BUFFER(10),
 CDC_RX_BUFFER(11),
 CDC_RX_BUFFER(12),
 CDC_RX_BUFFER(13),
 CDC_RX_BUFFER(14),
 CDC_RX_BUFFER(15)
};

#define CDC_TX_BUFFER(n)                            \
        {                                           \
            true,                                   \
            TxHandlerCDC,                           \
            (void *)&g_psCDCDevice[n],              \
            USBDCDCPacketWrite,                     \
            USBDCDCTxPacketAvailable,               \
            (void *)&g_psCDCDevice[n],              \
            g_ppcUSBTxBuffer[n],                    \
            UART_BUFFER_SIZE,                       \
        }

uint8_t g_ppcUSBTxBuffer[MAX_SERIAL_DEVICES][UART_BUFFER_SIZE];
tUSBBuffer g_psTxBuffer[MAX_SERIAL_DEVICES] =
{
 CDC_TX_BUFFER(0),
 CDC_TX_BUFFER(1),
 CDC_TX_BUFFER(2),
 CDC_TX_BUFFER(3),
 CDC_TX_BUFFER(4),
 CDC_TX_BUFFER(5),
 CDC_TX_BUFFER(6),
 CDC_TX_BUFFER(7),
 CDC_TX_BUFFER(8),
 CDC_TX_BUFFER(9),
 CDC_TX_BUFFER(10),
 CDC_TX_BUFFER(11),
 CDC_TX_BUFFER(12),
 CDC_TX_BUFFER(13),
 CDC_TX_BUFFER(14),
 CDC_TX_BUFFER(15)
};

Is there any limitation on number of endpoints or something?

  • Hello Oleg,

    There is not enough information posted here for me to really assess this. Can you provide the entire usb_structs.c and usb_structs.h files as attachments so I can review all declarations and defined variables?

    I am fairly confident that you can do more than 3 ports but I am not sure what the upper limit is and I definitely have not seen 8 much less 16 used. I have doubts that 16 would be possible without modifying the USB library.

    Best Regards,

    Ralph Jacobi

  • The problem starts with 4th CDC device. 3 devices are working well. External variable nPorts defines the number of active CDC devices. All my code for USB part is in the usb.c file, here it is:

    /*
     * usb.c
     *
     *  Created on: 8 ёхэЄ. 2021 у.
     *      Author: Kit
     */
    
    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "inc/hw_uart.h"
    #include "inc/hw_qei.h"
    #include "inc/hw_i2c.h"
    #include "inc/hw_can.h"
    #include "driverlib/debug.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/rom.h"
    #include "driverlib/rom_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/systick.h"
    #include "driverlib/timer.h"
    #include "driverlib/uart.h"
    #include "driverlib/usb.h"
    #include "driverlib/gpio.h"
    #include "driverlib/i2c.h"
    #include "driverlib/qei.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/can.h"
    #include "usblib/usblib.h"
    #include "usblib/usbcdc.h"
    #include "usblib/usbhid.h"
    #include "usblib/usb-ids.h"
    #include "usblib/device/usbdevice.h"
    #include "usblib/device/usbdcomp.h"
    #include "usblib/device/usbdcdc.h"
    #include "usblib/device/usbdhid.h"
    #include "usblib/device/usbdhidkeyb.h"
    
    
    //*****************************************************************************
    //
    // The languages supported by this device.
    //
    //*****************************************************************************
    const uint8_t g_pui8LangDescriptor[] =
    {
        4,
        USB_DTYPE_STRING,
        USBShort(USB_LANG_EN_US)
    };
    
    //*****************************************************************************
    //
    // The manufacturer string.
    //
    //*****************************************************************************
    const uint8_t g_pui8ManufacturerString[] =
    {
        (17 + 1) * 2,
        USB_DTYPE_STRING,
        'T', 0, 'e', 0, 'x', 0, 'a', 0, 's', 0, ' ', 0, 'I', 0, 'n', 0, 's', 0,
        't', 0, 'r', 0, 'u', 0, 'm', 0, 'e', 0, 'n', 0, 't', 0, 's', 0,
    };
    
    //*****************************************************************************
    //
    // The product string.
    //
    //*****************************************************************************
    const uint8_t g_pui8ProductString[] =
    {
        2 + (16 * 2),
        USB_DTYPE_STRING,
        'V', 0, 'i', 0, 'r', 0, 't', 0, 'u', 0, 'a', 0, 'l', 0, ' ', 0,
        'C', 0, 'O', 0, 'M', 0, ' ', 0, 'P', 0, 'o', 0, 'r', 0, 't', 0
    };
    const uint8_t g_pui8ProductStringComp[] =
    {
        2 + (16 * 2),
        USB_DTYPE_STRING,
        'P', 0, 'o', 0, 'r', 0, 't', 0, 'l', 0, 'a', 0, 'b', 0, ' ', 0,
        'B', 0, 'r', 0, 'e', 0, 'a', 0, 'k', 0, 'o', 0, 'u', 0, 't', 0
    };
    
    uint8_t g_pui8SerialNumberStringComp[] =
    {
        2 + (8 * 2),
        USB_DTYPE_STRING,
        '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '0', 0, '1', 0
    };
    
    //*****************************************************************************
    //
    // The control interface description string.
    //
    //*****************************************************************************
    const uint8_t g_pui8ControlInterfaceString[] =
    {
        2 + (21 * 2),
        USB_DTYPE_STRING,
        'A', 0, 'C', 0, 'M', 0, ' ', 0, 'C', 0, 'o', 0, 'n', 0, 't', 0,
        'r', 0, 'o', 0, 'l', 0, ' ', 0, 'I', 0, 'n', 0, 't', 0, 'e', 0,
        'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', 0
    };
    
    //*****************************************************************************
    //
    // The configuration description string.
    //
    //*****************************************************************************
    const uint8_t g_pui8ConfigString[] =
    {
     2 + (26 * 2),
     USB_DTYPE_STRING,
     'B', 0, 'u', 0, 's', 0, ' ', 0, 'P', 0, 'o', 0, 'w', 0,
     'e', 0, 'r', 0, 'e', 0, 'd', 0, ' ', 0, 'C', 0, 'o', 0, 'n', 0,
     'f', 0, 'i', 0, 'g', 0, 'u', 0, 'r', 0, 'a', 0, 't', 0, 'i', 0,
     'o', 0, 'n', 0
    };
    const uint8_t g_pui8ConfigStringComp[] =
    {
        2 + (26 * 2),
        USB_DTYPE_STRING,
        'B', 0, 'u', 0, 's', 0, ' ', 0, 'P', 0, 'o', 0, 'w', 0,
        'e', 0, 'r', 0, 'e', 0, 'd', 0, ' ', 0, 'C', 0, 'o', 0, 'n', 0,
        'f', 0, 'i', 0, 'g', 0, 'u', 0, 'r', 0, 'a', 0, 't', 0, 'i', 0,
        'o', 0, 'n', 0
    };
    
    //*****************************************************************************
    //
    // The descriptor string table.
    //
    //*****************************************************************************
    const uint8_t * const g_pui8StringDescriptorsCDC[] =
    {
        g_pui8LangDescriptor,
        g_pui8ManufacturerString,
        g_pui8ProductString,
        g_pui8SerialNumberStringComp,
        g_pui8ControlInterfaceString,
        g_pui8ConfigString
    };
    
    const uint8_t * const g_pui8StringDescriptorsComp[] =
    {
        g_pui8LangDescriptor,
        g_pui8ManufacturerString,
        g_pui8ProductStringComp,
        g_pui8SerialNumberStringComp,
        g_pui8ControlInterfaceString,
        g_pui8ConfigStringComp
    };
    
    #define NUM_STRING_DESCRIPTORS (sizeof(g_pui8StringDescriptorsCDC) /             \
                                    sizeof(uint8_t *))
    #define NUM_STRING_DESCRIPTORS_COMP (sizeof(g_pui8StringDescriptorsComp) /             \
                                    sizeof(uint8_t *))
    
    #define MAX_SERIAL_DEVICES      16
    #define UART_BUFFER_SIZE        256
    
    extern tUSBBuffer g_psTxBuffer[MAX_SERIAL_DEVICES];
    extern tUSBBuffer g_psRxBuffer[MAX_SERIAL_DEVICES];
    extern tUSBDCDCDevice g_psCDCDevice[MAX_SERIAL_DEVICES];
    extern uint8_t g_pui8USBTxBuffer[];
    extern uint8_t g_pui8USBRxBuffer[];
    extern uint32_t ControlHandler(void *pvCBData, uint32_t ui32Event,
                                   uint32_t ui32MsgValue, void *pvMsgData);
    extern uint32_t RxHandlerCDC(void *pvCBData, uint32_t ui32Event,
                                  uint32_t ui32MsgValue, void *pvMsgData);
    extern uint32_t TxHandlerCDC(void *pvlCBData, uint32_t ui32Event,
                                  uint32_t ui32MsgValue, void *pvMsgData);
    
    
    #define CDC_DEV_STRUCT(n)                           \
            {                                           \
                USB_VID_TI_1CBE,                        \
                USB_PID_SERIAL,                         \
                0,                                      \
                USB_CONF_ATTR_BUS_PWR,                  \
                ControlHandler,                         \
                (void *)&g_psCDCDevice[n],              \
                USBBufferEventCallback,                 \
                (void *)&g_psRxBuffer[n],               \
                USBBufferEventCallback,                 \
                (void *)&g_psTxBuffer[n],               \
                g_pui8StringDescriptorsCDC,             \
                NUM_STRING_DESCRIPTORS                  \
            }
    
    tUSBDCDCDevice g_psCDCDevice[MAX_SERIAL_DEVICES] =
    {
     CDC_DEV_STRUCT(0),
     CDC_DEV_STRUCT(1),
     CDC_DEV_STRUCT(2),
     CDC_DEV_STRUCT(3),
     CDC_DEV_STRUCT(4),
     CDC_DEV_STRUCT(5),
     CDC_DEV_STRUCT(6),
     CDC_DEV_STRUCT(7),
     CDC_DEV_STRUCT(8),
     CDC_DEV_STRUCT(9),
     CDC_DEV_STRUCT(10),
     CDC_DEV_STRUCT(11),
     CDC_DEV_STRUCT(12),
     CDC_DEV_STRUCT(13),
     CDC_DEV_STRUCT(14),
     CDC_DEV_STRUCT(15)
    };
    
    #define CDC_RX_BUFFER(n)                            \
            {                                           \
                false,                                  \
                RxHandlerCDC,                           \
                (void *)&g_psCDCDevice[n],              \
                USBDCDCPacketRead,                      \
                USBDCDCRxPacketAvailable,               \
                (void *)&g_psCDCDevice[n],              \
                g_ppui8USBRxBuffer[n],                  \
                UART_BUFFER_SIZE,                       \
            }
    
    uint8_t g_ppui8USBRxBuffer[MAX_SERIAL_DEVICES][UART_BUFFER_SIZE];
    tUSBBuffer g_psRxBuffer[MAX_SERIAL_DEVICES] =
    {
     CDC_RX_BUFFER(0),
     CDC_RX_BUFFER(1),
     CDC_RX_BUFFER(2),
     CDC_RX_BUFFER(3),
     CDC_RX_BUFFER(4),
     CDC_RX_BUFFER(5),
     CDC_RX_BUFFER(6),
     CDC_RX_BUFFER(7),
     CDC_RX_BUFFER(8),
     CDC_RX_BUFFER(9),
     CDC_RX_BUFFER(10),
     CDC_RX_BUFFER(11),
     CDC_RX_BUFFER(12),
     CDC_RX_BUFFER(13),
     CDC_RX_BUFFER(14),
     CDC_RX_BUFFER(15)
    };
    
    #define CDC_TX_BUFFER(n)                            \
            {                                           \
                true,                                   \
                TxHandlerCDC,                           \
                (void *)&g_psCDCDevice[n],              \
                USBDCDCPacketWrite,                     \
                USBDCDCTxPacketAvailable,               \
                (void *)&g_psCDCDevice[n],              \
                g_ppcUSBTxBuffer[n],                    \
                UART_BUFFER_SIZE,                       \
            }
    
    uint8_t g_ppcUSBTxBuffer[MAX_SERIAL_DEVICES][UART_BUFFER_SIZE];
    tUSBBuffer g_psTxBuffer[MAX_SERIAL_DEVICES] =
    {
     CDC_TX_BUFFER(0),
     CDC_TX_BUFFER(1),
     CDC_TX_BUFFER(2),
     CDC_TX_BUFFER(3),
     CDC_TX_BUFFER(4),
     CDC_TX_BUFFER(5),
     CDC_TX_BUFFER(6),
     CDC_TX_BUFFER(7),
     CDC_TX_BUFFER(8),
     CDC_TX_BUFFER(9),
     CDC_TX_BUFFER(10),
     CDC_TX_BUFFER(11),
     CDC_TX_BUFFER(12),
     CDC_TX_BUFFER(13),
     CDC_TX_BUFFER(14),
     CDC_TX_BUFFER(15)
    };
    
    #define DESCRIPTOR_DATA_SIZE    (COMPOSITE_DCDC_SIZE * MAX_SERIAL_DEVICES)
    
    //****************************************************************************
    //
    // The memory allocated to hold the composite descriptor that is created by
    // the call to USBDCompositeInit().
    //
    //****************************************************************************
    uint8_t g_pui8DescriptorData[DESCRIPTOR_DATA_SIZE];
    
    tCompositeEntry g_psCompEntries[MAX_SERIAL_DEVICES];
    
    //*****************************************************************************
    //
    //! The structure used by the application to define operating parameters for
    //! the composite device class.
    //
    //*****************************************************************************
    typedef struct
    {
        //
        //! The vendor ID that this device is to present in the device descriptor.
        //
        const uint16_t ui16VID;
    
        //
        //! The product ID that this device is to present in the device descriptor.
        //
        const uint16_t ui16PID;
    
        //
        //! The maximum power consumption of the device, expressed in mA.
        //
        const uint16_t ui16MaxPowermA;
    
        //
        //! Indicates whether the device is self or bus-powered and whether or not
        //! it supports remote wake up.  Valid values are \b USB_CONF_ATTR_SELF_PWR
        //! or \b USB_CONF_ATTR_BUS_PWR, optionally ORed with
        //! \b USB_CONF_ATTR_RWAKE.
        //
        const uint8_t ui8PwrAttributes;
    
        //
        //! A pointer to the callback function which will be called to notify
        //! the application of events relating to the operation of the composite
        //! device.
        //
        const tUSBCallback pfnCallback;
    
        //
        //! A pointer to the string descriptor array for this device.  This array
        //! must contain the following string descriptor pointers in this order.
        //! Language descriptor, Manufacturer name string (language 1), Product
        //! name string (language 1), Serial number string (language 1), Composite
        //! device interface description string (language 1), Configuration
        //! description string (language 1).
        //!
        //! If supporting more than 1 language, the descriptor block (except for
        //! string descriptor 0) must be repeated for each language defined in the
        //! language descriptor.
        //!
        //
        const uint8_t * const *ppui8StringDescriptors;
    
        //
        //! The number of descriptors provided in the ppStringDescriptors
        //! array.  This must be 1 + ((5 + (number of strings)) *
        //!                           (number of languages)).
        //
        const uint32_t ui32NumStringDescriptors;
    
        //
        //! The number of devices in the psDevices array.
        //
        uint32_t ui32NumDevices;
    
        //
        //! This application supplied array holds the the top level device class
        //! information as well as the Instance data for that class.
        //
        tCompositeEntry * const psDevices;
    
        //
        //! The private data for this device instance.  This memory must remain
        //! accessible for as long as the composite device is in use and must
        //! not be modified by any code outside the composite class driver.
        //
        tCompositeInstance sPrivateData;
    }
    tUSBDCompositeDeviceM;
    
    //****************************************************************************
    //
    // Allocate the Device Data for the top level composite device class.
    //
    //****************************************************************************
    tUSBDCompositeDeviceM g_sCompDevice =
    {
        //
        // Stellaris VID.
        //
        USB_VID_TI_1CBE,
    
        //
        // Stellaris PID for composite serial device.
        //
        USB_PID_COMP_HID_SER,
    
        //
        // This is in 2mA increments so 500mA.
        //
        250,
    
        //
        // Bus powered device.
        //
        USB_CONF_ATTR_BUS_PWR,
    
        //
        // There is no need for a default composite event handler.
        //
        0,
    
        //
        // The string table.
        //
        g_pui8StringDescriptorsComp,
        NUM_STRING_DESCRIPTORS_COMP,
    
        //
        // The Composite device array.
        //
        0,                                                          // To be changed on reinit
        g_psCompEntries
    };
    
    bool bConnected[16] = {false, false, false, false, false, false, false, false,
                           false, false, false, false, false, false, false, false};
    
    int nPorts = 1;
    
    uint32_t
    ControlHandler(void *pvCBData, uint32_t ui32Event,
                   uint32_t ui32MsgValue, void *pvMsgData)
    {
        tUSBDCDCDevice *pDev = (tUSBDCDCDevice *)pvCBData;
        uint8_t nPort = (((uint8_t *)pDev) - ((uint8_t *)g_psCDCDevice)) / sizeof(tUSBDCDCDevice);
        switch(ui32Event)
        {
            //
            // We are connected to a host and communication is now possible.
            //
            case USB_EVENT_CONNECTED:
            {
                int i;
                for(i = 0; i < nPorts; i++)
                {
                    bConnected[i] = true;
                    //
                    // Flush our buffers.
                    //
                    USBBufferFlush(&g_psTxBuffer[i]);
                    USBBufferFlush(&g_psRxBuffer[i]);
                }
    
                break;
            }
    
            //
            // The host has disconnected.
            //
            case USB_EVENT_DISCONNECTED:
            {
                bConnected[nPort] = false;
                break;
            }
    
            //
            // Return the current serial communication parameters.
            //
            case USBD_CDC_EVENT_GET_LINE_CODING:
            {
                {
                    tLineCoding *psLineCoding = (tLineCoding *)pvMsgData;
                    psLineCoding->ui32Rate = 19200;
                    psLineCoding->ui8Databits = 8;
                    psLineCoding->ui8Parity = USB_CDC_PARITY_NONE;
                    psLineCoding->ui8Stop = USB_CDC_STOP_BITS_1;
                }
                break;
            }
    
            //
            // Set the current serial communication parameters.
            //
            case USBD_CDC_EVENT_SET_LINE_CODING:
            {
                /*{
                    tLineCoding *psLineCoding = (tLineCoding *)pvMsgData;
                    BaudRate = psLineCoding->ui32Rate;
                }*/
                break;
            }
    
            //
            // Set the current serial communication parameters.
            //
            case USBD_CDC_EVENT_SET_CONTROL_LINE_STATE:
            {
                /*if(((unsigned short)ui32MsgValue) == 0)
                    RTSPaused[Port] = true;
                if(((unsigned short)ui32MsgValue) == 1)
                    RTSPaused[Port] = false;
                if(((unsigned short)ui32MsgValue) == 2)
                    RTSPaused[Port] = true;
                if(((unsigned short)ui32MsgValue) == 3)
                    RTSPaused[Port] = false;*/
                // TODO: control lines
                break;
            }
    
            //
            // Send a break condition on the serial line.
            //
            case USBD_CDC_EVENT_SEND_BREAK:
            {
                //SendBreak(true);
                break;
            }
    
            //
            // Clear the break condition on the serial line.
            //
            case USBD_CDC_EVENT_CLEAR_BREAK:
            {
                //SendBreak(false);
                break;
            }
    
            //
            // Ignore SUSPEND and RESUME for now.
            //
            case USB_EVENT_SUSPEND:
            case USB_EVENT_RESUME:
            {
                break;
            }
    
            //
            // We don't expect to receive any other events.  Ignore any that show
            // up in a release build or hang in a debug build.
            //
            default:
            {
                break;
            }
        }
    
        return(0);
    
    }
    
    void SendCAN(uint8_t nPort, uint8_t *Data, uint8_t Len);
    
    uint32_t RxHandlerCDC(void *pvCBData, uint32_t ui32Event,
                                  uint32_t ui32MsgValue, void *pvMsgData)
    {
        tUSBDCDCDevice *pDev = (tUSBDCDCDevice *)pvCBData;
        uint8_t nPort = (((uint8_t *)pDev) - ((uint8_t *)g_psCDCDevice)) / sizeof(tUSBDCDCDevice);
        //
        // Which event are we being sent?
        //
        switch(ui32Event)
        {
            //
            // A new packet has been received.
            //
            case USB_EVENT_RX_AVAILABLE:
            {
                uint32_t DataRead = 0;
                uint8_t Data[64];
                while((DataRead = USBBufferRead(g_psRxBuffer + nPort, Data, 64)) != 0)
                {
                    SendCAN(nPort, Data, DataRead);
                }
                break;
            }
    
            //
            // We are being asked how much unprocessed data we have still to
            // process. We return 0 if the UART is currently idle or 1 if it is
            // in the process of transmitting something. The actual number of
            // bytes in the UART FIFO is not important here, merely whether or
            // not everything previously sent to us has been transmitted.
            //
            case USB_EVENT_DATA_REMAINING:
            {
                return CANStatusGet(CAN0_BASE, CAN_STS_TXREQUEST) & (1 << (nPort + 1)) ? 1 : 0;
            }
    
            //
            // We are being asked to provide a buffer into which the next packet
            // can be read. We do not support this mode of receiving data so let
            // the driver know by returning 0. The CDC driver should not be
            // sending this message but this is included just for illustration and
            // completeness.
            //
            case USB_EVENT_REQUEST_BUFFER:
            {
                return(0);
            }
    
            //
            // We don't expect to receive any other events.  Ignore any that show
            // up in a release build or hang in a debug build.
            //
            default:
            {
                break;
            }
        }
    
        return(0);
    }
    
    uint32_t TxHandlerCDC(void *pvlCBData, uint32_t ui32Event,
                                  uint32_t ui32MsgValue, void *pvMsgData)
    {
        tUSBDCDCDevice *pDev = (tUSBDCDCDevice *)pvlCBData;
        uint8_t nPort = (((uint8_t *)pDev) - ((uint8_t *)g_psCDCDevice)) / sizeof(tUSBDCDCDevice);
        return(0);
    }
    
    void USBSend(uint8_t nPort, uint8_t *Data, uint8_t Len)
    {
        if(bConnected[nPort])
            USBBufferWrite((tUSBBuffer *)&g_psTxBuffer[nPort], Data, Len);
    }
    
    void *pCompInst = 0;
    uint8_t g_pucDescriptorData[DESCRIPTOR_DATA_SIZE];
    
    void ReinitUSB()
    {
        if(pCompInst)
        {
            USBDCompositeTerm(pCompInst);
            SysCtlPeripheralDisable(SYSCTL_PERIPH_USB0);
            SysCtlDelay(80000000);
            SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);
            uint32_t Clk = SysCtlClockGet();
            uint32_t Power = USBLIB_FEATURE_POWER_BUS;
            USBDCDFeatureSet(0, USBLIB_FEATURE_CPUCLK, &Clk);
            USBDCDFeatureSet(0, USBLIB_FEATURE_POWER, &Power);
            USBStackModeSet(0, eUSBModeForceDevice, 0);
        }
        int i;
        for(i = 0; i < nPorts; i++)
        {
            g_sCompDevice.psDevices[i].pvInstance =
                    USBDCDCCompositeInit(0, &g_psCDCDevice[i], &g_psCompEntries[i]);
            USBBufferInit(&g_psTxBuffer[i]);
            USBBufferInit(&g_psRxBuffer[i]);
        }
        g_sCompDevice.ui32NumDevices = nPorts;
        pCompInst = USBDCompositeInit(0, (tUSBDCompositeDevice *)&g_sCompDevice, COMPOSITE_DCDC_SIZE * nPorts,
                          g_pucDescriptorData);
    }
    
    int InitCtr = 0;
    
    void TimersInt()
    {
        TimerIntClear(TIMER1_BASE, TIMER_TIMA_TIMEOUT);
        if(InitCtr++ == 5)
        {
            ReinitUSB();
            TimerDisable(TIMER1_BASE, TIMER_A);
        }
    }
    
    void InitUSB()
    {
        SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
        GPIOPinTypeUSBAnalog(GPIO_PORTD_BASE, GPIO_PIN_5 | GPIO_PIN_4);
        uint32_t Clk = SysCtlClockGet();
        uint32_t Power = USBLIB_FEATURE_POWER_BUS;
        USBDCDFeatureSet(0, USBLIB_FEATURE_CPUCLK, &Clk);
        USBDCDFeatureSet(0, USBLIB_FEATURE_POWER, &Power);
        USBStackModeSet(0, eUSBModeForceDevice, 0);
    
        SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER1);
        TimerConfigure(TIMER1_BASE, TIMER_CFG_PERIODIC);
        TimerLoadSet(TIMER1_BASE, TIMER_A, SysCtlClockGet());
        TimerIntRegister(TIMER1_BASE, TIMER_A, &TimersInt);
        TimerIntEnable(TIMER1_BASE, TIMER_TIMA_TIMEOUT);
        TimerEnable(TIMER1_BASE, TIMER_A);
    
    }
    
    
    
    

  • Hello Oleg,

    Thanks for providing the code.

    The problem starts with 4th CDC device. 3 devices are working well. External variable nPorts defines the number of active CDC devices.

    My understanding then is the application is setting nPorts equal to some value, and if you set nPorts = 3 and call ReinitUSB, then it works fine, but if you set nPorts = 4 and call ReinitUSB then you only get three CDC interfaces?

    While I don't use the code you've put together exactly as you have it setup, I did get it ported into a project and tested and I was able to get up to 7 ports enumerated. It is not clear initially here if that is the limit of the USB library or not, but I definitely was able to get 4, 5, 6, and 7 CDC ports to enumerate properly.

    Further investigation on trying to do more than 7 ports would take a few days as I would need to dig into USB analyzer captures to understand what is different between seven and eight ports to see if its a library limitation or something else.

    Best regards,

    Ralph Jacobi

  • Wrong. ReinitUSB is called once, 5 seconds after startup, and nPorts is set to correct value this time. All CDC ports are set up and appear in Windows device manager, and I able to connect them. But when I connect any port greather than 3rd, I can write data to this port, and I receive all the data on my device, but when device writes data back to host, host does not receive it, and iCDCTxState field of the port is set to eCDCStateWaitData forever.

  • I found the cause.

    There are 2 IN endpoints for each CDC port used, one interrupt and one bulk.

    As there are maximum of 7 endpoints, 4th device is out of endpoints.

    Is there any workaround possible?

  • Just found the simple workaround: simply removed interrupt endpoint from descriptor structure. Everething is OK up to 7 devices.

  • Hello Oleg,

    Glad you were able to find a workaround. That would make sense to me as far as a root cause and a workaround. Sorry that I did not quite understand the core issue at first. Usually others have issues with enumeration of multiple devices when it comes to composites and so that was my initial focus, but I see in hindsight you were more concerned about the data transfer element.

    The 7 endpoint limit is definitely why there was a maximum of 7 devices connected allowed too, so that explains that element as well. I had honestly not been thinking about the hardware limitation as much as software yesterday.

    Best Regards,

    Ralph Jacobi