Skip to main content
Visitor II
March 18, 2022
Solved

USB HOST cannot parse the last EndPoint

  • March 18, 2022
  • 4 replies
  • 4009 views

Hello!

After two week of struggle I understood that this problem is beyond my abilities.

I have a NUCLEO-H7A3ZI-Q setted as USB Host. I connect a MIDI Keyboard and the Host start the communication, gets all the descriptor and then start the parsing phase to define the device descriptor, the configuration descriptor, the interfaces descriptors and then the END POINTS descriptors.

It works, but it can't parse the last END POINT so the code never get out of a while loop.

Before showing the code and the configuration settings, I have to say that I have used an USB sniffer to check that the end point really exist. It exist and is normally read by the PC. So it's not a device problem.

Ok, let's see the settings

0693W00000KdDN1QAN.png0693W00000KdDM3QAN.pngHonestly except for the buffer size (which is at the maximum 256 byte) i think that there aren't wrong settings here because it communicates.

Below I have drew the structure and the values of the device descriptors from the three interfaces to the four end points. (The interface [1] has no end points. Is it normal?)

0693W00000KdDRXQA3.pngThe values that we are seeing there come from the hUsbHostHS HandletTipeDef and are the same that I see in the USB sniffer. Except for the last endpoint (marked with a red "?") the values coincide.

I drew the scheme because the online visualization of this structure is too long to be show in only one image.

Below I report the code where I should get the end points parsing. It comes from the default ST middleware package and except for the comment to highlight some key zone, I haven't done any modification.

//usbh_ctlreq.c
//LINE 402
static USBH_StatusTypeDef USBH_ParseCfgDesc(USBH_HandleTypeDef *phost, uint8_t *buf, uint16_t length)
{
 USBH_CfgDescTypeDef *cfg_desc = &phost->device.CfgDesc;
 USBH_StatusTypeDef status = USBH_OK;
 USBH_InterfaceDescTypeDef *pif ;
 USBH_EpDescTypeDef *pep;
 USBH_DescHeader_t *pdesc = (USBH_DescHeader_t *)(void *)buf;
 uint16_t ptr;
 uint8_t if_ix = 0U;
 uint8_t ep_ix = 0U;
 
 pdesc = (USBH_DescHeader_t *)(void *)buf;
 //######################################### PARSING CONFIGURATION DESCRIPTOR ###############################################
 /* Parse configuration descriptor */
 cfg_desc->bLength = *(uint8_t *)(buf + 0);
 cfg_desc->bDescriptorType = *(uint8_t *)(buf + 1);
 cfg_desc->wTotalLength = MIN(((uint16_t) LE16(buf + 2)), ((uint16_t)USBH_MAX_SIZE_CONFIGURATION));
 cfg_desc->bNumInterfaces = *(uint8_t *)(buf + 4);
 cfg_desc->bConfigurationValue = *(uint8_t *)(buf + 5);
 cfg_desc->iConfiguration = *(uint8_t *)(buf + 6);
 cfg_desc->bmAttributes = *(uint8_t *)(buf + 7);
 cfg_desc->bMaxPower = *(uint8_t *)(buf + 8);
 
 /* Make sure that the Confguration descriptor's bLength is equal to USB_CONFIGURATION_DESC_SIZE */
 if (cfg_desc->bLength != USB_CONFIGURATION_DESC_SIZE)
 {
 cfg_desc->bLength = USB_CONFIGURATION_DESC_SIZE;
 }
 
 if (length > USB_CONFIGURATION_DESC_SIZE)
 {
 ptr = USB_LEN_CFG_DESC;
 pif = (USBH_InterfaceDescTypeDef *)NULL;
 //######################################### PARSING INTERFACES DESCRIPTORS ###############################################
 while ((if_ix < USBH_MAX_NUM_INTERFACES) && (ptr < cfg_desc->wTotalLength))
 {
 pdesc = USBH_GetNextDesc((uint8_t *)(void *)pdesc, &ptr);
 if (pdesc->bDescriptorType == USB_DESC_TYPE_INTERFACE)
 {
 /* Make sure that the interface descriptor's bLength is equal to USB_INTERFACE_DESC_SIZE */
 if (pdesc->bLength != USB_INTERFACE_DESC_SIZE)
 {
 pdesc->bLength = USB_INTERFACE_DESC_SIZE;
 }
 
 pif = &cfg_desc->Itf_Desc[if_ix];
 USBH_ParseInterfaceDesc(pif, (uint8_t *)(void *)pdesc);
 
 ep_ix = 0U;
 pep = (USBH_EpDescTypeDef *)NULL;
 //######################################### PARSING END POINTS DESCRIPTORS ###############################################
 // LOOP FROM HERE 
 while ((ep_ix < pif->bNumEndpoints) && (ptr < cfg_desc->wTotalLength))
 {
 pdesc = USBH_GetNextDesc((uint8_t *)(void *)pdesc, &ptr);
 // LOOP TO HERE
 if (pdesc->bDescriptorType == USB_DESC_TYPE_ENDPOINT)
 {
 /* Check if the endpoint is appartening to an audio streaming interface */
 if ((pif->bInterfaceClass == 0x01U) && (pif->bInterfaceSubClass == 0x02U))
 {
 /* Check if it is supporting the USB AUDIO 01 class specification */
 if ((pif->bInterfaceProtocol == 0x00U) && (pdesc->bLength != 0x09U))
 {
 pdesc->bLength = 0x09U;
 }
 }
 /* Make sure that the endpoint descriptor's bLength is equal to
 USB_ENDPOINT_DESC_SIZE for all other endpoints types */
 else if (pdesc->bLength != USB_ENDPOINT_DESC_SIZE)
 {
 pdesc->bLength = USB_ENDPOINT_DESC_SIZE;
 }
 else
 {
 /* ... */
 }
 
 pep = &cfg_desc->Itf_Desc[if_ix].Ep_Desc[ep_ix];
 
 status = USBH_ParseEPDesc(phost, pep, (uint8_t *)(void *)pdesc);
 
 ep_ix++;
 }
 }
 
 /* Check if the required endpoint(s) data are parsed */
 if (ep_ix < pif->bNumEndpoints)
 {
 return USBH_NOT_SUPPORTED;
 }
 
 if_ix++;
 }
 }
 
 /* Check if the required interface(s) data are parsed */
 if (if_ix < MIN(cfg_desc->bNumInterfaces, (uint8_t)USBH_MAX_NUM_INTERFACES))
 {
 return USBH_NOT_SUPPORTED;
 }
 }
 
 return status;
}

When I say that I spent two weeks on this problem I'm not exaggerating, I have studied every line of this function and I do not understand why it doesn't parse the end point.

I do not believe that much in those two possibilities but they are the only ones that come to mind:

  • The MAX SIZE CONFIGURATION BUFFER is too small
  • The Middleware is bugged somewhere

I mean, I have connected several other USB devices (Pen Drive, Mouse, keyboard even a Microscope) and from all of them I got the entire descriptors.

I hope I have presented the problem in a proper way.

If someone can help me i will be extremely grateful.

P.S.

The keyboard works well and I have tested it on the PC and it works properly.

    This topic has been closed for replies.
    Best answer by A.Ziru

    Ok, after several attempt i have discovered that if I define a MIDI class descriptor, the parsing operation can recognize the EP properly. At the end I have been able to complete the USB interfacing and create the pipes. It works smoothly but at the end I have understand that USB library provided by ST is only a starting point (a good starting point) to develop your own code.

    @Community member​, thank you very much for the hints!

    4 replies

    Super User
    March 19, 2022

    Maybe add some debug prints to this code.

    Yes it is likely to be buggy.

    A.ZiruAuthor
    Visitor II
    March 20, 2022

    Hi @Pavel A.​ 

    Seems that the only debug that the middleware gives me back is this.

    0693W00000KdKYkQAN.pngIf the library is bugged, how can I notify ST or open a ticket? Is there a procedure?

    AZ

    Super User
    March 21, 2022

    > Seems that the only debug that the middleware gives me back is this.

    You can add your own prints where it makes sense for debugging.

    > If the library is bugged, how can I notify ST or open a ticket? Is there a procedure?

    If you find a bug, please post your evidence here or in separate thread. Someone will notify the right people.

    Or you can locate the bug in the source of ST USBH library on github and create an issue there.

    Super User
    March 19, 2022

    > The MAX SIZE CONFIGURATION BUFFER is too small

    Sounds likely. What is the total length of Configuration descriptor in question?

    JW

    A.ZiruAuthor
    Visitor II
    March 20, 2022

    Hi @Community member​ 

    Below you can see the raw data descriptor. It seems to be long only 132 byte.

    0693W00000KdK1MQAV.pngCan you tell me if I'm showing to you the correct raw data?

    AZ

    Super User
    March 20, 2022

    It's impossible to parse descriptors without seeing them all... but you appear to have done that already, at least partially, so why don't give us all the information you have?

    JW

    A.ZiruAuthor
    Visitor II
    March 20, 2022

    Sorry, I was just worried to be verbose.

    Below you can find the CfgDesc_Raw values.

    In order to save some times to you and to whoever is reading, I created a google excel sheet to visualize in a better way the data. I have parsed the data and added some comments.

    The link is the following:

    https://docs.google.com/spreadsheets/d/1vQr6btGIMYUQ5eghiazCRV5Y22ukPMq8eI2iYHrUyks/edit?usp=sharing

    One more thing, is there a way to export and share a live expression from STM32 IDE? In this way I can show data in a more comfortable way.

    AZ

    hUsbHostHS->device.CfgDesc_Raw[255]
    Position / Value
    0	9
    1	2
    2	133
    3	0
    4	3
    5	1
    6	0
    7	0
    8	250
    9	9
    10	4
    11	0
    12	0
    13	2
    14	3
    15	0
    16	0
    17	0
    18	9
    19	33
    20	17
    21	1
    22	0
    23	1
    24	34
    25	52
    26	0
    27	7
    28	5
    29	129
    30	3
    31	32
    32	0
    33	1
    34	7
    35	5
    36	2
    37	3
    38	32
    39	0
    40	1
    41	9
    42	4
    43	1
    44	0
    45	0
    46	1
    47	1
    48	0
    49	0
    50	9
    51	36
    52	1
    53	0
    54	1
    55	9
    56	0
    57	1
    58	2
    59	9
    60	4
    61	2
    62	0
    63	2
    64	1
    65	3
    66	0
    67	0
    68	7
    69	36
    70	1
    71	0
    72	1
    73	65
    74	0
    75	6
    76	36
    77	2
    78	1
    79	1
    80	0
    81	6
    82	36
    83	2
    84	2
    85	2
    86	0
    87	9
    88	36
    89	3
    90	1
    91	3
    92	1
    93	2
    94	1
    95	0
    96	9
    97	36
    98	3
    99	2
    100	4
    101	1
    102	1
    103	1
    104	0
    105	9
    106	5
    107	3
    108	2
    109	64
    110	0
    111	0
    112	0
    113	0
    114	5
    115	37
    116	1
    117	1
    118	1
    119	9
    120	5
    121	132
    122	2
    123	64
    124	0
    125	0
    126	0
    127	0
    128	5
    129	37
    130	1
    131	1
    132	3
    133	0
    134	0
    135	0
    136	0
    137	0
    138	0
    139	0
    140	0
    141	0
    142	0
    143	0
    144	0
    145	0
    146	0
    147	0
    148	0
    149	0
    150	0
    151	0
    152	0
    153	0
    154	0
    155	0
    156	0
    157	0
    158	0
    159	0
    160	0
    161	0
    162	0
    163	0
    164	0
    165	0
    166	0
    167	0
    168	0
    169	0
    170	0
    171	0
    172	0
    173	0
    174	0
    175	0
    176	0
    177	0
    178	0
    179	0
    180	0
    181	0
    182	0
    183	0
    184	0
    185	0
    186	0
    187	0
    188	0
    189	0
    190	0
    191	0
    192	0
    193	0
    194	0
    195	0
    196	0
    197	0
    198	0
    199	0
    200	0
    201	0
    202	0
    203	0
    204	0
    205	0
    206	0
    207	0
    208	0
    209	0
    210	0
    211	0
    212	0
    213	0
    214	0
    215	0
    216	0
    217	0
    218	0
    219	0
    220	0
    221	0
    222	0
    223	0
    224	0
    225	0
    226	0
    227	0
    228	0
    229	0
    230	0
    231	0
    232	0
    233	0
    234	0
    235	0
    236	0
    237	0
    238	0
    239	0
    240	0
    241	0
    242	0
    243	0
    244	0
    245	0
    246	0
    247	0
    248	0
    249	0
    250	0
    251	0
    252	0
    253	0
    254	0

    Super User
    March 21, 2022

    Bytes 2 and 3 form a 16-bit value, wTotalLength, determining the length of complete configuration descriptor "assembly", and it's indeed 133 bytes, so that's OK.

    Descriptors you've marked "I don't know what it is" are class-specific descriptors - the first interface is HID, so look into the HID class documentation for that; the other interfaces are Audio class, again look into the Audio class documentation to find out what those are.

    What may happen here is, that the Audio class redefines the Endpoint descriptor, extending it from the standard 7 to 9 bytes. In the code snippet you posted above this is reflected in

    pdesc->bLength = 0x09U;

    but the descriptor you've posted uses 9-byte EP desciptors also for subclass 3. Now how does this exactly lead to failure to parse I don't know, the key is in the functions called from that snippet and I don't use Cube and have no intention to debug it myself.

    JW

    A.ZiruAuthorAnswer
    Visitor II
    March 28, 2022

    Ok, after several attempt i have discovered that if I define a MIDI class descriptor, the parsing operation can recognize the EP properly. At the end I have been able to complete the USB interfacing and create the pipes. It works smoothly but at the end I have understand that USB library provided by ST is only a starting point (a good starting point) to develop your own code.

    @Community member​, thank you very much for the hints!