USB Generic HID Device Example Code - How to Initiate Send and Receive Data

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 

USB Generic HID Device Example Code - How to Initiate Send and Receive Data

10,680 次查看
nbgatgi
Contributor IV

I am running the generic HID device code from the MCUXpresso SDK for the LPCXpresso54608 evaluation board.  I have modified the code to use the high-speed (HS) PHY and transmit 1024 byte packets.  The example code function receives data from a Windows C# program and echoes it back to be displayed on the PC.  The details of the PHY and packet size change as well as the C# code are located here.

Now, I need to take the example code and modify it to directly control data transfers from a custom application.  As I have never worked with this or any other USB stack prior to this project, and with the example code documentation limited, I am struggling to determine the highest level by which to initiate sending data and respond to received data.

After much time looking through several "Call Hierarchies" I found the following suspect send/receive pairs:

- USB_DeviceLpc3511IpSend / USB_DeviceLpc3511IpRecv

- USB_DeviceHidSend / USB_DeviceHidRecv

I am not sure if the above pairs are interconnected or independent.

I also found a @brief for USB_DeviceLpc3511IpEndpointPrime that states "Write the command/status entry to start a transfer", but looking for calls seems to lead me in circles.

What I need to accomplish in the end is not very complicated (for now).

1)  see when data has been received from the host and manipulate that data

2)  load data to be sent to the host and initiate the send request for the next host polling time slot

I emphasized the "for now" because we are not interested in doing this as a virtual com port so I respectfully request that you avoid VCOM related proposals and questions.  HID was chosen due to the readily available drivers and the guaranteed latency and bandwidth of interrupt transfers.  Down the road we intend to create custom report descriptors, but I digress.

The example code for the generic HID device is nearly identical for other dev boards covered in the MCUXpresso SDKs, so if you have a different LPC or Kinetis part, get the appropriate SDK and you should be able to duplicate what I'm doing.

Note also that my example code is running under FreeRTOS also not by accident.  I don't have much experience with it, but it is the OS we have used with other recent platforms here.  That said, if you are able to offer help under the bare-metal example code, I would bet it would still be helpful.

Thank you for any help you can provide!

标签 (4)
11 回复数

7,156 次查看
Huiyi
Contributor I

@Hui_Ma You mentioned "The USB_DeviceHidSend() function is an asynchronous function, which will using a specified endpoint to send data." Would you explain how to use the specified endpoint? Or do you have example on this usage? Thanks.

0 项奖励
回复

8,831 次查看
OliveiraNxp
Contributor II

Hi,

I downloaded your .zip file, inported to a MCUxpresso IDE and builded w/o problem. 

My Hardware uses the LPC54616J512BD100, so I successful migrated it project to it microcontroller and it is attached for everyone with uses.  

I Added 02 GPIO output pins (GPIO0_1 and GPIO1_11). It because, in my project these pins has visible Leds. If you uses these pins for another propposal, I reccomend to comments the code where they are created.

IMPORTANT:- I Could not test this code on USB_HID because the original source for LPC54608 uses GPIO0_22, GPIO_29 and GPIO_30 on USB Connection and on My project uses GPIO0_22(USB_VBUS) like original source, but uses other pins for other propposal. My USB channel uses USB_DM/PM pins.

Oliveira
标记 (1)
0 项奖励
回复

9,302 次查看
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi,

I would recommend customer to download MCU Bootloader Rev2.0 software, which provided USB device HID bootloader.

Please check here to find the software download link.

Customer can refer K64 freedom_bootloader project, which provide <hid_bootloader> using usb_device_hid_generic_callback() function to receive and send data.

The project is located at below default path:

C:\nxp\NXP_Kinetis_Bootloader_2_0_0\targets\MK64F12

Wish it helps.


Have a great day,
Mike

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 项奖励
回复

9,302 次查看
nbgatgi
Contributor IV

I'm not sure I follow the suggestion of looking at bootloader code.  I am simply wanting to initiate sending data from my device to the host.  Receiving data shouldn't be a problem.  In the example code, receiving a data packet initiates an interrupt, so stepping through the code starting with the ISR gets me to where I need to add my own code.  What I am not sure about is initiating sending data from the device to the host.  Which is the best routine in the stack to call to initiate sending data?

9,302 次查看
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi,

From the dev_hid_generic_bm project, the HID device send interface function USB_DeviceHidSend() will send data to USB host. Customer can call this function to send data.

USB_DeviceHidSend(g_UsbDeviceHidGeneric.hidHandle, USB_HID_GENERIC_ENDPOINT_IN,
                                  (uint8_t *)&g_UsbDeviceHidGeneric.buffer[g_UsbDeviceHidGeneric.bufferIndex][0],
                                  USB_HID_GENERIC_OUT_BUFFER_LENGTH);


Have a great day,
Mike

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 项奖励
回复

9,302 次查看
nbgatgi
Contributor IV

The BM version is very similar to the FreeRTOS version, but I need to make sure I have a full understanding of the Free RTOS version.  As I'm looking at the code, it seems that there is more to understand than just calling "USB_DeviceHidSend" directly.

The example code (attached to this thread with the initial question) simply echoes the packet(s) received back to the PC test program.  When the out-endpoint receives a packet from the PC, an interrupt is generated which eventually leads to the function "USB_DeviceHidGenericCallback" located in hid_generic.c.  For ease of reference, here is the complete "USB_DeviceHidGenericCallback" code: 

/* The hid class callback */

static usb_status_t USB_DeviceHidGenericCallback(class_handle_t handle, uint32_t event, void *param)

{

    usb_status_t error = kStatus_USB_Error;

 

    switch (event)

    {

        case kUSB_DeviceHidEventSendResponse:

            break;

        case kUSB_DeviceHidEventRecvResponse:

            if (g_UsbDeviceHidGeneric.attach)

            {

                    // Example code echo send occurs here NBG

                USB_DeviceHidSend(g_UsbDeviceHidGeneric.hidHandle, USB_HID_GENERIC_ENDPOINT_IN,

                           (uint8_t *)&g_UsbDeviceHidGeneric.buffer[g_UsbDeviceHidGeneric.bufferIndex][0],

                           USB_HID_GENERIC_OUT_BUFFER_LENGTH);

 

                g_UsbDeviceHidGeneric.bufferIndex ^= 1U;

 

                return USB_DeviceHidRecv(g_UsbDeviceHidGeneric.hidHandle, USB_HID_GENERIC_ENDPOINT_OUT,

(uint8_t *)&g_UsbDeviceHidGeneric.buffer[g_UsbDeviceHidGeneric.bufferIndex][0],

                           USB_HID_GENERIC_OUT_BUFFER_LENGTH);

            }

            break;

        case kUSB_DeviceHidEventGetReport:

        case kUSB_DeviceHidEventSetReport:

        case kUSB_DeviceHidEventRequestReportBuffer:

            error = kStatus_USB_InvalidRequest;

            break;

        case kUSB_DeviceHidEventGetIdle:

        case kUSB_DeviceHidEventGetProtocol:

        case kUSB_DeviceHidEventSetIdle:

        case kUSB_DeviceHidEventSetProtocol:

            break;

        default:

            break;

    }

     return error;

}

The parameter passed into the variable "event" is "kUSB_DeviceHidEventRecvResponse" which is enumerated as 2 and is used in the switch-case to initiate the receive action.  The first action is to call "USB_DeviceHidSend" as you have copied in your last reply.  That call completes the task of sending the data out via the in-endpoint which is confirmed by the PC program initially used to send the data to the device.  The next line toggles the bufferIndex presumably to prevent the next received packet from overwriting the previous packet.

Now is the interesting part.  "USB_DeviceHidRecv" is called which makes sense at first.  The following are called in the thread sequence:

            USB_DeviceRecvRequest --> USB_DeviceTransfer --> USB_DeviceLpc3511IpRecv ... All this makes sense, but the next call is to USB_DeviceLpc3511IpSend!  It does not appear to be from endpoint 0 (not control) and when this send is complete it does not show up as echoed data in the PC monitor program.

I theorized that both were included for the purpose of echoing the received data but my initial test by commenting out the first USB_DeviceHidSend call resulted in no data being echoed back to the PC.

At this point I have two questions (I'm sure more will follow):

1)  Do you know the purpose of the 2nd call to the SEND procedure?

2)  Rather than directly calling USB_DeviceHidSend from my application task, would it be a more appropriate/intended use of the stack to call USB_DeviceHidGenericCallback instead?

9,302 次查看
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi,

1)  Do you know the purpose of the 2nd call to the SEND procedure?

TS: I debug the code and find below code:

usb_status_t USB_DeviceLpc3511IpRecv(usb_device_controller_handle controllerHandle,
                                     uint8_t endpointAddress,
                                     uint8_t *buffer,
                                     uint32_t length)
{
    return USB_DeviceLpc3511IpSend(controllerHandle, endpointAddress, buffer, length);
}

In fact, the USB_DeviceLpc3511IpSend() function doesn't mean the USB device send data to USB host.

The data direction based on the endpoint is IN or OUT.

From the previous code, the endpoint direction is OUT, which means the USB host send data to USB slave.

The USB_DeviceLpc3511IpSend() function name does add the confusion.

While, the actual function called here to receive data from USB Host(PC).

2)  Rather than directly calling USB_DeviceHidSend from my application task, would it be a more appropriate/intended use of the stack to call USB_DeviceHidGenericCallback instead?

TS: The USB_DeviceHidSend() function is an asynchronous function, which will using a specified endpoint to send data.

The send result will be checked via HID class callback function (kUSB_DeviceHidEventSendResponse).

Wish it helps.


Have a great day,
Mike

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

9,302 次查看
nbgatgi
Contributor IV

I hope I'm not coming across as being difficult, but with so little documentation accompanying the example code, it is difficult for someone new to USB like me to make any progress.

Can you provide any more insight regarding USB_DeviceLpc3511IpSend()?  If the direction can be OUT for the SEND routine:

1) where is it "sending" the data if not to the host via the IN-endpoint?

2) what is the point of the USB_DeviceLpc3511IpRecv() routine if USB_DeviceLpc3511IpSend() is bidirectional?

Also, when USB_DeviceHidRecv() is called from USB_DeviceHidGenericCallback, I can't see that anything FUNCTIONALLY is happening other than calling USB_DeviceLpc3511IpSend() from USB_DeviceLpc3511IpRecv().  It even appears to be pointing to the wrong buffer address for the current received data packet!  Now, as I've mentioned before, USB_DeviceLpc3511IpSend() CANNOT be commented out of USB_DeviceLpc3511IpRecv() or the program stops functioning, so I accept leaving it as is though I don't understand it.  But since the receive thread doesn't appear to be doing anything with the OUT-endpoint received data packet other than echo it early on in the thread, if I want to do something with the received data such as transfer it to a separate array of received packets, within which of the following would you recommend I put that action?:

1)  USB_DeviceHidGenericCallback() in the "kUSB_DeviceHidEventRecvResponse" case immediately before calling USB_DeviceHidRecv()

2)  USB_DeviceHidRecv() immediately before calling USB_DeviceRecvRequest()

3)  USB_DeviceLpc3511IpRecv() immediately before calling USB_DeviceLpc3511IpSend()

4)  USB_DeviceTaskFunction() specific to the FreeRTOS implementation of the generic HID device example code

5)  or somewhere else I haven't thought of?

 

If you are aware of any documentation or other resource I can utilize to research this further please send me links.

9,072 次查看
crabbo_babbo
Contributor II

Did you have any luck finding an answer? I have the same problem and unbelievably there is still no documentation.

0 项奖励
回复

9,302 次查看
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi,

Sorry for the later reply.

Besides of <MCUXpresso SDK USB Stack Device Reference Manual.pdf> for USB HID device API functions introduction, I couldn't find very helpful documents for your reference.

While, there with below two question threads may bring some light to your questions:

https://community.nxp.com/thread/422363

https://community.nxp.com/message/768822?commentID=768822#comment-768822

Wish it helps.


Have a great day,
Mike

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 项奖励
回复

9,303 次查看
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi,

I am quite sorry for the so late reply.

I just back to office after one week out of office.

I am checking if we have related documents for your reference.

I will let you know later.


Have a great day,
Mike

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 项奖励
回复