cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4 USB device retrieve interface descriptor (setup stage)

debugging
Senior III

MCU: STMF32F401CCU6

On a Black pill board.

STM32CubeIDE

Version: 1.10.1

Build: 12716_20220707_0928 (UTC)

OS: Linux, v.5.15.0-46-lowlatency, x86_64 / gtk 3.24.33

Java vendor: Eclipse Adoptium

Java runtime version: 11.0.14.1+1

Java version: 11.0.14.1

Ubuntu 22.04.01

The device code is based on the CDC class

The device is just plugged in, no drivers are using it. After plugging in the device Linux transacted the the address (0x05) and configure (0x09) and retreved the string descriptors successfully.

No drivers are install as the class in not CDC but a custom class.

Using (linux) Libusb function (written in C code) to retrieve an class specific intetrface descriptor. Type:0x81 Request 0x06, Value:0x2601 . This fails

  

Added debug code in USBD_StatusTypeDef USBD_LL_SetupStage in usbdcore.c. All seems fine and this function is reached for retrieving device descriptor, serialnumber etc.. (request type 0x80). (See tranasctions below)

When making a USB transfer with bRequestType 0x81 or 0x82 (interface or endpoint ) This function is not called. Example: Type:0x81 Request 0x06, Value:0x2601.

 Libusb return an error -1: Input/Output Error

When changing this call to retrieve a device descritpor: Type:0x80 Request 0x06, Value:0x2601 the USBD_LL_SetupStage function is reached.

Any hints how to debug the HAL code why this is ?

Trying to figure out if this is due to uslib or the HAL code.

Per UM1734 p 17 :Most of the requests specified in Table 4 of the USB specification are handled as standard requests in the library. Table 4 lists all the standard requests and their valid parameters in

the library. Requests that are not in Table 4 are considered as non-standard requests.

Thus: it states that CONFIGURATION 0x80 are standard, As such 0x81 is non standard,

The library passes all the non-standard requests to the class-specific code with the

callback pdev->pClass->Setup (pdev, req) function. user code is responsible, in the pdev->pClass->Setup (pdev, req) to parse the content of the SETUP packet (req). If a request is invalid,

.. but ,, it seems USBD_StatusTypeDef USBD_LL_SetupStage is never called to handle this.

USBD_ClassTypeDef does contain the pointer to the function.

1 ACCEPTED SOLUTION

Accepted Solutions
debugging
Senior III

Mote then one year later ! The cause was the OS not sending the specific packet. It never reached the device, the Linux driver was changed and now does send the USB message. The MCU code was changed to reply the specific USB packet and things are working now

 

View solution in original post

6 REPLIES 6

Cube is open source, so you can/shall debug it as your own code.

The USB code is entangled, follow the path from the ISR (upon USB_OTG_DOEPINT_STUP flag being set) where it receives setup packets, down to USBD_LL_SetupStage. Note, that it goes through what is considered user code (probably generated by CubeMX within CubeIDE for you, I don't use Cube just look at the examples).

An USB bus analyzer (hardware) is of immense help when working with USB.

JW

debugging
Senior III

Thanks for this.

The only point I could find where USB_OTG_DOEPINT_STUP is used is in

stm32f4xx_hal_pcd.c. void HAL_PCD_IRQHandler(PCD_HandleTypeDef *hpcd).

line 1125: if ((epint & USB_OTG_DOEPINT_STUP) == USB_OTG_DOEPINT_STUP)

Is that the right point ot start? When i trace the called from there it does not end up to USBD_LL_SetupStage. Trying to find out att what point the code filters out interface from the device decscriptor requests.

UM1734 states: The library passes all the non-standard requests to the class-specific code with the callback pdev->pClass->Setup (pdev, req) function.

But which function is that ? is that USBD_LL_SetupStage ?

 Set a debug point at every  (USBD_StatusTypeDef)pdev->pClass->Setup(pdev, req); in the usb_ctlreq() and none of these are ever reached

What I currently do is to output debug data forom the device over an UART, so I can see all USB transactions coming in.

Something particular is that USB_LL_Setup is only called when the next request to StdDevReq is being processed. In others words, only when StdDev code is excuted the USB_LL_Setup gets executed bedfre that. that means, if there is no next transfer, USB_LL won't be executed, but only oncel the next request comes in. Maybe its a UART buffer/flsuh issue. need to check that.

FW0.00

USBD_LL_SetupStage bmRequest:00 bRequest:00 wValue:0000 wIndex:0000 wLength:0000

USBD_ParseSetupRequest req->bmRequest:00 req->bRequest:00 req->wValue:0000, req->wIndex:0000, req->wLength:0000

StdDevReq req->bmRequest:80 req->bRequest:06 req->wValue:0100, req->wIndex:0000, req->wLength:0040  

USBD_GetDescriptor req->bmRequest:80 req->bRequest:06 req->wValue:0100 , req->wIndex:0000, req->wLength:0040  

USBD_LL_SetupStage bmRequest:80 bRequest:06 wValue:0100 wIndex:0000 wLength:0040

USBD_ParseSetupRequest req->bmRequest:80 req->bRequest:06 req->wValue:0100, req->wIndex:0000, req->wLength:0040

StdDevReq req->bmRequest:00 req->bRequest:05 req->wValue:0049, req->wIndex:0000, req->wLength:0000  

USBD_SetAddress req->bmRequest:00 req->bRequest:05 req->wValue:0049, req->wIndex:0000, req->wLength:0000  

USBD_LL_SetupStage bmRequest:00 bRequest:05 wValue:0049 wIndex:0000 wLength:0000

USBD_ParseSetupRequest req->bmRequest:00 req->bRequest:05 req->wValue:0049, req->wIndex:0000, req->wLength:0000

StdDevReq req->bmRequest:80 req->bRequest:06 req->wValue:0100, req->wIndex:0000, req->wLength:0012  

USBD_GetDescriptor req->bmRequest:80 req->bRequest:06 req->wValue:0100 , req->wIndex:0000, req->wLength:0012  

USBD_LL_SetupStage bmRequest:80 bRequest:06 wValue:0100 wIndex:0000 wLength:0012

USBD_ParseSetupRequest req->bmRequest:80 req->bRequest:06 req->wValue:0100, req->wIndex:0000, req->wLength:0012

StdDevReq req->bmRequest:80 req->bRequest:06 req->wValue:0600, req->wIndex:0000, req->wLength:000A  

USBD_GetDescriptor req->bmRequest:80 req->bRequest:06 req->wValue:0600 , req->wIndex:0000, req->wLength:000A  

USBD_CtllError req->bmRequest:80 req->bRequest:06 req->wValue:0600, req->wIndex:0000, req->wLength:000A  

USBD_LL_SetupStage bmRequest:80 bRequest:06 wValue:0600 wIndex:0000 wLength:000A

USBD_ParseSetupRequest req->bmRequest:80 req->bRequest:06 req->wValue:0600, req->wIndex:0000, req->wLength:000A

StdDevReq req->bmRequest:80 req->bRequest:06 req->wValue:0600, req->wIndex:0000, req->wLength:000A  

USBD_GetDescriptor req->bmRequest:80 req->bRequest:06 req->wValue:0600 , req->wIndex:0000, req->wLength:000A  

USBD_CtllError req->bmRequest:80 req->bRequest:06 req->wValue:0600, req->wIndex:0000, req->wLength:000A  

USBD_LL_SetupStage bmRequest:80 bRequest:06 wValue:0600 wIndex:0000 wLength:000A

USBD_ParseSetupRequest req->bmRequest:80 req->bRequest:06 req->wValue:0600, req->wIndex:0000, req->wLength:000A

StdDevReq req->bmRequest:80 req->bRequest:06 req->wValue:0600, req->wIndex:0000, req->wLength:000A  

USBD_GetDescriptor req->bmRequest:80 req->bRequest:06 req->wValue:0600 , req->wIndex:0000, req->wLength:000A  

USBD_CtllError req->bmRequest:80 req->bRequest:06 req->wValue:0600, req->wIndex:0000, req->wLength:000A  

USBD_LL_SetupStage bmRequest:80 bRequest:06 wValue:0600 wIndex:0000 wLength:000A

USBD_ParseSetupRequest req->bmRequest:80 req->bRequest:06 req->wValue:0600, req->wIndex:0000, req->wLength:000A

StdDevReq req->bmRequest:80 req->bRequest:06 req->wValue:0200, req->wIndex:0000, req->wLength:0009  

USBD_GetDescriptor req->bmRequest:80 req->bRequest:06 req->wValue:0200 , req->wIndex:0000, req->wLength:0009  

USBD_LL_SetupStage bmRequest:80 bRequest:06 wValue:0200 wIndex:0000 wLength:0009

USBD_ParseSetupRequest req->bmRequest:80 req->bRequest:06 req->wValue:0200, req->wIndex:0000, req->wLength:0009

StdDevReq req->bmRequest:80 req->bRequest:06 req->wValue:0200, req->wIndex:0000, req->wLength:0065  

USBD_GetDescriptor req->bmRequest:80 req->bRequest:06 req->wValue:0200 , req->wIndex:0000, req->wLength:0065  

USBD_LL_SetupStage bmRequest:80 bRequest:06 wValue:0200 wIndex:0000 wLength:0065

USBD_ParseSetupRequest req->bmRequest:80 req->bRequest:06 req->wValue:0200, req->wIndex:0000, req->wLength:0065

StdDevReq req->bmRequest:80 req->bRequest:06 req->wValue:0300, req->wIndex:0000, req->wLength:00FF  

USBD_GetDescriptor req->bmRequest:80 req->bRequest:06 req->wValue:0300 , req->wIndex:0000, req->wLength:00FF  

USBD_LL_SetupStage bmRequest:80 bRequest:06 wValue:0300 wIndex:0000 wLength:00FF

USBD_ParseSetupRequest req->bmRequest:80 req->bRequest:06 req->wValue:0300, req->wIndex:0000, req->wLength:00FF

StdDevReq req->bmRequest:80 req->bRequest:06 req->wValue:0302, req->wIndex:0409, req->wLength:00FF  

USBD_GetDescriptor req->bmRequest:80 req->bRequest:06 req->wValue:0302 , req->wIndex:0409, req->wLength:00FF  

USBD_LL_SetupStage bmRequest:80 bRequest:06 wValue:0302 wIndex:0409 wLength:00FF

USBD_ParseSetupRequest req->bmRequest:80 req->bRequest:06 req->wValue:0302, req->wIndex:0409, req->wLength:00FF

StdDevReq req->bmRequest:80 req->bRequest:06 req->wValue:0301, req->wIndex:0409, req->wLength:00FF  

USBD_GetDescriptor req->bmRequest:80 req->bRequest:06 req->wValue:0301 , req->wIndex:0409, req->wLength:00FF  

USBD_LL_SetupStage bmRequest:80 bRequest:06 wValue:0301 wIndex:0409 wLength:00FF

USBD_ParseSetupRequest req->bmRequest:80 req->bRequest:06 req->wValue:0301, req->wIndex:0409, req->wLength:00FF

StdDevReq req->bmRequest:80 req->bRequest:06 req->wValue:0303, req->wIndex:0409, req->wLength:00FF  

USBD_GetDescriptor req->bmRequest:80 req->bRequest:06 req->wValue:0303 , req->wIndex:0409, req->wLength:00FF  

USBD_LL_SetupStage bmRequest:80 bRequest:06 wValue:0303 wIndex:0409 wLength:00FF

USBD_ParseSetupRequest req->bmRequest:80 req->bRequest:06 req->wValue:0303, req->wIndex:0409, req->wLength:00FF

StdDevReq req->bmRequest:00 req->bRequest:09 req->wValue:0001, req->wIndex:0000, req->wLength:0000  

USBD_SetConfig req->bmRequest:00 req->bRequest:09 req->wValue:0001, req->wIndex:0000, req->wLength:0000

USBD_LL_SetupStage bmRequest:00 bRequest:09 wValue:0001 wIndex:0000 wLength:0000

USBD_ParseSetupRequest req->bmRequest:00 req->bRequest:09 req->wValue:0001, req->wIndex:0000, req->wLength:0000

StdDevReq req->bmRequest:80 req->bRequest:06 req->wValue:0302, req->wIndex:0409, req->wLength:00FF  

USBD_GetDescriptor req->bmRequest:80 req->bRequest:06 req->wValue:0302 , req->wIndex:0409, req->wLength:00FF  

USBD_LL_SetupStage bmRequest:80 bRequest:06 wValue:0302 wIndex:0409 wLength:00FF

USBD_ParseSetupRequest req->bmRequest:80 req->bRequest:06 req->wValue:0302, req->wIndex:0409, req->wLength:00FF

StdDevReq req->bmRequest:80 req->bRequest:06 req->wValue:0301, req->wIndex:0409, req->wLength:00FF  

USBD_GetDescriptor req->bmRequest:80 req->bRequest:06 req->wValue:0301 , req->wIndex:0409, req->wLength:00FF  

An anlayzer seems to be a good idea, But I did succesfully buld several devices without, just bumping into this interface descriptor issue now. The RPPico one look to cover most, if not getting a DS pro 3. might be the last option. Prefer linux software. Not windows

But an analyzer does not help to debug what the firmware is doingm it only can show the transaction on the bus, and that is what I can't verify this moment.

> Is that the right point ot start?

​Probably.

> When i trace the called from there it does not end up to USBD_LL_SetupStage.

And where does it end up?

Also, from where is ​USBD_LL_SetupStage() called? Textual search the sources (and Cube *is* *your* sources now).

JW​

debugging
Senior III

[1] And where does it end up?

USB_OTG_DOEPINT_STUP only used i stmf4xxx_hal_pcd.c

0693W00000SttrbQAB.png

code:

0693W00000SttrqQAB.pngeither ends up in:

a CLEAR_OUT_EP_INTR(epnum, USB_OTG_DOEPINT_STPKTRX); for SETUP packet

clears out flags

d (USBx_OUTEP(epnum)->DOEPTSIZ & USB_OTG_DOEPTSIZ_XFRSIZ); for EO packet

clears out flags

c. (void)USB_EP0_OutStart(hpcd->Instance, 1U, (uint8_t *)hpcd->Setup); for ZLP

stm32Fxx_ll_usb, sets some flags

d. HAL_PCD_DataOutStageCallback(hpcd, (uint8_t)epnum);

 UNUSED(hpcd);

 UNUSED(epnum);

[2] Also, from where is ​USBD_LL_SetupStage() called? Textual search the sources (and Cube *is* *your* sources now).

That is exactly the answer I was looking for, : -)

Did that text search and failed to find anything. that why posting this, being stuck here and looking for clues...

debugging
Senior III

P.S Using wireshark as an USB anallyzer, A transaction with 0x80 transaction show up, but when using 0x81 is does not. (just one bit change in the source code...)

Analyzers:

https://www.ellisys.com/products/usbcompare.php (LS/FS/HS/SS)

http://www.internationaltestinstruments.com/products/97-1480a-usb-20-protocol-analyzer.aspx (LS/FS/HS)

https://teledynelecroy.com/protocolanalyzer/usb (LS/FS/HS/SS)

https://www.totalphase.com/protocols/usb/ (LS/FS/HS)

https://www.dreamsourcelab.com/product/dslogic-series/ (LS/FS)

https://www.acute.com.tw/logic-analyzer-en/product/logic-analyzer/travelbus (LS/FS)

https://www.eejournal.com/article/4-logic-analyzer-based-on-raspberry-pi-pico/

ITI is lowest cost for HS for about $695 but only USB

LS/HS and multiprotocol DSLogic for $199 or the DYI the RP2040 is the choice

debugging
Senior III

Mote then one year later ! The cause was the OS not sending the specific packet. It never reached the device, the Linux driver was changed and now does send the USB message. The MCU code was changed to reply the specific USB packet and things are working now