SmartMatrix APA102 Library / Open Hardware Photon APA102 Shield

Thanks for the ping! I had 100 shields manufactured, and got samples of 10 (the rest are in China). I found the JST cable supplier reversed the polarity on the connector, so the 90 still in China had to get reworked, but other than that I’m pretty happy with how the shields turned out.

The project has been stalled for a while as I’m working on a test fixture. Normally the test fixtures I’ve built have been hand wired, fragile, and are very product-specific in both hardware and software. Inspired by this post and the fact that there are about 64 test points on the APA102 shield (that I have no desire to hand wire), I started working on a reusable test fixture design. Right now it consists of an Arduino Uno shield with 64 GPIO and ADC inputs (96 in the future), custom adapter for the APA102 shield, and an Arduino shield-shaped board to hold pogo pin receptacles. By the end of this next week I will have put more hours into this test fixture design than into the APA102 shield and APA102 SmartMatrix Library modifications.

I’m flying to China in early November - for a few reasons, not just to work on the APA102 shield - and I plan to bring my test fixture, get all 90 shields tested, and if I’m lucky, find a company in China who can do worldwide fulfillment of the shields affordably. When the shields are available I’ll post a link here first.

I don’t plan on finalizing the SmartMatrix Library with APA102 support until the “Libraries v2.0” details get worked out. I want to be able to have a single release that supports both Teensy and Photon. @peekay123 do you have any insight into when that might be?


@Pixelmatix, sounds like your having a good time! Paul and his Teensy line never cease to impress me. As far as I know, Libraries 2.0 is due any time now and lots of folks are waiting. I’ll ping the Particle Team to get an update. :wink:


Just a follow-up. GBC works perfect with APA102. This enables me to lower the update frequency a lot (from 16Mhz to 2Mhz).

Since the APA102 leds where not so good available past year, I gave the SK9822 a try. However steps in GBC are visible on that chipset. Especially on the higher values. So I’ll stick with the APA102 leds.

Thanks for the followup! I was just in China visiting LED strip suppliers and they all said to switch to the SK9822 if possible as APA continues to have supply issues. Heard everything from that they have old fabs, oxidation issues, to disagreements with their Chinese side of the business (they’re based out of Taiwan).

I wonder if the ratios on the SK9822 for brightness adjustment are just a little bit different than APA102, and it can be adjusted with a tweak to the algorithm. I have some samples, but no time as of yet to try it out. I’ll report back if I get it to work.

The APA102 is great, especially with your algorithm, because that will give you essentially a 12/13 bit grayscale. Too bad, that they still keep having those suppling issues.

How would you see the algorithm, because now you step on each half value 128, 64, 32, 16, 8 with bit math. That would mean several if-statements with the SK9822?

How did you found the algorithm with the APA102, was it directly a lucky shot?
If you have some ideas I might be able to try something.

It wasn’t a lucky shot, it was more trial and error. My test code is here if it helps, though I probably cleaned it up a bit after realizing I could just shift values instead of using multiplication and an offset. I adjusted the global brightness algorithm until I didn’t see stepping.

From memory, the APA102 data sheet uses 1/31 as the unit for fractional brightness, so following the data sheet you shouldn’t be able to set brightness to 1/2, 1/4, etc, but in practice you can. (Thats where there trial and error came in). Maybe the SK9822 actually uses the 1/31 fractions.

Of course, now I remember that topic. I’ll try make a small setup with an Arduino and your test code:

I have roughly 80 SmartMatrix APA102 Shields that passed testing and are sitting on a shelf in China waiting for me to figure out order fulfillment. If you’re interested in purchasing one, can you send me a DM with the country you want it shipped to so I can get quotes on shipping cost?

1 Like

I’ve made a first sketch to see if I could match GBC with the normal RGB values.

What happens is that the SK9822 seems to change the hue a bit. The green pixel with GBC seems more lime then without GBC. This make it impossible to match, or I have some strange bug.

Maybe this happens because power is different (because of the addition PWM).

Any suggestions or idea’s are welcome.

Kasper, you might want to try what Tim tried here, and hook up the power rails to a scope. Try changing the global brightness with a LED set to (255,255,255) and see what it looks like on a scope. I haven’t tried your code yet.

@kasper I just tried for an hour to reproduce Tim’s APA102 experimental setup, and couldn’t get anything to show up on my scope that looked like PWM. I thought I was missing a part of the setup or was using my scope improperly, but if I substitute an APA102 LED I see the GBC PWM in my scope. I’m guessing the SK9822 is using a much higher PWM frequency for GBC, so at least with my 50MHz Rigol scope, and cheap probes, I’m not going to be able to get anything out of it. (I used a 10ohm LED in series with the power line to get a good voltage drop between LED off and on, at least with the APA102)

I’ll try match colors by eyeball later, but I’m not sure how successful that will be. My next idea for figuring out the GBC PWM method with measurements is to use a color sensor. Here’s a blog post with a similar setup. I can’t find the sensor breakout board, but maybe something like this could work (if the white LED was disabled).

I think I don’t have the skills either to work with a scope. In my opinion using GBC on the SK9822 causes a hue shift instead of brightness. I tried a lot of values, but I couldn’t get a visual match.

It’s worth mentioning that the SK9822 also requires a different “end frame” than the APA102. I sent a SK9822 panel I was testing to Daniel Garcia (FastLED author) once I realized my menus were displaying “one frame behind” the one that was sent to He ascertained that the end frame for SK9822 needs to be all zeros in order to force the LEDs to latch & show their data. The end frame for APA102 is 32 ones, whereas the start frame is 32 zeros – hence the one frame behind behavior.

As for the GBC support, I’m told by a friend who develops commercial APA102-based lighting solutions that it is totally broken in the SK9822. Scary stuff that it is being marketed as completely APA102-compatible.

1 Like

Thanks for the feedback. I’ll try the different end frame, however it think this doesn’t matter. I’m comparing pixels within the SK9822 strip, so they would have all a delay then.

I’ve read somewhere (couldn’t find where) that the GBC is totally broken. My first impression confirms that. If you have more info about what is exactly broken or what the experiences of your friend are please let us know.

1 Like

Hmm, I’m not sure about that.
The end frame for APA102 can be zeros too - AFAIK that’s also preferable since all 1 would make any non-set LEDs go all white, while all 0 would just be interpreted as (dummy) start frame till the first high bit is seen.
But actually it’s not fix 32bit but should be something like LEDCOUNT/2 +1 bits to ensure enough clock cycles to shift all the data through, since you lose 1/2 clock per LED on the strips.
So 32bit works for strips up to 64 LEDs, but beyond the strip will show inconsistent frame numbers.

A more elaborate discussion about this can be found here

1 Like

You’re right, @ScruffR… you need LEDCOUNT/2 + 1. It has been too long since i reviewed that site. But as for the end frame, the fact is the two chips are not 1:1 compatible. “Ones” work for the APA102 but not for the SK9822, and the site you linked suggests using ones is acceptable. This is why FastLED added a new class for the SK9822.

I have not seen the effect of non-set frames going all white, but perhaps that’s because I’ve always relied on libraries.

@kasper I’ll ask my friend to chime in here about GBC.

1 Like

Hi - I’m the friend who has used APA102s (and tried to use SK9822s) in several large installations. As far as I can tell, the GBC on the SK9822 seems to not only effect the brightness, but it also influences the color output. In other words, if you display a “bright green” color (RGB:20,240,70) and ramp the GBC from 0x0 to 0x1f, the perceived color shifts quite drastically. The APA102s don’t do this.


@zachr Thanks for chiming in. Good to hear another confirmation of the color shift.

I added initial SK9822 support to the SmartMatrix Library, it’s on GitHub now. You need to edit SmartMatrix_Impl.h and change #define LEDTYPE at the top. Later I’ll make it able to select the LED type from the sketch using template parameters.

APA102 LEDs don’t follow their datasheet, and appear to use /32 math for GBC instead of /31. I didn’t verify that with a scope, but using /32 math got rid of the stepping. /31 math makes no sense on an embedded platform, it should be a power of two. The SK9822 engineers must have wanted to follow the APA102 datasheet to the letter, and used /31 math for GBC. I have GBC working without stepping, but the unoptimized code uses four division operations per pixel, where with the APA102 you could just use bitwise math and shifts which are much more efficient.

The SmartMatrix Library code isn’t easy to follow because it combines the overall matrix brightness value with the RGB pixel scaling calculation, I’ll have to add comments explaining the math later. This code should be easy to use in a non-SmartMatrix project (though it still doesn’t have comments):

        uint16_t maxrgb = max(max(led16bit_r, led16bit_g), led16bit_b);
        value = maxrgb * 0x10000 / 31;

        // load pixels with 8-bit color plus 5-bit global brightness
        src[spilength++] = 0xE0 | (value + 1);                //  Pixel start with global brightness
        src[spilength++] = ((led16bit_b * 31) / (value + 1)) >> 8;
        src[spilength++] = ((led16bit_g * 31) / (value + 1)) >> 8;
        src[spilength++] = ((led16bit_r * 31) / (value + 1)) >> 8;

I’m not seeing the hue shift with the SK9822s. I didn’t directly trying ramping the GBC from 0x0 to 0x1f, but ran this code with the SmartMatrix Library using 48-bit math, and it should have taken care of changing the GBC in the background:

  buffer = backgroundLayer.backBuffer();
  for(int i=0; i<64; i++) {
    buffer[i] = rgb48(20*4*i,240*4*i,70*4*i);

I get this on an 8x8 matrix diffused with a sheet of paper. It’s admittedly not a great photo, but I don’t see any dramatic hue shifts.

Here’s a SK9822 and APA102 side by side running the same sketch.

And here’s a slow motion video recording (iPhone 6) of the two with the lower speed PWM on the APA102s showing. The whole frame flickering is because I was shining a fluorescent lamp above the diffuser.

1 Like

I’m trying out iPixel as a distributor and they have just a few (at this point there are probably only 3 left) SmartMatrix APA Shields for sale in their Aliexpress store:

iPixel makes LED strips and matrices and Adafruit and SparkFun are some of their customers. I haven’t fully evaluated the LED samples I ordered from them but I was happy with the packaging (better than most Chinese companies). The LED strip/matrix pinout unfortunately doesn’t match the SmartMatrix APA Shield (or the pictures on their site), but that should be easy enough to fix with a knife or resoldering the wires. Eventually I’d like iPixel to carry strips and matrices with pinout and colors matching the SmartMatrix APA Shield cable, and to price their shipping so you get a discount if you order a shield and LEDs at the same time, but we’re not there yet.

If you want a SmartMatrix APA Shield in the next month or so, I suggest ordering ASAP as I only gave iPixel a few of these and there are only a few days left until shipping companies shut down for Chinese New Year. I won’t be able to make more available for sale until after Chinese New Year.