2022-02-03 09:55 PM
Let me preface this by saying I'm a novice when it comes to programming for MCUs. I made a keyboard using STM32F4 MCUs and in my code I create an 8 character data set for the keycodes to be sent to the computer. I created the project using the STMCubeIDE software selecting the USB HID device option and then I updated the USB HID descriptor to a keyboard (changed descriptor to a keyboard in usbd_hid.c and changed the descriptor length to match in usbd_hid.h). In my code I repeatedly update the 8 character data set and send it to the computer using USBD_HID_SendReport. The keyboard works without any issue for a long time but, after a while, the data the computer receives will have the keycode characters shifted over by 4 characters (the keycode character that should be in the first location of the data set is moved to the fourth location; other keycodes are also shifted by 4 characters). If I check in the debugger the data being sent with USBD_HID_SendReport is as expected when the error is occurring (source data has all characters in the correct location). Once the shift happens it is consistent with many data transfers all having the same shift. So, for example, if the data in the vector in the MCU is {0x20, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00} which are the keycodes for Shift + M then the data that the computer receives at the end of the USB transfer sequence is {0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x10, 0x00}. But this only happens after operating for some time and having already done many correct data transfers. Using wireshark I can see that the rest of the information the computer sees preceeding the 8 character data set is identical, just the last 8 characters are different. For quite a while the data the computer is receiving is fine after starting up and everything operates as it should. I'm a bit at a loss since my code seems relatively simple. My understanding is that, although USB polling is controlled by the computer, calling USBD_HID_SendReport can be called repeatedly without causing any buffer issues and will simply update the data that is available to send when the computer polls for it. So no syncronization should be necessary to prevent issues. Any help would be appreciated. Here is some psuedocode (in reality these are broken up into more functions and operations for interpreting the keyboard scans but this is the essence of what I'm doing):
extern USBD_HandleTypeDef hUsbDeviceFS;
uint8_t kbUSB_data[8]={0x00};
int main(void)
{
while(1){
// Determine if keys are pressed by writing/reading from GPIO pins
scan_matrix();
// Update the character data that is sent to the computer
update_kbUSB_data();
// Send the data to the computer over USB
USBD_HID_SendReport(&hUsbDeviceFS,kbUSB_data,8);
}
}
Is there any issue using USBD_HID_SendReport like I am? Is it likely there is a memory leak in my code? Is it a buffer issue? Are there lower level USB functions I can try out to debug the problem or better diagnose what's going on?
2022-02-05 05:21 PM
I believe I may have found the culprit. Although I am still quite new to this so if anyone is able to confirm that this is likely that'd be awesome. I had updated the USB HID descriptor in the "usbd_hid.c" to be a keyboard descriptor with a data packet of length 8 which is consistent with what I am sending with the USBD_HID_SendReport. I also updated the descriptor size in "usbd_hid.h" to match the size of the keyboard descriptor. I did not, however, update the the endpoint size in "usbd_hid.h" so it was still the endpoint size of the mouse example generated by the STM32CubeIDE. So HID_EPIN_SIZE was set to 0x04U. I watched the STM USB training videos and I saw that in the keyboard example that value was changed to 0x08U to match with the size of the data in the descriptor and the size that is transmitted. So now in my "usbd_hid.h" file I have:
#define HID_EPIN_SIZE 0x08U
So I am guessing the previous value of 0x04U meant that my data was split into two packets instead of sent as one. Then I'm guessing this worked fine as long as there were no data transmission errors and both chunks were sent one after the other. Eventually if there is an error in the transmission of one of the packets that is severe enough then it seems possible to me that the data packet transmissions are shifted with the second packet of the previous transmission being combined with the first packet of the next transmission. This was then causing a state that would persist with the data being interpreted by the computer being shifted by 4 bytes. My understanding of the USB protocol is that there should be corrections to try to prevent this through ACK and NAK but maybe there is the possibility these fail resulting in loss of a data packet and the concatenation of data packets that weren't sent together to USBD_HID_SendReport. In any event, after updating to 0x08U endpoint size I have not gotten the same error/issue.
2022-02-06 03:36 AM
> My understanding is that ....USBD_HID_SendReport can be called repeatedly without causing any buffer issues and will simply update the data that is available to send when the computer polls for it. So no syncronization should be necessary to prevent issues.
If I remember correctly, the data created by USBD_HID_SendReport is treated like any other USB TX data - that is, you need to wait until the endpoint has free space for the data.
Also as you've noticed, if the endpoint packet size is less than the entire report, it will be split to several packets and this is a ticking bomb. Good analysis.