cancel
Showing results for 
Search instead for 
Did you mean: 

USB HOST cannot parse the last EndPoint

A.Ziru
Associate II

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.

1 ACCEPTED SOLUTION

Accepted Solutions

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!

View solution in original post

10 REPLIES 10
Pavel A.
Evangelist III

Maybe add some debug prints to this code.

Yes it is likely to be buggy.

> The MAX SIZE CONFIGURATION BUFFER is too small

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

JW

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

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

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

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

> 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.

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

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!