Skip to main content
Graduate II
September 12, 2024
Solved

How to send USB HID Reports without guessing the HAL_Delay()?

  • September 12, 2024
  • 4 replies
  • 2063 views

I want to send USB HID Reports as fast as the MCU or the USB protocol allows.

 

In order to send an USB HID Report on an STM32F103 I'm doing something like:

 

USBD_HID_SendReport(&hUsbDeviceFS, (u8*)&report,sizeof(report));
HAL_Delay(some_delay);

 

or even:

 

USBD_HID_SendReport(&hUsbDeviceFS, (u8*)&report,sizeof(report));
for(volatile int k=0; k<some_other_delay; ++k) asm volatile("nop");

 

but it's obviously dicey and suboptimal to "guess" at the correct sleep value (which in my case changes from situation to situation, and also depending on the size of the USB HID Report).

 

What I really want is to do is something like:

 

for(int i=0; i<N; ++i) USBD_HID_SendReport(&hUsbDeviceFS, (u8*)&report,sizeof(report));

 

and have it just work (which it currently doesn't).

 

I tried modifying USBD_HID_SendReport() from the original:

 

 

uint8_t USBD_HID_SendReport(USBD_HandleTypeDef* pdev, uint8_t* report, uint16_t len){
	USBD_HID_HandleTypeDef* hhid = (USBD_HID_HandleTypeDef*)pdev->pClassData;

	if(pdev->dev_state==USBD_STATE_CONFIGURED){
		if(hhid->state==HID_IDLE){ // if it's not idle, then it discards!
			hhid->state = HID_BUSY;
			USBD_LL_Transmit(pdev, HID_EPIN_ADDR, report, len);
		}
	}
	return USBD_OK;
}

 

 

to the following:

 

uint8_t USBD_HID_SendReport(USBD_HandleTypeDef* pdev, uint8_t* report, uint16_t len){
	USBD_HID_HandleTypeDef* hhid = (USBD_HID_HandleTypeDef*)pdev->pClassData;

	if(pdev->dev_state==USBD_STATE_CONFIGURED){
		while(hhid->state!=HID_IDLE) asm volatile("nop");
		hhid->state = HID_BUSY;
		USBD_LL_Transmit(pdev, HID_EPIN_ADDR, report, len);
	}
	return USBD_OK;
}

 

 but it's not working as intended.

 

So how I can achieve the desired result of sending USB HID Reports as fast as possible, without any manual wait, ie. something like:

 

for(int i=0; i<N; ++i) USBD_HID_SendReport(&hUsbDeviceFS, (u8*)&report,sizeof(report));

 

 

    This topic has been closed for replies.
    Best answer by FBL

    Hi @smoothmanifolds 

    To clarify, we check if the size of the first bits in HID_Buffer (which indicates the size of the remaining data) is zero. If it is, we can proceed to call SendReport again.

    https://github.com/STMicroelectronics/STM32CubeF1/blob/ac682c6bc31ea589f3c552531171aa0c9faeb0a9/Projects/STM3210E_EVAL/Applications/USB_Device/HID_Standalone/Src/stm32f1xx_it.c#L152

     

    4 replies

    Graduate II
    September 12, 2024

    False alarm; I don't know what I was doing wrong. This actually works.

    Graduate II
    September 12, 2024

    But I still wonder if there's something wrong with this approach.

    I may have found a situation where it's not working as intended.

    Technical Moderator
    September 13, 2024

    Hi @smoothmanifolds 

    I suggest ensuring that the endpoint is ready before sending the next report. 

     

    I rephrase my answer: 

    >> In HID class, we need to check first item in report descriptor, the remaining size of data or query the poll time from EP descriptor using USBD_HID_GetPollingInterval()

     

    Also, you may need to check USB traffic if you observe NAKs from device side to make sure if the device is limiting the throughput.

    Graduate II
    September 13, 2024

    Hi @FBL how can I add a callback or use a SW flag?

    How can I check (on the USB device) that the transmission is complete or that the USB endpoint is ready?

    FBLAnswer
    Technical Moderator
    September 13, 2024

    Hi @smoothmanifolds 

    To clarify, we check if the size of the first bits in HID_Buffer (which indicates the size of the remaining data) is zero. If it is, we can proceed to call SendReport again.

    https://github.com/STMicroelectronics/STM32CubeF1/blob/ac682c6bc31ea589f3c552531171aa0c9faeb0a9/Projects/STM3210E_EVAL/Applications/USB_Device/HID_Standalone/Src/stm32f1xx_it.c#L152