SmartLED Shield for Teensy 4

I’m excited to announce that the SmartLED Shield for Teensy 4 campaign has launched on Crowd Supply!

The shield makes it easy to drive high quality graphics to HUB75 RGB matrix panels using the Teensy 4. As with my previous Teensy 3 based shields, this is a fully open source project: you can find the hardware files, and the work in progress but very functional latest branch of the SmartMatrix Library up on GitHub. If you don’t want to wait for the shield to come out, there’s an adapter board you can order (e.g. through OSH Park) that plugs into the SmartLED Shield for Teensy 3, or pick up a few ICs and a bunch of jumper wires and you can wire up the circuit yourself.

The Teensy 4 shield truly wouldn’t exist if not for open source, as I wasn’t planning on porting SmartMatrix Library to run on the Teensy 4. SmartMatrix Library user Eric Eason figured out how to drive HUB75 panels with the DMA and FlexIO peripherals in the Teensy 4 (not an easy task!), and integrated his work into SmartMatrix Library, and we collaborated on the new SmartLED Shield.

As with SmartMatrix Library and SmartLED Shield for Teensy 3, you get easy to assemble hardware, an accessible to program but powerful Arduino Library with a variety of examples, and the refreshing happens in the background (using interrupts and DMA) with high-quality graphics by default (36-bit color refresh, high refresh rate, automatic gamma correction). The Teensy 4 is so powerful, both the pixel count and refresh rate can be doubled compared to the Teensy 3 while keeping the same quality graphics. You can drive 128x64 pixels with 240Hz refresh rate, 36-bit color refresh, and plenty of CPU cycles and memory left to generate cool graphics or do other things needed for your application. 120 Hz refresh rate looks pretty smooth to most people, but 240Hz looks good on camera too, and just a little bit above 240Hz even looks good on a phone’s 240Hz slow motion video setting.

If you’re willing to lower the quality a bit, you can drive even more pixels. 128x128 is very doable even with 36-bit color, though that is a long string of data that needs to be refreshed thousands of times a second. The long string is limiting the max refresh rate to 168 Hz, and limiting the max brightness as the LEDs need to be off sometimes while waiting to shift out the next set of data.

The latest SmartMatrix Library branch (which will be released later this year as SmartMatrix Library 4.0) has support for driving APA102 LEDs using DMA and FlexIO on the Teensy 4. The Library takes advantage of the Global Brightness Control (GBC) bits on APA102 LEDs to get more color depth, and refreshing is done in the background just like with HUB75 panels.

I’m really looking forward to seeing what kind of projects can be made with SmartMatrix Library and the power of the Teensy 4.


Ordered mine but couldn’t wait for next year! I have the OSH Park adapter running with a Teensy 4.1. For other impatient people - the teensy 4 branch needs this library installed or it won’t compile if you’re using the Teensy 4 adapter.

1 Like

Glad to hear it Blake, and thanks for posting that tip for others!

Open question what should I work on next for SmartMatrix Library?

I’m planning to work on support and examples for streaming video from the computer over USB, or adding support for more font options including larger fonts. Which are you most interested in?

Video over USB is a good new feature to add

I know you’re a bpp snob :slight_smile: but honestly supporting larger displays in lower bpp (16 if required).
Also, making memory intensive thigns like double buffering, optional, would be nice. There are plenty of applications where you don’t need to scroll or worry about tearing, and where 16bpp is more than plenty :slight_smile:
I’ll go a step further in saying that for many applications, higher refresh rate is much more important than higher bpp. A flashing image is unbearable to watch, or looks terrible in pictures if you only ever get half the picture and half black bars :slight_smile:

1 Like

The latest version does allow lower color depth to increase display size / refresh rate - but currently only for Teensy 4…

I’m working on an Adafruit_GFX compatible Layer, mainly to get the nice Font support that’s now in Adafruit_GFX. If it’s fairly easy to add in support for lower bpp storage options and maybe disabling double buffering at the same time, I’ll do it!

I’ll try to make that consistent across platforms.

“I’m working on an Adafruit_GFX compatible Layer, mainly to get the nice Font support that’s now in Adafruit_GFX”
If I may, that’s exactly what SmartMatrix::GFX does (including more). Would you like to take/integrate the code in your tree?

TL;DR: SmartMatrix::GFX is FastLED backed Adafruit::GFX, so you have a 24bit framebuffer, you can use all the FastLED primitives on each pixel, use 16bit adafruit::GFX primitives on top, or use GFX with 24bits thanks to an override (a bit ugly to get around the fixed 16bit API, but it works in case of need).
Then I have that hack to also have the LEDMatrix API if you need extra stuff like screen transformations (it also supports native 24bit everything that GFX supports, and more)

Hi @marcmerlin, thanks for the reminder on SmartMatrix:GFX. I looked at it recently but didn’t realize a lot of the magic was in FrameBuffer::GFX and not the relatively simple SmartMatrix:GFX Library. I unfortunately wasn’t able to pull much from either library except for the idea of using passThruColor.

The teensy4 branch now has a new SMLayerBackgroundGFX class that is nearly fully backwards compatible with SMLayerBackground, but is Adafruit_GFX compatible and uses the Adafruit_GFX drawing functions for the more complicated drawing operations. (This was a lot of work! Mostly with dealing with multiple inheritance issues and obscure compiler errors)

Adafruit_GFX uses uint16_t (aka rgb16 or rgb565) for passing color, so it’s not good for high color depth graphics. If you call something like drawLine(rgb24) with SMLayerBackgroundGFX, the SmartMatrix Library wrapper function stores the rgb24 color until the operation gets down to a drawPixel() function, then it uses the rgb24 color for drawing instead of a uint16_t color with loss of fidelity. (Thanks Marc for this idea!)

Adafruit_GFX has more advanced support for drawing text to the screen, with support for large custom fonts, writing text to the display with a cursor and Arduino Print Library support, etc. That’s available now when using SMLayerBackgroundGFX. I haven’t converted the old SmartMatrix Library fonts yet, and the default fonts shipping with Adafruit_GFX are mostly larger fonts. For the time being, if you use the SmartMatrix Library setFont() method using one of the old built in fonts, it only uses a single 5 character tall font. You can use the Adafruit_GFX Libraries’ setFont function to choose a new font.

I can’t assume that everyone wants to use Adafruit_GFX or has it installed. For now, you need to add #define SUPPORT_ADAFRUIT_GFX_LIBRARY at the top of your Arduino Sketch before including any SmartMatrix Library headers. I can’t figure out a cleaner way to choose between having SmartMatrix Library look for “Adafruit_GFX.h” (and throwing an error if not found) and not supporting Adafruit_GFX at compile time. I think the default will be to support Adafruit_GFX with SmartMatrix Library 4.0, with an option #define to exclude the library.

There’s an Adafruit_GFX example. FeatureDemo also works with the new Layer by adding #define SUPPORT_ADAFRUIT_GFX_LIBRARY at the top and changing SMARTMATRIX_ALLOCATE_BACKGROUND_LAYER to SMARTMATRIX_ALLOCATE_BACKGROUND_GFX_LAYER

Still to come is Indexed and Scrolling Layers that support Adafruit_GFX. I also believe it should be possible to support rgb8 and rgb16 storage with this new Layer class, and I’ll look into that later.

Marc, I want to work with you on making sure this new layer has FrameBuffer::GFX compatibility.

Thanks for the update and progress. A few notes:

  • yes Smartmatrix::GFX used to have all the code in it when I first wrote it, but it didn’t take me long to agree that 98% of the code was identical with FastLED::NeoMatrix, so I factored that out in the base class FrameBuffer::GFX

  • The only tricky part in code I wrote, is this:
    because Smartmatrix uses templates, its objects can’t be passed to libraries, because well, templates suck for that :wink:
    So, I’m forced to create the Smartmatrix background layer object, keep it in my code, I can’t pass it to the library, so instead I have to create a callback and send a pointer to that callback.

  • Good that you were able to implement the 24bit passthrough hack. I can’t take credit for it, it came from the original Neomatrix code from adafruit

  • for your last question, I think that your code partially implements what Framebuffer::GFX does (you’re probably missing XY() , some other helper functions in my lib, plus all pixel manipulation functions that come from the FastLED pixel container). This is the XY bit in case you’re curious:
    but honestly it’s mostly useful with complex arrays wired in “interesting” ways, so it’s unlikely to be useful to most RGBPanel users since the layout mapping you support in your base lib, is good enough for 99% of the cases

I’m not sure if there is any need to modify framebuffer::GFX though, basically it seems that you partially implemented it, built in in your library (I didn’t find which branch I should look into).
The way I understand what you have done, you offer compat with GFX, so that most users would be able to get GFX from your library without external libs.
If you’d like to check how well it works, try running MatrixGFXDemo :

on top of your new branch. The code should work is outside of the init section at the top.

Then, if people want FastLED CRGB container support and/or LEDMatrix compat support in parallel (for instance to run Mark Estes’ demos you’ve seen), they would continue to use SmartMatrix::GFX and Framebuffer::GFX as is, and those libs would ignore the new code you wrote since they implement a superset of it (basically they only use SmartMatrix to pass a pointer to a framebuffer to render, all the higher level stuff is ignored).

The only integration that could be added I suppose is some integration with smartmatrix layers, but I’ve never had the need for it, so I’ve never looked into it.

Does this kind of make sense? Did I miss anything?

It’s in the teensy4 branch.

Thanks for the pointers on getting our two libraries working together (or just leaving them alone for now). I’ll come back to this after I get scrolling and indexed color working.

I forgot to mention that one big plus of framebuffer::gfx for me is that I can now compile and run all my code on linux and render it on my laptop with ASAN (memory checker) and gdb.
This is life changing :slight_smile:
(also, the save, compile run cycle is so much faster too)

Here’s an update on the new Adafruit_GFX compatible layers: Adafruit_GFX Compatible Layers - Modern Font Support coming to SmartMatrix Library 4.0

I’m trying to keep the discussion on Adafruit_GFX and the new layers in one place for now, so I’ll probably update on Framebuffer::GFX compatibility there when I get to it. I didn’t expect this layer update to take most of my free time for over a week, so I haven’t gotten to all the things I wanted to do with the new layers like smaller rgb storage, and Framebuffer::GFX compatibility, and I’ll probably have to put those on hold for at least a bit as my SmartLED Shield for Teensy 4 campaign is ending and I’ll need to focus on manufacturing the shields.