2023-12-06 07:39 AM
Greetings,
Sorry if I am posting in the wrong place. Maybe someone can point to the correct forum for me.
Problem: USB HID 04 Joystick intermittently sends incorrect 12-bit analog data.
Micro: STM32F103R8T6
Details: A 1/2 Hz signal applied to analog inputs that vacillates above below an 8-bit boundary (i.e., 2047 to 2048) I sometimes get a value of 1792 or 2303 decimal sent. It appears as if the upper 4 bits of the 12-bit word is out of sync with the lower 8 bits and subsequently sends 0x700 instead of 0x800 or 0x8FF instead of 0x7FF.
The problem was first discovered using a Microchip 8-Bit microcontroller. No one could solve the puzzle, se we went with an NXP MK20DX256VLH7 32-bit processor and the problem went away. NXP has a 1-year lead time, so we switched to ST Micro. Now the problem has returned with the F103 part.
To eliminate the possibility of data corruption of the USB structure we put in a trap just before the call to:
USBD_HID_SendReport(&hUsbDeviceFS, (uint8_t*) &gameHID, sizeof(struct gameHID_t));
To test for something wrong with the analog DMA data we parsed that data for out-of-bounds conditions, then set a fault flag. The flag never got set, but the USB data continued to post intermittent erroneous values of 1792 and 2303 on one of the five analog channels. This issue was confirmed on multiple host PCs using different capture software.
It gets stranger yet. We complied the same code for an STM32F722 and an STM32F730 micro and the problem disappeared,
I can't believe this is a problem with the chip (or HAL library), so there must be something we are doing wrong with the way we have the USB configured as a Full-Speed USB (both for the F103 and F7xx).
The only thing different between the F103 and the NXP and F7xx chips is the F103 is not USB OTG.
Sorry for the long post, but I want to frame the problem as best I can. Thanks in advance.
Solved! Go to Solution.
2023-12-08 03:49 AM
Ran without error last night. I'm going to call this thread as resolved for now.
I'll run the suggested test of 0x0101...0x0202... tonight as a second verification.
Thank you for all your help!
2023-12-06 10:07 AM
Doesn't sound like a USB configuration issue. Sounds like you are overwriting the data before it's actually sent out. Note that USB happens in the background and needs to be valid/unchanged until the sending operation is complete.
2023-12-06 10:49 AM
Thanks for the quick reply!
The structure that is sent to the HAL USB handler is sent once at the end of the main loop (about 4 mS).
So, there might be an issue with overwriting data while the USB handler is still sending data.
I'll look into a mechanism to determine the last transfer was complete before modifying that data structure and see if that fixes the issue.
Might there be something with USB OTG that is a factor here? All the chips that do not have the problem are USB OTG. Just a thought.
2023-12-06 11:51 AM
> Might there be something with USB OTG that is a factor here?
I doubt it.
You can test the above theory easily. Instead of sending data, send 0x0101, then 0x0202, etc... This is easy and will tell you if you are mixing data between different sends. It will also let you know how often sends fail.
2023-12-06 01:05 PM
Is there a function call that can determine the state of the USB transfer (in-progress vs complete) for this?
2023-12-06 04:00 PM
Not sure if there's a function, but you can dig into the structure to find it. Look at how the USBD_HID_SendReport determines if it's busy or not and duplicate that check.
2023-12-06 05:24 PM
Perfect, thank you. I'll try that in the morning.
2023-12-07 12:27 PM
This is what I did to quickly test this idea. I added some code to the USBD_HID_SendReport function.
A local array that is used to transmit the USB data was created. That local array only gets updated when hhid->state is idle. The function call USBD_LL_Transmit() now sends the local copy instead of the original array, which should decouple any changes made in main from the USB transfer process...
The results are unchanged. We still get erroneous values of 1792 and 2303. Something else must be happening.
uint8_t USBD_HID_SendReport(USBD_HandleTypeDef *pdev, uint8_t *report, uint16_t len)
{
uint16_t i;
uint8_t data [len];
USBD_HID_HandleTypeDef *hhid = (USBD_HID_HandleTypeDef *)pdev->pClassDataCmsit[pdev->classId];
#endif /* USE_USBD_COMPOSITE */
if (hhid == NULL)
{
return (uint8_t)USBD_FAIL;
}
#ifdef USE_USBD_COMPOSITE
/* Get the Endpoints addresses allocated for this class instance */
HIDInEpAdd = USBD_CoreGetEPAdd(pdev, USBD_EP_IN, USBD_EP_TYPE_INTR, ClassId);
#endif /* USE_USBD_COMPOSITE */
if (pdev->dev_state == USBD_STATE_CONFIGURED)
{
if (hhid->state == USBD_HID_IDLE)
{
for (i = 0; i < len; i++)
{
data [i] = report [i];
}
hhid->state = USBD_HID_BUSY;
(void)USBD_LL_Transmit(pdev, HIDInEpAdd, data, len);
}
}
return (uint8_t)USBD_OK;
}
2023-12-07 01:40 PM - edited 2023-12-07 01:41 PM
That's worse. Now you're sending a variable on the stack which immediately goes out of scope when this function returns. Same core issue.
Right idea, bad implementation. You could make data static and size it according to the max possible size to fix these issues.
static uint8_t data[MAX_LEN];
2023-12-07 01:46 PM
Oh, my! I see that now. Thanks.