Electronic – arduino – MIDI sequencer timing accuracy using the Arduino

arduinomiditiming

I build these music sequencers.

enter image description here

Only it's not exactly a sequencer, it's a physical interface for a sequencer. The sequencer is an application that runs on a laptop that the sequencer connects to, this thing lets the user make drum loops on the fly. It's pretty fun, but it requires a laptop because the sequencer isn't 'on-board'.

What I would love is to do the sequencing on-board my device.

Now let's assume I know how to solve for class compliance for USB MIDI connectivity, and let's also assume I can figure out how to wire up an arduino to send MIDI notes from a 5 pin DIN port. What I'm most concerned about is tempo drift over time due to inconsistent timing in minute amounts over every run of the event loop.

Some things I know:

  1. You should not rely on delay() to control the tempo loop. Delay stops all operation of the firmware, and that can't work because i need to poll the physical user interface for changes while the sequence is running.

  2. Calculations based on millis() are better because the firmware can continue to operate and act when a certain count has elapsed.

  3. Even though none of my physical controls are triggering interrupt routines, some operations can delay the main loop() from running. If I design a function that waits for user input, that can obviously cause a problem of missing a "deadline" to act if the millis() count is way over. I know this problem is of my own design…

Questions:

A. Is the AVR-based arduino an appropriate microcontroller to poll a user interface and run a mission critical timing loop? I know there's an ARM based Arduino now that's a lot faster. Would a Teensy 3.0 be a better alternative? Both of these are 3.3V boards, so that's another set of issues to work with… but I'll ignore that for now.

B. Should I split the task into two microprocessors? One to handle polling and updating the user interface and one for mission critical timing loop.

c. Something else?

My main goal is to not have to use a computer at all. I also want to calculate for swing, but in this case, swing don't mean a thing if I ain't got a locked and timing accurate tempo. Thanks for your advice!

Best Answer

Interrupts are your friend for timing sensitive tasks, but only if you put the timing critical aspects into the interrupt, and there are no other interrupts happening that have a higher priority. The microcontrollers on the "AVR-based" Arduino (e.g. the ATmega328P) have fixed interrupt priorities as detailed on page 58ff of the datasheet. So if you used TIMER2 COMPA as your critical timing interrupt and no other interrupts you should be OK (as it has the highest priority). If you also want to use lower priority interrupts, you need to make sure that all of them re-enable global interrupts when entering their interrupt service routine:

When an interrupt occurs, the Global Interrupt Enable I-bit is cleared and all interrupts are disabled. The user software can write logic one to the I-bit to enable nested interrupts. All enabled interrupts can then interrupt the current interrupt routine.

(p. 14 of the datasheet)

This is slightly different on ARM based Arduinos as their Cortex-M3 core has a "Nested Vector Interrupt Controller", where the priorities aren't fixed (can be set in software), and nested interrupt handling is the norm. So for timing critical applications, the ARM based Arduino would give you more flexibility. However, I don't think that's really necessary for your application.

The bigger question is really how easy these things can be implemented with the Arduino libraries. To get the best performance you will probably have to code outside the libraries to some degree, at least for the timing critical bits, i.e. avoid things like delay() or millis() altogether.

Whether or not you need to split depends on how much processing you intend to do. Again, going outside the libraries can potentially give you better performance.