I have a custom board running an STM32F303VCTx connected via USB (Full Speed Device) to a Linux machine as a Custom HID peripheral. A majority of the time the system works correctly sending data in both directions, but under some circumstances (details to follow), the system gets into a state where Linux’s libusb library begins to report timeouts (error code -7) for every write attempt. Forcing a re-enumeration via Linux recovers the system. I have tried this on an embedded Linux machine and a desktop Linux machine which is one of the reasons I suspect the STM32 side.
The STM32 driver libraries being used (including USB stack) are those provided by the STM32CubeMX4.9.0 application using the STM32Cube FW_F3 V1.2.0 firmware package. All I have done is implement the custom HID callback functions and customise the descriptors. I have 4 endpoints:
HAL_PCDEx_PMAConfig(pdev->pData , 0x00 , PCD_SNG_BUF, 0x18);
HAL_PCDEx_PMAConfig(pdev->pData , 0x80 , PCD_SNG_BUF, 0x58);
HAL_PCDEx_PMAConfig(pdev->pData , 0x81 , PCD_SNG_BUF, 0x100);
HAL_PCDEx_PMAConfig(pdev->pData , 0x02 , PCD_SNG_BUF, 0x140);
I have been using LED toggling in the code and a scope to investigate where the system is when the issue occurs. It appears that the scenario is that a call to HAL_PCD_EP_Transmit() (to send some data to the host), is being interrupted by an incoming packet (from the host) (i.e. PCD_EP_ISR_Handler() enters the “if ((wEPVal & USB_EP_CTR_RX) != 0)” condition).
My Best Guess:
The incoming data is received on endpoint 0x02, and the outgoing data is sent on endpoint 0x81, so I don’t see any reason why the one should impact the other. My best guess is that the incoming frame is corrupting the out-going frame, and so the frame that linux receives, triggers the Linux driver to block the device assuming it has malfunctioned. A re-enumeration resets the linux driver. This suggested the USB shared memory functions (PCD_WritePMA() and PCD_ReadPMA()) were trampling each other, but from what I can tell, the offsets and lengths of each are correct so they don’t overlap. I even tried moving the offsets around and increasing the lengths, but that made no difference.
Can anyone propose a solution and/or further investigations, and/or point me to somewhere that might be able to shed some light on this issue?