tinyusb icon indicating copy to clipboard operation
tinyusb copied to clipboard

Midihost

Open rppicomidi opened this issue 2 years ago • 21 comments

Describe the PR This pull request adds MIDI host functionality to tinyusb.

Additional context This code is a work in progress and should be treated as a draft. I am submitting it as a pull request in hopes it will be helpful.

Working now

  • Compiles and loads on a RP2040 board in the Visual Studio Code IDE
  • Both devices I have tried enumerate correctly (Yamaha Reface CS, Korg nanoKONTROL Studio)
  • The code will correctly format a MIDI message and send it to the device via the bulk OUT endpoint; the example code will blink the LEDs behind the REC button on the Korg nanoKONTROL Studio configured for use with a DAW that uses Mackie Control messages.

There are a lot of known defects

  • It is not structured correctly to work with USB hubs. This is laziness on my part and can easily be fixed.
  • It has only been tested so far on a Raspberry Pi Pico board
  • The bulk IN endpoint code I wrote for the RP2040 does not work reliably. See Blocking Issues below
  • It probably will not correctly enumerate USB Audio Class 2 devices with a MIDI interface because of the interface association descriptor. I know how to fix this if it is a problem.
  • There are asserts in the code that will fail sometimes on after an unplug or after a re-plug. I fixed one but I have randomly hit others.

Blocking Issues @hathach I am struggling with the IN endpoint. The Korg device I use for most of my testing should be sending a NAK for each transfer request when no controls are touched, but the RP2040 is happily reporting completed transfer for each transfer request. The buffers contain all 0s. I don't have a bus analyzer so I don't know whether the Korg test device or my code is at fault there. Also not clear is what to do with the NAK_POLL register at offset 0x6c; I would think that a bulk IN endpoint that shares hardware with bulk OUT should not automatically retry on NAK, nor should it time out. It should set the NAK flag in the SIE status register, but I don't observe that. Do you know of a support path from the Raspberry Pi foundation where I can get direct answers to questions about the USB on the RP2040?

rppicomidi avatar Dec 01 '21 05:12 rppicomidi

I converted this pull request to draft because the bulk IN endpoint for the RP2040 is not working yet.

rppicomidi avatar Dec 04 '21 00:12 rppicomidi

@rppicomidi thank you very much for your PR, sorry for late response. I am bit busy and lagging behind PRs. I will try to test and help with bulk IN later as soon as I could.

hathach avatar Dec 07 '21 12:12 hathach

@hathach I am making progress again and have the IN endpoint working with the OUT endpoint disabled. I am about to push a change. Once that is done I will see if both can work together.

rppicomidi avatar Dec 09 '21 23:12 rppicomidi

@hathach I am making progress again and have the IN endpoint working with the OUT endpoint disabled. I am about to push a change. Once that is done I will see if both can work together.

great thanks, I am also looking at bullk-iso endpoint host as well

hathach avatar Dec 10 '21 03:12 hathach

I pushed changes that show the Raspberry Pi Pico as MIDI host supporting both IN and OUT endpoints at the same time. It's showing proof of life, but after a short while the system gets in a state where it will neither send nor receive until I unplug and re-plug the MIDI device. I am investigating.

rppicomidi avatar Dec 10 '21 05:12 rppicomidi

Commit 5e4364f fixed what appears to me to be a timing issue in the rp2040. I believe now that bulk endpoints are working. I have some cleanup and testing to do and will then take this pull request out of draft. Not sure when that will be.

rppicomidi avatar Dec 12 '21 18:12 rppicomidi

This code is not perfect but it is far enough along that I believe it is ready for review. It handles concurrent MIDI send and receive. Whether the API I came up with is good for any host other than the RP2040 should be considered. I have tested it with the following MIDI devices:

  • Casio PS-X3000
  • Yamaha reface CS
  • Korg nanoKONTROL2
  • Korg nanoKONTROL Studio
  • Arturia Keylab 88 Essential

rppicomidi avatar Dec 23 '21 01:12 rppicomidi

@rppicomidi many thanks, I have revised hcd for rp2040 recently and also have some ideas on how to implement the bulk endpoints. Basically it is similar to your changes, we add an struct for each bulk ep and process them one by one after the previous one is complete. I will check this out asap I could. sorry for late response, I am still catching up with PRs

hathach avatar Dec 28 '21 17:12 hathach

@hathach No need to say you are sorry. Thank you for running this project. I understand you are busy.

rppicomidi avatar Dec 29 '21 03:12 rppicomidi

Hi, I'm very interested in testing this out. Can you share how you have your Pico / RP2040 board hooked up? How are you seeing the printf() messages?

todbot avatar Jan 10 '22 02:01 todbot

@todbot For my development setup, I am using a picoprobe for code load and for serial port printouts. See Getting started with the Raspberry Pi Pico, Appendix A. The one difference from the Figure 36 in Appendix A is instead of hooking VSYS from the picoprobe to the target Pico board VSYS, I hooked the VBUS pin of the picoprobe Pico board to the VBUS pin of the target Pico board. That is:

Pico A GND -> Pico B GND
Pico A GP2 -> Pico B SWCLK
Pico A GP3 -> Pico B SWDIO
Pico A GP4/UART1 TX -> Pico B GP1/UART0 RX
Pico A GP5/UART1 RX -> Pico B GP0/UART0 TX
Pico A VBUS -> Pico B VBUS

I connect the picoprobe to my test PC via a powered hub to make sure I don't screw up and damage my PC. I hook a microUSB male to original USB A female adapter to the target Pico board microUSB connector. There is no current limit on the USB host, so be careful.

If you check my github repository in a day or two I will have an example pushed that shows the USB host converted to old school 5-pin DIN MIDI. Testing it now.

rppicomidi avatar Jan 11 '22 01:01 rppicomidi

I've done some initial testing on this PR, using @rppicomidi's repo's midihost branch as of 537150f931d218e16b88dc5ac50a625622812c2b. My test setup is the standard Pico-as-picoprobe to Pico arrangement, with the Pico's VBUSs connected together and a USB OTG adapter to provide a USB-A socket.

The Pico MIDI host is running the examples/host/midi/src/midi_app.c with LOG=1 but with test_tx() commented out to just test MIDI receive.

USB MIDI devices tested were:

  • Arturia Keystep
  • Novation Launchpad Mini
  • Korg SQ-1 sequencer
  • Mcmillen K-board
  • M-Audio Keystation Mini-32
  • Trinket M0 running CircuitPython 7.0 MIDI sketch

All three types of common MIDI messages seem to be received correctly: 1-byte (MIDI clock), 2-byte (channel pressure), and 3-byte (note on/off).

All devices work, except the M-Audio Keystation, which causes a *** PANIC *** Data Seq Error. This seems to be in hcd_rp2040_irq() from the statement if (status & USB_INTS_ERROR_DATA_SEQ_BITS).

The only obvious difference in the USB Descriptors between the Keystation and the rest are that all other devices in their Device Descriptor have Device MaxPacketSize of 64 and the Keystation has Device MaxPacketSize 8.

I'd be happy to investigate this panic more if there's obvious things I can try or data I can collect.

todbot avatar Jan 11 '22 19:01 todbot

@hathach I pushed some bug fixes. Somehow I broke a lot of the builds for processors I do not have access to. Any idea how I can fix it? Do I need to merge with the latest tinyusb?

@todbot I pushed an example project that uses the midihost code called midi2usbhost sends MIDI from the USB host to the Pico's UART1 TX pin and takes UART1 RX pin MIDI data and sends it back to the USB host. There are detailed instructions and pictures.

rppicomidi avatar Jan 11 '22 22:01 rppicomidi

@rppicomidi no problem, I will pull and fix that later on. Sorry late response again, I am still busy with other works, and catching up with your PR. Will try to wrap this bulk/midi host support as soon as I could. Please be patient.

hathach avatar Jan 17 '22 13:01 hathach

@hathach Thank you for the update. It looks like #1285 is also looking at bulk endpoints for the RP2040.

@todbot When does the M-Audio Keystation panic? Has it successfully enumerated and panics on the first attempt at MIDI transfer, or does it panic during enumeration? The former indicates an issue with the bulk endpoints, the latter with the control endpoint. Also, can you confirm the RP2040 is only attempting 8-byte transfers before it panics? Finally, please have a look at the USB descriptor. Is the 8 byte packet size bMaxPacketSize0 from the device descriptor or wMaxPacketSize from the endpoint descriptor (or both)?

rppicomidi avatar Jan 19 '22 04:01 rppicomidi

With regard to NAK retries - have you tried setting NAK_POLL to zero? Just a thought.

esky-software avatar Jan 19 '22 14:01 esky-software

@eskimo-software I thought about it but it applies globally and so I didn't do it. What I did is discussed here #1261. If you tried it and it works, that would be very cool to know.

rppicomidi avatar Jan 20 '22 04:01 rppicomidi

Well, it shouldn't apply to interrupt transfers, so it applying (otherwise) globally shouldn't matter, should it?

In any case, if I can set up a test for this I'll share any results I get.

esky-software avatar Jan 20 '22 06:01 esky-software

More thinking out loud - even though it's declared in the descriptor as a Bulk endpoint, is there any reason the host can't operate the IN endpoint as if it's an Interrupt endpoint? That would result in automatic polling and (presumably) correct NAK handling without any special consideration. (Perhaps this is already standard practice - or there's a glaringly obvious reason why this can't be done. I have no idea.)

esky-software avatar Jan 20 '22 07:01 esky-software

@hathach The host API in the master branch is different from the API I used to write this pull request. Do you need me to close this pull request and submit a new one written to the current API, or is the API still fluid?

rppicomidi avatar Apr 19 '22 03:04 rppicomidi

I'm also interested in this, it would be good to have an update on the host API status from you, @hathach.

If the host API changed but is stable again I might also try my hand at changing this PR over if @rppicomidi isn't on it already, although I'm much less familiar with tinyusb or the changes at this point.

s-ol avatar Jul 05 '22 13:07 s-ol

At this point, this pull request is obsolete. Merged pull request #1434 implemented RP2040 bulk endpoints more cleanly. Some of the other changes I made are either already in TinyUSB from other pull requests or have been implemented in TinyUSB in an equally functional way. Pull request #1627 fixed several bugs in this pull request. Finally, I have used the code from #1627 to create this application host driver; the driver also implements BULK IN endpoint polling more cleanly so the application no longer needs to do it in the main loop.

For these reasons, I am closing this pull request.

rppicomidi avatar Aug 17 '23 22:08 rppicomidi