USB MIDI / libavr32 troubleshooting

i’ve been working on adding support for MIDI to teletype, and i’ve got it working for incoming MIDI events, but having issues with sending events. any help will be much appreciated! i’ve been debugging for a few evenings now and here are my findings so far.

polling for incoming MIDI events is done this way:

  • midi_read (from midi.c) is called from a timer callback (ansible polls every 8ms)
  • it returns if no MIDI connected or if there is already a read in progress (rxBusy is set)
  • otherwise it calls uhi_midi_in_run which calls uhd_ep_run on the in endpoint

once uhd_ep_run is called here is what happens next (all functions are in usbb_host.c):

  • uhd_ep_run sets up a job for the in endpoint
  • uhd_pipe_trans_complet executes and exits here

at this point if there are no incoming MIDI events nothing happens until it times out (the timeout is 20s):

if a MIDI event arrives before the timeout, the following happens:

so, basically, polling for MIDI events creates a job that either gets complete once a MIDI event is received, or once it times out.

now, if i disable midi_read and send events using midi_write it works, MIDI events get sent successfully. here is what happens exactly:

here is the problem: if midi_read is called, it creates a job on the in endpoint, and this somehow blocks jobs on the out endpoint. any subsequent calls to send MIDI fail because there is already a job scheduled. once the in job completes (either because of an incoming MIDI event or a timeout), it unblocks the out job and it completes normally.

i tried setting the MIDI timeout to a much shorter value (using the same value as the timer that calls midi_read). it unblocked sending MIDI but it stopped receiving MIDI events. another thing i could try is checking if there is anything waiting to be sent and doing that first before calling midi_read. but this feels like a hack - it should just work, from what i understand - FTDI uses the same USB functions and it works fine. this also implies the USB implementation itself is fine. it must be something specifically with the MIDI code. i have a feeling this is some misconfiguration issue, maybe something to do with interrupt masks? but i’m not entirely sure where to check and what to look for.


i’ve got both MIDI send and receive working, sort of. a timer calls a function that does the following:

  • if there are any MIDI events to be sent (stored in a temp buffer) and there is already a read job in progress, the read job will get aborted first, then a send job is created which can proceed normally as it’s not blocked by the read job

  • it then schedules another read job which will get interrupted/completed by an incoming MIDI event / a timeout / aborted by the next send.

this is working ok (judging form a quick test), but still feels hacky.

now another issue is disconnecting/reconnecting. it works if i already have the USB-MIDI adapter plugged it during bootup. if i disconnect and reconnect, receiving still works but sending stops working. i added logging to most of the functions in usbb_host.c and from what i can see the sequence of calls is the same during the bootup process and after a reconnect. some USB config / interrupts must be getting messed up though - i don’t see anything obvious, other than read jobs just timing out instead of completing.

not sure what else i can try, and without having the necessary domain knowledge this feels like a bunch of fragile hacks.

Wanted to reply here and ping @tehn for some feedback on a related Teensy Midi device issue I posted awhile back - where basically plugging in a device with an HID interface on ansible would cause ansible to freeze/crash

Yesterday I managed to find where the problem was happening and hacked a fix .

I’d like to submit a PR, but would really appreciate some guidance and my fix might be very hacky (and I realize maybe that issue needs to move to the libavr32 repo?)

best submit a PR and we can discuss it on GitHub!

yep it’s a libavr32 issue

1 Like

:+1: PR sent on libavr32 repo.