Daisy Patch missing MIDI events

I’m working on a drum sample player for my Daisy Patch. Sometimes the samples fail to trigger, and I’m trying to find out why.

I maintain a stack of MIDI notes – when a note-on occurs, I add the note to the stack, and when a note-off occurs I remove it from the stack. When the failed triggers occur (or rather, don’t occur :slight_smile:), there is a note-off with apparently no corresponding note-on. So it seems like the note-on is being lost.

I pop events off of the queue in the audio callback, which is called every 0.25ms (12 sample output buffer at 48kHz). So it’s not possible that the queue is overflowing – I’m processing the queue faster than MIDI events can come in.

I thought that perhaps my audio callback was hogging the CPU and somehow interfering with whatever ISR polls the UART and enqueues MIDI events. But I got rid of most of the processing in the callback and note-on events are still being missed. The issue seems to occur less frequently with the barebones callback, so that suggests that it’s related to the processing load somehow. Maybe something else is interfering with the USART polling, perhaps the USB serial monitor?

Does anyone have an idea what might be going on, or suggestions for how to debug?

It might be related to this issue

Thanks for the link. Sadly, it doesn’t look like there has been any activity on that issue for over a year. I’m using libDaisy v5.2.0, by the way.

Another puzzling thing is that when I pop the queue there can be more than one event waiting. Even with running status the minimum time between MIDI messages is >0.6 ms, and I’m popping the queue every 0.25 ms. So it shouldn’t be possible for events to pile up, and yet I’m seeing 3 or more events in the queue. So that also points to issues receiving and enqueuing MIDI events.

Ah, I guess the use of DMA for the UART probably explains why multiple messages end up in the queue, even with frequent polling. It doesn’t explain what’s happening to the missing messages, though.

Has libDaisy always used DMA for MIDI? I don’t think DMA is a good fit for MIDI traffic, which is asynchronous and tends to be sparse. Interrupt-driven handling seems like a much better fit.

The idea with using DMA for UART transmissions is that you can terminate the transaction when peripheral raises the IDLE interrupt and process whatever data arrives. So you can setup transactions in a way that you’ll receive as much data as you can accept in your buffer or less if data is no longer being sent. This is more efficient than handling data byte by byte with interrupts only.

I don’t think there is a strong efficiency case to be made for DMA with MIDI. All the ISR needs to do is read a byte from the UART and stuff it into a circular buffer. The message parsing can (and probably should) be done asynchronously.

There is a strong performance (or at least rhythmic) case to be made against DMA with MIDI. If there are a number of “simultaneous” notes being triggered, they will of course be sent sequentially back-to-back. With DMA, the IDLE condition will only be reached after the last note has arrived. So the first note will be delayed by how many notes there are in the burst, which could be several milliseconds. That can not only ruin the feel rhythmically, it can also create spikes of work parsing and handling events. The application can spread the processing out over time, but that adds even more latency.

I have an ISR-based MIDI implementation from the baremetal project that I’m porting to Daisy. I’m going to try to cram it into my project.

Is possible to deinitialize the UART and reinitialize it from user code?

I have switched to interrupt-based handling for MIDI input and things are working much, much better. No dropped notes. It seems tighter, in terms of latency and jitter, but it might be my imagination. I’ll have to see if there is a measurable performance difference between interrupts and DMA.

@shensley, is dropped MIDI events a known issue? It’s not hard to reproduce, I’m just sending a bunch of 64th notes.

Do you have midi clock flowing on the wire too ? Do you take care of filtering out the “MIDI system realtime messages” in the stream of “normal” MIDI messages ?

from the MIDI spec p30

I’m a novice, trying to learn. Please share code if you can.

edit: I guess that’s handled by libdaisy libDaisy/midi.h at ef4cc6a0a934c5074204175be32663705c7189f4 · electro-smith/libDaisy · GitHub

I don’t have anything I can readily share, unfortunately. The implementation is very specific to my project and is nowhere near “library-ready”.

I think the first order of business would be getting the current DMA approach working reliably. Then the Daisy devs can think about adding interrupts as an alternative if it seems worthwhile.

I should note that I’m compiling with -Os optimization to fit in the 128KB flash. So that might be bringing the issue to the surface.