Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add usb audio example #12

Merged
merged 18 commits into from
Sep 6, 2024
Merged

add usb audio example #12

merged 18 commits into from
Sep 6, 2024

Conversation

Dicklessgreat
Copy link
Owner

from embassy-rs/embassy#3212
and
https://github.com/elagil/embassy/blob/feat_usb_prepare_for_uac/examples/stm32f4/src/bin/usb_uac_speaker.rs

changes from STM32F4 example:

  • hal::Config to daisy_embassy::default_rcc()
  • replace TIM2 with TIM5

not yet works, just quick trying it out for a bit.

@elagil
Copy link

elagil commented Aug 24, 2024

If you are testing this, my own implementation is for STM32H723: https://github.com/blus-audio/firmware-rs
See especially https://github.com/blus-audio/firmware-rs/blob/main/firmware/src/usb_audio.rs

It requires this, though: embassy-rs/stm32-data#511
Otherwise, the USB_SOF signal is not available on the timer, because it uses the wrong set of registers.
You have to check, which timers actually have the USB_SOF signal available to them, it could be that TIM2 is the only one.

@Dicklessgreat
Copy link
Owner Author

Dicklessgreat commented Aug 25, 2024

Thanks for your answer.
I did:

  • git clone https://github.com/elagil/stm32-data.git
  • cd stm32-data
  • git switch fix_stm32h7_timer_versions
  • ./d download-all
  • cargo run --release --bin stm32-data-gen
  • cargo run --release --bin stm32-metapac-gen
  • (and in another directory) git clone https://github.com/elagil/embassy
  • cd embassy
  • git switch feat_usb_prepare_for_uac
  • and edit embassy/embassy-stm32/Cargo.toml to specify the local stm32-metapac, likestm32-metapac = { path = "../../stm32-data/build/stm32-metapac" }
  • edit daisy_embassy/Cargo,toml to specify the local embassy (see my previous commit)
  • cargo build then...
Compiling stm32-metapac v15.0.0 (/Users/dicklessgreat/Documents/Rust/_third_party/stm32-data/build/stm32-metapac)
rustc-LLVM ERROR: Global variable '__INTERRUPTS' has an invalid section specifier '.vector_table.interrupts': mach-o section specifier requires a segment and section separated by a comma.
error: could not compile `stm32-metapac` (lib)

Do you have any ideas what this error means?
Thanks.

@elagil
Copy link

elagil commented Aug 25, 2024

That looks exactly like what I was doing. It seems to not find that vector table section in your linker file, but I don't know why that would be the case. Is it building for the right target (arm)?

You don't have to use my stm32-data if you don't enable feedback. It's fine to run without feedback, but you will get an occasional glitch. Maybe that is a g good first step?

An unrelated thing in your Cargo.toml: you cannot use time-driver-tim2 if you want to use it as the feedback timer. I guess that's why you switched the feedback timer to tim5.

@Dicklessgreat
Copy link
Owner Author

Dicklessgreat commented Aug 26, 2024

It is for the right target, I think,
I have run examples with this settings for many times.

If I do comment out specifying local metapac and comment in as embassy do in embassy/embassy-stm32/Cargo.toml, I mean...:

stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-e0cfd165fd8fffaa0df66a35eeca83b228496645" }
# stm32-metapac = { path = "../../stm32-data/build/stm32-metapac" }

then it is buildable...

But anyway, I'll try the "good first step" later!
Thanks!

@elagil
Copy link

elagil commented Aug 26, 2024

If i remember correctly, I had to change the metapac in two places in the Cargo.toml, but maybe you already did.

Good luck!

@Dicklessgreat
Copy link
Owner Author

OK, now my Windows recognizes the device as a "speaker"!
I haven't checked if it really sounds well or not.
I'll try again tomorrow!

@Dicklessgreat
Copy link
Owner Author

current status: It is now possible to receive audio from the host and output what appears to be that audio through the SAI. But as expected, it does not works well, because audio buffer from USB is exhausted while SAI is running, which makes short "glitches" to the output audio(if I understand correctly).

I'll check if the passing audio buffer from USB task to audio receiver really works (I'll check the detail of blus-audio's firmware).
And after that, I'll try patched metapac , but I have to tuckle the error: rustc-LLVM ERROR: Global variable '__INTERRUPTS' has an invalid section specifier '.vector_table.interrupts'
I found this and tried [workspace] resolver="2", but same error.
embassy-rs/embassy#1165
I don't know where this error comes from...

@elagil
Copy link

elagil commented Aug 31, 2024

Not sure about the build issue, because I am not using a workspace.

Regarding the glitches, that is expected without active feedback, because the rates of receiving and consuming don't match. For transferring data between the USB streaming task and the SAI task, I had good results with a zerocopy-channel. You will find that in the blus-audio firmware, or in the example that I wrote for embassy (STM32F4).

@Dicklessgreat
Copy link
Owner Author

Dicklessgreat commented Sep 1, 2024

It turns out that rustc-LLVM ERROR comes from I missed to add default-features = false, features = ["metadata"] to the stm32-metapac in [build-dependencies] of the local embassy-stm32/Cargo.toml.
OUCH!!

@Dicklessgreat
Copy link
Owner Author

Dicklessgreat commented Sep 1, 2024

from RM0433 "Reference Manual" P.1682 Table338
(STM32H742, STM32H743/753 and STM32H750 Value line
advanced Arm ® -based 32-bit MCUs)
image

@Dicklessgreat
Copy link
Owner Author

Dicklessgreat commented Sep 1, 2024

There are still glitches in output audio from SAI.

I found use_feedback_task infinitely do await for the connection.
So feedback not yet works.
Hmm, I have no idea to solve.
Do you have any ideas? @elagil

I checked TIM2 interrupt and control task is working(by adding info! macro and checking defmt output).
sampling rate of SAI: 48000Hz
audio block length: 32(samples per channel)

@elagil
Copy link

elagil commented Sep 1, 2024

That is strange. Are you on Windows or Linux? If the latter, can you show lsusb -d 0xdead:0xbeef -v for me to check if the descriptors are correct?

You may also look at dmesg, it can give hints for issues with the USB device.

Regarding the audio block length, I don't quite understand. You will get blocks of (around) 1 ms of stereo samples at 48 kHz, which is 48 (stereo) samples per ms -> 384 byte. You may get even more samples than that when the feedback mechanism indicates a consumption rate above 48 kHz. So, you should probably allow for a bigger audio block length.

Then, you are only allowing for a timeout of 500 micro seconds for receiving samples in the audio_receiver_task. Samples in USB full-speed arrive at a fixed spacing of 1 ms, so that will not work. You should allow for maybe 2 ms of timeout - but definitely more than 1 ms.

@Dicklessgreat
Copy link
Owner Author

Dicklessgreat commented Sep 2, 2024

Thanks for your feedback!

Sorry, I missed some logs from debug probe.
Let me correct current state. The feedback is properly connected, but endpoint is stucked. So the feedback loop infinitely await at the second loop of feedback.write_packet(&packet).await?; here.
I don't know how feedback should work but I think feedback should be periodically feed to host during the playback, right?

I'm using Windows.
So I did usbipd wsl attach --busid x-x on Windows Power Shell to pass the device to WSL, and did the command you suggested.

lsusb -d 0xdead:0xbeef -v

Bus 001 Device 002: ID dead:beef Embassy USB-audio-speaker example
Couldn't open device, some information will be missing
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.10
  bDeviceClass          239 Miscellaneous Device
  bDeviceSubClass         2
  bDeviceProtocol         1 Interface Association
  bMaxPacketSize0        64
  idVendor           0xdead
  idProduct          0xbeef
  bcdDevice            0.10
  iManufacturer           1
  iProduct                2
  iSerial                 3
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength       0x007f
    bNumInterfaces          2
    bConfigurationValue     1
    iConfiguration          0
    bmAttributes         0x80
      (Bus Powered)
    MaxPower              100mA
    Interface Association:
      bLength                 8
      bDescriptorType        11
      bFirstInterface         0
      bInterfaceCount         2
      bFunctionClass          1 Audio
      bFunctionSubClass       1 Control Device
      bFunctionProtocol       0
      iFunction               0
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           0
      bInterfaceClass         1 Audio
      bInterfaceSubClass      1 Control Device
      bInterfaceProtocol      0
      iInterface              0
      AudioControl Interface Descriptor:
        bLength                 9
        bDescriptorType        36
        bDescriptorSubtype      1 (HEADER)
        bcdADC               1.00
        wTotalLength       0x0028
        bInCollection           1
        baInterfaceNr(0)        1
      AudioControl Interface Descriptor:
        bLength                12
        bDescriptorType        36
        bDescriptorSubtype      2 (INPUT_TERMINAL)
        bTerminalID             1
        wTerminalType      0x0101 USB Streaming
        bAssocTerminal          0
        bNrChannels             2
        wChannelConfig     0x0003
          Left Front (L)
          Right Front (R)
        iChannelNames           0
        iTerminal               0
      AudioControl Interface Descriptor:
        bLength                10
        bDescriptorType        36
        bDescriptorSubtype      6 (FEATURE_UNIT)
        bUnitID                 2
        bSourceID               1
        bControlSize            1
        bmaControls(0)       0x00
        bmaControls(1)       0x03
          Mute Control
          Volume Control
        bmaControls(2)       0x03
          Mute Control
          Volume Control
        iFeature                0
      AudioControl Interface Descriptor:
        bLength                 9
        bDescriptorType        36
        bDescriptorSubtype      3 (OUTPUT_TERMINAL)
        bTerminalID             3
        wTerminalType      0x0301 Speaker
        bAssocTerminal          0
        bSourceID               2
        iTerminal               0
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       0
      bNumEndpoints           0
      bInterfaceClass         1 Audio
      bInterfaceSubClass      2 Streaming
      bInterfaceProtocol      0
      iInterface              0
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        1
      bAlternateSetting       1
      bNumEndpoints           2
      bInterfaceClass         1 Audio
      bInterfaceSubClass      2 Streaming
      bInterfaceProtocol      0
      iInterface              0
      AudioStreaming Interface Descriptor:
        bLength                 7
        bDescriptorType        36
        bDescriptorSubtype      1 (AS_GENERAL)
        bTerminalLink           1
        bDelay                  0 frames
        wFormatTag         0x0001 PCM
      AudioStreaming Interface Descriptor:
        bLength                11
        bDescriptorType        36
        bDescriptorSubtype      2 (FORMAT_TYPE)
        bFormatType             1 (FORMAT_TYPE_I)
        bNrChannels             2
        bSubframeSize           4
        bBitResolution         32
        bSamFreqType            1 Discrete
        tSamFreq[ 0]        48000
      Endpoint Descriptor:
        bLength                 9
        bDescriptorType         5
        bEndpointAddress     0x01  EP 1 OUT
        bmAttributes            5
          Transfer Type            Isochronous
          Synch Type               Asynchronous
          Usage Type               Data
        wMaxPacketSize     0x0300  1x 768 bytes
        bInterval               1
        bRefresh                0
        bSynchAddress         129
        AudioStreaming Endpoint Descriptor:
          bLength                 7
          bDescriptorType        37
          bDescriptorSubtype      1 (EP_GENERAL)
          bmAttributes         0x01
            Sampling Frequency
          bLockDelayUnits         2 Decoded PCM samples
          wLockDelay         0x0000
      Endpoint Descriptor:
        bLength                 9
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes           17
          Transfer Type            Isochronous
          Synch Type               None
          Usage Type               Feedback
        wMaxPacketSize     0x0004  1x 4 bytes
        bInterval               1
        bRefresh                3
        bSynchAddress           0

dmesg | grep usb(and omit some unrelevant messages)


[   51.505104] usb 1-1: new full-speed USB device number 2 using vhci_hcd
[   51.855109] usb 1-1: SetAddress Request (2) to port 0
[   52.084792] usb 1-1: not running at top speed; connect to a high speed hub
[   52.173119] usb 1-1: New USB device found, idVendor=dead, idProduct=beef, bcdDevice= 0.10
[   52.173124] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[   52.173132] usb 1-1: Product: USB-audio-speaker example
[   52.173136] usb 1-1: Manufacturer: Embassy
[   52.173139] usb 1-1: SerialNumber: 12345678

BTW, the dmesg results reminded me that your example on the STM32F4 was USB "FS", and blus-audio was doing USB "HS". Although your main field is "HS", you would assume this example works with USB FS, right? (Daisy Seed has only a USB FS port.) I ask just for the confirmation!:)

@Dicklessgreat
Copy link
Owner Author

Dicklessgreat commented Sep 2, 2024

And about audio callback, sorry I didn't clearly say I'm suspicious about my current settings(that's why I wrote it).
But your answer really hits what I want to ask! Thanks.
I'll try fix after my works!
I'll be back after finishing my daily tasks.

@Dicklessgreat
Copy link
Owner Author

In relation to other committers' PRs, I will close this PR for now, but I plan to open a new issue and reopen it at a later time.

@Dicklessgreat Dicklessgreat reopened this Sep 6, 2024
@Dicklessgreat Dicklessgreat marked this pull request as ready for review September 6, 2024 10:07
@Dicklessgreat Dicklessgreat merged commit 6c88886 into master Sep 6, 2024
@Dicklessgreat Dicklessgreat changed the title add usb audio example #16 fix usb_audio example Sep 6, 2024
@Dicklessgreat Dicklessgreat changed the title #16 fix usb_audio example add usb audio example Sep 6, 2024
@elagil
Copy link

elagil commented Sep 6, 2024

@Dicklessgreat I didn't see your high-speed vs. full-speed question. This is only expected to work correctly with full-speed USB, as UAC 1.0 is specified for USB 1.0/1.1.

In fact, I use my HS phy in FS mode.

@Dicklessgreat
Copy link
Owner Author

Dicklessgreat commented Sep 6, 2024

In fact, I use my HS phy in FS mode.

I didn't know that's possible! And I missed it's in FS mode.

I didn't see your high-speed vs. full-speed question.

Never mind! Just I wondered if it really works on my device!

Let me correct current state. The feedback is properly connected, but endpoint is stucked. So the feedback loop infinitely await at the second loop of feedback.write_packet(&packet).await?; here.

And do you have any ideas about this?
Not yet commited but in local, I tried to expand SAI callback length, and to expand zerocopy's timeout period to 2ms, but had no luck.
Thanks

@elagil
Copy link

elagil commented Sep 6, 2024

I didn't know that's possible! And I missed it's in FS mode.

It is, as of recently 😄: embassy-rs/embassy#3281
I had to add support for it, because it didn't work correctly on Windows in high-speed mode. I am not sure why.

And do you have any ideas about this?

Are you sure it's stuck there and not waiting for the signal? I don't know why it would get stuck, except if the host doesn't poll the endpoint. I will test on Windows again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants