2021-07-22 12:59 AM
I have read online and saw that people can use the USB custom hid class generated by the CubeIde and they get good transfer speeds.
Also in the past I have worked with stm32(F103RE/L462RE) and a older usblib for custom HID and KeilIDE. I used this together with a c# app that read and wrote data to it pretty fast (just a few seconds to transfer some blocks of data of max 3kb).
Now with the same processor and CUBEIDE with the newest usb custom hid library the same transfer takes aver 1 min and 30 sec.
On the PC side to read data from the stm32 with the old library I used HidD_GetInputReport method from hid.dll. With the newer usb hid library I have to use ReadFile(overlaped) since HidD_GetInputReport is not working.
This is a very significant difference so I think I am not using the new USB CUSTOM HID library properly.
Here is what I did so far:
- The project uses freertos v2.0 some IOs / ADC coverter / USART2 / DMA(usart and adc) and a few timmers.
1. I am using CUBEIDE
2. I set the USB interrupt priority to 0.
3. I set the CUSTOM_HID_FS_BINTERVAL to 1.
4. Set the CUSTOM_HID_OUTREPORT_BUF_SIZE to 2 or 64. (tested with 2 and 64 bytes - for 64 bytes the readfile (stm32->pc) fails more often)
5. Updated the report descriptor and in/out endpoint sizes (for 64 bytes / 2 bytes)
6. The usb transfer works as follows: PC sends a request, the stm32 processes it and creates a reply and the PC must read this reply then send a new request and so on.
Here is the code for read/write on the STM32(c/c++ language)
//====================================================================================
__ALIGN_BEGIN static uint8_t CUSTOM_HID_ReportDesc_FS[USBD_CUSTOM_HID_REPORT_DESC_SIZE] __ALIGN_END =
{
/* USER CODE BEGIN 0 */
0x06, 0x00, 0xFF, /*HID_UsagePageVendor( 0x00)*/
0x09, 0x01, /*HID_Usage ( 0x01)*/
0xA1, 0x01, /*HID_Collection ( HID_Application)*/
0x15, 0x00, /*HID_LogicalMin ( 0 ) value range: 0 - 0xFF */
0x26, 0xFF, 0x00, /*HID_LogicalMaxS ( 0xFF)*/
0x75, 0x08, /*HID_ReportSize ( 8 ) 8 bits */
//in
0x95, 0x40, /*HID_ReportCount ( HID_INPUT_REPORT_BYTES ) HERE I Tested with 64 or 2 bytes */
0x09, 0x01, /*HID_Usage ( 0x01 )*/
0x81, 0x02, /*HID_Input ( HID_Data | HID_Variable | HID_Absolute )*/
//out
0x95, 0x40, /*HID_ReportCount ( HID_OUTPUT_REPORT_BYTES ) HERE I Tested with 64 or 2 bytes */
0x09, 0x01, /*HID_Usage ( 0x01 )*/
0x91, 0x02, /*HID_Output ( HID_Data | HID_Variable | HID_Absolute )*/
//feature
0x95, 0x01, /*HID_ReportCount ( HID_FEATURE_REPORT_BYTES )*/
0x09, 0x01, /*HID_Usage ( 0x01 )*/
0xB1, 0x02, /*HID_Feature ( HID_Data | HID_Variable | HID_Absolute )*/
/* USER CODE END 0 */
0xC0 /* END_COLLECTION */
};
//====================================================================================
/**
* @brief Manage the CUSTOM HID class events
* @param event_idx: Event index
* @param state: Event state
* @retval USBD_OK if all operations are OK else USBD_FAIL
*/
static int8_t CUSTOM_HID_OutEvent_FS(uint8_t event_idx, uint8_t state)
{
/* USER CODE BEGIN 6 */
UNUSED(event_idx);
UNUSED(state);
/*get the data from the PC*/
USBD_CUSTOM_HID_HandleTypeDef *hhid = (USBD_CUSTOM_HID_HandleTypeDef*)hUsbDeviceFS.pClassData;
for(unsigned char i=0;i<USBD_CUSTOMHID_OUTREPORT_BUF_SIZE;i++)
USB_RX_Buffer[i] = hhid->Report_buf[i];
/*update the TX buffer with the corect response*/
ProcessMultipleRequest();
/*send back the answers for the requests*/
USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS, USB_TX_Buffer, USBD_CUSTOMHID_OUTREPORT_BUF_SIZE);
return (USBD_OK);
/* USER CODE END 6 */
}
//====================================================================================
Here is the code for read/write on the PC
//...
System.Threading.Thread.CurrentThread.Priority = ThreadPriority.Highest;
//...
readHandle = FileIO.CreateFile(myDevicePathName, FileIO.GENERIC_READ, FileIO.FILE_SHARE_READ | FileIO.FILE_SHARE_WRITE, IntPtr.Zero, FileIO.OPEN_EXISTING, FileIO.FILE_FLAG_OVERLAPPED, 0);
//...
EventObject = FileIO.CreateEvent(IntPtr.Zero, false, false, "");
HidOverlapped.OffsetLow = 0;
HidOverlapped.OffsetHigh = 0;
HidOverlapped.EventHandle = eventObject;
nonManagedBuffer = Marshal.AllocHGlobal(inputReportBuffer.Length);
nonManagedOverlapped = Marshal.AllocHGlobal(Marshal.SizeOf(HidOverlapped));
Marshal.StructureToPtr(HidOverlapped, nonManagedOverlapped, false);
success = FileIO.ReadFile(readHandle, nonManagedBuffer, inputReportBuffer.Length, ref numberOfBytesRead, nonManagedOverlapped);
if (!success)
{
result = FileIO.WaitForSingleObject(eventObject, 3000);
switch (result)
{
case (System.Int32)FileIO.WAIT_OBJECT_0:
// ReadFile has completed
success = true;
FileIO.GetOverlappedResult(readHandle, nonManagedOverlapped, ref numberOfBytesRead, false);
break;
case FileIO.WAIT_TIMEOUT:
/ Cancel the operation on other error.
CancelTransfer(hidHandle, readHandle, writeHandle, eventObject);
success = false;
break;
default:
// Cancel the operation on other error.
CancelTransfer(hidHandle, readHandle, writeHandle, eventObject);
success = false;
break;
}
}
if (success)
{
// A report was received.
// Copy the received data to inputReportBuffer for the application to use.
Marshal.Copy(nonManagedBuffer, inputReportBuffer, 0, numberOfBytesRead);
}
//.......
I also attempted to make a thread with priority set to highest that continuously reads from the smt32 but this does not work.
I use read with overlapping but when the read thread starts both write and read operations fail.
Read fails with timeout even though the USBD_CUSTOM_HID_SendReport was called.
Has anyone achieved better transfer times?
Does pc write and read fail often in your experience?
Any idea what I am doing wrong or what I could do to improve this?
Solved! Go to Solution.
2021-07-27 05:37 AM
The main issue why most of the packets failed was in the interrupt routine for the usb.
After a lot of debugging I finally looked at the irq and saw that after I transmitted any data the IRQ allways excecuted a portion of code from stm32l4xx_hal_pcd.c.
/* Double Buffer Iso/bulk IN (bulk transfer Len > Ep_Mps) */
else {
(void) HAL_PCD_EP_DB_Transmit(hpcd, ep, wEPVal);
I saw that other encountered this issue and applied a patch to fix it. I tried it and the speed is not a LOT better.
This is because now most of my requests are processed correctly. Before the patch a lot of packets with the direction STM32->PC failed.
Patch:
diff --git a/stm32l4xx_hal_pcd.c b/stm32l4xx_hal_pcd.c
index 3a3d967342b9560ad96b0c19c829dc800c8ee527..68fd199979281a75b840ae095286093895fa01f0 100644
--- a/stm32l4xx_hal_pcd.c
+++ b/stm32l4xx_hal_pcd.c
@@ -2497,6 +2497,29 @@ static HAL_StatusTypeDef PCD_EP_ISR_Handler(PCD_HandleTypeDef *hpcd)
(void)USB_EPStartXfer(hpcd->Instance, ep);
}
}
+ else if((ep->type == EP_TYPE_INTR) && ep->doublebuffer == 0) {
+ /* multi-packet on the NON control IN endpoint */
+ TxByteNbre = (uint16_t)PCD_GET_EP_TX_CNT(hpcd->Instance, ep->num);
+ if (ep->xfer_len > TxByteNbre)
+ {
+ ep->xfer_len -= TxByteNbre;
+ }
+ else
+ {
+ ep->xfer_len = 0U;
+ }
+
+ /* Zero Length Packet? */
+ if (ep->xfer_len == 0U)
+ {
+ /* TX COMPLETE */
+ #if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
+ hpcd->DataInStageCallback(hpcd, ep->num);
+ #else
+ HAL_PCD_DataInStageCallback(hpcd, ep->num);
+ #endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
+ }
+ }
/* Double Buffer Iso/bulk IN (bulk transfer Len > Ep_Mps) */
else
{
2021-07-27 05:37 AM
The main issue why most of the packets failed was in the interrupt routine for the usb.
After a lot of debugging I finally looked at the irq and saw that after I transmitted any data the IRQ allways excecuted a portion of code from stm32l4xx_hal_pcd.c.
/* Double Buffer Iso/bulk IN (bulk transfer Len > Ep_Mps) */
else {
(void) HAL_PCD_EP_DB_Transmit(hpcd, ep, wEPVal);
I saw that other encountered this issue and applied a patch to fix it. I tried it and the speed is not a LOT better.
This is because now most of my requests are processed correctly. Before the patch a lot of packets with the direction STM32->PC failed.
Patch:
diff --git a/stm32l4xx_hal_pcd.c b/stm32l4xx_hal_pcd.c
index 3a3d967342b9560ad96b0c19c829dc800c8ee527..68fd199979281a75b840ae095286093895fa01f0 100644
--- a/stm32l4xx_hal_pcd.c
+++ b/stm32l4xx_hal_pcd.c
@@ -2497,6 +2497,29 @@ static HAL_StatusTypeDef PCD_EP_ISR_Handler(PCD_HandleTypeDef *hpcd)
(void)USB_EPStartXfer(hpcd->Instance, ep);
}
}
+ else if((ep->type == EP_TYPE_INTR) && ep->doublebuffer == 0) {
+ /* multi-packet on the NON control IN endpoint */
+ TxByteNbre = (uint16_t)PCD_GET_EP_TX_CNT(hpcd->Instance, ep->num);
+ if (ep->xfer_len > TxByteNbre)
+ {
+ ep->xfer_len -= TxByteNbre;
+ }
+ else
+ {
+ ep->xfer_len = 0U;
+ }
+
+ /* Zero Length Packet? */
+ if (ep->xfer_len == 0U)
+ {
+ /* TX COMPLETE */
+ #if (USE_HAL_PCD_REGISTER_CALLBACKS == 1U)
+ hpcd->DataInStageCallback(hpcd, ep->num);
+ #else
+ HAL_PCD_DataInStageCallback(hpcd, ep->num);
+ #endif /* USE_HAL_PCD_REGISTER_CALLBACKS */
+ }
+ }
/* Double Buffer Iso/bulk IN (bulk transfer Len > Ep_Mps) */
else
{