Open chris-se opened 3 years ago
Sorry I can't be of much help in solving this particular problem, but I wanted to check in with a couple things:
1) We're using this project on multiple physical products (with composite USB devices) that are in production and working well, so I'm sure there's a way to get it working.
2) This is a really great way to report issues, the amount of detail and tone are both super!
Hello Christian,
First of all, cudos for taking the leap to use STM32_XPD as well as this library, I don't see many people taking it over the Cube HAL (I can't blame them as there's no full support in XPD). Secondly, let me recommend the HidReportDef macros that will make your report descriptor humanly readable. Also, I fully share Luke's opinion about your issue reporting.
With these out of the way, let's get into it:
send 64 bytes via HID to device: appears to work (send appears to be successful), but interrupt handle on device is not triggered (checked via gdb via STLink)
- Please make sure that you have
#define USBD_HID_OUT_SUPPORT 1
in yourusbd_config.h
- The HID interface can receive OUT reports via two paths:
- Through the control channel, a SetReport request (HID_REQ_SET_REPORT). This path is always available (it's buffered in
CtrlData
), but the host drivers usually don't use this path (for OUT reports at least, for FEATURE reports this is the only path available).- Through the HID interface's OUT endpoint. For this path you need to provide a buffer to receive the data into, before it will be successful. The recommended way to do this is to define an
Init
callback for your HID application, where you callUSBD_HID_ReportOut()
, and to also callUSBD_HID_ReportOut()
from theSetReport
callback if you want to keep this path always open for reception.receive 64 bytes via HID from device: timeout (because the handler is not executed and no report is ever sent back -- if reports are sent back from the main loop manually, the can be received by the application)
When you're trying to send data the length of which matches the maximum packet size of the endpoint, it might be necessary to send a zero length packet afterwards, so the host knows that the data chunk is complete. Whether this is needed depends on multiple factors, e.g. host driver design.
however: send less than 64 bytes via HID to device (e.g. 63 bytes): handler is executed, but second "data" argument of SetReport handler is set to NULL (seen in debugger), so garbage is sent back (but something is sent back) after the send with less than 64 bytes the USB stack on the device appears to have gone into some undefined state and nothing appears to work correctly anymore and I have to reset the device to perform further USB operations (the device itself is not hung totally, if I add a button and some LEDs and some simple logic, those will still work -- and the debugger just tells me that the USB interrupt isn't called anymore for some reason.
That is a behavior that I didn't expect. I'd like to test this myself as well, could you provide the source code for me for debugging? Thanks in advance.
Hi Benedek,
many thanks for the quick response, and many thanks for the XPD and USBDevice libraries!
Your feedback was very helpfui, what was missing was that I wasn't calling USBD_HID_ReportOut() anywhere, because I didn't know that was necessary (I thought I'd just get an interrupt whenever data was available). I've now added that to the two places you suggested, and it now works as expected. :-)
Also thanks for your suggestion for HidReportDef, I'll definitely take a look at that.
I do have a quick follow-up question though: which of the following logic would you recommend?
HID_SetReport(...) {
handle_report(...);
// wait for next
USBD_HID_ReportOut(...);
}
or:
int request_present;
HID_SetReport(...) {
request_present = 1;
}
// in main loop:
while (!request_present) /* wait */;
handle_request(...);
USBD_HID_ReportOut(...);
I assume the latter is better unless handling a request is always quick, correct?
Thanks again!
As for the weird case I had when I transferred less than 64 bytes -- the weird behavior only occurs when I don't call USBD_HID_ReportOut() -- but since that function may not be called immediately after receiving a report, it could be the case that this may be trigger-able from the PC by sending to things quickly back to back (haven't tried though). If you want to reproduce this, I've uploaded a ZIP file with both the project for the MCU as well as the code that may be run on the PC to trigger it:
https://gist.github.com/chris-se/aef26cf3d9fbe76fadc7afac1dc0bf06#file-github_issue29-zip
Just unpack the ZIP file, clone the XPD_STM32 & USBDevice repositories into there (so that the XPD_STM32 directory is next to the main.c file).
To build the MCU code:
# current working directory is where this was unpacked
mkdir build
cd build
cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/linux-toolchain.cmake
make
# upload hid_github29.hex
You may need to adapt linux-toolchain.cmake if your embedded compiler is not in /usr/bin or not called exactly arm-none-eabi-gcc.
My setup currently assumes that you have a STM32F407VG, so if that's not the case, you'll need to adapt a couple of things.
To build the test code for talking with the device:
# current working directory is where this was unpacked
cd test
mkdir build
cd build
cmake ..
make
# you can now run ./hid_github29_test:
# attempt to send 64 bytes:
./hid_github29_test 64
# attempt to send 63 bytes:
./hid_github29_test 63
Hope that helps with reproducing this issue.
(Note that when I do add USBD_HID_ReportOut() in the correct places the 63 byte variant works perfectly, so this only occurs if a smaller-size packet is received when USBD_HID_ReportOut() hasn't been called previously.)
Sorry for the delayed response on your open question. How you schedule receiving the next packet depends on the use case, I usually go with a 2 page buffer, so I can already receive another report while processing the last received one hasn't been started in the super loop.
I'll leave this ticket open until I can get to investigating the 63 byte issue.
Thank goodness for this discussion. We also didn't know about having to call USBD_HID_ReportOut() and were wondering why we weren't getting any output reports on our device. With those calls in place, the world is round again.
I'm having issues with getting a USB HID device with an OUT endpoint to work. My goal here is to use the USB HID protocol to provide a generic communication channel to a device with which I can then control the device from a PC. HID was chosen because it doesn't require drivers on any operating system, and many libraries for the PC side are available.
Environment: Chip used: STM32F407VG (in 3.3V mode with 32.768kHz + 25MHz external oscillators) Programming via SWD programming header with a STLink3 (official, not a clone) Used current master branch (2021-06-22) of both STM32_XPD and USBDevice repositories
I've observed the following behavior with STM32_XPD + USBDevice:
The following code was used for setup:
mcu_hwconfig.h:
mcu_hwconfig.c:
main.c:
On the computer side, the following code via HIDAPI:
For comparison, I created a very simple project with STM32CubeIDE and used the ST-integrated library instead of XPD and this one, and there I can get the USB HID communication to work. (The ST library has other drawbacks, which is why I attempted to use this one, because I liked the design a lot more.)
I've used the debugger via the STLink device to attempt to get more information, and step through parts of the XPD and/or USBDevice code, but I don't understand the code well enough to easily see what's wrong. (From a plain reading of the code that is triggered by the USB interrupt it seems correct to me at first glance.)
So it appears to me that either I'm using USBDevice wrong, in which case it would be great to know how, or there's a bug there, and I'm not quite sure how to find it.
If necessary I can provide more information, such as a tarball with the complete code, or USB traces on Linux/Windows, or gdb expressions taken at certain places, but the bug report is long enough as-is, so I'll wait for responses first.
Many thanks in advance!