anonymou8 / stm32_usb_audio

STM32F103 (Blue Pill) USB Audio Class: 192 kHz, 16 bit, 1 channel capture device (e.g. microphone). CMSIS only; binary is less than 2 kB.
16 stars 6 forks source link

Driver error #1

Closed xfce closed 1 year ago

xfce commented 1 year ago

Hi, I update the usb_audio_flash.bin file, and the PC system can find the USB AUDIO DEVICE, and display the name Prod, but didn't find the correct driver, when can I find the driver, thanks

viteo commented 1 year ago

What OS are you using? It successfully detects on linux with ALSA, but fails on Windows. I guess, Windows can't receive all string descriptors. TDD log:

String Descriptor Table

Index  LANGID  String
0x00   0x0000  
0x01   0x0000  Request failed with 0x0000001F
0x02   0x0000  Request failed with 0x0000001F
anonymou8 commented 1 year ago

@xfce Hello. The device is of generic Audio Class and it doesn't need a driver. I tested the firmware under Linux only. Probably there's an issue with the descriptor as mentioned by @viteo. Sorry for that.

One assumption is that I used 4 bytes for the tSamFreq instead of 3 as required by the USB specification. As I remember Linux complains on that but just ignores the fourth byte. Try to change the line to .byte 0x00, 0xee, 0x02. Or maybe it's unrelated and an issue in the strings themselves.

viteo commented 1 year ago

I've changed tSamFreq to 3 bytes. Still same error. I found something interesting worth consider: in the TinyUSB examples there is a comment

the Windows driver always needs an extra sample per channel of space more, otherwise it complains... found by trial and error

Might it be related to this issue? I'm not sure what to modify in the code: set_ep1_counters maybe?

anonymou8 commented 1 year ago

set_ep1_counters maybe?

I don't quite remember:) Seems set_ep1_counters() sets the actual count of bytes to be sent, while TinyUSB's example alters endpoint buffer size which is, in our case, equals to 512 bytes, 128 bytes more than needed. In another TinyUSB example for mono audio device they don't add an extra sample. Therefore I don't think this is related.

It's hard to tell what's going on without seeing the exact USB connection log. Probably the issue is in the device configuration phase. Or maybe it's just "wrong" VID:PID pair.

viteo commented 1 year ago

In another TinyUSB example for mono audio device they don't add an extra sample.

yeah. but that example fails to initialize. but ok, this might not be related.

I've tried to capture usb log with WireShark + pCap. It looks wierd, but it is software analyzer (maybe you could suggest something more suitable for usb traffic analysis).

Host requests several times the same String descriptor with index=2 ("Prod"), but the Device answers differs: "P" then "Prod" then again "P" then "Prod" and then communication stops. Request image Anwser image full log for wireshark: usb_audio.zip


I've tried to feed to get_descriptor() predefined hand-written string descriptors, but nothing changed in the initialization log. Tried short length descriptors to fit in 8 byte EP0 buffer, but nothing changed. Something with epn_tx() and bytes_remain in it? No more ideas for now.

anonymou8 commented 1 year ago

@viteo

Thank you, Viktar, I will take a look at this as soon as possible.

maybe you could suggest something more suitable for usb traffic analysis

I think that Wireshark is pretty good choice. USBPcap is what Wireshark itself recommends.

anonymou8 commented 1 year ago

Ok, the log looks good to me until host-device communication stops. Probably "Unknown type" function code (URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR) is just ignored. What about string descriptors requests — they're fine, a host first try find string descriptor length by requesting only 4 bytes (Setup Data -> wLength: 4) of a descriptor, these 4 bytes contain total string descriptor length information + first string letter ("P"). With subsequent request, knowing full string length, host receives entire string.

To me it looks like device eventually "stalls" and becomes unavailable. Maybe. But I can't see any other host -> device requests that would make it unresponsive. STALL condition may be checked by adding if (status == STALL) LED_OFF(); to the ep0_set_stat_tx() function. Then if this is the case the onboard LED (PC13) will go off.

What also strange is that there's no string descriptor 0 (language ID) request but when host requests a string it already knows the ID. AFAIK there's no default LANG_ID. Maybe something is missing in the log.

viteo commented 1 year ago

It is really in STALL condition, led turns off almost immediately.

I've tried another approach to get USB log with virtual machine. It looks almost the same. LangID request is present. image vusb-analyzer on WSL + Ubuntu 16 vm_usb.log

anonymou8 commented 1 year ago

I see that host requests a Device_Qualifier descriptor (GetDescriptor(0x06, 0), response text is in red on the image) which is not implemented. USB 2.0 specification says:

9.6.2 Device_Qualifier: If a full-speed only device (with a device descriptor version number equal to 0200H) receives a GetDescriptor() request for a device_qualifier, it must respond with a request error.

So, this is our case. "Request error" means:

9.2.7 Request Error: When a request is received by a device that is not defined for the device, is inappropriate for the current setting of the device, or has values that are not compatible with the request, then a Request Error exists. The device deals with the Request Error by returning a STALL PID in response to the next Data stage transaction or in the Status stage of the message. It is preferred that the STALL PID be returned at the next Data stage transaction, as this avoids unnecessary bus activity.

Everything is ok to this point. Next comes another standard configuration phase and then strange repeating string descriptor requests after which all communication stops. Maybe MCU hangs?

Based on the logs there's no reason for the device to stop responding. I don't see it. Last GetDescriptor() request has been responded, according to the attached vm_usb.log.

Maybe try to implement Device_Qualifier descriptor?

viteo commented 1 year ago

I've implemented Device_Qualifier descriptor and added LED toggle in while(PWR). Descriptor request answered, MCU doesn't hang.


Also I found logic analyzer and sniff USB lines with Sigrok's PulseView, then convert data to WireShark. Here is filtered result: image Wireshark 4.0.1 dslog_usb.zip

anonymou8 commented 1 year ago

Wow, that's awesome! Thank you, I'm already trying to investigate the problem)

anonymou8 commented 1 year ago

@viteo Viktar, you will be laughing but I don't see any problem. All descriptors were transferred successfully with acknowledgements from both sides.

So it seems that Windows doesn't like these descriptors. Though all string descriptors are optional, maybe fill in iSerialNumber from device_descriptor? Another assumption is that Interface descriptor is malformed from the Windows' point of view.

Have a look to these projects:

  1. https://github.com/LonelyWolf/stm32/blob/master/usb-mic/usb_microphone/usb_desc.c
  2. https://github.com/migite2232/stm32_usb_audio/blob/master/Src/usb_audio_dscr.c

I know that STM has it's own registered VID for their example USB devices, maybe try to use VID:PID as in the second project?

viteo commented 1 year ago

Well, the only big difference is that they both (1, 2) have Alternate Setting (with 0 endpoints) for AS Interface Descriptor. I've read somewhere that this alternate setting is used to disable streaming. So, I've added it. Not sure how to handle this request properly, because looks like they are just ignoring this. I've uncommented current_configuration lines. But now, the device is no longer recognized in Device Manager. image usb_fault.zip

It looked like this before: image

Compared descriptors byte-to-byte and changed:

Differences left:

anonymou8 commented 1 year ago

I've read somewhere that this alternate setting is used to disable streaming.

I remember something, but I'm not sure whether an interface altsetting with 0 endpoints is strictly required for audio class devices. Specification only says that a device "may" or "can" have interface alternate settings. There is an example of USB Microphone at p.105, it also has altsetting with 0 endpoints:

recent

The descriptors diff for the altsetting could look something like:

--- descriptors_audio.s
+++ descriptors_audio.s
@@ -121,0 +122,12 @@
+        interface_descriptor_as_alt:
+            .byte   IDAS_ALT_SZ         @; bLength
+            .byte   DESC_TYPE_INTERFACE @; bDescriptorType
+            .byte   1                   @; bInterfaceNumber         : Zero based
+            .byte   0                   @; bAlternateSetting
+            .byte   0                   @; bNumEndpoints            = No endpoints interface altsetting
+            .byte   0x01                @; bInterfaceClass          = AUDIO
+            .byte   0x02                @; bInterfaceSubClass       = AUDIO_STREAMING
+            .byte   0                   @; bInterfaceProtocol       = No protocol
+            .byte   0                   @; iInterface
+        IDAS_ALT_SZ = . - interface_descriptor_as_alt
+
@@ -126 +138 @@
-            .byte   0                   @; bAlternateSetting
+            .byte   1                   @; bAlternateSetting

Not sure how to handle this request properly

Try to "uncomment" line #418 by writing #if 1. Otherwise SetInterface() and GetInterface() requests will be stalled. Though I don't see any in the log attached.

Isochronous endpoint buffer size is the maximum bytes to be transferred at each USB frame which, for Full Speed USB 2.0, happens every 1 ms. Actual number of bytes to be transferred may vary and don't have to be equal to EP buffer size, it may be less. If you want to change the setting, just type in any value you wish to EP1_BUF_SZ, e.g. (192+1)*2.

viteo commented 1 year ago

yep. alt setting was the issue with windows driver

anonymou8 commented 1 year ago

Woohoo! 🎉

Glad to hear that :)