[sdiy] Techniques for Multiplying MIDI Clock frequency?

Brian Willoughby brianw at audiobanshee.com
Sat Dec 25 02:31:54 CET 2021



On Dec 24, 2021, at 08:40, mskala at northcoastsynthesis.com wrote:
> On Thu, 23 Dec 2021, Brian Willoughby wrote:
>> On Dec 23, 2021, at 19:06, mskala at northcoastsynthesis.com wrote:
>>> I've seen over 40 poll/NAK sequences per frame (maybe over 70; both
>>> numbers are in my memory but I'm not sure the faster one was actually with
> 
>> What operating system was serving as the USB Host?
> 
> That was my own PIC24 host code, with no operating system as such.  The
> device on the other end of the connection was an Akai "MPK mini" USB-MIDI
> keyboard.

Ah. I see. So, when you talk about throttling the rate you're talking about Host code, which is totally within the USB spec, I suppose (unless they require lots of polling somehow).

>> My USB-MIDI Device firmware experience is with the PIC18 8-bit MCU with
>> a 48 MHz clock.
> 
> Probably very similar hardware to what I'm working on, then; I think
> Microschip uses basically the same IP block for the USB peripheral on
> PIC18 and PIC24.

Maybe not. The PIC18 that I worked with is limited to Device only. It cannot be a Host. The electronics would be vastly different. I suppose it's possible that the PIC24 peripheral register set could be a strict superset, but I assume they're very different peripherals due to the additional capabilities of the PIC24.

The USB firmware stack could be very similar at the top level, though, and hide the peripheral register details deep in the code. I've noticed that Microchip has a huge number of headers - one for every chip model - describing the various memory-mapped registers.

>> I believe that USB allows multiple 64-byte Bulk packets per USB frame.
> 
> Yes, and I've seen that working in practice, although many devices will
> return a whole lot of NAKs between successful packet transfers, with the
> speed of actual data traffic they can support being much less than a
> maxed-out bus could carry.

I seems like "a whole lot of poll/NAKs" are actually required in order for everything to work. USB defines Isochronous endpoints to have guaranteed bandwidth, and then other endpoints get fit in according to opportunity. The Host is in control of the timing within each (sub)frame, but there's no way to predict how everything will fit together, especially considering a random assortment of Devices sharing the same port.

USB is designed to cater to cheap devices that have bandwidth or processing limitations, while still allowing faster devices to work.

One mystery I've never dug in to is this: What happens when a USB Host schedules a packet for a USB Device and that device responds really slowly (due to poor firmware optimization)? I know that if the delay is very long - such as when you set a breakpoint and the firmware literally stops dead in its tracks - then the Host will basically disconnect that Device. But those delays are way longer than a single USB frame. I'm wondering about within a frame.

Say a Host schedules a packet at the beginning of a frame, and the Device burns a third or a half of the frame time just getting the bytes out? Does this just ruin the total USB bandwidth, leaving little or none for other Devices on that bus?

The answer is partly made evident because most USB Device firmware stacks require the code to set up the complete data for a packet in advance, so that the hardware interrupt can immediately enable DMA to transfer the data faster than the processor could handle in code alone.

However, Control endpoints have Host query commands that switch between OUT and IN during a transaction, and I've wondered what would happen if firmware grabs a piece of data for the Control endpoint from a slow peripheral, and thus delays the Control endpoint timing.

> Flash memory sticks in particular seem to be
> quite bursty - they may return a few packets at maximum bus speed, then
> just NAK for a few milliseconds before waking up again.

I assume that this has more to do with Flash memory speed. Flash write is particularly slow, but even Flash read can be slower than USB. Also, the way USB works seems to introduce latency because data has to be prepared ahead of time and available in a buffer, rather than actually being fed across the bus in real time as it becomes available.

>> My goal for supporting a Hub was to provide cheap isolation (I'd rather
>> burn out a $4.99 Hub than my custom USB hardware), and also to allow for
>> some way to save and restore custom settings on a USB memory stick
>> without literally removing the controller Device from the Host USB jack.
> 
> Interesting point about the isolation.  That's a possible advantage of
> using a hub, that I hadn't thought of.

I've designed USB Device prototypes that burned up when the custom PCB was first attached to a computer. At least I lost something that I could easily make more of. But it was alarming enough that I worried about worse damage.

I've had clients who designed their own USB Device prototypes that were so messed up that they took out my client's laptop - or at least took out the USB ports. This had more to do with external supplies for the USB Device and grounding issues. I'd already made my mind up to use a Hub with all prototypes, but my client's experience convinced me to be particularly careful.

>> Given their prevalence, it seems like a very useful feature to be able
>> to Host USB-MIDI controllers.
> 
> I hope so!  It's also a hole in my product line - up to now I've been
> having to tell customers "Well, you'll need to get a controller or
> interface from someone else to play this module."

Personally, I think it's fair to include a MIDI input and require customers to obtain a MIDI keyboard - just like every sound module before. But adding support for USB-MIDI makes things easier these days, although it's way more complicated (and potentially more expensive).

>> I think it would be fair for you to say that your product supports a
>> Hub, but only with Devices attached that are already supported without
>> the Hub. I guess that could be a problem if you support a mouse and/or
>> keyboard, because then that support would go away with a Hub.
> 
> I do have support for mouse and (typing) keyboard, so the limitation would
> have to be a little more complicated.  But it may be something to look at
> for some future firmware version.

Ouch. I can see how mouse and keyboard would be helpful.

I hate to say it, but you may need to chose another processor - at least for the USB Host function. Either that, or get Microchip to fix the hardware errata so you can leverage the work you've already done.

>> sampling rate is 125 kHz, and that works out to only a 976.5625 Hz
>> packet rate. Although the Host USB clock is not locked to the Device
>> sample rate, it's still true that the Host wants about 1,000 packets per
>> second. This means that 1 out of every 42+2/3 frames has a 0-byte
>> Isochronous packet instead of a 384-byte packet. Everything still
>> manages to work out, because USB was designed for this.
> 
> Almost like NTSC frame drop.

I was just surprised that it worked. This isn't written down anywhere, but I think that an Apple engineer on their (now defunct) USB mailing list gave me the hints that I needed.

USB requires that the maximum packet size be defined for each endpoint. You can send "more" data than the maximum size by stringing together several packets that are exactly the maximum size, following by a packet that's less than maximum - or zero. For isochronous, if you define the endpoint maximum size to be the actual size that you want, the USB Host will always assume there's "more" data coming. The trick is to define the Isochronous endpoint to be 1 or 2 bytes larger than your actual maximum. Then, the Host won't expect "more" data, because the packet is smaller than maximum. Meanwhile, any "drop frame" packets simply have a size of zero.

It's basically the same as with Bulk except that you have a maximum of one packet per frame, or zero packets.

>> p.s. To get back to the subject... any of these 8-bit or 16-bit or
>> 32-bit processors should be able to handle incoming MIDI clock, lock in
>> a Timer channel, and multiply the frequency for rock-solid output
>> timing. Because the TM4C129x has 8 full UART peripherals, I've been
>> tempted for several years to design an 8-input, 8-output MIDI merger
>> than properly handles MIDI clock between everything (although that could
>> be a mess if you don't have a way to turn off conflicting clocks).
> 
> It would probably call for some kind of out-of-band control to specify
> which clocks to trust and which not to.

Well, out-of-band control and/or a front panel !  A display, or at least rudimentary indicators, would help. That and some buttons.

But I'm a fan of including out-of-band control for everything. Whether it's MIDI System Exclusive or tacking on Vendor commands to the Control endpoint, it's always helpful to be able to make out-of-band settings. I've even used Control endpoint Vendor commands to debug USB Device firmware by sending internal variable values across USB in near-real-time so that an application running on the USB Host could display things. This is very powerful for debugging.

> -- 
> Matthew Skala
> North Coast Synthesis Ltd.
> 





More information about the Synth-diy mailing list