I haven't had success with async feedback bInterval = 4 in Windows. Only bInterval = 1 works. But device does not need to send feedback at that rate so actual interval can be greater.
Last edited:
Hm, I do not remember any issues with the feedback EP IN bInterval=4 on Win10 from the current linux gadget. Quite a few people use it, combined with CamillaDSP.
lsusb -v (descriptor dump):
The way the linux host driver views the device:
lsusb -v (descriptor dump):
Code:
Bus 001 Device 006: ID 1d6b:0101 Linux Foundation Audio Gadget
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.01
bDeviceClass 239 Miscellaneous Device
bDeviceSubClass 2
bDeviceProtocol 1 Interface Association
bMaxPacketSize0 64
idVendor 0x1d6b Linux Foundation
idProduct 0x0101 Audio Gadget
bcdDevice 6.01
iManufacturer 1
iProduct 2
iSerial 0
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 0x010d
bNumInterfaces 3
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xc0
Self Powered
MaxPower 0mA
Interface Association:
bLength 8
bDescriptorType 11
bFirstInterface 0
bInterfaceCount 3
bFunctionClass 1 Audio
bFunctionSubClass 0
bFunctionProtocol 32
iFunction 4
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 1 Audio
bInterfaceSubClass 1 Control Device
bInterfaceProtocol 32
iInterface 5
AudioControl Interface Descriptor:
bLength 9
bDescriptorType 36
bDescriptorSubtype 1 (HEADER)
bcdADC 2.00
bCategory 8
wTotalLength 0x0077
bmControls 0x00
AudioControl Interface Descriptor:
bLength 8
bDescriptorType 36
bDescriptorSubtype 10 (CLOCK_SOURCE)
bClockID 8
bmAttributes 1 Internal fixed clock
bmControls 0x03
Clock Frequency Control (read/write)
bAssocTerminal 0
iClockSource 6
AudioControl Interface Descriptor:
bLength 8
bDescriptorType 36
bDescriptorSubtype 10 (CLOCK_SOURCE)
bClockID 7
bmAttributes 1 Internal fixed clock
bmControls 0x03
Clock Frequency Control (read/write)
bAssocTerminal 0
iClockSource 7
AudioControl Interface Descriptor:
bLength 17
bDescriptorType 36
bDescriptorSubtype 2 (INPUT_TERMINAL)
bTerminalID 1
wTerminalType 0x0101 USB Streaming
bAssocTerminal 0
bCSourceID 7
bNrChannels 2
bmChannelConfig 0x00000003
Front Left (FL)
Front Right (FR)
iChannelNames 0
bmControls 0x0003
Copy Protect Control (read/write)
iTerminal 8
AudioControl Interface Descriptor:
bLength 18
bDescriptorType 36
bDescriptorSubtype 6 (FEATURE_UNIT)
bUnitID 5
bSourceID 1
bmaControls(0) 0x0000000f
Mute Control (read/write)
Volume Control (read/write)
bmaControls(1) 0x00000000
bmaControls(2) 0x00000000
iFeature 13
AudioControl Interface Descriptor:
bLength 17
bDescriptorType 36
bDescriptorSubtype 2 (INPUT_TERMINAL)
bTerminalID 2
wTerminalType 0x0201 Microphone
bAssocTerminal 0
bCSourceID 8
bNrChannels 2
bmChannelConfig 0x00000003
Front Left (FL)
Front Right (FR)
iChannelNames 0
bmControls 0x0003
Copy Protect Control (read/write)
iTerminal 9
AudioControl Interface Descriptor:
bLength 18
bDescriptorType 36
bDescriptorSubtype 6 (FEATURE_UNIT)
bUnitID 6
bSourceID 2
bmaControls(0) 0x0000000f
Mute Control (read/write)
Volume Control (read/write)
bmaControls(1) 0x00000000
bmaControls(2) 0x00000000
iFeature 12
AudioControl Interface Descriptor:
bLength 12
bDescriptorType 36
bDescriptorSubtype 3 (OUTPUT_TERMINAL)
bTerminalID 4
wTerminalType 0x0101 USB Streaming
bAssocTerminal 0
bSourceID 6
bCSourceID 8
bmControls 0x0003
Copy Protect Control (read/write)
iTerminal 10
AudioControl Interface Descriptor:
bLength 12
bDescriptorType 36
bDescriptorSubtype 3 (OUTPUT_TERMINAL)
bTerminalID 3
wTerminalType 0x0301 Speaker
bAssocTerminal 0
bSourceID 5
bCSourceID 7
bmControls 0x0003
Copy Protect Control (read/write)
iTerminal 11
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0006 1x 6 bytes
bInterval 4
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 0
bNumEndpoints 0
bInterfaceClass 1 Audio
bInterfaceSubClass 2 Streaming
bInterfaceProtocol 32
iInterface 14
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 1
bNumEndpoints 2
bInterfaceClass 1 Audio
bInterfaceSubClass 2 Streaming
bInterfaceProtocol 32
iInterface 15
AudioStreaming Interface Descriptor:
bLength 16
bDescriptorType 36
bDescriptorSubtype 1 (AS_GENERAL)
bTerminalLink 1
bmControls 0x00
bFormatType 1
bmFormats 0x00000001
PCM
bNrChannels 2
bmChannelConfig 0x00000003
Front Left (FL)
Front Right (FR)
iChannelNames 0
AudioStreaming Interface Descriptor:
bLength 6
bDescriptorType 36
bDescriptorSubtype 2 (FORMAT_TYPE)
bFormatType 1 (FORMAT_TYPE_I)
bSubslotSize 4
bBitResolution 32
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x02 EP 2 OUT
bmAttributes 5
Transfer Type Isochronous
Synch Type Asynchronous
Usage Type Data
wMaxPacketSize 0x0308 1x 776 bytes
bInterval 1
AudioStreaming Endpoint Descriptor:
bLength 8
bDescriptorType 37
bDescriptorSubtype 1 (EP_GENERAL)
bmAttributes 0x00
bmControls 0x00
bLockDelayUnits 0 Undefined
wLockDelay 0x0000
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x83 EP 3 IN
bmAttributes 17
Transfer Type Isochronous
Synch Type None
Usage Type Feedback
wMaxPacketSize 0x0004 1x 4 bytes
bInterval 4
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 2
bAlternateSetting 0
bNumEndpoints 0
bInterfaceClass 1 Audio
bInterfaceSubClass 2 Streaming
bInterfaceProtocol 32
iInterface 16
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 2
bAlternateSetting 1
bNumEndpoints 1
bInterfaceClass 1 Audio
bInterfaceSubClass 2 Streaming
bInterfaceProtocol 32
iInterface 17
AudioStreaming Interface Descriptor:
bLength 16
bDescriptorType 36
bDescriptorSubtype 1 (AS_GENERAL)
bTerminalLink 4
bmControls 0x00
bFormatType 1
bmFormats 0x00000001
PCM
bNrChannels 2
bmChannelConfig 0x00000003
Front Left (FL)
Front Right (FR)
iChannelNames 0
AudioStreaming Interface Descriptor:
bLength 6
bDescriptorType 36
bDescriptorSubtype 2 (FORMAT_TYPE)
bFormatType 1 (FORMAT_TYPE_I)
bSubslotSize 4
bBitResolution 32
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x85 EP 5 IN
bmAttributes 5
Transfer Type Isochronous
Synch Type Asynchronous
Usage Type Data
wMaxPacketSize 0x0308 1x 776 bytes
bInterval 1
AudioStreaming Endpoint Descriptor:
bLength 8
bDescriptorType 37
bDescriptorSubtype 1 (EP_GENERAL)
bmAttributes 0x00
bmControls 0x00
bLockDelayUnits 0 Undefined
wLockDelay 0x0000
The way the linux host driver views the device:
Code:
Linux 6.1.43-467115-gad02bcf12c1d-dirty with ff400000.usb Linux USB Audio Gadge
: USB Audio
Playback:
Status: Stop
Interface 1
Altset 1
Format: S32_LE
Channels: 2
Endpoint: 0x02 (2 OUT) (ASYNC)
Rates: 48000, 96000, 192000, 384000, 768000
Data packet interval: 125 us
Bits: 32
Channel map: FL FR
Sync Endpoint: 0x83 (3 IN)
Sync EP Interface: 1
Sync EP Altset: 1
Implicit Feedback Mode: No
Capture:
Status: Stop
Interface 2
Altset 1
Format: S32_LE
Channels: 2
Endpoint: 0x85 (5 IN) (ASYNC)
Rates: 48000, 96000, 192000, 384000, 768000
Data packet interval: 125 us
Bits: 32
Channel map: FL FR
Thanks for the feedback phofman. From readintg the above, I also note that the linux gadget seems seems to only propose 32 bits interface (and several sampling frequencies). This is interesting to me as it would allow to avoid to manage different alt settings for 12, 24 and 32 bits.
Do you confirm? Does it has some inconvenience in practice? Is it OK as Windows/Linux/Mac easily map 16 and 24 bits to 32 bits?
Nota: I also noted that that the OpenUAC bridge has only 2 configs (24 and 32 bits, no 16 bits).
Do you confirm? Does it has some inconvenience in practice? Is it OK as Windows/Linux/Mac easily map 16 and 24 bits to 32 bits?
Nota: I also noted that that the OpenUAC bridge has only 2 configs (24 and 32 bits, no 16 bits).
It's just that specific configuration of mine. Any number of bytes (integer format only, for now), any channels, any samplerate combination can be specified https://www.kernel.org/doc/Documentation/ABI/testing/configfs-usb-gadget-uac2 . It's just about copying byte arrays from/to the packet in the end 🙂From readintg the above, I also note that the linux gadget seems seems to only propose 32 bits interface (and several sampling frequencies). This is interesting to me as it would allow to avoid to manage different alt settings for 12, 24 and 32 bits.
Multiple altsets with individual configurations are coming too https://lore.kernel.org/all/CAB0kiB.../T/#mc2b68c2e74ed57e2998c1b0f42bfca82e07db181
It has been a while since I worked on this but IIRC it is about Synopsys OTG used in STM32 MCUs. If FB packet frame number parity (odd or even) does not match to what host has sent Synopsys OTG sends an empty feedback packet. I did not spend much time on a workaround as easiest fix is to use bInterval = 1.I do not remember any issues with the feedback EP IN bInterval=4 on Win10 from the current linux gadget.
OK, so IIUC the OTG IP does not actually send the FB packet data, not that the Win10 host driver ignores the feedback message. Thanks for the clarification.
FB packets are sent but Win10 driver ignores them as they are empty.
This is how it looks like in Win10 uac2 driver logs:
This is how it looks like in Win10 uac2 driver logs:
Code:
[0]464C.4744::04/28/2024-17:05:08.806 [USBAudio2](0x01): FEEDBACK Isoch Buffers: BufferCount=3 BytesPerPacket=4 PacketsPerBuffer=16 PacketFreq=1000 PollingInterval=8
...
[0]464C.4744::04/28/2024-17:05:08.810 [USBAudio2](OUT): packetNumber=1 flags=0x00000000 eosPacketLength=21504
[0]0000.0000::04/28/2024-17:05:08.829 [USBAudio2](0x01): COMPL OUT buf 0 CurrenLinearPosition=1344
[0]0000.0000::04/28/2024-17:05:08.830 [USBAudio2](0x01): buf 0 feedback packet 0 has invalid packet length 0, ignoring packet
[0]0000.0000::04/28/2024-17:05:08.830 [USBAudio2](0x01): buf 0 feedback packet 1 has invalid packet length 0, ignoring packet
[0]0000.0000::04/28/2024-17:05:08.830 [USBAudio2](0x01): buf 0 feedback packet 2 has invalid packet length 0, ignoring packet
[0]0000.0000::04/28/2024-17:05:08.830 [USBAudio2](0x01): buf 0 feedback packet 3 has invalid packet length 0, ignoring packet
[0]0000.0000::04/28/2024-17:05:08.830 [USBAudio2](0x01): buf 0 feedback packet 4 has invalid packet length 0, ignoring packet
I will have a look at the Win10 uac2 driver logs to check if I have the same behaviour.
After some searches on the net, and old posrs on ST community, I reverted to bInterval=5 and tried to see if I got some IsoInIncompleteCallbacks.
I have, and at each uFrame.
In that case, the ST usbx adaptation layer does:
HAL_PCD_EP_Transmit(dcd_stm32 -> pcd_handle,
endpoint->ux_slave_endpoint_descriptor.bEndpointAddress,
endpoint->ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer,
endpoint->ux_slave_endpoint_transfer_request.ux_slave_transfer_request_requested_length);
Which looks similar to OpenUAC2 code in case of IsoInIncomplete, which seems to work with bInterval=4 for feedback:
if (epnum == FEEDBACK_EP_NUM)
{
USBD_LL_Transmit(pdev, FEEDBACK_EP_ADDR, (uint8_t*)&haudio->feedback_value, FEEDBACK_PACKET_SIZE);
}
And possibly https://community.st.com/t5/stm32-m...eedback-problem-and-even-odd-frame/m-p/542335
But the usbx code is not sufficient to get the thing right :-(
This could to be a sort of odd behaviour of the stm32 USB peripheral...
JMF,
After some searches on the net, and old posrs on ST community, I reverted to bInterval=5 and tried to see if I got some IsoInIncompleteCallbacks.
I have, and at each uFrame.
In that case, the ST usbx adaptation layer does:
HAL_PCD_EP_Transmit(dcd_stm32 -> pcd_handle,
endpoint->ux_slave_endpoint_descriptor.bEndpointAddress,
endpoint->ux_slave_endpoint_transfer_request.ux_slave_transfer_request_data_pointer,
endpoint->ux_slave_endpoint_transfer_request.ux_slave_transfer_request_requested_length);
Which looks similar to OpenUAC2 code in case of IsoInIncomplete, which seems to work with bInterval=4 for feedback:
if (epnum == FEEDBACK_EP_NUM)
{
USBD_LL_Transmit(pdev, FEEDBACK_EP_ADDR, (uint8_t*)&haudio->feedback_value, FEEDBACK_PACKET_SIZE);
}
And possibly https://community.st.com/t5/stm32-m...eedback-problem-and-even-odd-frame/m-p/542335
But the usbx code is not sufficient to get the thing right :-(
This could to be a sort of odd behaviour of the stm32 USB peripheral...
JMF,
USBD_LL_Transmit() and HAL_PCD_EP_Transmit() are the same thing. No test that would make not execute the needed action...
So if OpenUAC2 bridge is working, this should work.
Same type of solution/workaround based on IsoInIncomplete is reported here https://community.st.com/t5/stm32-m...ue-with-stm32h7-series-and-usb3320/m-p/198584.
Good that the bInterval=1 should be a workaround, but I would be happy to clarify that point...
USBD_StatusTypeDef USBD_LL_Transmit(USBD_HandleTypeDef *pdev, uint8_t ep_addr, uint8_t *pbuf, uint32_t size)
{
HAL_StatusTypeDef hal_status = HAL_OK;
USBD_StatusTypeDef usb_status = USBD_OK;
hal_status = HAL_PCD_EP_Transmit(pdev->pData, ep_addr, pbuf, size);
usb_status = USBD_Get_USB_Status(hal_status);
return usb_status;
}
So if OpenUAC2 bridge is working, this should work.
Same type of solution/workaround based on IsoInIncomplete is reported here https://community.st.com/t5/stm32-m...ue-with-stm32h7-series-and-usb3320/m-p/198584.
Good that the bInterval=1 should be a workaround, but I would be happy to clarify that point...
My assumption is that when host polling period is more than 1 (e.g. bInterval=4) device does not know when host polling occurs. This leads to IsoInIncomplete event if host does not read the feedback in time (IN event). Sending feedback at IsoInIncomplete is a workaround as feedback is then sent much more frequently than needed. So instead of sending feedback at 1ms period the actual period is closer to 125us.
I may understand it wrong (as very often) but how would device -> host capture run at bInterval > 1 then? That should require device responding to host polling too and sending the data. But I may get it wrong.My assumption is that when host polling period is more than 1 (e.g. bInterval=4) device does not know when host polling occurs
My understanding is that when feedback processing is working there should be zero IsoInIncomplete events and same number of In events as feedback messages sent.
I did some testing and with bInterval=1 this is the case: number of IsoInIncomplete events is close to zero and number of In events close to feedbacks sent. So almost all feedback messages processed ok.
However with bInterval=4 the number of IsoInIncomplete events is close to number of feedbacks sent if host polling and device are not in sync. So almost all feedback messages are not processed ok. Syncing host polling and device feedbacks with bInterval > 1 is quite tricky so the workaround of sending feedback at IsoInIncomplete events is easier although IMO not a proper fix.
All this applies to STM32 MCUs with Synopsys OTG. Other implementations may work differently.
I did some testing and with bInterval=1 this is the case: number of IsoInIncomplete events is close to zero and number of In events close to feedbacks sent. So almost all feedback messages processed ok.
However with bInterval=4 the number of IsoInIncomplete events is close to number of feedbacks sent if host polling and device are not in sync. So almost all feedback messages are not processed ok. Syncing host polling and device feedbacks with bInterval > 1 is quite tricky so the workaround of sending feedback at IsoInIncomplete events is easier although IMO not a proper fix.
All this applies to STM32 MCUs with Synopsys OTG. Other implementations may work differently.
I find it hard to believe that the Synopsys OTG IP were so buggy in STM, the sync feedback communication is a standard USB method. Synopsys OTG IPs are ubiquitous (dwc2 in RPi or Rockchips, dwc3 in Rockchips or Intel), of course the implementations always differ a bit.
Maybe there really is some issue with generating the sync EP IN packets in your FW which prevents the host controller/USB core driver from accepting them. Maybe the packets would be visible in wireshark (if the host controller accepts them). Best would be tracking the traffic using wire capture, using e.g. that simple https://www.diyaudio.com/community/threads/usb-sniffer-protocol-analyzer-using-wireshark.407540/
Maybe there really is some issue with generating the sync EP IN packets in your FW which prevents the host controller/USB core driver from accepting them. Maybe the packets would be visible in wireshark (if the host controller accepts them). Best would be tracking the traffic using wire capture, using e.g. that simple https://www.diyaudio.com/community/threads/usb-sniffer-protocol-analyzer-using-wireshark.407540/
I would not call Synopsys OTG buggy as it works according to USB specifications. What is the bug in your opinion?
Regarding my FW you should take a closer look at e.g. the links in post #69 & #70. There are plenty of similar links to be found. So this behaviour is not limited to my FW.
Regarding my FW you should take a closer look at e.g. the links in post #69 & #70. There are plenty of similar links to be found. So this behaviour is not limited to my FW.
Last edited:
I am afraid I cannot help with STM code, zero knowledge here 🙂 Also the question is what those HAL methods do internally, they could be buggy too.
But if you wanted I could capture some linux gadget UAC2 packets with bInterval=4 in wireshark which could be compared with packets generated by your device (if they can be captured by software in your case, i.e. if they make it past the host controller/usb core driver).
But if you wanted I could capture some linux gadget UAC2 packets with bInterval=4 in wireshark which could be compared with packets generated by your device (if they can be captured by software in your case, i.e. if they make it past the host controller/usb core driver).
As I've said there is nothing wrong at bInterval=1. The behaviour at bInterval > 1 is not related to UAC2 feedback packets themselves but something else. I may test with Linux later.
BTW here is another similar issue which was fixed with setting bInterval=1.
https://learn.microsoft.com/en-us/a...cit-feedback-for-asynchronous-audio-with-usba
BTW here is another similar issue which was fixed with setting bInterval=1.
https://learn.microsoft.com/en-us/a...cit-feedback-for-asynchronous-audio-with-usba
IIUC that report concerns the linux gadget and IMO the bInterval discussed relates to the EP OUT, not to the sync packet. That thread is from 2021, and the commit which fixed the behavior for HS EP OUT bInterval > 1 is from September 2021 https://github.com/torvalds/linux/c...b2fd31a0a731bcad75b48ee8eb5386ea7b77R133-R139 - which happened to be submitted by me (with help of a number of great developers, of course).BTW here is another similar issue which was fixed with setting bInterval=1.
https://learn.microsoft.com/en-us/a...cit-feedback-for-asynchronous-audio-with-usba
The HS sync fback EP IN bInterval has always been fixed at 4 https://github.com/torvalds/linux/blame/master/drivers/usb/gadget/function/f_uac2.c#L406-L413
For traceability purpose, with bInterval = 4,
I have the packet length=0
There is a IsoInIncomplete event every uFrame. See traceX below:
Red II = IsoInIncomplete events
Single SP interrupts = Feedback read events
SP/IR interrupts = EP01 OUT datastream
SP alone are strange. I thought is war related to the feedback Read, but it is the same Semaphore as for DataOut (and should not be)
Next message, I will provide the same for bInterval=1
I have the packet length=0
[0]0000.0000::04/30/2024-19:02:59.319 [USBAudio2](0x01): buf 0 feedback packet 0 has invalid packet length 0, ignoring packet
[0]0000.0000::04/30/2024-19:02:59.319 [USBAudio2](0x01): buf 0 feedback packet 1 has invalid packet length 0, ignoring packet
[0]0000.0000::04/30/2024-19:02:59.319 [USBAudio2](0x01): buf 0 feedback packet 2 has invalid packet length 0, ignoring packet
[0]0000.0000::04/30/2024-19:02:59.319 [USBAudio2](0x01): buf 0 feedback packet 3 has invalid packet length 0, ignoring packet
[0]0000.0000::04/30/2024-19:02:59.319 [USBAudio2](0x01): buf 0 feedback packet 4 has invalid packet length 0, ignoring packet
[0]0000.0000::04/30/2024-19:02:59.319 [USBAudio2](0x01): buf 0 feedback packet 5 has invalid packet length 0, ignoring packet
[0]0000.0000::04/30/2024-19:02:59.319 [USBAudio2](0x01): buf 0 feedback packet 6 has invalid packet length 0, ignoring packet
...
There is a IsoInIncomplete event every uFrame. See traceX below:
Red II = IsoInIncomplete events
Single SP interrupts = Feedback read events
SP/IR interrupts = EP01 OUT datastream
SP alone are strange. I thought is war related to the feedback Read, but it is the same Semaphore as for DataOut (and should not be)
Next message, I will provide the same for bInterval=1
Attachments
With bInterval=1:
There is no IsoInIncomplete (red II)
The SP are Semaphore Put, when the USBX stack receives data requests.
Single SP interrupts = Feedback read events every 2 uFrames. It is a different Semaphore than the DataOut (as expected), and it activates the Feedback Thread every 2 uFrames (bottom line)
SP/IR interrupts = EP01 OUT datastream
But, I still have in UAC2 logs [USBAudio2](0x01): buf 1 feedback packet 50 has invalid packet length 0, ignoring packet
Arghh. And stopping at the breakpoint at the transmit, the length on stm32 side is 0x04, and pointer to data looks correct: value 0x00060000 (in memory 00000600).
Back to the workbench...
There is no IsoInIncomplete (red II)
The SP are Semaphore Put, when the USBX stack receives data requests.
Single SP interrupts = Feedback read events every 2 uFrames. It is a different Semaphore than the DataOut (as expected), and it activates the Feedback Thread every 2 uFrames (bottom line)
SP/IR interrupts = EP01 OUT datastream
But, I still have in UAC2 logs [USBAudio2](0x01): buf 1 feedback packet 50 has invalid packet length 0, ignoring packet
Arghh. And stopping at the breakpoint at the transmit, the length on stm32 side is 0x04, and pointer to data looks correct: value 0x00060000 (in memory 00000600).
Back to the workbench...
Attachments
- Home
- Source & Line
- Digital Line Level
- STM32 USB to I2S multi channel - log - ask for help