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.

USB custom data pipe enumeration problem

Other Parts Discussed in Thread: TM4C123GH6PM

I'm trying to convert the keyboard example for the Tiva C arms over to a custom data pipe with 64 byte frame size in and out.  I started off by loading the keyboard example from the USB libraries (v1.1) into CCS.  I've got that ported over for the TM4C123GH6PM launchpad and running. 

I'm now just trying to mod the example to enumerate as a custom hid device so my windows application will see it.  I have the custom data pipe running on an MSP430 board and it works fine with my application...no problems seeing the device.  This keyboard example seems to still be enumerating as a system device though.  I've got a packet sniffer to monitor the enumeration and it looks like no matter what I change in the usbdkeyb.c file (where all the descritpor values are) I can't change the USB_HID_SCLASS_BOOT and the USB_HID_PROTOCOL_KEYB.  Those defines are for the keyboard and from what I understand I need to change them both to 0x00.  I do this here, but when I check my packet sniffer log I still see it as 0x01 in the descriptors which says the subclass is of type keyboard.  I've been struggling with this custom data pipe for a while now.  I had to switch to these arm's and the usb support with the usblib library has been beyond confusing.  Anyways, I feel like after fixing this it shouldn't come up as  a keyboard anymore.  It would be a huge help if someone could at least point me in the right direction as to what to modify where and if I've been on the right track or not.  Below is some code snippets from the pertinant sections and I'll also upload my project.  It isn't much different from the example since all I've been trying to do is get it to not come up as a keyboard (system device) but rather a custom hid device.

Descriptors:

static uint8_t g_pui8KeybDescriptor[] =
{
    //
    // Configuration descriptor header.
    //
    9,                          // Size of the configuration descriptor.
    USB_DTYPE_CONFIGURATION,    // Type of this descriptor.
    USBShort(34),               // The total size of this full structure.
    1,                          // The number of interfaces in this
                                // configuration.
    1,                          // The unique value for this configuration.
    5,                          // The string identifier that describes this
                                // configuration.
    USB_CONF_ATTR_SELF_PWR,     // Bus Powered, Self Powered, remote wake up.
    250,                        // The maximum power in 2mA increments.
};

//*****************************************************************************
//
// The remainder of the configuration descriptor is stored in flash since we
// don't need to modify anything in it at runtime.
//
//*****************************************************************************
static uint8_t g_pui8HIDInterface[HIDINTERFACE_SIZE] =
{
    //
    // HID Device Class Interface Descriptor.
    //
    9,                          // Size of the interface descriptor.
    USB_DTYPE_INTERFACE,        // Type of this descriptor.
    0,                          // The index for this interface.
    0,                          // The alternate setting for this interface.
    1,                          // The number of endpoints used by this
                                // interface.
    USB_CLASS_HID,              // The interface class
    //USB_HID_SCLASS_BOOT,        // The interface sub-class.
    0,
    //USB_HID_PROTOCOL_KEYB,      // The interface protocol for the sub-class
    0,
                                // specified above.
    4,                          // The string index for this interface.
};

static const uint8_t g_pui8HIDInEndpoint[HIDINENDPOINT_SIZE] =
{
    //
    // Interrupt IN endpoint descriptor
    //
    7,                          // The size of the endpoint descriptor.
    USB_DTYPE_ENDPOINT,         // Descriptor type is an endpoint.
    USB_EP_DESC_IN | USBEPToIndex(USB_EP_1),
    USB_EP_ATTR_INT,            // Endpoint is an interrupt endpoint.
    USBShort(USBFIFOSizeToBytes(USB_FIFO_SZ_64)),
                                // The maximum packet size.
    16,                         // The polling interval for this endpoint.
};

static const uint8_t g_pui8HIDOutEndpoint[HIDOUTENDPOINT_SIZE] =
{
    //
    // Interrupt OUT endpoint descriptor
    //
    7,                          // The size of the endpoint descriptor.
    USB_DTYPE_ENDPOINT,         // Descriptor type is an endpoint.
    USB_EP_DESC_OUT | USBEPToIndex(USB_EP_2),
    USB_EP_ATTR_INT,            // Endpoint is an interrupt endpoint.
    USBShort(USBFIFOSizeToBytes(USB_FIFO_SZ_64)),
                                // The maximum packet size.
    16,                         // The polling interval for this endpoint.
};

//*****************************************************************************
//
// The following is the HID report structure definition that is passed back
// to the host.
//
//*****************************************************************************
static const uint8_t g_pui8KeybReportDescriptor[] =
{
    //UsagePage(USB_HID_GENERIC_DESKTOP),
    //Usage(USB_HID_KEYBOARD),
    //Collection(USB_HID_APPLICATION),
	UsagePage(0xFF00),
	Usage(0x01),
	Collection(0x01),

    0x15, 0x00,                         //   LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x00,                   //   LOGICAL_MAXIMUM (255)
    0x75, 0x08,                         //   REPORT_SIZE (8)   - bits
                                        // ------ input report ------
    0x95, 0x40,	//   REPORT_COUNT      - bytes
    0x09, 0x01,                         //   USAGE (Vendor Usage 1)
    0x81, 0x02,                         //   INPUT (Data,Var,Abs)
                                        // ------ output report ------



    EndCollection
};

//*****************************************************************************
//
// The HID descriptor for the keyboard device.
//
//*****************************************************************************
static const tHIDDescriptor g_sKeybHIDDescriptor =
{
    9,                              // bLength
    USB_HID_DTYPE_HID,              // bDescriptorType
    //0x111,                          // bcdHID (version 1.11 compliant)
    0x200
    0,                              // bCountryCode (not localized)
    1,                              // bNumDescriptors
    {
        {
            USB_HID_DTYPE_REPORT,   // Report descriptor
            sizeof(g_pui8KeybReportDescriptor)
                                    // Size of report descriptor
        }
    }
};

//*****************************************************************************
//
// The HID configuration descriptor is defined as four or five sections
// depending upon the client's configuration choice.  These sections are:
//
// 1.  The 9 byte configuration descriptor (RAM).
// 2.  The interface descriptor (RAM).
// 3.  The HID report and physical descriptors (provided by the client)
//     (FLASH).
// 4.  The mandatory interrupt IN endpoint descriptor (FLASH).
// 5.  The optional interrupt OUT endpoint descriptor (FLASH).
//
//*****************************************************************************
static const tConfigSection g_sHIDConfigSection =
{
    sizeof(g_pui8KeybDescriptor),
    g_pui8KeybDescriptor
};

static const tConfigSection g_sHIDInterfaceSection =
{
    sizeof(g_pui8HIDInterface),
    g_pui8HIDInterface
};

static const tConfigSection g_sHIDInEndpointSection =
{
    sizeof(g_pui8HIDInEndpoint),
    g_pui8HIDInEndpoint
};

static const tConfigSection g_sHIDOutEndpointSection =
{
    sizeof(g_pui8HIDOutEndpoint),
    g_pui8HIDOutEndpoint
};

//*****************************************************************************
//
// Place holder for the user's HID descriptor block.
//
//*****************************************************************************
static tConfigSection g_sHIDDescriptorSection =
{
   sizeof(g_sKeybHIDDescriptor),
   (const uint8_t *)&g_sKeybHIDDescriptor
};

//*****************************************************************************
//
// This array lists all the sections that must be concatenated to make a
// single, complete HID configuration descriptor.
//
//*****************************************************************************
static const tConfigSection *g_psHIDSections[] =
{
    &g_sHIDConfigSection,
    &g_sHIDInterfaceSection,
    &g_sHIDDescriptorSection,
    &g_sHIDInEndpointSection,
    &g_sHIDOutEndpointSection
};

#define NUM_HID_SECTIONS        ((sizeof(g_psHIDSections) /                   \
                                  sizeof(g_psHIDSections[0])) - 1)

My report descriptor looks different because I initially thought it might be that and have tried a million different usage page configurations.  Thats formed from the MSP430 like code.  If that is wrong, I had something like this with the macros.

ReportSize(8),
        UsageMinimum(0),
        UsageMaximum(255),

        // Input report
        ReportCount(0x40),
        Usage(0x01),
		Input(USB_HID_INPUT_DATA | USB_HID_INPUT_VARIABLE | USB_HID_INPUT_ABS),

I realize these usb projects are somewhat complicated so I don't expect a solution, but after getting into the c files in the /usblib/dev directory I'm not sure where to go from here.  Also here are some screen shots of what I see on the sniffer when the device is truned one/connected to my computer.

Here in the first descriptor response it looks like the subclass and protocol settings are applied b/c they are both 0.  For some reason though my bcdUSB status shows a 0x0110 which is usb1.1.  I set this to 0x200 (usb 2.0) in the descriptor in the usbdhidkeyb.c file. 

Next is Configuration descriptor (I think first time it is sent) and it doesn't have a lot of info in it.  It looks like it gets the self powered, no remote wake up settings correct, but i'm not sure why it says must be 1 for usb 1.1 and higher.  It also looks like it gets the power setting correct.

This is the second sending of the configuration descriptor and this is where my settings are incorrect:

It shows the subclass and protocol, both, being 0x01 forcing it to the keyboard protocol.  I'm assuming this is messing up my custom hid functionality.  I'm not sure why one report says one thing and one says another. 

That is the end of communication.  I get this every time and when I compare it to the MSP430 in datapipe mode I don't see the subclass and protocol 0x01's.  Here is a screen shot of the second configuration descriptor from the MSP430 board I have running the HID data pipe code:

My questions are:  Why do the two config reports say different things?  Is that a problem?  If so, looking at my code, what have I missed or where should I look for these settings other thant the usbdhidkeyb.c library file where I've already changed them?  Also, any input or advice to porting this project over to a simple hid data pipe would be greatly appreciated.

I've attached my project and the screenshots in case you can't see them well in this post.

2514.usb_dev_keyboard.zip

1050.ss.zip

Thanks,

Rob

  • Hi Rob,

    I share your pain regarding USB, I just spent a month learning it all. My device is a USB host though, so there is even more complexity and no way to packet trace unless you have an expensive hardware based packet sniffer.

    As a test, instead of replacing the USB_HID_PROTOCOL_KEYB and USB_HID_SCLASS_BOOT with zeros in usbdhidkeyb.c as you have done. Try changing the original  DEFINES for these to 0 in the usbhid.h file, lines 52 and 60. 

    If you find that works, then possibly changing the code referencing these DEFINES through out the usbdhidkeyb.c and usbdhid.c files will help. You will need to replace all USB_HID_PROTOCOL_KEYB and USB_HID_SCLASS_BOOT  with USB_HID_PROTOCOL_NONE and USB_HID_SCLASS_NONE.

    Also, I'd suggest downloading a trial version of USBlyzer (usblyzer.com). It provides a an excellent list of all the USB properties a device has, so you don't need to look through packets to try and work out what the computer has enumerated.

    Glenn.

  • Hey Glenn,

    Thanks for the response those are all good ideas and I'll be getting on them tonight and this weekend and we'll see where they leave me.  I can't imaging having to do a USB host lol!  Thanks again and I'll report back once I get this solved! 

  • So Glen, I took your advice and downloaded USBlyzer.  It is very nicely formatted.  So, after recording the enumeration I see the same thing I saw before.  I also took your advice and set the USB_HID_SCLASS_BOOT definition in the library header to 0 and set the USB_HID_PROTOCOL_KEYB to 0 and still no go.  I also noticed, using USBlyzer, that the usage page stuff is still all keyboard settings.  It doesn't seem to be changing over to my custom one.  I'm not sure what could be going on here as I've changed all this in the code.  Also, the descriptor that has my correct information is the device descriptor.  When it requests descriptors a third time (it does 3 requests...the first and the third are the only ones that have any real info in them) the configuration descriptor, the interface descriptor, the hid descriptor and an endpoint descriptor are all sent over.  In this transmission the interface descriptor has the wrong subclass settings.

    After the transmission of all of the descriptors mentioned above there is a report descriptor that is sent and it is setup for the keyboard from the original project.  I've modified this as shown in my code so where is this coming from?  I feel like the USB framework is pulling information/settings from somewhere other than the usbdhidkyb.c file in the usblib/dev library. 

    I understand that the wrong information is being sent to windows, but what exactly (in this wrong info) is telling windows this is a keyboard and not a generic hid device?  Is it the subclass value?  Is it the usage page?

    Below are some screens of my USBlyzer captures. 

    Device descriptor: (you can see here my subclass field and boot field are 0 like I want them to be)

    Configuration descriptor:

    Multiple Descriptors: (in interface, my subclass and boot fields have changed to 0x01!)

    Report descriptor:

    Its a bit frustrating because I feel like I understand the USB side I just can't figure out how to use TIs driver libraries!  Thanks again to everyone for the help!

    Rob

  • I'll preface this by saying it's past beer thirty on a Saturday in my locale, so I won't be too detailed. I'll check back in on Monday.

    It strikes me as weird that you've changed the define and are not seeing it. Are you sure you are linking in the changes you've made to the usbdhidkb.c? Are you rebuilding the usb library?

    One trick is not to modify the library's file, but copy it into your project with a different name. Use a different name so you can check the .map to see what is linked in. This is rather "advanced" as it depends on understanding the linker and how it looks up symbols (the order of the files on the command line matter). Copy both the .h and .c with new names and modify the #include statements to use the new .h file.

    I'm still working on my HID "datapipe", but I probably won't get back to it until mid next week...

  • Here is a simple echo program using the TivaWare USBlib. It implements MSP430 example programs "datapipe". It enumerates and responses to the MSP430 example java program. It takes a SET REPORT on the control EP0 and responses on EP1 with an interrupt IN packet. Other than that I can't say I've looked into it further.

    I'm using the MSP430's VID and PID.

    Hope it helps

    /*
     * main.c
     *
     *  Created on: Oct 17, 2013
     *
     */
    
    #include <stdbool.h>
    #include <stdint.h>
    
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "driverlib/gpio.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/rom.h"
    
    #include "driverlib/usb.h"
    #include "usblib/usblib.h"
    #include "usblib/usbhid.h"
    #include "usblib/device/usbdevice.h"
    #include "usblib/device/usbdhid.h"
    
    // App globals
    volatile uint8_t USBState=0;
    
    //*****************************************************************************
    //
    // The error routine that is called if the driver library encounters an error.
    //
    //*****************************************************************************
    #ifdef DEBUG
    void
    __error__(char *pcFilename, uint32_t ui32Line)
    {
        while(1)
        {
                USBState|=0x80;
        }
    }
    #endif
    
    #define MAX_PACKET_SIZE   0x40              // Max size of the USB packets. Full Speed is 64 bytes
    
    
    
    typedef struct
    {
        uint8_t buffer[MAX_PACKET_SIZE];
        uint16_t size;
        volatile uint8_t state;
    } tDataBuffer;
    tDataBuffer RXData;
    tDataBuffer TXData;
    // Defined later
    extern tUSBDHIDDevice g_sHIDDataPipeDevice;
    
    // Handler functions
    // Receive handler
    uint32_t
    TXHandler(void *pvCBData, uint32_t ui32Event, uint32_t ui32MsgData,
                    void *pvMsgData)
    {
        int i;
        RXData.state=0;
        RXData.size=0;
        for(i=0;i<MAX_PACKET_SIZE;i++)
            {
                RXData.buffer[i]=0;
            }
        return 0;
    }
    // Receive handler
    uint32_t
    RXHandler(void *pvCBData, uint32_t ui32Event, uint32_t ui32MsgData,
                    void *pvMsgData)
    {
        // Debug info
        static int countRXAvailable=0;
        // static int countTXAvailable=0;
        static int countIdleTimeout=0;
        static int countGetReportBuffer=0;
        static int countGetReport=0;
        static int countSetReport=0;
        static int countDefault=0;
        static uint32_t eventList[20];
        static int eventListIdx=0;
        // End debug vars
        uint32_t readPacketSize;
        uint32_t writePacketSize;
        uint32_t retCode;
        tDataBuffer * myData = pvCBData;
    
        //Debug info
        eventList[eventListIdx++]=ui32Event;
        if(eventListIdx==20)
            {
                eventListIdx=0;
            }
    
        switch(ui32Event)
        {
        case USB_EVENT_CONNECTED:
            USBState|=1;
            break;
        case USB_EVENT_DISCONNECTED:
            USBState&=0xfe;
            break;
        case USB_EVENT_RX_AVAILABLE:
            countRXAvailable++;
            // Untested code
    #if 0
            // Handle set report on the OUT endpoint
            readPacketSize=USBDHIDRxPacketAvailable(&g_sHIDDataPipeDevice);
            if(readPacketSize==0)
            {
                    _nop();//Shouldn't happen
            }
            writePacketSize=USBDHIDPacketRead(&g_sHIDDataPipeDevice,
                    myData->buffer,
                    MAX_PACKET_SIZE
                    ,1);
            if(writePacketSize==0)
            {
                _nop();//Shouldn't happen
            }else if (writePacketSize!=readPacketSize)
            {
                _nop();//Shouldn't happen
            }
            // TODO, may need to wait here for tx available.
            retCode=USBDHIDTxPacketAvailable(&g_sHIDDataPipeDevice);
            if(writePacketSize==0)
            {
                _nop();//Shouldn't happen
            }
            // Echo it out
            retCode=USBDHIDReportWrite(&g_sHIDDataPipeDevice, myData->buffer, writePacketSize,1);
            if (writePacketSize!=readPacketSize)
            {
                _nop();//Shouldn't happen
            }
            return 0;
    #endif
            break;
        case USBD_HID_EVENT_IDLE_TIMEOUT:
            // Not defining a timeout.
            countIdleTimeout++;
            break;
    
        case USBD_HID_EVENT_GET_REPORT_BUFFER:
            countGetReportBuffer++;
            // TODO: Check report id
    
            readPacketSize=(uint32_t)pvMsgData;
            if(readPacketSize>MAX_PACKET_SIZE)
                {
                    _nop(); //Shouldn't happen
                }
    
            return((uint32_t)RXData.buffer);
            break;
        case USBD_HID_EVENT_GET_REPORT:
            countGetReport++;
            break;
        case USBD_HID_EVENT_SET_REPORT:
            countSetReport++;
            // TODO: check report ID
            //set size to let the application know that there is data.
            RXData.size=(uint16_t) (ui32MsgData&0xffff);
            RXData.state=1;
            break;
        default:
            countDefault++;
            break;
        }
    
        // Pretty sure default return should be 0. Need to verify
        return 1;
    }
    
    // USB Descriptors
    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[] =
    {
    		38,
        USB_DTYPE_STRING,
        'M',0x00,'S',0x00,'P',0x00,'4',0x00,'3',0x00,'0',0x00,
        '-',0x00,'U',0x00,'S',0x00,'B',0x00,' ',0x00,'E',0x00,
        'x',0x00,'a',0x00,'m',0x00,'p',0x00,'l',0x00,'e',0x00,
    
    };
    
    //*****************************************************************************
    //
    // The serial number string.
    // MSP code has 0, leaving with this
    //*****************************************************************************
    const uint8_t g_pui8SerialNumberString[] =
    {
        (8 + 1) * 2,
        USB_DTYPE_STRING,
        '1', 0, '2', 0, '3', 0, '4', 0, '5', 0, '6', 0, '7', 0, '8', 0
    };
    
    //*****************************************************************************
    //
    // The data interface description string.
    //
    //*****************************************************************************
    const uint8_t g_pui8DataInterfaceString[] =
    {
    		28,
        USB_DTYPE_STRING,
        'H',0x00,'I',0x00,'D',0x00,' ',0x00,'I',0x00,'n',0x00,
        't',0x00,'e',0x00,'r',0x00,'f',0x00,'a',0x00,'c',0x00,
        'e',0x00
    };
    
    
    //*****************************************************************************
    //
    // The descriptor string table.
    //
    //*****************************************************************************
    const uint8_t * const g_ppui8StringDescriptors[] =
    {
        g_pui8LangDescriptor,
        g_pui8ManufacturerString,
        g_pui8ProductString,
        g_pui8SerialNumberString,
        g_pui8DataInterfaceString
    };
    
    #define NUM_STRING_DESCRIPTORS (sizeof(g_ppui8StringDescriptors) /                \
                                    sizeof(uint8_t *))
    
    // From MSP code. Unused
    /*-----------------------------------------------------------------------------+
    | String Descriptor                                                            |
    |-----------------------------------------------------------------------------*/
    /*
    const uint8_t abromStringDescriptor[] = {
    
        // String index0, language support
        4,        // Length of language descriptor ID
        3,        // LANGID tag
        0x09, 0x04,    // 0x0409 for English
    
        // String index1, Manufacturer
        36,        // Length of this string descriptor
        3,        // bDescriptorType
        'T',0x00,'e',0x00,'x',0x00,'a',0x00,'s',0x00,' ',0x00,
        'I',0x00,'n',0x00,'s',0x00,'t',0x00,'r',0x00,'u',0x00,
        'm',0x00,'e',0x00,'n',0x00,'t',0x00,'s',0x00,
    
        // String index2, Product
        38,        // Length of this string descriptor
        3,        // bDescriptorType
        'M',0x00,'S',0x00,'P',0x00,'4',0x00,'3',0x00,'0',0x00,
        '-',0x00,'U',0x00,'S',0x00,'B',0x00,' ',0x00,'E',0x00,
        'x',0x00,'a',0x00,'m',0x00,'p',0x00,'l',0x00,'e',0x00,
    
        // String index3, Serial Number
        4,        // Length of this string descriptor
        3,        // bDescriptorType
        '0',0x00,
    
        // String index4, Configuration String
        22,        // Length of this string descriptor
        3,        // bDescriptorType
        'M',0x00,'S',0x00,'P',0x00,'4',0x00,'3',0x00,'0',0x00,
        ' ',0x00,'U',0x00,'S',0x00,'B',0x00,
    
        // String index5, Interface String
        28,        // Length of this string descriptor
        3,        // bDescriptorType
        'H',0x00,'I',0x00,'D',0x00,' ',0x00,'I',0x00,'n',0x00,
        't',0x00,'e',0x00,'r',0x00,'f',0x00,'a',0x00,'c',0x00,
        'e',0x00
    };
    */
    
    
    // HUT =  HID Usage Tables 1.12 document
    // 			http://www.usb.org/developers/devclass_docs/Hut1_12v2.pdf
    // HID = Human Interface Devices (HID) Version 1.11
    //			http://www.usb.org/developers/devclass_docs/HID1_11.pdf
    // Note the byte ordering in HID 6.2.2.2
    // See 6.2.2.7 for global items. The Tiva USBlib seems to follow
    // 	the USB HID document's naming convention.
    static const uint8_t g_pui8ucDataPipeReportDescriptor[] =
    {
    
        // 0x06, 0x00, 0xff,
        // HUT chap 3 table 1
        // Vendor specific value 0xff00
        UsagePageVendor(0xff00),
        // 0x09, 0x01,
        // Arbitrary number as we are vendor specific
        Usage(0x01),
        // 0xa1, 0x01,
        Collection(USB_HID_APPLICATION),
            // 0x85, 0x3f,
            // Vendor specific. Appears arbitrary.
            // ID can be left undefined if only one report type is created
            ReportID(0x3f),
                // 0x95, 0x3f,
                // The number of items in the report
                ReportCount(MAX_PACKET_SIZE-1),
                // 0x75, 0x08,
                // As this is just generic data, 8 bits in a byte
                ReportSize(0x08),
                // 0x25, 0x01,
                // Not sure why this is defined
                // Or why it's not max 0xff and min 0x00
                LogicalMaximum(0x1),
                // 0x15, 0x01,
                // See above
                LogicalMinimum(0x1),
                // 0x09, 0x01,
                // Arbitrary number as we are vendor specific
                Usage(0x01),
                // 0x81, 0x02, Input (Data,Var,Abs)
                // This shows we are describing the report that goes to the host
                Input(USB_HID_INPUT_DATA | USB_HID_INPUT_VARIABLE | USB_HID_INPUT_ABS),
                // Second report, same except it's output
            ReportID(0x3f),
                ReportCount(MAX_PACKET_SIZE-1),
                ReportSize(0x08),
                LogicalMaximum(0x1),
                LogicalMinimum(0x1),
                Usage(0x01),
                Output(USB_HID_INPUT_DATA | USB_HID_INPUT_VARIABLE | USB_HID_INPUT_ABS),
        EndCollection
    };
    //*****************************************************************************
    //
    // The HID class descriptor table. For the mouse class, we have only a single
    // report descriptor.
    //
    //*****************************************************************************
    static const uint8_t * const g_pui8ucDataPipeClassDescriptors[] =
    {
            g_pui8ucDataPipeReportDescriptor
    };
    
    //*****************************************************************************
    //
    // HID device configuration descriptor.
    //
    // It is vital that the configuration descriptor bConfigurationValue field
    // (byte 6) is 1 for the first configuration and increments by 1 for each
    // additional configuration defined here.  This relationship is assumed in the
    // device stack for simplicity even though the USB 2.0 specification imposes
    // no such restriction on the bConfigurationValue values.
    //
    // Note that this structure is deliberately located in RAM since we need to
    // be able to patch some values in it based on client requirements.
    //
    //*****************************************************************************
    uint8_t g_pui8DataPipeDescriptor[] =
    {
        //
        // Configuration descriptor header.
        //
        9,                          // Size of the configuration descriptor.
        USB_DTYPE_CONFIGURATION,    // Type of this descriptor.
        USBShort(34),               // The total size of this full structure.
        1,                          // The number of interfaces in this
                                    // configuration.
        1,                          // The unique value for this configuration.
        5,                          // The string identifier that describes this
                                    // configuration.
        USB_CONF_ATTR_SELF_PWR,     // Bus Powered, Self Powered, remote wake up.
        250,                        // The maximum power in 2mA increments.
    };
    
    //*****************************************************************************
    //
    // The HID descriptor for the datapipe device.
    //
    //*****************************************************************************
    static const tHIDDescriptor g_sDataPipeHIDDescriptor =
    {
        9, // bLength
        USB_HID_DTYPE_HID, // bDescriptorType
        0x111, // bcdHID (version 1.11 compliant)
        0, // bCountryCode (not localized)
        1, // bNumDescriptors
        USB_HID_DTYPE_REPORT, // Report descriptor
        sizeof(g_pui8ucDataPipeReportDescriptor) // Size of report descriptor
    };
    
    
    //*****************************************************************************
    //
    // The remainder of the configuration descriptor is stored in flash since we
    // don't need to modify anything in it at runtime.
    //
    //*****************************************************************************
    uint8_t g_pui8HIDInterface[HIDINTERFACE_SIZE] =
    {
        //
        // HID Device Class Interface Descriptor.
        //
        9,                          // Size of the interface descriptor.
        USB_DTYPE_INTERFACE,        // Type of this descriptor.
        0,                          // The index for this interface.
        0,                          // The alternate setting for this interface.
        1,                          // The number of endpoints used by this
                                    // interface.
        USB_CLASS_HID,              // The interface class
        USB_HID_SCLASS_NONE,        // The interface sub-class.
        USB_HID_PROTOCOL_NONE,     // The interface protocol for the sub-class
                                    // specified above.
        5,                          // The string index for this interface.
    };
    
    const uint8_t g_pui8HIDInEndpoint[HIDINENDPOINT_SIZE] =
    {
        //
        // Interrupt IN endpoint descriptor
        //
        7,                          // The size of the endpoint descriptor.
        USB_DTYPE_ENDPOINT,         // Descriptor type is an endpoint.
        USB_EP_DESC_IN | USBEPToIndex(USB_EP_1),
        USB_EP_ATTR_INT,            // Endpoint is an interrupt endpoint.
        USBShort(USBFIFOSizeToBytes(USB_FIFO_SZ_64)),
                                    // The maximum packet size.
        16,                         // The polling interval for this endpoint.
    };
    
    // Not needed until the out interrupt is enabled
    // TODO: enable by adding this array to g_psHIDSections
    //      and setting g_sHIDDataPipeDevice.bUseOutEndpoint to true
    //
    const uint8_t g_pui8HIDOutEndpoint[HIDOUTENDPOINT_SIZE] =
    {
        //
        // Interrupt Out endpoint descriptor
        //
        7,                          // The size of the endpoint descriptor.
        USB_DTYPE_ENDPOINT,         // Descriptor type is an endpoint.
        USB_EP_DESC_OUT | USBEPToIndex(USB_EP_1),
        USB_EP_ATTR_INT,            // Endpoint is an interrupt endpoint.
        USBShort(USBFIFOSizeToBytes(USB_FIFO_SZ_64)),
                                    // The maximum packet size.
        16,                         // The polling interval for this endpoint.
    };
    
    //*****************************************************************************
    //
    // The HID configuration descriptor is defined as four or five sections
    // depending upon the client's configuration choice.  These sections are:
    //
    // 1.  The 9 byte configuration descriptor (RAM).
    // 2.  The interface descriptor (RAM).
    // 3.  The HID report and physical descriptors (provided by the client)
    //     (FLASH).
    // 4.  The mandatory interrupt IN endpoint descriptor (FLASH).
    // 5.  The optional interrupt OUT endpoint descriptor (FLASH).
    //
    //*****************************************************************************
    const tConfigSection g_sHIDConfigSection =
    {
        sizeof(g_pui8DataPipeDescriptor),
        g_pui8DataPipeDescriptor
    };
    
    const tConfigSection g_sHIDInterfaceSection =
    {
        sizeof(g_pui8HIDInterface),
        g_pui8HIDInterface
    };
    
    const tConfigSection g_sHIDInEndpointSection =
    {
        sizeof(g_pui8HIDInEndpoint),
        g_pui8HIDInEndpoint
    };
    
    const tConfigSection g_sHIDOutEndpointSection =
    {
        sizeof(g_pui8HIDOutEndpoint),
        g_pui8HIDOutEndpoint
    };
    
    //*****************************************************************************
    //
    // HID descriptor block.
    //
    //*****************************************************************************
    tConfigSection g_sHIDDescriptorSection =
    {
       sizeof(g_sDataPipeHIDDescriptor),
       (const uint8_t *)&g_sDataPipeHIDDescriptor
    };
    
    //*****************************************************************************
    //
    // This array lists all the sections that must be concatenated to make a
    // single, complete HID configuration descriptor.
    //
    //*****************************************************************************
    const tConfigSection *g_psHIDSections[] =
    {
        &g_sHIDConfigSection,
        &g_sHIDInterfaceSection,
        &g_sHIDDescriptorSection,
        &g_sHIDInEndpointSection,
    //    &g_sHIDOutEndpointSection,
    };
    
    #define NUM_HID_SECTIONS        (sizeof(g_psHIDSections) /                    \
                                     sizeof(g_psHIDSections[0]))
    
    //*****************************************************************************
    //
    // The header for the single configuration we support.  This is the root of
    // the data structure that defines all the bits and pieces that are pulled
    // together to generate the configuration descriptor.  Note that this must be
    // in RAM since we need to include or exclude the final section based on
    // client supplied initialization parameters.
    //
    //*****************************************************************************
    tConfigHeader g_sHIDConfigHeader =
    {
        NUM_HID_SECTIONS,
        g_psHIDSections
    };
    
    //*****************************************************************************
    //
    // Configuration Descriptor.
    //
    //*****************************************************************************
    const tConfigHeader * const g_ppsHIDConfigDescriptors[] =
    {
        &g_sHIDConfigHeader
    };
    
    
    
    tHIDReportIdle g_psReportIdle[1] =
    {
            { 0, 0x3f, 0, 0 } // Report 0x3f never polled
    };
    
    // From msp430 example descriptor.h
    // Configuration Constants that can change
    // #define that relates to Device Descriptor
    #define USB_VID               0x2047        // Vendor ID (VID)
    #define USB_PID               0x0301        // Product ID (PID)
    
    tUSBDHIDDevice g_sHIDDataPipeDevice =
    {
        //
        // Stealing the MSP430 id so it works with the java app
        //
        //
        USB_VID,
        //
        // The product ID you have assigned for this device.
        //
        USB_PID,
        //
        // The power consumption of your device in milliamps.
        //
        250,
        //
        // The value to be passed to the host in the USB configuration descriptor�s
        // bmAttributes field.
        //
        USB_CONF_ATTR_BUS_PWR,
        //
        // This mouse supports the boot subclass.
        //
        USB_HID_SCLASS_NONE,
        //
        // This device supports the BIOS mouse report protocol.
        //
        USB_HID_PROTOCOL_NONE,
        //
        // The device has a single input report.
        //
        1,
        //
        // A pointer to our array of tHIDReportIdle structures. For this device,
        // the array must have 1 element (matching the value of the previous field).
        //
        g_psReportIdle,
        //
        // A pointer to your receive callback event handler.
        //
        RXHandler,
        //
        // A value that you want passed to the receive callback alongside every
        // event.
        //
        (void *)&RXData,
        //
        // A pointer to your transmit callback event handler.
        //
        TXHandler,
        //
        // A value that you want passed to the transmit callback alongside every
        // event.
        //
        (void *)&TXData,
        //
        // This device does not want to use a dedicated interrupt OUT endpoint
        // since there are no output or feature reports required.
        //
        false,
        //
        // A pointer to the HID descriptor for the device.
        //
        &g_sDataPipeHIDDescriptor,
        //
        // A pointer to the array of HID class descriptor pointers for this device.
        // The number of elements in this array and their order must match the
        // information in the HID descriptor provided above.
        //
        g_pui8ucDataPipeClassDescriptors,
        //
        // A pointer to your string table.
        //
        g_ppui8StringDescriptors,
        //
        // The number of entries in your string table. This must equal
        // (1 + (5 + (num HID strings)) * (num languages)).
        //
        NUM_STRING_DESCRIPTORS,
    
        // Config section
        g_ppsHIDConfigDescriptors
    
    };
    const char report_desc_HID0[]=
    {
        0x06, 0x00, 0xff,    // Usage Page (Vendor Defined)
        0x09, 0x01,    // Usage Page (Vendor Defined)
        0xa1, 0x01,    // COLLECTION (Application)
        0x85, 0x3f,    // Report ID (Vendor Defined)
        0x95, MAX_PACKET_SIZE-1,    // Report Count
        0x75, 0x08,    // Report Size
        0x25, 0x01,    // Usage Maximum
        0x15, 0x01,    // Usage Minimum
        0x09, 0x01,    // Vendor Usage
        0x81, 0x02,    // Input (Data,Var,Abs)
        0x85, 0x3f,    // Report ID (Vendor Defined)
        0x95, MAX_PACKET_SIZE-1,    // Report Count
        0x75, 0x08,    // Report Size
        0x25, 0x01,    // Usage Maximum
        0x15, 0x01,    // Usage Minimum
        0x09, 0x01,    // Vendor Usage
        0x91 ,0x02,    // Ouput (Data,Var,Abs)
        0xc0    // end Application Collection
    };
    
    
    
    int main(void)
    {
        //
        // Enable lazy stacking for interrupt handlers.  This allows floating-point
        // instructions to be used within interrupt handlers, but at the expense of
        // extra stack usage.
        //
        ROM_FPULazyStackingEnable();
    
        //
        // Set the clocking to run from the PLL at 50MHz.
        //
        ROM_SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
                           SYSCTL_XTAL_16MHZ);
    
        //
        // Enable the GPIO peripheral used for USB, and configure the USB
        // pins.
        //
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
        ROM_GPIOPinTypeUSBAnalog(GPIO_PORTD_BASE, GPIO_PIN_4 | GPIO_PIN_5);
    
        // Init buffer
        RXData.state=0;
        RXData.size=0;
        //
        // Set the USB stack mode to Device mode with VBUS monitoring.
        //
        USBStackModeSet(0, eUSBModeForceDevice, 0);
    
        //
        // Pass our device information to the USB library and place the device
        // on the bus.
        //
        USBDHIDInit(0, &g_sHIDDataPipeDevice);
        while(1)
        {
            if(RXData.state==1)
                {
                    // Echo the report back to PC
                    USBDHIDReportWrite(&g_sHIDDataPipeDevice,RXData.buffer,RXData.size,0);
                    RXData.state=2;
                }
        }
    
    }
    

    edit: clarify that this is for a Tiva part.

  • Hey stepman,

    Thanks so much for the data pipe example!!  I took your advice in your second to last post and moved all of the necessary files from the usblib directory to my project's working directory and that solved my issue with the settings not being changed in all the descriptors.

    I've been studying the example you sent me, but I need to spend some more time on it.  I think the descriptors are setup correctly after comparing my descriptor values to what you have which is good.  I got tripped up in thinking I need two endpoints (one in one out), but now I see you can just use the control end point 0 which doesn't count in the numEndpoint value in the HID interface descriptor.

    The RxHandler and some of the other code is a bit daunting to me so I need to spend some time studying it and working through the usual compilation bugs etc before I can really begin to understand it well.  I'll report back after after this though.  Thanks so much for that file!  It looks like a great solution/learning example!

    One quick clarification. What does the #if 0 -#endif do in this section?

    #if 0
            // Handle set report on the OUT endpoint
            readPacketSize=USBDHIDRxPacketAvailable(&g_sHIDDataPipeDevice);
            if(readPacketSize==0)
            {
                    _nop();//Shouldn't happen
            }
            writePacketSize=USBDHIDPacketRead(&g_sHIDDataPipeDevice,
                    myData->buffer,
                    MAX_PACKET_SIZE
                    ,1);
            if(writePacketSize==0)
            {
                _nop();//Shouldn't happen
            }else if (writePacketSize!=readPacketSize)
            {
                _nop();//Shouldn't happen
            }
            // TODO, may need to wait here for tx available.
            retCode=USBDHIDTxPacketAvailable(&g_sHIDDataPipeDevice);
            if(writePacketSize==0)
            {
                _nop();//Shouldn't happen
            }
            // Echo it out
            retCode=USBDHIDReportWrite(&g_sHIDDataPipeDevice, myData->buffer, writePacketSize,1);
            if (writePacketSize!=readPacketSize)
            {
                _nop();//Shouldn't happen
            }
            return 0;
    #endif

    Also,  it looks like this section actually echos the receive message out so why do you have the below in main?

    if(RXData.state==1)
                {
                    // Echo the report back to PC
                    USBDHIDReportWrite(&g_sHIDDataPipeDevice,RXData.buffer,RXData.size,0);
                    RXData.state=2;
                }
  • #if 0

    #endif

    just comments out the code using the preprocessor. I use it because /* */ style comments can't be nested. It doesn't get compiled.

    Ignore the USB_EVENT_RX_AVAILABLE case as it was coded for the OUT endpoint 1 event. Only the USBD_HID_EVENT_GET_REPORT_BUFFER (misleading name BTW) and  USBD_HID_EVENT_SET_REPORT cases have meaningful code that get executed.

    USB_EVENT_RX_AVAILABLE would happen if you receive the HID report on OUT Endpoint 1. That isn't enabled in the posted code (nor did I get it working in my testing).

    Also ignore the variables that get incremented (someVar++) and the eventList array. They are just there so I could see what happened without using breakpoints.

  • Ok cool that makes sense now.  I've got a project put together using that code and it looks like CCS is having problems with structures in usblib.h that are using the PACKED directive.  What compiler are you using?  I'm wondering if I"m seeing a compatibility issue. 

    It looks like your code compiles, but all of the included libraries have issues with the structures and what not your main is calling.  I've attached to console log file for example sake.  Still working on this...

    The source code you gave me is making a lot more sense after spending some time with it. 

    Log File:

    **** Build of configuration Debug for project usb_customHID_datapipe ****
    
    "C:\\ti\\ccsv5\\utils\\bin\\gmake" -k all 
    'Building file: ../main.c'
    'Invoking: ARM Compiler'
    "C:/ti/ccsv5/tools/compiler/arm_5.0.6/bin/armcl" -mv7M4 --code_state=16 --float_support=FPv4SPD16 --abi=eabi -me -g --include_path="C:/ti/TivaWare_C_Series-1.1" --include_path="C:/ti/ccsv5/tools/compiler/arm_5.0.6/include" --define=PART_TM4C123GH6PM --define=ccs="ccs" --diag_warning=225 --display_error_number --diag_wrap=off --preproc_with_compile --preproc_dependency="main.pp"  "../main.c"
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 198: error #80: expected a type specifier
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 198: error #66: expected a ";"
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 320: error #80: expected a type specifier
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 320: error #102: "__attribute__" has already been declared in the current scope
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 320: error #66: expected a ";"
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 409: error #80: expected a type specifier
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 409: error #102: "__attribute__" has already been declared in the current scope
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 409: error #66: expected a ";"
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 531: error #80: expected a type specifier
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 531: error #102: "__attribute__" has already been declared in the current scope
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 531: error #66: expected a ";"
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 590: error #80: expected a type specifier
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 590: error #102: "__attribute__" has already been declared in the current scope
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 590: error #66: expected a ";"
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 663: error #80: expected a type specifier
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 663: error #102: "__attribute__" has already been declared in the current scope
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 663: error #66: expected a ";"
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 713: error #80: expected a type specifier
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 713: error #102: "__attribute__" has already been declared in the current scope
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 713: error #66: expected a ";"
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 788: error #80: expected a type specifier
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 788: error #102: "__attribute__" has already been declared in the current scope
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 788: error #66: expected a ";"
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 818: error #80: expected a type specifier
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 818: error #102: "__attribute__" has already been declared in the current scope
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 818: error #66: expected a ";"
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 919: error #20: identifier "tUSBRequest" is undefined
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 1129: error #20: identifier "tDescriptorHeader" is undefined
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 1131: error #20: identifier "tDescriptorHeader" is undefined
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 1131: error #20: identifier "tDescriptorHeader" is undefined
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 1135: error #20: identifier "tConfigDescriptor" is undefined
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 1137: error #20: identifier "tInterfaceDescriptor" is undefined
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 1137: error #20: identifier "tConfigDescriptor" is undefined
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 1140: error #20: identifier "tEndpointDescriptor" is undefined
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 1141: error #20: identifier "tInterfaceDescriptor" is undefined
    "C:/ti/TivaWare_C_Series-1.1/usblib/usblib.h", line 1187: warning #230-D: trailing comma is nonstandard
    "C:/ti/TivaWare_C_Series-1.1/usblib/usbhid.h", line 541: error #80: expected a type specifier
    "C:/ti/TivaWare_C_Series-1.1/usblib/usbhid.h", line 541: error #102: "__attribute__" has already been declared in the current scope
    "C:/ti/TivaWare_C_Series-1.1/usblib/usbhid.h", line 541: error #66: expected a ";"
    "C:/ti/TivaWare_C_Series-1.1/usblib/usbhid.h", line 588: error #20: identifier "tHIDClassDescriptorInfo" is undefined
    "C:/ti/TivaWare_C_Series-1.1/usblib/usbhid.h", line 590: error #80: expected a type specifier
    "C:/ti/TivaWare_C_Series-1.1/usblib/usbhid.h", line 590: error #102: "__attribute__" has already been declared in the current scope
    
    >> Compilation failure
    "C:/ti/TivaWare_C_Series-1.1/usblib/usbhid.h", line 590: error #66: expected a ";"
    "C:/ti/TivaWare_C_Series-1.1/usblib/device/usbdevice.h", line 171: error #20: identifier "tDescriptorHeader" is undefined
    "C:/ti/TivaWare_C_Series-1.1/usblib/device/usbdevice.h", line 178: error #20: identifier "tInterfaceDescriptor" is undefined
    "C:/ti/TivaWare_C_Series-1.1/usblib/device/usbdevice.h", line 182: error #20: identifier "tEndpointDescriptor" is undefined
    "C:/ti/TivaWare_C_Series-1.1/usblib/device/usbdhid.h", line 899: error #20: identifier "tHIDDescriptor" is undefined
    "../main.c", line 165: warning #112-D: statement is unreachable
    "../main.c", line 88: warning #552-D: variable "eventList" was set but never used
    "../main.c", line 92: warning #179-D: variable "writePacketSize" was declared but never referenced
    "../main.c", line 93: warning #179-D: variable "retCode" was declared but never referenced
    "../main.c", line 94: warning #179-D: variable "myData" was declared but never referenced
    "../main.c", line 413: error #20: identifier "tHIDDescriptor" is undefined
    "../main.c", line 526: error #42: expression must have arithmetic or pointer type
    "../main.c", line 700: warning #225-D: function declared implicitly
    "../main.c", line 705: warning #225-D: function declared implicitly
    "../main.c", line 712: warning #225-D: function declared implicitly
    "../main.c", line 713: warning #225-D: function declared implicitly
    48 errors detected in the compilation of "../main.c".
    gmake: *** [main.obj] Error 1
    gmake: Target `all' not remade because of errors.
    
    **** Build Finished ****
    

    So are the RxHandler and TxHandler basically your service routine for the USB0 device?  Also, why does it look like you define the datapipe_report_descriptor twice?

  • Robbie Valentine said:
      I've got a project put together using that code and it looks like CCS is having problems with structures in usblib.h that are using the PACKED directive.

    Enable support for GCC extensions so the compiler supports the __attribute__ keyword. In CCS it's under: Project Properites -> build -> ARM Compiler -> Advanced -> Language options. Another artifact of making your own project in CCS rather than using the examples. I ran into it too.

    usblib.h has #define PACKED __attribute__ ((packed)) which changes the way the compiler stores the variable in memory.

    Robbie Valentine said:
    So are the RxHandler and TxHandler basically your service routine for the USB0 device?

    Yes. I believe you could even make them into a single function and handle both the read and write events. My example is far from complete, as I don't have a full enough understanding of the USB architecture to know the exact requirements are.

    Robbie Valentine said:
    Also, why does it look like you define the datapipe_report_descriptor twice?

    I pulled that from the MSP430 code, which I don't have hardware for (hmm... I might have some around...). The are 2 reports, one for the IN case and one for the OUT case.

  • Hey Stepman,

    So I got your code up and running after pointing out the GCC extensions issue.  I can't thank you enough for this!!!  The ARM is now being recognized by my python application just like before!  I don't think I could have quite figured this out on my own so thank you so much!!  It makes so much more sense to me now though after seeing a working solution.  I was wondering though...

    You don't seem to use the below structure anywhere...was this just for reference while you were writing the other report descriptor with the macros?

    const char report_desc_HID0[]=
    {
        0x06, 0x00, 0xff,    // Usage Page (Vendor Defined)
        0x09, 0x01,    // Usage Page (Vendor Defined)
        0xa1, 0x01,    // COLLECTION (Application)
        0x85, 0x3f,    // Report ID (Vendor Defined)
        0x95, MAX_PACKET_SIZE-1,    // Report Count
        0x75, 0x08,    // Report Size
        0x25, 0x01,    // Usage Maximum
        0x15, 0x01,    // Usage Minimum
        0x09, 0x01,    // Vendor Usage
        0x81, 0x02,    // Input (Data,Var,Abs)
        0x85, 0x3f,    // Report ID (Vendor Defined)
        0x95, MAX_PACKET_SIZE-1,    // Report Count
        0x75, 0x08,    // Report Size
        0x25, 0x01,    // Usage Maximum
        0x15, 0x01,    // Usage Minimum
        0x09, 0x01,    // Vendor Usage
        0x91 ,0x02,    // Ouput (Data,Var,Abs)
        0xc0    // end Application Collection
    };

    You seem to reference the other structure for the report descriptor in the HIDdatapipedevice.

    Also, how did you figure out how to write the RxHandler that way?  Is there a template or something I'm missing or did you just follow the verbage in the USB users guide?  I used the keyboard example but I wasn't even close to understanding it because of how hard it was to follow.  I'm just curious about how you went about developing that since I spent so much time on it and was not nearly as successful lol.

    With the direction from step man I can attest this works on the Tiva C launchpad with the TM4C123G

  • report_desc_HID0[] is a straight copy of the msp430 usb code. I planned on comparing it to the one I created the TivaWare USB report macros (like Usage(), Collection(USB_HID_APPLICATION), etc.) in code, but ended up eyeballing it. Feel free to get rid of it.

    The code and comments are really not up to snuff as reference for this, but I thought I'd post it anyways as it worked for me. I may or may not get a chance to clean it up and code it up with similar abstractions as the library.

    I'll post tomorrow on how I attacked the problem, if you are interested. But it may just end up being a bit of rambling, just like my lab notes...

    Also, are you seeing the SET REPORT on EP0, or on EP1 via an OUT interrupt (on the USB side)? I tried to enable the OUT (ie input to the microcontroller) on EP1, but it didn't seem to work. If you get a chance what does the MSP example do?

  • Hey man np.  I haven't messed with the dedicated out EP yet.  I'm having  a lot of intermittent issues debugging with my USB device plugged in and communicating with my PC application.  I have noticed that I'm not able to get hit any break points in the TXhandler..like it never gets in the routine.  Have you had this problem?

  • Robbie Valentine said:
    I have noticed that I'm not able to get hit any break points in the TXhandler..like it never gets in the routine.  Have you had this problem?

    TXHandler worked for me, perhaps have it increment a global debug variable to see if it's running.

    I'm pretty sure the handler code I posted is not reliable in that I'm not check for an overrun condition. I haven't looked into getting USB to slow down a SET REPORT from the host.

    Robbie Valentine said:
    I'm having  a lot of intermittent issues debugging with my USB device plugged in and communicating with my PC application.

    This may seem obvious, but remember that while the debugger has halted your MCU, it can't respond to the USB interface.

    Also, make sure the debug USB interface is on a different root hub/pc host interface as the application interface. That way, if the host notices a fault, it won't take down the debug connection.

    I'm pretty sure the RX and TX handler are part of the ISR for USB. Setting breakpoints in ISR code can have issues. I know setting a breakpoint in between GET_REPORT_BUFFER* and SET_REPORT events will have problems. Make sure the handler doesn't do anything that takes too long, delays, or depends on other interrupts such as an unbuffered uart.

    *Slight digression, but GET_REPORT_BUFFER took me longer than it should have for me to figure out. I kept looking at that as the buffer for a "Get Report", not get the "Set Report" buffer. Ahh the power of a name.

  • Ok having them on different root hubs makes sense...I need to double check that.  The names got me too.  That one in particular was  a bit misleading. 

    I think my problem may be more with the timer module than USB now after spending the last two nights working on it.  I've got a GUI that sends commands to the ARM like start timer, stop timer and change timer speed to a speed I pick out of a drop down box.  It runs fine the first time and I can reconfigure it if I go down in speed but I can never reconfigure it to go faster.    It may have something to do with the two 32bit timers being concatenated or that i'm re-running the same setup function for it to change it's period register...not sure yet. 

    The USB seems to be echoing the packet back reliably though so I may have been mistaken in putting the issue on USB.

  • I know this is an old post but would you mind sharing the keyboard example that you ported over to the TM4C123GH6PM launchpad? I've been working on the same thing but am quite a novice.

  • Morris3,

    I am not able to post up my source code/project because I have incorporated this data pipe USB functionality in a larger product design.  To get this to work, I used step man's code and just worked it into the USB example that TI provides for this Tiva part.  I'll see if I can get some code together for you when I get home, but I'm on travel right now and it will be over a week before I get back.  I had to spend a lot of time and put a lot of work into getting this to work because it is much more difficult to accomplish this on Tivas then it is on the MSP430's. 


    Stepman's code DOES work for the these parts so stick with it and keep working on it.  I'll try to provide more support when I get home to my source code.  Feel free to remind me i a few weeks if I forget :)

    Thanks,

    Rob

  • I was able, with the help of some others on these forums, to take the example program for another board from the Tivaware 2.0 package and make it work on the TM4C123GXL. So thanks for the reply but my problem has been solved.

  • Hi Chris,

    Can you please post your code?

    I am trying to create a "Data Pipe" between TM4C123GXL Device and an Android Host. So, a working example between the Launchpad and PC would be a great starting point for me.

    --
    Alok