Skip to main content
Associate III
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));

 

 

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

Associate III
September 12, 2024

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

Associate III
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.

To give better visibility on the answered topics, please click on "Best answer" on the reply which solved your issue or answered your question.Best regards,FBL
Associate III
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?

FBLBest answer
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

 

To give better visibility on the answered topics, please click on "Best answer" on the reply which solved your issue or answered your question.Best regards,FBL