cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4 USB HID: transmit interrupt

koster
Associate III
Posted on September 16, 2014 at 13:42

Hi,

The STM USB HID stack generates an interrupt when new data have been received (eg 64 bytes). It is necessary to poll the status (using the USBD_HID_RecReport function), but this is no problem in my application.

If I want to transmit data from the MCU to the PC, which exceeds the max. 64 bytes buffer, I need to start several transmits (using the USBD_HID_SendReport function), of course.

As HID max transfer rate is 1ms and I did not yet found any flag, which tells me that the last package has been transferred successful to the PC (ACK), I need to slow down the transmit rate much slower than the 1ms.

As the package size can be up to 64kB I need to do 1000 tranmits wich takes a while. Up to 2 seconds would be acceptable, but I need >10 seconds with my procedure.

If I do not wait long enough the receive process on the PC will stop after several 10 packages.

cheers
8 REPLIES 8
chen
Associate II
Posted on September 16, 2014 at 13:58

Hi

Are you actually implementing a Human Interface Device (Mouse/keyboard or Joystick) or are you just using the HID because that is an easy example you found on the internet?

There are other USB device types that are better suited to (large amounts of ) data transfer.

The next simplest one after HID is Communications Device Class - CDC

One simple CDC device is a COMM port (ie emulation of a RS232 port)

koster
Associate III
Posted on September 16, 2014 at 16:08

I want to use HID, to avoid driver issues and COM emulation. For the end application the data transfer speed is fast enough and works pretty good.

For development, failure analysis, factory reprogramming (hopefully not, but HID speed is fast enough) and update (not yet planned, but HID speed is fast enough) I need the larger amount of data transfer.

Speed is just a problem when sending Data from MCU to PC (opposite, PC itself is waiting if USB read is performed, but the device is not responding).

As there are ACK somewhere in the USB handling, I would expect the USB stack providing the ‘Transfer ACK’.

chen
Associate II
Posted on September 16, 2014 at 16:53

Hi

''

I want to use HID, to avoid driver issues and COM emulation.

''

''

update (not yet planned, but HID speed is fast enough) I need the larger amount of data transfer.

''

OK, I understand that HID means the end user does not get problems with finding and loading drivers

BUT

HID Keyboard and Mouse will always be limited on data transfer size!

Maybe look at HID joystick device?

The main problem of using HID is that the only data transport is

''USB HID interface communicates with the host using either a control pipe or an interrupt pipe''

My understanding is that the control pipe is very limited.

It will cause you big problems in trying to implement firmware update.

However, I am not answering the question you asked. Sorry.

The 'Acking' you want to know about is bound in with the 'control pipe' part of the USB protocol. I have not had any problems with this and the ST drivers worked so I have not looked at how/what it is doing.

The only thing ST documentation tell you about is how to change the PID.

tsuneo
Senior
Posted on September 16, 2014 at 19:25

> I did not yet found any flag, which tells me that the last package has been transferred successful to the PC (ACK),

When the transfer on the IN interrupt EP completes, DataIn (USBD_HID_DataIn) callback is called by the stack.

\STM32_USB-Host-Device_Lib_V2.1.0\Libraries\STM32_USB_Device_Library\Class\hid\src\usbd_hid_core.c
\STM32Cube_FW_F4_V1.3.0\Middlewares\ST\STM32_USB_Device_Library\Class\HID\Src\usbd_hid.c
USBD_Class_cb_TypeDef USBD_HID_cb =
{
USBD_HID_Init,
USBD_HID_DeInit,
USBD_HID_Setup,
NULL, /*EP0_TxSent*/ 
NULL, /*EP0_RxReady*/
USBD_HID_DataIn, /*DataIn*/ <---------
NULL, /*DataOut*/
NULL, /*SOF */
NULL,
NULL, 
USBD_HID_GetCfgDesc,
#ifdef USB_OTG_HS_CORE 
USBD_HID_GetCfgDesc, /* use same config as per FS */
#endif 
};

> As the package size can be up to 64kB I need to do 1000 tranmits wich takes a while. To exchange such a large data over HID, you may apply Set/Get_Report (Control transfer), instead of the interrupt endpoints. The DATA stage of Control transfer is scheduled like bulk transfer - you’ll get multiple packets (transactions) in 1ms frame, as long as bandwidth allows. And then, the transfer speed could be faster than interrupt transfer. To run multiple transactions in the DATA stage, you have to define large-size report, for example 1K bytes, on the report descriptor. Tsuneo
koster
Associate III
Posted on September 18, 2014 at 09:46

> When the transfer on the IN interrupt EP completes, DataIn (USBD_HID_DataIn) callback is called by the stack.

I thought so, too. I tried this by adding a flag within this function, which indicates my transmit function to start the next transfer. Even so the transmission stucks after several transfers. Maybe this function is being called not only by my data transfer. But I need to further investigate on this.

>> As the package size can be up to 64kB I need to do 1000 transmits wich takes a while.

> To exchange such a large data over HID, you may apply Set/Get_Report (Control transfer), instead of the interrupt endpoints. The DATA stage of Control transfer is scheduled like bulk transfer - you’ll get multiple packets (transactions) in 1ms frame, as long as bandwidth allows. And then, the transfer speed could be faster than interrupt transfer.

To run multiple transactions in the DATA stage, you have to define large-size report, for example 1K bytes, on the report descriptor.

As I’m really a beginner with USB, I have started with the Interrupt Transfer, as I found a functioning sample software for the MCU and the PC (Jan Axelson) which worked from the beginning, without modification. One function call for transmit 64 byte and polling a flag for receiving.

The PC software also contains a function calls for data transfer (buffer) with control transfer, but the STM software seems to be limited to interrupt transfer (even the HID USB stack seems to be the complete STM stack for HID).

Is there any sample software available on STM for control transfer, with simple function calls for receive and transmit?

tsuneo
Senior
Posted on September 19, 2014 at 21:48

> I thought so, too. I tried this by adding a flag within this function, which indicates my transmit function to start the next transfer. Even so the transmission stucks after several transfers.

Sound like you are working on STM32_USB-Host-Device_Lib_V2.1.0 This library has a bug, which slows down core execution by flooded ''empty FIFO'' interrupts, after your firmware puts a packet to the IN endpoint, until the packet is sent out to host. This bug should disturb other tasks on your firmware.

/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flat.aspx?RootFolder=/public/STe2ecommunities/mcu/Lists/cortex_mx_stm32/Flooded%20empty%20FIFO%20interrupts%20still%20make%20USB%20devices%20crawl

is a fix. > Is there any sample software available on STM for control transfer, with simple function calls for receive and transmit? Here is an implementation snippet. Copy usbd_hid_core.c to your project folder, and modify it as follows. \STM32_USB-Host-Device_Lib_V2.1.0\Libraries\STM32_USB_Device_Library\Class\hid\src\usbd_hid_core.c

#undef HID_MOUSE_REPORT_DESC_SIZE
#define HID_MOUSE_REPORT_DESC_SIZE 34
static uint8_t usbd_hid_EP0_RxReady (void *pdev);
USBD_Class_cb_TypeDef USBD_HID_cb = 
{
USBD_HID_Init,
USBD_HID_DeInit,
USBD_HID_Setup,
NULL, /*EP0_TxSent*/ 
// NULL, /*EP0_RxReady*/ // <--- replace this line with next line
usbd_hid_EP0_RxReady, /*EP0_RxReady*/
USBD_HID_DataIn, /*DataIn*/
NULL, /*DataOut*/
NULL, /*SOF */
NULL,
NULL, 
USBD_HID_GetCfgDesc,
#ifdef USB_OTG_HS_CORE 
USBD_HID_GetCfgDesc, /* use same config as per FS */
#endif 
};

Replace the report descriptor,

#define HID_INPUT_LENGTH 64
#define HID_OUTPUT_LENGTH 64
#define HID_FEATURE_LENGTH 1024
#define LEW(x) (x) & 0xFF, (x) >> 8
__ALIGN_BEGIN static uint8_t HID_MOUSE_ReportDesc[HID_MOUSE_REPORT_DESC_SIZE] __ALIGN_END =
{
0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined Page 1)
0x09, 0x01, // USAGE (Vendor Usage 1)
0xa1, 0x01, // COLLECTION (Application)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x75, 0x08, // REPORT_SIZE (8)
0x95, HID_INPUT_LENGTH, // REPORT_COUNT (64)
0x09, 0x01, // USAGE (Vendor Usage 1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, HID_OUTPUT_LENGTH, // REPORT_COUNT (64)
0x09, 0x01, // USAGE (Vendor Usage 1)
0x91, 0x02, // OUTPUT (Data,Var,Abs)
0x96, LEW(HID_FEATURE_LENGTH), // REPORT_COUNT (1024)
0x09, 0x01, // USAGE (Vendor Usage 1)
0xb1, 0x02, // FEATURE (Data,Var,Abs)
0xc0 // END_COLLECTION
};

Add this routine,

uint8_t hid_large_buf[ HID_FEATURE_LENGTH ];
static uint8_t usbd_hid_EP0_RxReady (void *pdev)
{
//
// this routine is called by the stack, when Set_Report completes.
// At this point, hid_large_buf[] is filled by the data sent by the host
// Process this data, here
//
}

Modify USBD_HID_Setup()

enum {
HID_INPUT = 1,
HID_OUTPUT = 2,
HID_FEATURE = 3
};
static uint8_t USBD_HID_Setup (void *pdev, 
USB_SETUP_REQ *req)
{
uint16_t len = 0;
uint8_t *pbuf = NULL;
switch (req->bmRequest & USB_REQ_TYPE_MASK)
{
case USB_REQ_TYPE_CLASS : 
switch (req->bRequest)
{
//========== add, from here ==========
case HID_REQ_GET_REPORT:
{
if ( (req->wValue >> 8) == HID_FEATURE )
{
//
// here, fill hid_large_buf[] with your data
//
USBD_CtlSendData (pdev, 
hid_large_buf,
HID_FEATURE_LENGTH);
}
break;
}
case HID_REQ_SET_REPORT:
{
if ( (req->wValue >> 8) == HID_FEATURE )
{
USBD_CtlPrepareRx (pdev,
hid_large_buf,
HID_FEATURE_LENGTH); 
}
break;
}
//========== add, to here ==========

Tsuneo
tsuneo
Senior
Posted on September 19, 2014 at 22:03

In above snippet, the large report is assigned to Feature Report, so that the size doesn’t impact input/output reports over the interrupt endpoints.

On the Windows app, single call of HidD_GetFeature() / HidD_SetFeature() exchanges the large report at a time. You’ll find the usage of these routines in Jan Axelson’s VB example.

Tsuneo

koster
Associate III
Posted on September 23, 2014 at 16:04

Hi Tsuneo,

The fix is already integrated in the firmware, which I’m

using (which I found in the web, modified by someone).

Many thanks for your brief sample. It was easy and fast

to integrate it into my firmware and it is really easy to use,

even I could only test the function, as I could not yet integrate

it into my data transmission concept.

Many thanks for your fast and accurate replies, very much appreciated.