Linux USB-Audio Gadget (RPi4 OTG)

The reason I needed to test the maximum bitrate was that there was a device tree misconfiguration which prevents larger packet sizes than approx. 900 bytes (out of the 1024 limit). I will push all the patches upstream, when they are ready.

Just looking in to the RPi usb audio gadget functionality - this thread looks like the best place to confirm the current state of play.

The patch referred to above looks like it got pushed to the raspberry pi fork of the kernel. Patches were submitted to upstream but don't look like they got accepted?

My understanding is that there was 3 issues:

1. buffer under-runs when maxing out the capacity of usb2 (ARM: dts: bcm283x: increase dwc2's RX FIFO size - Patchwork)
2. current uac2 mode not compatible with windows (Re: Re: [PATCH] usb: gadget: f_uac2: EP OUT adaptive instead of async — Linux USB)
3. current uac2 mode doesn't allow the host device to select the data format (sample rate/bit depth)?

From poking around the mailing lists it looks like 1 and 2 had patches but they haven't ended up in kernel (yet).

Is that a reasonable summary? I grabbed an rpi 4 today and am about to start dabbling with this and was just reading up on what's currently working.
 
1. buffer under-runs when maxing out the capacity of usb2 (ARM: dts: bcm283x: increase dwc2's RX FIFO size - Patchwork)

I just resent the patch with shorter description. Hopefully it will finally get upstream. But the increased buffer is not required for typical audio samplerates which do not need packet sizes larger than the existing 960 bytes limit.

2. current uac2 mode not compatible with windows (Re: Re: [PATCH] usb: gadget: f_uac2: EP OUT adaptive instead of async — Linux USB)

Just in time [PATCH 0/3] UAC2 Gadget: feedback endpoint support — Linux USB

[PATCH] [RFC] alsaloop: add feedback frequency control support for UAC2 gadgets — ALSA Devel

3. current uac2 mode doesn't allow the host device to select the data format (sample rate/bit depth)?

Not yet. IMO it will need specifying a list of rates in the module params, and adding the UAC2 clock feature for switching the rates.

Bit depths are through altsets? IMO a single size (S32_LE: c_ssize/p_ssize=4) should do for any real-world use case. Many PCI soundcards have only S32_LE too.
 
Ruslan's explicit feedback for windows 10 support Linux USB - Patchwork rebased, Julian's rate switching patch [3/3] usb: gadget: f_uac*: Support multiple sampling rates - Patchwork rebased on top, added multiple rates to g_audio module config, all in my fork Commits * pavhofman/linux-rpi * GitHub . Rpi4 DMA issue preventing correct rate switching fixed today by the RPi team RNDIS USB Gadget fails to function * Issue #127 * raspberrypi/Raspberry-Pi-OS-64bit * GitHub .

Now making all the patches get into the mainline, that will take a while. Afterwards the audio gadget should finally be ready to use.
 
The output side - RPi4 I2S data output at 768kHz 24bit, both BCLK and FCLK slaved to an external clock generator. And just for the fun - 1,536kHz samplerate, the same I2S signal. But I have no DAC capable of 1.5MHz 24bit :)
 

Attachments

  • NewFile2.png
    NewFile2.png
    39.8 KB · Views: 321
  • NewFile3.png
    NewFile3.png
    39.8 KB · Views: 324
I2S loopback bit-perfect up to 1,024kHz samplerate and 48bit frame width (i.e. the same bitclock 49.152MHz as would be with 768kHz samplerate and 64bit frame width).

Recorded 341kHz sine signal played by the I2S-out and captured by I2S-in, connected at the pinheader.

No xruns, period size was 1024 which corresponds to 1k period_elapsed calls per second for playback and the same for capture. Since the two DMA-filled buffers in the PCM peripheral are only 64 frames long (and fill watermarks are set rather tight), we can assume several ten thousand DMA operations for each direction per second. All handled safely, no xruns, no CPU load detected.

The 1.536MHz samplerate (i.e. 73MHz bitclock) was already corrupted, maybe CM4 with extra short routes would do.
 

Attachments

  • spectrogram.png
    spectrogram.png
    6.9 KB · Views: 241
Does this system support multichannel?

No, the PCM peripheral of RPi can only encode 2 channels.

That could make a nice 16-bit high data rate ADC...

Good idea. 1,536 x 32 bits yields the 49,152MHz bitrate, already tested to work.

Simple change in I2S DTS config (dai-tdm-slot-width = 16 instead of 24) + trivial change in my clock generator config (bitclock divider = frame clock divider / 32 instead of / 48), checking that the soundcard receives the correct signal


Code:
access: RW_INTERLEAVED
format: S16_LE
subformat: STD
channels: 2
rate: 1536000 (1536000/1)
period_size: 2048
buffer_size: 16384

and look at the I2S loopback spectrum of 700kHz sine signal at 1,536kHz/16bit/2ch. If you have a DAC and ADC capable of these rates, the RPi4 (or better CM4 with shorter traces) gives you the I2S interface. REW runs perfectly on RPi4, the linux version already supports 1,536kHz samplerate and increased 4M FFT for this purpose. If you need windows, use the USB gadget mode (provided windows could handle the 1.5MHz samplerate advertised by the USB gadget, linux has no problem with it, of course). The packetsize (1536000Hz * 4bytes /8000 uframes = 768 bytes) is well below the max USB isochronous packetsize of 1024 bytes.
 

Attachments

  • spectrogram.png
    spectrogram.png
    7.5 KB · Views: 347
No, the PCM peripheral of RPi can only encode 2 channels.

Damn. I'll have to dust off that USB2 soundcard code... someday lol.

> Good idea. 1,536 x 32 bits yields the 49,152MHz bitrate, already tested to work.

👍

Highspeed low noise ADC would be nice to fish out the harmonics when testing an amp at 20-40 kHz... Of course it's easier on my part to blow hot air than to design a board :D
 
No, the PCM peripheral of RPi can only encode 2 channels.

I suppose with all the dependencies this would be very difficult to get working on a Xilinx Zynq Ultrascale+? I think they are using the Synopsys IP for USB but not sure, and probably not the same rev as the RPi 4. Well, that's relevant to the patches for it, only and not the gadget itself. I guess it would be doable if the kernel isn't too old. I think Xilinx finally may be at the 5.x since PetaLinux is based on Yocto.
 
Last edited:
Most ARM SoCs use the DesignWare Core (dwc2, dwc3) for their USB functionality. The Xilinx would likely work OK, in the end, but pricewise and effortwise I do not see the reason. Any special needs?

It's for a non-audio device, but occasionally it could be handy to be able to output heavily downsampled data as an audio device. Not sure it's practical, just curious :).
 
I see where you are heading, your high-speed ADC would use some custom-designed interface programmed in the Xilinx.

The USB gadget would give you up to 4MHz samplerate at 16bit 1 channel (1024bytes max. isochronous packetsize). You needed some 18MHz, right? You would have to downsample /4 and run at 16MHz.
 
I see where you are heading, your high-speed ADC would use some custom-designed interface programmed in the Xilinx.

The USB gadget would give you up to 4MHz samplerate at 16bit 1 channel (1024bytes max. isochronous packetsize). You needed some 18MHz, right? You would have to downsample /4 and run at 16MHz.

That's not too bad, actually. Right now I have 2 channels of 16-bit 15 MHz working via FT600. Those USB gadget rates are definitely better than I have found you can push via the usual XMOS stuff, but that board has an FPGA without an ARM SoC.

I thought it might be fun to try it out on a different device at work actually that uses even higher speed ADCs. It already has a Zynq, so I was curious.
 
Running some recent kernel on Zynq would likely be a nontrivial project. But maybe they have something ready-made. I have no idea about performance (DMA access for the USB gadget etc.), all my tests are on RPi4 (which fares pretty well, IMO).

Still the gadget code is missing adjusting playback rate (i.e. USB IN), the feedback patches deal with capture direction (controlling rate at which the USB host sends data to the gadget). I will have to look at it, that should not be overly complicated as support for the requested rate is already there.
 
Running some recent kernel on Zynq would likely be a nontrivial project. But maybe they have something ready-made. I have no idea about performance (DMA access for the USB gadget etc.), all my tests are on RPi4 (which fares pretty well, IMO).

Still the gadget code is missing adjusting playback rate (i.e. USB IN), the feedback patches deal with capture direction (controlling rate at which the USB host sends data to the gadget). I will have to look at it, that should not be overly complicated as support for the requested rate is already there.

Yeah I think they are just up to 5.4 finally. Appreciate your efforts on this project for the community btw, even if I never actually get a chance to use it.