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.

Composite Mass Storage on TIVA tm4c129 not working

Other Parts Discussed in Thread: TM4C129XNCZAD

Hi,

I am using the TIVA TM4C129XNCZAD to create an application that uses a USB port to act as a composite device supporting a custom HID, CDC, and a mass storage device.  I am able to get both the custom HID and CDC working and I am currently adding the mass storage.  If I configure the USB port to be standalone mass storage device, the port actually works and is recognized by the PC as a mass storage drive (I have not tried file access or data transfer yet over this interface).  

However, if I use USBDMSCCompositeInit to initialize the mass storage to be under a composite device, the PC does not see the mass storage device.  Using a USB sniffer, I see that the TIVA is stalling on both the Get Max LUN message and the Control Transfer message.  

With the MSD in standalone USB, the sniffer shows that both messages go through.  

I have scrubbed my code and the TI documentation several times already - I even found an error in the TI USB documentation spmu297a.pdf: 

p144-145

//
// The media access functions.
//
{
USBDMSCStorageOpen,
USBDMSCStorageClose,
144 May 07, 2015
Device Functions
USBDMSCStorageRead,
USBDMSCStorageWrite,
USBDMSCStorageNumBlocks
},

tMSCDMedia defined in the usblib is defined as having 6 elements.

The code to add the MSD is also quite straightforward.  At this point, I am suspecting that there is a bug in the TIVA USB library.  Please confirm or deny and give guidance.

-Yan

  • Hello Yan

    I would suggest attaching your code that we can try on the DK-TM4C129x to see the issue

    Regards
    Amit
  • Sorry, but I found a bug in my code and got past the issue. I had an extra call to USBDHIDCompositeInit after I initialized the composite device. After taking out the extra USBDHIDCompositeInit call, the device is responding to the LUN query.

    Thank you for responding.

    Yan
  • Hello Yan,

    Please post any issues/query regarding TM4C12x devices to the TM4C Forum

    e2e.ti.com/.../908

    Regards
    Amit
  • Hi,

    I got past the initial issue of Mass Storage not working under composite. However, right now I am having issues with HID and mass storage under composite. Individually, they work, but when I combine them under a composite, they don't enumerate correctly. I threw my code into one file and attached it below:

    Please help.

    Yan


    /*
    * main.c
    */

    #include <stdint.h>
    #include <string.h>
    #include <stdbool.h>
    #include "usblib/usblib.h"
    #include "usblib/usbhid.h"
    #include "usblib/usbcdc.h"
    #include "usblib/device/usbdevice.h"
    #include "usblib/device/usbdhid.h"
    #include "usblib/device/usbdcdc.h"
    #include "usblib/device/usbdcomp.h"
    #include "usblib/device/usbdmsc.h"
    #include "driverlib/rom.h"
    #include "driverlib/rom_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/systick.h"
    #include "pinout.h"
    #include "inc/hw_memmap.h"
    #include "driverlib/gpio.h"

    #define LEDOn() ROM_GPIOPinWrite(CLP_D1_PORT, CLP_D1_PIN, CLP_D1_PIN);

    #define LEDOff() ROM_GPIOPinWrite(CLP_D1_PORT, CLP_D1_PIN, 0)
    #define LEDToggle() \
    ROM_GPIOPinWrite(CLP_D1_PORT, CLP_D1_PIN, \
    (ROM_GPIOPinRead(CLP_D1_PORT, CLP_D1_PIN) ^ \
    CLP_D1_PIN));


    #define USB_MASS_STORAGE_CURRENT_CONSUMPTION_MA 0
    #define USB_MSD_BUFFER_SIZE 0x1000
    #define USB_MSD_1_BLOCK_SIZE 512
    #define USB_MSD_1_NUM_SECTORS 131072
    #define USB_MSD_1_MAX_BLOCKS_PER_TRANSACTION (USB_MSD_BUFFER_SIZE / USB_MSD_1_BLOCK_SIZE)
    #define TI_USB_VID 0x1CBE
    #define TI_USB_MSD_PID 0x0005


    // One byte for Report ID - only used in USB transport, but still part of message.
    #define NUM_USB_HID_PHY_BYTES 1

    // Function status codes
    #define USB_SUCCESS 0
    #define USB_UNSUPPORTED_CONFIG (USB_SUCCESS + 1)

    // USB configuration. Currently support USB HID only. Composite HID and Bulk is on the roadmap.
    #define USB_CONFIG_HID 1

    #define TI_USB_VID 0x1CBE
    #define TI_USB_SERIAL_PID_HID 0x0301
    #define TI_USB_SERIAL_PID_CHIDCDC 0x0009

    // USB HID Report size 64x8 bits
    #define USB_HID_REPORT_CNT 63
    #define USB_HID_REPORT_SZ 8

    // Assume our device is not drawing any current as the TIVA does not rely on power from USB host
    #define USB_HID_CURRENT_CONSUMPTION_MA 0
    #define USB_CDC_CURRENT_CONSUMPTION_MA 0
    #define USB_MASS_STORAGE_CURRENT_CONSUMPTION_MA 0

    // Initially support one report. Can add more in the future if needed.
    #define USB_HID_SINGLE_INPUT_REPORT 1

    // 0 indicates infinite period basically disabling periodic sending of reports
    #define USB_HID_DEVICE_IDLE_REPORT_PERIOD_INF 0

    // only 1 report so set to 0
    #define USB_HID_DEVICE_IDLE_REPORT_ID_TAG 0

    // HID release 1.11
    #define USB_HID_RELEASE_1_11 0x0111

    // Number of class specific descriptors in this device. Must be at least 1.
    #define USB_HID_FSS_NUM_CLASS_SPECIFIC_DESCRIPTORS 1

    //*************** Configuration Descriptor constants *********************************************
    // Based on HID_1_11.pdf section E.2
    #define USB_HID_CONFIGURATION_DESCRIPTOR_SIZE 9

    // Max power consumption in units of 2mA
    #define USB_HID_GCQ_MAX_POWER_CONSUMPTION 1

    #define USB_HID_GCQ_NUM_INTERFACES 1

    // Since we only support one configuration, not sure if this value matters
    #define USB_HID_GCQ_CONFIG_VAL 1

    // Index into g_p_usb_hid_string_Descriptor_arry for config string
    #define USB_HID_GCQ_CONFIG_STRING_IDX 6

    //*************** Interface Descriptor constants *********************************************
    // Based on HID_1_11.pdf section E.3
    #define USB_HID_INTERFACE_DESCRIPTOR_SIZE 9

    // Interface number
    #define USB_HID_GCQ_INTERFACE0_DESCRIPTOR_IDX 0

    // No alternate interface setting
    #define USB_HID_GCQ_INTERFACE0_ALTERNATE_SETTING 0

    // 1 IN interrupt end point used
    #define USB_HID_GCQ_INTERFACE0_NUM_ENDPTS 2

    // Index into g_p_usb_hid_string_Descriptor_arry
    #define USB_HID_GCQ_INTF_STRING_IDX 5

    //*************** Endpoint Descriptor constants *********************************************
    // Based on HID_1_11.pdf section E.5
    #define USB_HID_ENDPOINT_DESCRIPTOR_SIZE 7

    // IN endpoint, end point number 1
    #define USB_HID_ENDPOINT1_ADDRESS 0x81

    // OUT endpoint, end point number 2
    #define USB_HID_ENDPOINT2_ADDRESS 0x01

    // Set Max packet size to 64 bytes - we want to be able to do 64KB/s
    #define USB_HID_ENDPOINT1_MAX_PACKET_SIZE 0x40
    #define USB_HID_ENDPOINT2_MAX_PACKET_SIZE USB_HID_ENDPOINT1_MAX_PACKET_SIZE

    // Max possible payload is 64 bytes minus one byte for the EndPoint ID
    #define USB_HID_MAX_PAYLOAD_SIZE (USB_HID_ENDPOINT1_MAX_PACKET_SIZE - 1)

    // One byte reserved for future utilization
    #define USB_HID_GCQ_MAX_PAYLOAD_SIZE (USB_HID_MAX_PAYLOAD_SIZE - 1)

    // HID messages have a 2 byte header - first byte as report ID and second as a undefined reserved byte
    #define USB_HID_MSG_HEADER_SIZE 2


    // Use 100ms for the poll interval since GCQ will use interrupts to send low latency data.
    // Lower poll intervals incur more processing from the processor
    #define USB_HID_ENDPOINT1_POLL_INTERVAL 100
    #define USB_HID_ENDPOINT2_POLL_INTERVAL USB_HID_ENDPOINT1_POLL_INTERVAL

    #define USB_HID_USAGE_UNDEFINED 0
    #define USB_HID_USAGE_PAGE_VENDOR 0xFF
    #define USB_HID_USAGE_VENDOR_DEF1 1
    #define USB_HID_REPORT_ID_GCQ 0x3F

    #define USB_HID_RCV_BUF_SIZE USB_HID_ENDPOINT2_MAX_PACKET_SIZE

    #define USB_UART_BUFFER_SIZE 256

    #define CMD_BUF_SIZE USB_UART_BUFFER_SIZE

    #define NUM_UART_BACKSPACE_ECHO_SIZE 3

    typedef enum
    {
    // Unconfigured.
    STATE_DISCONNECTED,

    // Connected, awake and not communicating.
    STATE_CONNECTED_AWAKE,

    // USB received suspend event
    STATE_SUSPENDED
    }usb_hid_state_t;


    typedef struct {
    uint8_t event_id;
    uint16_t result;
    }t_usb_hid_gcq_rcv_handler;


    typedef struct {
    uint8_t event_id;
    uint16_t result;
    }t_usb_hid_gcq_transmit_handler;


    uint32_t UsbCompMassStorageDeviceEventCallback(void *pvCBData, uint32_t ui32Event,
    uint32_t ui32MsgParam, void *pvMsgData);
    void *UsbCompMassStorageDeviceOpenHandler(uint_fast32_t ui32Drive);
    void UsbCompMassStorageDeviceCloseHandler(void * pvDrive);
    uint32_t UsbCompMassStorageDeviceReadHandler(void * pvDrive,
    uint8_t *pui8Data,
    uint_fast32_t ui32Sector,
    uint_fast32_t ui32NumBlocks);
    uint32_t UsbCompMassStorageDeviceWriteHandler(void * pvDrive,
    uint8_t *pui8Data,
    uint_fast32_t ui32Sector,
    uint_fast32_t ui32NumBlocks);
    uint32_t UsbCompMassStorageDeviceNumBlocksHandler(void * pvDrive);
    uint32_t UsbCompMassStorageDeviceBlockSizeHandler(void * pvDrive);
    uint32_t UsbHidDeviceTransmitHandler(void *pvCBData, uint32_t ui32Event,
    uint32_t ui32MsgParam, void *pvMsgData);
    uint32_t UsbHidDeviceReceiveHandler(void *pvCBData, uint32_t ui32Event,
    uint32_t ui32MsgParam, void *pvMsgData);


    const uint8_t g_a_lang_descriptor[] = {
    // First Byte is string length
    4,
    USB_DTYPE_STRING,
    USBShort(USB_LANG_EN_US)
    };

    const uint8_t g_a_manufacturer_string[] = {
    // First Byte is string length
    16*2+2,
    USB_DTYPE_STRING,
    'A',0,'b',0,'c',0,'d',0,'e',0,'f',0,'g',0,'h',0,
    'i',0,'j',0,'k',0,'l',0,'m',0,'n',0,'t',0,'s',0
    };

    const uint8_t g_a_product_string[] = {
    // First Byte is string length
    7*2+2,
    USB_DTYPE_STRING,
    'F',0,'S',0,'S',0,' ',0,'A',0,'B',0,'C',0
    };

    const uint8_t g_a_version_string[] = {
    // First Byte is string length
    3*2+2,
    USB_DTYPE_STRING,
    '0',0,'0',0,'1',0
    };

    //*****************************************************************************
    // The data interface description string.
    //*****************************************************************************
    const uint8_t g_a_usb_msd_data_interface_string[] =
    {
    (19 + 1) * 2,
    USB_DTYPE_STRING,
    'B', 0, 'u', 0, 'l', 0, 'k', 0, ' ', 0, 'D', 0, 'a', 0, 't', 0,
    'a', 0, ' ', 0, 'I', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0,
    'a', 0, 'c', 0, 'e', 0
    };

    const uint8_t g_a_module_string[] = {
    // First Byte is string length
    15*2+2,
    USB_DTYPE_STRING,
    'M',0,'a',0,'i',0,'n',0,' ',0,'B',0,'o',0,'a',0,
    'r',0,'d',0,' ',0,'T',0,'i',0,'v',0,'a',0
    };


    //*****************************************************************************
    // The configuration description string.
    //*****************************************************************************
    const uint8_t g_a_usb_msd_config_string[] =
    {
    (23 + 1) * 2,
    USB_DTYPE_STRING,
    'B', 0, 'u', 0, 'l', 0, 'k', 0, ' ', 0, 'D', 0, 'a', 0, 't', 0,
    'a', 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_a_msd_serial_number_string[] =
    {
    (12 + 1) * 2,
    USB_DTYPE_STRING,
    '0', 0, '1', 0, '2', 0, '3', 0, '4', 0, '5', 0, '6', 0, '7', 0,
    '8', 0, '9', 0, 'A', 0, 'B', 0
    };




    // ***********************************************************
    // Uninitialized variables
    // ***********************************************************
    // Workspace for collection of items to be used by USB HID receive handler
    t_usb_hid_gcq_rcv_handler g_usb_hid_device_receive_fabric;


    // Workspace for collection of items to be used by USB HID transmit handler
    t_usb_hid_gcq_transmit_handler g_usb_hid_device_transmit_fabric;


    // ***********************************************************
    // Initialized variables
    // ***********************************************************
    // Array of tHIDReportIdle. Must match number of Input reports specified in ui8NumInputReports field
    // of tUSBDHIDDevice.
    tHIDReportIdle g_hid_report_idle_arry[USB_HID_SINGLE_INPUT_REPORT] = {
    // The periodicity for sending the IDLE Report
    USB_HID_DEVICE_IDLE_REPORT_PERIOD_INF,

    // Idle report ID
    USB_HID_DEVICE_IDLE_REPORT_ID_TAG,

    // populated and tracked by USB driver
    0,
    0
    };


    // ***********************************************************
    // Report Descriptor
    // ***********************************************************
    const uint8_t g_usb_hid_gcq_report_descriptor[] = {
    UsagePageVendor(USB_HID_USAGE_PAGE_VENDOR),
    Usage(USB_HID_USAGE_VENDOR_DEF1),
    Collection(USB_HID_APPLICATION),
    ReportID(USB_HID_REPORT_ID_GCQ),
    ReportCount(USB_HID_REPORT_CNT),
    ReportSize(USB_HID_REPORT_SZ),
    LogicalMinimum(1),
    LogicalMaximum(1),
    Usage(USB_HID_USAGE_VENDOR_DEF1),
    Input(USB_HID_INPUT_DATA | USB_HID_INPUT_VARIABLE | USB_HID_INPUT_ABS),
    ReportID(USB_HID_REPORT_ID_GCQ),
    ReportCount(USB_HID_REPORT_CNT),
    ReportSize(USB_HID_REPORT_SZ),
    LogicalMinimum(1),
    LogicalMaximum(1),
    Usage(USB_HID_USAGE_VENDOR_DEF1),
    Output(USB_HID_OUTPUT_DATA | USB_HID_OUTPUT_VARIABLE | USB_HID_OUTPUT_ABS),
    EndCollection
    };


    const uint8_t * const g_p_usb_hid_class_descriptor_arry[] = {
    g_usb_hid_gcq_report_descriptor
    };


    // ***********************************************************
    // HID Specific String Descriptors
    // ***********************************************************
    const uint8_t g_a_hid_interface_string[] = {
    // First Byte is string length
    8*2+2,
    USB_DTYPE_STRING,
    'H',0,'I',0,'D',0,' ',0,'G',0,'A',0,'M',0,'E',0
    };

    const uint8_t g_a_hid_config_string[] = {
    // First Byte is string length
    15*2+2,
    USB_DTYPE_STRING,
    'H',0,'I',0,'D',0,' ',0,'G',0,'A',0,'M',0,'E',0,
    ' ',0,'C',0,'O',0,'N',0,'F',0,'I',0,'G',0
    };

    // String descriptor must be at least 5 elements deep
    const uint8_t * const g_p_usb_hid_string_Descriptor_arry[] = {
    g_a_lang_descriptor,
    g_a_manufacturer_string,
    g_a_product_string,
    g_a_version_string,
    g_a_module_string,
    g_a_hid_interface_string,
    g_a_hid_config_string
    };
    #define NUM_HID_DEV_STRING_DESCRIPTORS (sizeof(g_p_usb_hid_string_Descriptor_arry) / sizeof(uint8_t *))


    // ***********************************************************
    // HID Endpoint Descriptors
    // ***********************************************************
    // Endpoint descriptor for data in to host through interrupt from device
    const uint8_t g_s_usb_hid_gcq_endpoint_descriptor_int[] = {
    // length of endpoint descriptor
    USB_HID_ENDPOINT_DESCRIPTOR_SIZE,

    // descriptor type
    USB_DTYPE_ENDPOINT,

    // address of endpoint
    USB_HID_ENDPOINT1_ADDRESS,

    // endpoint attribute
    USB_EP_ATTR_INT,

    // max packet size
    USBShort(USB_HID_ENDPOINT1_MAX_PACKET_SIZE),

    // interval for polling endpoint for data transfers in ms
    USB_HID_ENDPOINT1_POLL_INTERVAL
    };


    // Endpoint descriptor for data out from host and into device
    const uint8_t g_s_usb_hid_gcq_endpoint_descriptor_out[] = {
    // length of endpoint descriptor
    USB_HID_ENDPOINT_DESCRIPTOR_SIZE,

    // descriptor type
    USB_DTYPE_ENDPOINT,

    // address of endpoint
    USB_HID_ENDPOINT2_ADDRESS,

    // endpoint attribute
    USB_EP_ATTR_INT,

    // max packet size
    USBShort(USB_HID_ENDPOINT2_MAX_PACKET_SIZE),

    // interval for polling endpoint for data transfers in ms
    USB_HID_ENDPOINT2_POLL_INTERVAL
    };

    // ***********************************************************
    // HID Interface Descriptor
    // ***********************************************************
    const uint8_t g_s_usb_hid_gcq_interface_descriptor[] = {
    // length of interface descriptor
    USB_HID_INTERFACE_DESCRIPTOR_SIZE,

    // Descriptor type
    USB_DTYPE_INTERFACE,

    // Interface Number
    USB_HID_GCQ_INTERFACE0_DESCRIPTOR_IDX,

    // Alternate setting
    USB_HID_GCQ_INTERFACE0_ALTERNATE_SETTING,

    // Number of endpoints
    USB_HID_GCQ_INTERFACE0_NUM_ENDPTS,

    // Class Code
    USB_CLASS_HID,

    // Subclass Code
    USB_HID_SCLASS_NONE,

    // Protocol Code
    USB_HID_PROTOCOL_NONE,

    // Index of string descriptor describing this interface
    USB_HID_GCQ_INTF_STRING_IDX
    };


    // ***********************************************************
    // HID Descriptor
    // ***********************************************************
    const tHIDDescriptor g_usb_hid_device_descriptor = {
    // length in bytes of this descriptor. We use only 1 Descriptor class so sizeof will work
    sizeof(tHIDDescriptor) + (USB_HID_FSS_NUM_CLASS_SPECIFIC_DESCRIPTORS - 1) * sizeof(tHIDClassDescriptorInfo),

    // type of the descriptor
    USB_HID_DTYPE_HID,

    // A BCD value identifying the HID Class specification release supported
    // by the device
    USB_HID_RELEASE_1_11,

    // The country code for which this hardware is localized or 0 for no specific region
    0,

    // The number of class-specific descriptors that exist for this device
    USB_HID_FSS_NUM_CLASS_SPECIFIC_DESCRIPTORS,

    // Class specific descriptor 1 - type
    USB_HID_DTYPE_REPORT,

    // Class specific descriptor 1 - total length
    sizeof(g_usb_hid_gcq_report_descriptor)
    };


    // ***********************************************************
    // HID Configuration Descriptor
    // ***********************************************************
    #define USB_HID_SIZE_OF_MAIN_DESCRIPTOR (USB_HID_CONFIGURATION_DESCRIPTOR_SIZE \
    + sizeof(g_s_usb_hid_gcq_interface_descriptor) + sizeof(g_s_usb_hid_gcq_endpoint_descriptor_int) \
    + sizeof(g_s_usb_hid_gcq_endpoint_descriptor_out) + sizeof(g_usb_hid_device_descriptor) )

    const uint8_t g_s_usb_hid_gcq_config_descriptor[] = {
    // length of configuration descriptor
    USB_HID_CONFIGURATION_DESCRIPTOR_SIZE,

    // Descriptor type
    USB_DTYPE_CONFIGURATION,

    // Total length of data returned for this configuration.
    USBShort(USB_HID_SIZE_OF_MAIN_DESCRIPTOR),

    // Number of interfaces supported by this configuration
    USB_HID_GCQ_NUM_INTERFACES,

    // Configuration Value
    USB_HID_GCQ_CONFIG_VAL,

    // Index of string descriptor describing this configuration
    USB_HID_GCQ_CONFIG_STRING_IDX,

    // Configuration characteristics
    (USB_CONF_ATTR_SELF_PWR | USB_CONF_ATTR_RWAKE),

    // Max power consumption. Expressed in 2mA units
    //USB_HID_GCQ_MAX_POWER_CONSUMPTION
    10
    };


    const tConfigSection g_s_usb_hid_gcq_config_section = {
    sizeof(g_s_usb_hid_gcq_config_descriptor),
    g_s_usb_hid_gcq_config_descriptor
    };

    const tConfigSection g_s_usb_hid_gcq_interface_section = {
    sizeof(g_s_usb_hid_gcq_interface_descriptor),
    g_s_usb_hid_gcq_interface_descriptor
    };

    const tConfigSection g_s_usb_hid_gcq_hid_section = {
    sizeof(g_usb_hid_device_descriptor),
    (const uint8_t *)(&g_usb_hid_device_descriptor)
    };
    const tConfigSection g_s_usb_hid_gcq_endpoint_section = {
    sizeof(g_s_usb_hid_gcq_endpoint_descriptor_int),
    g_s_usb_hid_gcq_endpoint_descriptor_int
    };
    const tConfigSection g_s_usb_hid_gcq_endpointout_section = {
    sizeof(g_s_usb_hid_gcq_endpoint_descriptor_out),
    g_s_usb_hid_gcq_endpoint_descriptor_out
    };

    const tConfigSection *g_p_usb_hid_gcq_config_descriptor_sections[] = {
    &g_s_usb_hid_gcq_config_section,
    &g_s_usb_hid_gcq_interface_section,
    &g_s_usb_hid_gcq_hid_section,
    &g_s_usb_hid_gcq_endpoint_section,
    &g_s_usb_hid_gcq_endpointout_section
    };

    #define USB_HID_GCQ_NUM_CONFIG_SECTIONS (sizeof(g_p_usb_hid_gcq_config_descriptor_sections)/sizeof(tConfigSection *))

    const tConfigHeader g_s_usb_hid_config_descriptor_gcq = {
    USB_HID_GCQ_NUM_CONFIG_SECTIONS,
    g_p_usb_hid_gcq_config_descriptor_sections
    };

    const tConfigHeader *g_p_usb_hid_config_descriptor_header[] = {
    &g_s_usb_hid_config_descriptor_gcq
    };


    // ***********************************************************
    // USB HID Device Descriptor
    // ***********************************************************
    tUSBDHIDDevice g_usb_hid_device_gcq = {
    // Vendor ID
    TI_USB_VID,

    // Product ID
    TI_USB_MSD_PID,

    // Device power consumption in MA
    USB_HID_CURRENT_CONSUMPTION_MA,

    // Configuration Descriptor's bmAttributes field
    USB_CONF_ATTR_SELF_PWR,

    // The interface subclass to publish to the server for this HID device
    USB_HID_SCLASS_NONE,

    // The interface protocol to publish to the server for this HID device
    USB_HID_PROTOCOL_NONE,

    // The number of Input reports that this device supports
    USB_HID_SINGLE_INPUT_REPORT,

    // A pointer to the first element in an array of structures used to track
    // idle time for each Input report.
    g_hid_report_idle_arry,

    // A pointer to the callback function which is called to notify
    // the application of general events
    UsbHidDeviceReceiveHandler,

    // A pointer to a structure that is passed to the receive callback function every time
    (void *)&g_usb_hid_device_receive_fabric,

    // A pointer to the callback function which is called to notify
    // the application of events related to transmission of Input reports
    UsbHidDeviceTransmitHandler,

    // A pointer to a structure that is passed to the transmit callback function every time
    (void *)&g_usb_hid_device_transmit_fabric,

    // If set to true, this field indicates that the device should use a
    // dedicated interrupt OUT endpoint to receive reports from the host.
    false,

    // A pointer to the HID descriptor that the device is to publish
    &g_usb_hid_device_descriptor,

    // The HID class descriptors offered by the device are defined in an
    // array of byte pointers and this field points to that array.
    g_p_usb_hid_class_descriptor_arry,

    // A pointer to the string descriptor array for this device
    g_p_usb_hid_string_Descriptor_arry,

    // Number of string descriptors
    NUM_HID_DEV_STRING_DESCRIPTORS,

    // The configuration descriptor for this HID device.
    g_p_usb_hid_config_descriptor_header

    // The private instance data for this device instance. Driver will take care of this memory space
    };




    const uint8_t * const g_p_usb_msd_string_descriptors[] =
    {
    g_a_lang_descriptor,
    g_a_manufacturer_string,
    g_a_product_string,
    g_a_msd_serial_number_string,
    g_a_usb_msd_data_interface_string,
    g_a_usb_msd_config_string
    };
    #define NUM_USB_MASS_STORAGE_STRING_DESCRIPTORS (sizeof(g_p_usb_msd_string_descriptors) / \
    sizeof(uint8_t *))


    tUSBDMSCDevice g_s_comp_mass_storage_device =
    {
    // Vendor ID
    TI_USB_VID,

    // Product ID
    TI_USB_MSD_PID,

    // Vendor Information - 8 bytes max
    "ABCDEFGH",

    // Product Indentification - 16 bytes max
    "Mass Storage ",

    // Revision - 4 bytes max
    "1.00",

    // Device power consumption in MA
    USB_MASS_STORAGE_CURRENT_CONSUMPTION_MA,

    // Bus Power/Self Powered
    USB_CONF_ATTR_SELF_PWR,

    // A list of string descriptors and the number of descriptors.
    g_p_usb_msd_string_descriptors,
    NUM_USB_MASS_STORAGE_STRING_DESCRIPTORS,

    // Media Access Functions
    {
    UsbCompMassStorageDeviceOpenHandler,
    UsbCompMassStorageDeviceCloseHandler,
    UsbCompMassStorageDeviceReadHandler,
    UsbCompMassStorageDeviceWriteHandler,
    UsbCompMassStorageDeviceNumBlocksHandler,
    UsbCompMassStorageDeviceBlockSizeHandler,
    },

    // Event Notification
    &UsbCompMassStorageDeviceEventCallback,

    };

    // Final application will have 3, but for simplicity, try two for now
    #define NUM_USB_DEVICES_IN_COMPOSITE0 2
    #define USB_HID_COMPOSITE_ENTRY 0
    #define USB_MSD_COMPOSITE_ENTRY 1

    tCompositeEntry g_a_comp_entries[NUM_USB_DEVICES_IN_COMPOSITE0];
    #define GCQ_USB_COMPOSITE_DESCRIPTOR_DATA_SIZE (COMPOSITE_DCDC_SIZE + COMPOSITE_DMSC_SIZE + USB_HID_SIZE_OF_MAIN_DESCRIPTOR)
    uint8_t g_a_composite_descriptor[GCQ_USB_COMPOSITE_DESCRIPTOR_DATA_SIZE];


    //****************************************************************************
    // String descriptor for composite device.
    //****************************************************************************
    const uint8_t * const g_p_usb_composite_string_Descriptor_arry[] = {
    g_a_lang_descriptor,
    g_a_manufacturer_string,
    g_a_product_string,
    g_a_msd_serial_number_string,
    g_a_version_string,
    g_a_module_string
    };
    #define NUM_USB_COMPOSITE_STRING_DESCRIPTORS (sizeof(g_p_usb_composite_string_Descriptor_arry)/sizeof(uint8_t *))



    //****************************************************************************
    // Allocate the Device Data for the top level composite device class.
    //****************************************************************************
    tUSBDCompositeDevice g_s_composite_device =
    {
    TI_USB_VID,

    TI_USB_MSD_PID,

    // Max current consumption (mA) in 2mA.
    USB_MASS_STORAGE_CURRENT_CONSUMPTION_MA,

    // Bus powered device.
    USB_CONF_ATTR_SELF_PWR,

    // There is no need for a default composite event handler
    0,

    // The string table.
    g_p_usb_composite_string_Descriptor_arry,
    NUM_USB_COMPOSITE_STRING_DESCRIPTORS,

    // number of serial devices
    NUM_USB_DEVICES_IN_COMPOSITE0,

    // The Composite device array.
    g_a_comp_entries
    };


    volatile usb_hid_state_t g_usb_hid_gcq_dev_state = STATE_DISCONNECTED;
    volatile bool g_usb_hid_xmission_in_prog = false;



    void ConfigureUSB0()
    {
    #if 1
    // Initialize the first instance of the composite device to be HID.
    g_s_composite_device.psDevices[USB_HID_COMPOSITE_ENTRY].pvInstance =
    USBDHIDCompositeInit(0, &g_usb_hid_device_gcq, &g_a_comp_entries[USB_HID_COMPOSITE_ENTRY]);

    // Initialize the next instance of the composite device to be Mass Storage.
    g_s_composite_device.psDevices[USB_MSD_COMPOSITE_ENTRY].pvInstance =
    USBDMSCCompositeInit(0, &g_s_comp_mass_storage_device, &g_a_comp_entries[USB_MSD_COMPOSITE_ENTRY]);

    // Pass the device information to the USB library and place the device on the bus.
    USBDCompositeInit(0, &g_s_composite_device, GCQ_USB_COMPOSITE_DESCRIPTOR_DATA_SIZE,
    g_a_composite_descriptor);
    #else
    USBDMSCInit(0, &g_s_comp_mass_storage_device);
    #endif

    }


    /******************************************************************************
    * USB Mass Storage Device
    ******************************************************************************/
    uint32_t UsbCompMassStorageDeviceEventCallback(void *pvCBData, uint32_t ui32Event,
    uint32_t ui32MsgParam, void *pvMsgData)
    {

    switch(ui32Event)
    {
    // Writing to the device.
    case USBD_MSC_EVENT_WRITING:
    {
    // Handle write case.
    break;
    }

    // Reading from the device.
    case USBD_MSC_EVENT_READING:
    {
    // Handle read case.
    break;
    }

    case USBD_MSC_EVENT_IDLE:
    {
    // Handle idle case.
    }

    default:
    {
    break;
    }

    }
    return(0);
    }


    //*****************************************************************************
    // This function opens the drive number and prepares it for use by the Mass
    // storage class device.
    //
    // /param ui32Drive is the driver number to open.
    //
    // This function is used to initialize and open the physical drive number
    // associated with the parameter /e ui32Drive. The function will return zero if
    // the drive could not be opened for some reason. In the case of removable
    // device like an SD card this function should return zero if the SD card is
    // not present.
    //
    // /return Returns a pointer to data that should be passed to other APIs or it
    // will return 0 if no drive was found.
    //*****************************************************************************
    void *UsbCompMassStorageDeviceOpenHandler(uint_fast32_t ui32Drive)
    {

    /* uint_fast32_t ui32Temp;

    ASSERT(ui32Drive == 0);

    // Return if already in use.
    if(g_sDriveInformation.ui32Flags & SDCARD_IN_USE)
    {
    return(0);
    }

    // Initialize the drive if it is present.
    ui32Temp = disk_initialize(0);

    if(ui32Temp == RES_OK)
    {
    // Card is present and in use.
    g_sDriveInformation.ui32Flags = SDCARD_PRESENT | SDCARD_IN_USE;
    }
    else if(ui32Temp == STA_NODISK)
    {
    // Allocate the card but it is not present.
    g_sDriveInformation.ui32Flags = SDCARD_IN_USE;
    }
    else
    {
    return(0);
    }

    return((void *)&g_sDriveInformation);*/
    return(&g_s_comp_mass_storage_device);
    }


    //*****************************************************************************
    // This function closes the drive number in use by the mass storage class device.
    //
    // /param pvDrive is the pointer that was returned from a call to
    // USBDMSCStorageOpen().
    //
    // This function is used to close the physical drive number associated with the
    // parameter /e pvDrive. This function will return 0 if the drive was closed
    // successfully and any other value will indicate a failure.
    //
    // /return Returns 0 if the drive was successfully closed or non-zero for a
    // failure.
    //*****************************************************************************
    void UsbCompMassStorageDeviceCloseHandler(void * pvDrive)
    {

    /* uint_fast8_t ui8Power;

    ASSERT(pvDrive != 0);

    // Clear all flags.
    g_sDriveInformation.ui32Flags = 0;

    // Power up the card.
    ui8Power = 0;

    // Turn off the power to the card.
    disk_ioctl(0, CTRL_POWER, &ui8Power);*/
    }


    //*****************************************************************************
    //
    // This function will read a block from a device opened by the
    // USBDMSCStorageOpen() call.
    //
    // /param pvDrive is the pointer that was returned from a call to
    // USBDMSCStorageOpen().
    // /param pui8Data is the buffer that data will be written into.
    // /param ui32NumBlocks is the number of blocks to read.
    //
    // This function is use to read blocks from a physical device and return them
    // in the /e pui8Data buffer. The data area pointed to by /e pui8Data should be
    // at least /e ui32NumBlocks * Block Size bytes to prevent overwriting data.
    //
    // /return Returns the number of bytes that were read from the device.
    //
    //*****************************************************************************
    uint32_t UsbCompMassStorageDeviceReadHandler(void * pvDrive,
    uint8_t *pui8Data,
    uint_fast32_t ui32Sector,
    uint_fast32_t ui32NumBlocks)
    {
    uint32_t retval = 0;

    // Check if block will fit in pui8Data without overflow and
    // if the requested data exists in memory
    if( ((ui32Sector + ui32NumBlocks) <= USB_MSD_1_NUM_SECTORS) &&
    (ui32NumBlocks < USB_MSD_1_MAX_BLOCKS_PER_TRANSACTION) )
    {
    //for now, return 0
    memset (pui8Data, 0, ui32NumBlocks * USB_MSD_1_BLOCK_SIZE);
    retval = ui32NumBlocks * USB_MSD_1_BLOCK_SIZE;
    }

    /* ASSERT(pvDrive != 0);

    if(disk_read (0, pui8Data, ui32Sector, ui32NumBlocks) == RES_OK)
    {
    // TODO remove fixed 512
    return(ui32NumBlocks * 512);
    }*/
    return(retval);
    }

    //*****************************************************************************
    //
    // This function will write a block to a device opened by the
    // USBDMSCStorageOpen() call.
    //
    // /param pvDrive is the pointer that was returned from a call to
    // USBDMSCStorageOpen().
    // /param pui8Data is the buffer that data will be used for writing.
    // /param ui32NumBlocks is the number of blocks to write.
    //
    // This function is use to write blocks to a physical device from the buffer
    // pointed to by the /e pui8Data buffer. If the number of blocks is greater than
    // one then the block address will increment and write to the next block until
    // /e ui32NumBlocks * Block Size bytes have been written.
    //
    // /return Returns the number of bytes that were written to the device.
    //
    //*****************************************************************************
    uint32_t UsbCompMassStorageDeviceWriteHandler(void * pvDrive,
    uint8_t *pui8Data,
    uint_fast32_t ui32Sector,
    uint_fast32_t ui32NumBlocks)
    {
    /* ASSERT(pvDrive != 0);

    if(disk_write(0, pui8Data, ui32Sector, ui32NumBlocks) == RES_OK)
    {
    return(ui32NumBlocks * 512);
    }*/
    return(0);
    }

    //*****************************************************************************
    //
    // This function will return the number of blocks present on a device.
    //
    // /param pvDrive is the pointer that was returned from a call to
    // USBDMSCStorageOpen().
    //
    // This function is used to return the total number of blocks on a physical
    // device based on the /e pvDrive parameter.
    //
    // /return Returns the number of blocks that are present in a device.
    //
    //*****************************************************************************
    uint32_t UsbCompMassStorageDeviceNumBlocksHandler(void * pvDrive)
    {
    /* uint_fast32_t ui32SectorCount;

    // Read the number of sectors.
    disk_ioctl(0, GET_SECTOR_COUNT, &ui32SectorCount);

    return(ui32SectorCount); */
    return (USB_MSD_1_NUM_SECTORS);

    }


    uint32_t UsbCompMassStorageDeviceBlockSizeHandler(void * pvDrive)
    {

    /* uint_fast32_t ui32SectorCount;

    // Read the number of sectors.
    disk_ioctl(0, GET_SECTOR_COUNT, &ui32SectorCount);

    return(ui32SectorCount); */
    return (USB_MSD_1_BLOCK_SIZE);

    }



    //*****************************************************************************
    //
    // Handles asynchronous events from the HID driver.
    //
    // \param pvCBData is the event callback pointer provided during
    // USBDHIDInit(). This is a pointer to the HID device structure (g_usb_hid_device_gcq)
    // \param ui32Event identifies the event we are being called back for.
    // \param ui32MsgData is an event-specific value.
    // \param pvMsgData is an event-specific pointer.
    //
    // This function is called by the HID driver to inform the application
    // of particular asynchronous events related to operation of the HID device.
    //
    // \return Returns 0 in all cases.
    //
    //*****************************************************************************
    uint32_t UsbHidDeviceReceiveHandler(void *pvCBData, uint32_t ui32Event,
    uint32_t ui32MsgParam, void *pvMsgData)
    {
    //printf("Rx event%d\n",ui32Event);
    switch (ui32Event)
    {
    //
    // The host has connected to us and configured the device.
    //
    case USB_EVENT_CONNECTED:
    {
    g_usb_hid_gcq_dev_state = STATE_CONNECTED_AWAKE;
    break;
    }

    //
    // The host has disconnected from us.
    //
    case USB_EVENT_DISCONNECTED:
    {
    g_usb_hid_gcq_dev_state = STATE_DISCONNECTED;
    break;
    }

    //
    case USB_EVENT_RX_AVAILABLE:
    {
    //Semaphore_post(sem_usb_receive);
    // Receive handler gets called anyway so no need to set any flags here
    break;
    }

    //
    // This event indicates that the host has suspended the USB bus.
    //
    case USB_EVENT_SUSPEND:
    {
    g_usb_hid_gcq_dev_state = STATE_SUSPENDED;
    break;
    }

    //
    // This event signals that the host has resumed signalling on the bus.
    //
    case USB_EVENT_RESUME:
    {
    g_usb_hid_gcq_dev_state = STATE_CONNECTED_AWAKE;
    break;
    }

    //
    // We ignore all other events.
    //
    default:
    {
    // Notify user of unsupported event received
    //printf("Warning: Unsupported receive event%d\n",ui32Event);

    break;
    }
    }

    return(0);
    }


    uint32_t UsbHidDeviceTransmitHandler(void *pvCBData, uint32_t ui32Event,
    uint32_t ui32MsgParam, void *pvMsgData)
    {
    switch (ui32Event)
    {
    case USB_EVENT_TX_COMPLETE:
    {
    //
    // Enter the idle state since we finished sending something.
    //
    g_usb_hid_xmission_in_prog = false;
    break;
    }

    //
    // We ignore all other events.
    //
    default:
    {
    // Notify user of unsupported event received
    //printf("Warning: Unsupported transmit event%d\n",ui32Event);

    break;
    }
    }

    return(0);
    }




    volatile uint32_t g_ui32SysTickCount = 0;
    //****************************************************************************
    //
    // Interrupt handler for the system tick counter.
    //
    //****************************************************************************
    void
    SysTickIntHandler(void)
    {
    //
    // Update our system time.
    //
    g_ui32SysTickCount++;
    }



    //****************************************************************************
    //
    // The system tick rate expressed both as ticks per second and a millisecond
    // period.
    //
    //****************************************************************************
    #define SYSTICKS_PER_SECOND 100
    #define SYSTICK_PERIOD_MS (1000 / SYSTICKS_PER_SECOND)

    // Variable to remember our clock frequency
    uint32_t g_ui32SysClock = 0;

    int main(void)
    {

    //
    // Run from the PLL at 120 MHz.
    //
    g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
    SYSCTL_OSC_MAIN |
    SYSCTL_USE_PLL |
    SYSCTL_CFG_VCO_480), 120000000);

    // Enable the peripheral.
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);


    //
    // Configure the device pins.
    //
    PinoutSet(false, true);


    //
    // Turn off the LED.
    //
    //LEDOff();


    ConfigureUSB0();

    //
    // Enable the system tick.
    //
    //SysTickPeriodSet(g_ui32SysClock / SYSTICKS_PER_SECOND);
    //SysTickIntEnable();
    //SysTickEnable();


    //
    // Main application loop.
    //
    while(1)
    {

    }

    }
  • Just saw this message. I'll put future TM4C posts there.

    Yan
  • Hello Yan,

    I would suggest attaching the CCS project to make sure I do not make copy paste errors or change any setting that is not being used or being used in your project.

    Regards
    Amit
  • Ok, I created a new post in TM4C forum: e2e.ti.com/.../478028 and attached my code there. Please take a look.

    Thank you

    Yan