Teensy: USB MIDI Bandwidth

Status
Not open for further replies.
Hi guys!

I have a very sensitive question on the speed Teensy can read MIDI messages over the USB. I've faced issues with receiving MIDI over regular 5 DIN serial port at 31250 bit/s speed.

Basically, my project has to receive around 500 midi note ONs and OFFs for a time of less than 12 ms (which is audible latency). Simple math tells it's impossible on 31K bit/s speed - and I saw that already. And all the Arduino projects I saw, which used USB to transfer MIDI also had 31K speed hard coded in their sketches for the whole MIDI over USB capability.

Having in mind that Teensy has a built in MIDI support I am guessing on whether underneath its drivers it also uses that regular for old MIDI protocol 31K speed. Any clue? Does it use that speed per MIDI channel? In the terms of that I may read 16 channels at a time using the whole USB Bandwidth?

Do you guys had similar projects experience or heard about such?

My initial goal is to control the light of ~500 Leds with MIDI messages sent from the Ableton DAW. Does it sound realistic with MIDI?
 
The USB MIDI runs at 12 Mbit/sec speed. Slow serial speed is not used. It really does use the native USB bulk transport speed.

The protocol is slightly different. MIDI messages are always sent as 4 bytes, even if they would use only 2 or 3 on serial MIDI. They are packed into USB packets, up to 64 bytes. Each packet has USB protocol overhead, so the max throughput depends on whether they get efficiently packed. Teensy will pack them, if you send fast. Your PC may or may not. Same could be true for other gear.

In a best case scenario, the USB protocol overhead results in a speed of 1.1 Mbyte/sec for actual data, with is the 4 byte messages.

USB bulk transport protocol has built in flow control. This is good, in that you don't lose data if unable to keep up with the data rate. It's similar to how Serial uses RTS/CTS, but automatically built into the USB packets. Of course, this means the actual data rate can depend on how fast each side runs.

Teensy is very fast, especially 3.5 and 3.6. The USB is very efficient too, using DMA and well optimized code. It can easily handle the full 12 Mbit speed. But of course everything depends on how you write your code. If you add delays or wait on things like analogRead, it will impact how often your code can deal with MIDI messages.

Likewise, code on a PC or MAC can hold things up. You might not expect a multi GHz multi core machine with gigabytes of RAM to be a bottleneck, but some software on the PC side can be astoundingly slow. Programs that intertwine handling GUI events and MIDI messages can really limit your speed.

USB is designed to share bandwidth. Bulk transport gets all the bandwidth not in use by other devices. If you have a USB webcam or use a flash memory stick, you MIDI messages may get much less bandwidth. Cheap single TT hubs only convert one device at a time between 12 and 480 Mbit speed, so if you have another slower than 480 device plugged into the same cheap hub, they compete for only 12 Mbit bandwidth. Better multi TT hubs allow the high speed to be shared.

Even though there are lots of these details with USB that can impact you actual speed (it is a complex protocol), you can rest assured that the USB MIDI on Teensy really does run at the full 12 Mbit USB speed, not slow 31250 baud.
 
Thank you very much for the quick reply Paul! So I believe that the bottle-neck for my project may be the Ableton, but I have to try.

Am I right that in USB MIDI mode Teensy is recognized by the OS as a MIDI compliant device? So like plug-n-play, no any drivers required?
Any thought on whether Windows may treat it as an old-fashioned MIDI device and try to communicate using 31250 baud?
Also, I am about to read MIDI data sent to Teensy by DAW: is it as efficient, easy and fast as sending it from Teensy?


Also, I am pretty new to the web site and got lost there. Could you please guide me to where I can see the description for all the available ports and features for Teensy 3.6? I am particularly interested in the MOSI which is used to control the LED strip.

One more question: I suppose I can power Teensy with the external 5V power supply which I use for the LED strip. Am I right that with both supply and USB cable connected the board is not going to drain any power from the PC's USB port?
 
Last edited:
Many questions packed into one message.... let's see if I can quickly answer them all.

Am I right that in USB MIDI mode Teensy is recognized by the OS as a MIDI compliant device?

Yes, confirmed, it absolutely is a "class compliant" USB MIDI device.

Any thought on whether Windows may treat it as an old-fashioned MIDI device and try to communicate using 31250 baud?

It should use the full speed.

I personally use Linux and occasionally Macintosh, and generally I only touch Windows for software testing. I'm not a musician and I personally do not use MIDI for much, so I don't have a deep experience with the Windows MIDI features.

Obviously only Microsoft can definitely answer questions about the inner workings of their device drivers....

Also, I am about to read MIDI data sent to Teensy by DAW: is it as efficient, easy and fast as sending it from Teensy?

I can only answer regarding the implementation on the Teensy side. On Windows, I have personally only ever run MIDI-OX. I have personally never used *any* DAW software on *any* platform.


Could you please guide me to where I can see the description for all the available ports and features for Teensy 3.6?

https://www.pjrc.com/teensy/techspecs.html

https://www.pjrc.com/teensy/pinout.html

When you buy a Teensy board, it comes with a printed copy of the pinout.

I am particularly interested in the MOSI which is used to control the LED strip.

If using APA102 and FastLED, the by default pins 11 and 13 are used.

One more question: I suppose I can power Teensy with the external 5V power supply which I use for the LED strip. Am I right that with both supply and USB cable connected the board is not going to drain any power from the PC's USB port?

On the bottom side are pads meant to be cut apart, to separate VIN from VUSB. If you're using external power and you connect a USB cable, this is the way to prevent the external power from being able to flow back into your PC.

LED projects usually consume a large amount of current. The best wiring is to connect the power directly from the power supply to the LEDs, keeping those wires as short as reasonably possible. Do not run the power first to Teensy and then to the LEDs. The path carrying the high current should be as short and direct as possible, using wires large enough to conduct the high current without significant voltage drop.
 
Thank you very much for answering all the above questions!

If using APA102 and FastLED, the by default pins 11 and 13 are used.

It is WS2813, so no clock/pwm is used there, just the data signal. Any issues you foresee?


On the bottom side are pads meant to be cut apart, to separate VIN from VUSB. If you're using external power and you connect a USB cable, this is the way to prevent the external power from being able to flow back into your PC.

Does it really require cutting something on the board? With arduino like devices I was able to accomplish this with just wiring Power supply GRNd and 5V to the appropriate ports on the board. No built in voltage security?
So then, if I want to do a new project which uses power from USB I need to recreate the pads?

P.S. Is 5.2V external power ok for Teensy?
 
...
Does it really require cutting something on the board? With arduino like devices I was able to accomplish this with just wiring Power supply GRNd and 5V to the appropriate ports on the board. No built in voltage security?
So then, if I want to do a new project which uses power from USB I need to recreate the pads?

P.S. Is 5.2V external power ok for Teensy?

Teensy card (T-3.2/3.5/3.6) shows VIN can be 3.6 to 6.0V, so yes 5.2V is in that range for those devices.

I just cut that pad connector on a T_3.1, 3.5 and 3.6 - it is a small trace and the pads remain to re-solder. But these are now marked with wife's fingernail polish on the USB hood to remind me of the cut and to use a different one when it has to run from USB power - buy more. These were running 1024 LEDs in a 32x32 matrix and at 2 amps they needed external power - and can't have to sources without added parts.
 
Teensy card (T-3.2/3.5/3.6) shows VIN can be 3.6 to 6.0V, so yes 5.2V is in that range for those devices.
These were running 1024 LEDs in a 32x32 matrix and at 2 amps they needed external power - and can't have to sources without added parts.

I've calculated that to run ~600 of WS2813 LEDs you need something about 30 AMPs. Am I wrong?
 
For WS2813 (and WS2811, WS2812 or WS2812B) you can choose from 3 different libraries: Adafruit_Neopixel, FastLED and OctoWS2811.

Adafruit_Neopixel disables interrupts during the entire LED update time, which blocks the USB stack from processing incoming data. Terrible for performance of anything else, like receiving MIDI messages.

FastLED blocks interrupts some of the time. Better, but still likely to cause performance issues.

OctoWS2811 doesn't block interrupts during the LED update. For best communication performance, this is really the only choice.

The other alternative is to use APA102 or similar LEDs, which have clock and data. FastLED can update those without blocking interrupts.
 
[Have] you guys had similar projects experience or heard about such?
Search for a user called 'sargentpilcher' as he had a number of threads on issues he encountered doing something similar.
 
Hi guys! I am reviving this thread as I finally got some time for my teensy and eager to try more sketches on it.

The main question:

do I need OCTO28_ADAPTOR to use OctoWS2811 library? Or I can do a simple LED set up

leds_Wiring-Diagram.png


and just use library's functions?

NOTE:

I've applied logic level converter as it's mentioned for teensy to communicate with 5V LED strip:
https://learn.adafruit.com/neopixel-levelshifter/shifting-levels
 
Last edited:
For 500 LEDs, a single strip with 1 pin using any of the libraries should work.

Most modern WS2812B strips can work with a 3.3V signal. It's not ideal. But then neither is the LXM0108 chip, which is very sensitive to noise on the output if you connect a wire more than a few inches long. If your LEDs work with the 3.3V signal, that's probably better than using the LXM0108 (a poor choice for Adafruit to recommend - not everything you read on Adafruit is great engineering advice).

The 74AHCT125 chip is a very good way to level shift. So is the 74HCT245 chip on the Octo shield. If you need a really reliable solution, like a DJ setup you take to other locations and it needs to work for a show, definitely use one of those.

500 LEDs is too many for power applied at only 1 end of the strip. As a general rule, you want to limit the distance from power to about 100 to 150 LEDs. So if you power the 500 LEDs at both ends and also in the middle, then the LEDs at 1/4 and 3/4 of the length would be 125 away from the power connections.

Or if you measure with a voltmeter while the LEDs are at full brightness, ideally you'd like to limit the loss of 5V power to no less than 4.5V anywhere along the strip.
 
Hi Paul! Thank you very much for a quick response.

I did a quick test yesterday with Adafruit NeoPixel library and a strip of 60 LEDs to just check that the set up works. It unfortunately didn't work without level shifter and I was getting a very nice randomly colored blinking light show. Therefore, I've used the only shifter I had which you don't recommend for projects like this. Namely:

IIC-I2C-Logic-Level-Converter-Bi-Directional-Module-5V-to-3-3V-For-Arduino-Upgrade-to.jpg

I was able to successfully run the examples from Adafruit Neopixel library with it.

Reading further I've found one more of your most recent libraries, namely WS2812Serial.
I've tried it with the same set up and it worked. I am of course not satisfied with how fast LEDs are updating: on a strip of 60 LEDs I see how they are getting updating one by one, though the library writes the whole strip at once. Is it really the MOSFET transistors level shifter drastic drawback? And if I use 74AHCT125 I won't have this issue? Do I need to have high hopes on 74AHCT125?

Following your advice, when I use all the 500 LEDs I will definitely do at least 4 dedicated 5V Power connections all along the strip parts.

I also don't mind to have my strip being divided into parts data signal wise, however, I thought I still can use just one data connection and write to the whole strip at once as it's more convenient. Unless you tell me that performance wise it's better to have it divided at least at 4 parts (125 LEDs each).

If the latter is true, is it possible for me to teach OctoWS library to work with 4 strips instead of 8 and can I abandon an OctoShield in this case?


Also, was anything changed for a year to the libraries? With the latest WS2812Serial in mind do we still have the leadership of OctoWS one? Any more libraries appeared for that period?
 
Whew, lots of questions.... let's see if I can get them all quickly....

I am of course not satisfied with how fast LEDs are updating: on a strip of 60 LEDs I see how they are getting updating one by one,

This is very likely a problem with the code. No matter how fast the hardware updates, you need good animation code to actually achieve pleasing effects. The non-blocking libraries like WS2812Serial and OctoWS2811 can make that code easier by giving you more time to do complex calculations.... but for only 60 LEDs that's rarely an issue, even using the blocking libs, especially on a fast board like Teensy.

But a poor algorithm will always look bad, no matter what hardware & library is used.

Is it really the MOSFET transistors level shifter drastic drawback? And if I use 74AHCT125 I won't have this issue? Do I need to have high hopes on 74AHCT125?

It's unlikely to make any difference. Usually bad level shifting manifests as random flickering or no LEDs working at all.


I also don't mind to have my strip being divided into parts data signal wise, however, I thought I still can use just one data connection and write to the whole strip at once as it's more convenient. Unless you tell me that performance wise it's better to have it divided at least at 4 parts (125 LEDs each).

500 LEDs from a single pin will take 15.3 ms to update. That's usually plenty fast enough. 4 signals (half of OctoWS2811) is usually overkill for this sort of relatively small project.


is it possible for me to teach OctoWS library to work with 4 strips instead of 8 and can I abandon an OctoShield in this case?

No. OctoWS2811 is always 8 signals. That's why it's called "Octo"! But it's pretty easy to just use only the first 4.


was anything changed for a year to the libraries? With the latest WS2812Serial in mind do we still have the leadership of OctoWS one? Any more libraries appeared for that period?

No significant changes, only minor improvements in the documentation and examples. WS2811 / WS2812 / WS2812B LEDs have been around for a little over 6 years. Other than the longer reset time (50 vs 300 us), they really haven't changed much as far as the libraries are concerned.

Likewise, we've had 6 different 32 bit Teensy boards over those years, all with very similar hardware as far as the library is concerned. Only minor changes have been needed.

However, I am considering rewriting the examples, maybe in late 2019 or early 2020. Achieving good animation is not easy or obvious. Many of the examples have delay() in such a way that it's difficult to reuse the code in other projects.
 
This is very likely a problem with the code. No matter how fast the hardware updates, you need good animation code to actually achieve pleasing effects. The non-blocking libraries like WS2812Serial and OctoWS2811 can make that code easier by giving you more time to do complex calculations.... but for only 60 LEDs that's rarely an issue, even using the blocking libs, especially on a fast board like Teensy.

But a poor algorithm will always look bad, no matter what hardware & library is used.

I've used the "WS2812Serial BasicTest Example" sketch with no changes other than altering the wait interval for my tests. I think it's simple enough to cause any problems by its algorithm. So then I am indeed really surprised by the performance of the LED strip. When the code is about to write to a strip I can visually see step by step changes of the LEDs. Not like it's utter slow, but slow enough to see the change.


UPDATED: here's the video with 144 LEDs. Looks like an animation, however, it should be a one time color change. Please ignore flickering, I blame the level converter or data ping soldering.

https://drive.google.com/file/d/1uLy9Fi4yf_syQm9s-fx56qOm3_g2aJAW/view?usp=sharing
 
Last edited:
You’ll never know as long as you don’t systematic diagnosing which would start by checking the LED data stream with a logic analyzer or preferably an oscilloscope to see if it’s a soldering, level conversion, or general bad signal quality issue. Or if there is perhaps a little bug in the library or the example sketch which can only be verified by looking closely at what the Teensy outputs.
None of us willing to help can tell without you giving the needed detail information.
 
Hi guys.

I think I misinterpreted the code. I will look at the sketch closely today. I think it works as designed. So my apologies for confusing you.

UPDATE:

It was indeed my wrong interpretation of the code. When I corrected the example I was able to get all the 144 LEDs changing at one single point of time with no visual latency. Thanks everyone!
 
Last edited:
By the way friends, what is the best practice for Midi messages read: callback functions or simple read and process then? The performance is the key here.

Some background: application should only react on few Midi types, e.g. Note On and Off. Everything else is ignored.

Or it really doesn't matter?
 
Status
Not open for further replies.
Back
Top