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.

Hi, @miminashi

This issue was actually found, and fixed a little bit before your note here, but we never synced up DaisyExamples with libDaisy after fixing it.

We’ll get it synced up with the latests fixes this week, but in the meantime if you haven’t already you can update libDaisy to the master branch by navigating inside the libDaisy folder within DaisyExamples, and running git checkout master, and then git pull.
Once you’ve done that you can rebuild the library, and then MIDI should start being reliable.

If you’re still experiencing dropped, or inconsistent MIDI input after that definitely let us know.

Thanks, I’ll try it out. Does this solve the issue of multiple messages piling up due to the use of DMA for serial RX? If so I’ll probably stick with my interrupt-based handling since low latency is a top priority for me.

Receiving multiple messages is not an issue that needs solving, but rather a design choice that lets you process large amount of data (i.e. events from an MPE controller) more efficiently. Latency is not a problem here, because your UART interrupts will likely be running at priority below the SAI auidio callback, so both approaches would mean that MIDI effects audio only while you wait for the next audio buffer to arrive.

Fair enough about it being a design choice; I posed it as such earlier in this thread. I certainly am not proposing that the DMA approach be replaced with an interrupt approach. But I think the interrupt approach is probably a better fit for many use cases (like it is for my own), and it’s exceedingly simple to support – even I managed to make it work.

Latency is very much a problem for me because I am running with a small buffer (4 samples at 48KHz) in order to achieve very low latency. So to have 3 or more MIDI note events accumulate before they are presented to my application has an appreciable effect on the latency and jitter of my application. Reducing latency and jitter is my primary motivation for targeting an embedded platform; otherwise I’d just use VSTs. :slight_smile:

Also, in my application there is a fair amount of overhead to handing a note-on event. I can easily handle one note-on in the span of my audio callback, but more than that starts eating into my audio processing budget. I could buffer the messages and spread the processing over multiple callback invocations, but that would increase the latency even more.

Hi, I think I’m still running into a similar issue using a UART in DMA FIFO mode. Sometimes it completely misses a number of messages (my current test is to send a burst of 9 bytes, quite quickly (I’m running at 1 Mbaud), and it frequently seems to miss them all.
I’m also wondering if an IRQ-based approach would be more reliable and not have the latency and other issues identified here.

Thanks.

Hi TallMike!

I’m sorry for the delay in response.

It could be worth trying out the IRQ-based approach. For example, if the DMA buffer isn’t emptied out fast enough, IRQ could help to make sure that buffer stays serviced. Though, this may not be the ideal solution.

Good news is that there are some MIDI reliability improvements that are coming to libDaisy soon so those could very well fix your issue.