Hello, dear experts. I have a problem with the USB component ver 6.5 of MDK-Professional Middleware. I'm developing vendor specific device and I use USB0 of the microcontroller LPC4337JBD144. I use USB component ver 6.5. After sending OUT Vendor Request with data stage it's impossible to process any IN Vendor Request. It looks as if it's processed successfully in my firmware program (it continues to work), but my PC application just freezes and waits for a response of a driver untill I detach my device or reset it using debugger. I added a file "USBD_User_Device_0.c" to my project and modified it in order to process Vendor specific Requests. I changed a callback function the next way
usbdRequestStatus USBD_Device0_Endpoint0_SetupPacketReceived (const USB_SETUP_PACKET *setup_packet, uint8_t **buf, int32_t *len) { switch (setup_packet->bmRequestType.Type) { ... case USB_REQUEST_VENDOR: switch (setup_packet->bmRequestType.Recipient){ case USB_REQUEST_TO_DEVICE: switch (setup_packet->bRequest){ ... // some code case USB_VEND_REQ_LONG_COMM: // bRequest = 4 CommStruct.CommLength = setup_packet->wLength; CommStruct.RespLength = setup_packet->wIndex; // When I call this function, the problem appears. Without calling it everything works properly usbReadStat = USBD_EndpointRead(0, USB_ENDPOINT_OUT(0), CommStruct.CommBuff, 64/*CommStruct.CommLength*/); // Here you can see that I tried different ways to solve the problem. I waited, aborted transition, but nothing helped me. //while (USBD_EndpointReadGetResult(0, 0x00) != CommStruct.CommLength); //USBD_EndpointAbort(0, USB_ENDPOINT_OUT(0)); ... // some code break; } } break; } }
I have to add, that OUT Vendor Requests without data stage are processed successfully even after OUT Vendor Requests with data stage. I use the toolchain MDK-ARM Professional version 5.14.0.0 and Windows 7 64-bit. Thank you for any help.
Finally I've got a solution from technical support. That's what I was advised to do: ---------------------------------------------------------- The USBD_EndpointWrite and USBD_EndpointRead should not be used for Endpoint 0 communication as it is handled by the library itself. As it can be seen in a template for custom device handling file USBD_User_Device_SerNum.c communication on Endpoint 0 is done through parameters of this function. So in this case you should do something like below:
*buf = global_buffer; // Where OUT data will be received *len = setup_packet->wLength; // Number of bytes to be received return usbdRequestOK; // Return status that custom handling for this request is used
after that function USBD_Device0_Endpoint0_OutDataReceived will be called by the library when OUT data is received and you should then analyze received data in there. ---------------------------------------------------------- I hope it can help someone.
That post already made things cleare to me. Thank you. I still have a question regarding the CTRL OUT transfer.
When the host issues a CTRL OUT transfer with a data stage does that mean that:
1. The USBD_Device0_Endpoint0_SetupPacketReceived() function is called by the middleware, and you have to detect that a data stage is following and prepare yourself to process the data, e.g. with a flag similar to the handle_request flag of the example.
2. Wait until USBD_Device0_Endpoint0_OutDataReceived() is called some time later, then process tha data and reset the flag?
I yes, a confirmation would be fine, if no please provide more code.
Thanks a lot regards Lutz
Hello, Lutz. I've done it next way: 1. I have only ONE Vendor Request with data stage. My callback function USBD_Device0_Endpoint0_SetupPacketReceived looks like this:
usbdRequestStatus USBD_Device0_Endpoint0_SetupPacketReceived (const USB_SETUP_PACKET *setup_packet, uint8_t **buf, int32_t *len) { switch (setup_packet->bmRequestType.Type) { ... case USB_REQUEST_VENDOR: switch (setup_packet->bmRequestType.Recipient){ case USB_REQUEST_TO_DEVICE: switch (setup_packet->bRequest){ ... // some code case USB_VEND_REQ_LONG_COMM: // This is my Vend Req bRequest = 5 *buf = myBuff; *len = myBuffLength; return usbdRequestOK; break; } } break; } }
2. Then a callback USBD_Device0_Endpoint0_OutDataReceived is called and it looks like this:
usbdRequestStatus USBD_Device0_Endpoint0_OutDataReceived (uint32_t len) { // Here I process data storing in myBuff. }
As you can see, I don't use any flags because the callback USBD_Device0_Endpoint0_OutDataReceived is always called if you return usbdRequestOK from USBD_Device0_Endpoint0_SetupPacketReceived for Vendor Request with data stage. But I guess using some flag as you described is a good idea.
The only time you need some flag is when you have multiple different request handling so you can differentiate for which request OUT data was received, for single request handling you can basically work without any flags as USBD_Device0_Endpoint0_OutDataReceived will only be called if function USBD_Device0_Endpoint0_SetupPacketReceived returned usbdRequestOK.
Hello again, still I have some questions, or let me express it the other way: I need a more detailed documentation of the API to the middleware.
Let me explain how far I can follow the examples shown here:
For a CTRL OUT tranfer, i.e. the host sends not only a setup packet but additional data to the device ('data stage').
--> Middleware calls
USBD_Device0_Endpoint0_SetupPacketReceived (const USB_SETUP_PACKET *setup_packet, uint8_t **buf, int32_t *len)
--> User (me) has to check if the request is for the user (me) If yes, user can set an optional flag and has to return usbdRequestOK, user has to provide a buffer for the data stage to be received
*buf = myBuffer;
The parameter len has to be set to what? My understanding is that len has to be set to buffer size or to setup_packet->wLength, whichever is lower. Please advise.
*len = sizeof(myBuffer); if(*len > setup_packet->wLength) *len = setup_packet->wLength
--> A few 100us later the Middleware will call
USBD_Device0_Endpoint0_OutDataReceived(int32_t len)
Middleware meanwhile has copied (written) the data from the data stage to the given buffer. Correct?
Now user (me) can read and process the data, the amount of data I can use is given in parameter len. Correct? When I use the data I shall return usbdRequestOK. Correct? Under what circumstances shall I return usbdRequestNotProcessed, usbdRequestOK, usbdRequestStall, usbdRequestNAK? In my code it seemed to be of no meaning wheter I returned usbdRequestNotProcessed or usbdRequestOK.
.
For a CTRL IN tranfer, i.e. the host sends a setup packet and requests data to be sent from the device to the host.
--> User (me) has to check if the request is for the user (me) If yes, user (me) has to provide the data in a buffer and point **buf to this buffer, the return value for len has to be set to the buffer size or the size of setup_packet->wLength, whichever is lower. Please advise. An optional flag can be set from the user for the user for later use in
USBD_Device0_Endpoint0_InDataSent(int32_t len)
Now user (me) knows that the data is read from the buffer and sent over the USB so that user can reuse the buffer again. Correct? The parameter len provides information on how much bytes were sent this time? Please advise. What do I do when len is smaller than the buffer I wanted to send?
There is nothing else to do at this moment from the point of view of the middleware. Correct?
The return value shall be usbdRequestOK. Correct? Again the question: Under what circumstances shall I return usbdRequestNotProcessed, usbdRequestOK, usbdRequestStall, usbdRequestNAK?
Please point out what is the idea behind the concept of the middleware, a simple function reference without having an idea how an when to use the functions with what parameters and what return values is not enough, at least for me.
Best regards Lutz
Hi Lutz,
> still I have some questions, or let me express it the other way: I need a more detailed > documentation of the API to the middleware. Only available documents regarding custom device/class handling are here: www.keil.com/.../group__usbd__class_functions.html www.keil.com/.../group__usbd__core_functions__api.html www.keil.com/.../group__usbd__class_functions__api.html
> Let me explain how far I can follow the examples shown here: > > For a CTRL OUT transfer, i.e. the host sends not only a setup packet but additional data to > the device ('data stage'). > > --> Middleware calls
> --> User (me) has to check if the request is for the user (me) If yes, user can set an > optional flag and has to return usbdRequestOK, user has to provide a buffer for the data > stage to be received
> The parameter len has to be set to what? My understanding is that len has to be set to > buffer size or to setup_packet->wLength, whichever is lower. Please advise. As a matter of fact is should be setup_packet->wLength or at least that, not less as Host knows how many bytes it wants to send and if you provide a smaller buffer than this might fail.
*len = sizeof(myBuffer); if(*len > setup_packet->wLength) *len = setup_packet->wLength;
No. myBuffer should be at least as maximum data stage request.
> --> A few 100us later the Middleware will call When it receives all expected OUT data.
> Middleware meanwhile has copied (written) the data from the data stage to the given buffer. > Correct? It has actually received it directly there from the driver, and it is available there.
> Now user (me) can read and process the data, the amount of data I can use is given in > parameter len. Correct? Yes.
> When I use the data I shall return usbdRequestOK. Correct? Yes.
> Under what circumstances shall I return usbdRequestNotProcessed, usbdRequestOK, > usbdRequestStall, usbdRequestNAK? This is written in the documentation and it says: - usbdRequestNotProcessed:request was not processed; processing will be done by USB library -> meaning: if you handle it in setup stage then you will probably not return this - usbdRequestOK: request was processed successfully (send Zero-Length Packet) -> meaning: you will do that to tell the library to send status stage ZLP - usbdRequestStall: request was processed but is not supported (stall Endpoint 0) -> meaning: you will do that to stall the status stage - usbdRequestNAK: request was processed but the device is busy (return NAK) -> meaning: you will do that to NAK the status stage So each of status stage responses signals different thing to Host. But it seems that usbdRequestNotProcessed on data stage is meaningless as if you handle the request then you need to say you handled it OK, you did not manage to handle it with NAK or you do not understand the request by returning STALL.
> In my code it seemed to be of no meaning whether I returned usbdRequestNotProcessed or > usbdRequestOK. Yes, they behave the same on the data stage, as mentioned usbdRequestNotProcessed is meaningless here.
View all questions in Keil forum