WS2811 on Teensy 3.0 using FastSPI_LED library

Status
Not open for further replies.

Wozzy

Well-known member
Hello Everyone,

First, I'll introduce myself: I'm Bob W., I'm new to using the Teensy, C and Arduino IDE, although I have been playing around with PIC microcontrollers programming under PICBASIC for a few years now.

Secondly, I'd like to thank Paul, for all his efforts and the amazing amount of excellent work he has put into the Teensy and supporting his customers.

I just received a Teensy 3.0 and was amazed how easy it was to get it going... I was successfully modifying Blinky within 30 minutes of unpacking it. I compare that to probably a week or more before I was able to figure out how to successfully program my first PIC chip. I also purchased one of the PJRC Micro SD Card Adaptors.

I have a few light strips that I have been playing with, both LPD8806 and WS2811 types.
I've been successful in operating the LPD8806 strip on the T3 using the Adafruit LPD8806 library compiled in the Arduino IDE.
I also had both light strips working on the PIC, however the WS2811 required so much attention from the PIC processor, there was nothing left so I could only do rudimentary light patterns.

I've tried to run both strip types using the FastSPI_LED library, but have been unsuccessful. I suspect it's due to the high clock speed of the Teensy 3.0. I have loaded the latest versions of all the software and everything compiles successfully, but get only junk on the light outputs. The same wiring setup works with LDP8806 library however.

My ultimate goal is to operate the WS2811 strip and be able to read various color patterns from the SD card and control all of this from an android phone using bluetooth. This leads to my questions.

1) Has anyone successfully operated a WS2811 RGB light strip using the FastSPI_LED library on the Teensy 3.0?
If so could you please share any tips for setting up the clock speeds correctly.

2) Considering that the WS2811 has no clock, CS or MISO, is there any way I can share the SPI port, or will I need to bitbang one of them?

I prefer the WS2811 strip over the LPD8806 because it's narrower, and has a higher LED density.

Thanks for any help getting me up and running, and I promise to share what I learn.
 
Last edited:
I spent some time playing with these LEDs which have an integrated WS2811 controller. (Thanks to Ward Ramsdell from Dorkbot for spotting me a few of them to play with.)

I could get it to light up and even change color a bit but I never felt like I got the full spectrum of color out of it. I assumed this was some timing issue. I know there have been some fixes to the teensy SPI stuff since then. The code I used was something like:

Code:
uint8_t *leds;
uint8_t count = 1;
FastSPI_LED.setLeds(count);
FastSPI_LED.setChipset(FastSPI_LED.SPI_WS2811);
FastSPI_LED.setPin(11);

FastSPI_LED.init();
leds = (uint8_t*)FastSPI_LED.getRGBData();
for (int i = 0; i < count*3; ++i) leds[i] = 0;
FastSPI_LED.start();
while(1) {
    for (int i = 0; i < count*3; ++i) {
        if (leds[i] < 255) {
            leds[i]++;
            break;
        } else {
           if (i == count*3-1) {
               for(int j = 0; j < count * 3; ++j) leds[j] = 0;
           }
        }
    }
    FastSPI_LED.setDirty();
    FastSPI_LED.show();
    delay(100);
}


I haven't gotten back to it. Please do let us know if you get this to work. I'm pretty psyched for that integrated LED/controller; it's like $0.14/ea not including shipping.
 
Hi, I'm surprisingly similar to yourself. Used PICs for a few years, first go at arduino, using ws2811 (ws2812) led strips with teensy and bluetooth control. I plan to build a matrix for use on a top hat, with animations stored on an SD card. I ordered both the teensy 2 and teensy 3 along with SD adapter. I emailed Paul about it and he said if you're using around 200 LEDs use the teensy 2 as the fastspi does not yet support the single pin protocol on the teensy 3.
Also, the sd adapter only fits nicely on the teensy 2. Since I want all electronics inside the hat, the teensy 2 is ideal. However I can't seem to get the fastspi testleds sketch to compile. I read there is a patch but I'm not entirely sure how to apply it.
I also spoke to Frollard (Jamie) about the teensy 3 and SD card and he encountered issues with running the SD card and led strip at high speeds sue to library issues. He had to use a signal transistor for accessing the SD card or the the LED strip
I plan to stick with the teensy 2 once I get the patch applied and use the bluetooth module through the UART pins. I'm looking at the MIT app inventor beta for designing my android application as it seems rather easy to use

Hope this has been of some help if any. I'm currently busy at the moment, so I haven't had a chance to play around with anything yet
 
Hi! I'm currently working on a rewrite of the FastSPI_LED library, in part to make it more easily portable to arduino variants (like the teensy 2.0/3.0) as well as other arduino platforms. So far, I've only done SPI support for the teensy 3.0 platform (and that's up there) - the TM180X and ws281x family of chips require very very specific timings - and the different clock speeds mess with those, so I haven't done them yet. I'm hoping to have the rewrite done and up by the end of the month.
 
Great, hopefully I should have more free time round then. Look forward to playing around with it. Will the FastSPI library be able to work with an SD card, or will there be problems even if a PWM pin is used for the LED strip?
 
Great, hopefully I should have more free time round then. Look forward to playing around with it. Will the FastSPI library be able to work with an SD card, or will there be problems even if a PWM pin is used for the LED strip?

For strips that are SPI based (ws2801, LPD8806, etc...) - the problem with something like the SD card, which is also SPI based is that you need a way to determine which thing will receive SPI data. It's a little bit of a misnomber to say that the ws2801 and lpd8806 and friends are "SPI" - as they only use the clock/data lines from SPI, they don't use the channel select line. As part of the re-write, i'm going to add support for defining a channel select pin to use when using SPI - though you will have to do some hardware to fake that out (short version - something that sits between the MOSI pin and the leds that only lets data through when the chosen channel select pin is high). The other thing the rewrite is going to have is support for software-based SPI so that you can use other pins for SPI based chipsets, freeing up the main SPI system for things like the SD card.
 
I assumed this was some timing issue. I know there have been some fixes to the teensy SPI stuff since then. The code I used was something like:

I played around with your code. it's very similar to mine, and saw no real difference.
I tried adjusting several of the parameters listed in the FastSPI_LED.h file, but it didn't really change anything.
I suspect the higher clock speed (24, 49, 96MHz vs 16MHz) is the real issue.
I'm still too new to C programming and also to understanding the Freescale manual (which is very different from a Microchip PIC manual) to be able to make these kinds of changes.
Thanks for your help.
 
Hi! I'm currently working on a rewrite of the FastSPI_LED library,... the TM180X and ws281x family of chips require very very specific timings

First off, thanks Dan, for all of your efforts in creating the FastSPI_RGB library.
I'm glad to hear that your are working on an updated version of the library. From my rambling around on the web, I can see that a lot of people are using it.

As for the timings on the WS2811 chips, I was able to successfully operate a 60 LED strip of WS2811 LEDs from a 48Mhz 8 bit PIC chip, but only the most rudimentry patterns.
The PIC had only an 8 bit SPI buffer, and no DMA so it required almost all of the processor, just to feed the SPI buffer.

It was the wider path, and DMA features that led me to the Teensy 3.0... Now I just need to figure out how to use those features.

Thanks Again
 
Last edited:
I plan to stick with the teensy 2 once I get the patch applied and use the bluetooth module through the UART pins. I'm looking at the MIT app inventor beta for designing my android application as it seems rather easy to use

I've use MIT App Inventor to create several apps, but not yet for the bluetooth. For simple stuff and trouble shooting, I have used Bluetooth SPP by Jerry Li successfully. I'm using a JY-MCU BT-Board V1.05

Good Luck with the Top Hat, I'd really love to see some project photos when done... Perhaps you can include a few bright white LEDs embedded in the rim near the front, to use as headlights at night. I made a baseball cap with 10 x 100mA white LEDS embedded in the rim and it's amazing that you can walk about without the need for any lights, but your field of view is always perfectly illuminated.
 
Last edited:
The other thing the rewrite is going to have is support for software-based SPI so that you can use other pins for SPI based chipsets, freeing up the main SPI system for things like the SD card.

That's a great idea, to give some flexibility.
If it's not really using the Hardware SPI, then the ability to change the pins, will allow other peripherals to be used.
 
I actually ordered four WS2811-based LED strips over a month ago... which arrived only days ago.

Now that beta 11 is published, maybe this is a good time to see if I can quickly put together some code to drive them?
 
Last edited:
Thanks to Dan for updating the library!!!! much gratitude. I was hesitating to adopt the teensy3.0 because of reported problems with controlling the NeoPixel (ws2801) LED strip. So I'm delaying my mobius clock project for a bit while things develop.

Will your new library work with the Arduino Due?
 
Hi, these are actually known as WS2812 LED strips, since they have the WS2811 IC built within the 5050 SMD LED. In some case they are advertised with WS2811 (WS2801) and no mention of WS2812. I assume it's cause people search those terms. Here is the datasheet for this strip. It's just those LEDs with their own capacitor across the voltage rails. World-semi seem to make all these WSXXXX devices.

Hi Charlie, I noticed Adafruit always rename their LED strips and pixels. Also, you can get the strips elsewhere for around $50 per reel (4-5m) with free shipping. Also you can get them with a black flexi PCB. I plan to take a black marker to my strips around the LEDs and contacts, so when off they aren't too noticeable against a black background.
 
I actually ordered four WS2811-based LED strips over a month ago... which arrived only days ago.
Now that beta 11 is published, maybe this is a good time to see if I can quickly put together some code to drive them?

Oh for me that's great news...If anyone can really get this right, you can.


Here's what I know about the WS2811 light strip timing.
The light strip wants an 800 kHz bit stream or 1.25uSec per pulse width. (a few strips are wired for 400 kHz)
If you break each bit up into FIVE 0.250uSec segments, then the bits can be represented as follows:
1 = 11110
0 = 10000
The strip wants a stream of Bytes with 3 Bytes per RGBLED times the number of RGBLEDs per strip without pausing
A low pause of 50 ms, causes the chips to latch, display the values latched, and get ready to receive the next data stream.
The acceptable timing error is +/- 150nS

I've heard, but never verified: That all the WS2811 really cares about is the line state 650nSec after the start of the first high pulse.
If this is true, then it would be possible to break each bit up into FOUR 0.3125uSec segments, then the Bits can be represented as follows
1 = 1110
0 = 1000
This could greatly simplify and speed up the processing.

I've attached a sketch of the timings below:
WS2811 Timing.jpg

The WS2811 really doesn't use SPI, though I think most people go that route, because due to the high bit rates, the SPI can offload a little of work on the CPU by sending one or two bytes at a time.
An ideal solution, would use an ordinary digital I/O pin, this would allow flexibility, allow the use of SPI for an SD card interface (with DMA), and possibly allow driving multiple light strips on different pins.

Thanks,
Bob Wozniak
 
Last edited:
Here's my first attempt.

I tested by checking the waveforms on a scope, and driving 2 LEDs. The strip has 20 total.... would do something more interesting, but Robin & I are going out for dinner. Will look at this more tomorrow (hopefully doing something more interesting).

Hopefully this code ought to be easy to build upon?

Code:
#define WS2811_PIN  2
#define NUMLED      2

unsigned char pixels[NUMLED*3];

void setup(void)
{
        pinMode(WS2811_PIN, OUTPUT);
        digitalWrite(WS2811_PIN, LOW);

        pixels[0] = 0xFF;  // LED #1 - red
        pixels[1] = 0xFF;  // LED #1 - blue
        pixels[2] = 0xFF;  // LED #1 - green
        pixels[3] = 0xCF;  // LED #2 - red
        pixels[4] = 0x00;  // LED #2 - blue
        pixels[5] = 0x8F;  // LED #2 - green
}

void loop()
{
        ws2811();
        delay(10);
}




#if F_CPU == 96000000
        #define DELAY_T0H       3
        #define DELAY_T0L       23
        #define DELAY_T1H       12
        #define DELAY_T1L       13
#elif F_CPU == 48000000
        #define DELAY_T0H       1
        #define DELAY_T0L       13
        #define DELAY_T1H       7
        #define DELAY_T1L       7
#elif F_CPU == 24000000
        #error "24 MHz not supported, use 48 or 96 MHz"
#endif

static inline void delayShort(uint32_t) __attribute__((always_inline, unused));
static inline void delayShort(uint32_t num)
{
        asm volatile(
                "L_%=_delayMicroseconds:"               "\n\t"
                "subs   %0, #1"                         "\n\t"
                "bne    L_%=_delayMicroseconds"         "\n"
                : "+r" (num) :
        );
}

void ws2811() {
        noInterrupts();
        for (unsigned char *p = pixels; p < pixels + sizeof(pixels); p++) {
                unsigned char n = *p;
                for (int mask = 0x80; mask; mask >>= 1) {
                        if (n & mask) {
                                digitalWriteFast(WS2811_PIN, HIGH);
                                delayShort(DELAY_T1H);
                                digitalWriteFast(WS2811_PIN, LOW);
                                delayShort(DELAY_T1L);
                        } else {
                                digitalWriteFast(WS2811_PIN, HIGH);
                                delayShort(DELAY_T0H);
                                digitalWriteFast(WS2811_PIN, LOW);
                                delayShort(DELAY_T0L);
                        }
                }
        }
        interrupts();
        delayMicroseconds(50);
}
 
So, can someone help double check my math here on the timing for using SPI?

This diagram (from here):

529845357_942.jpeg

shows 1.25us cycle. I think what happens with these chips is that in the middle of the cycle, it samples the line; if high 1 is registered, if low 0. Does this agree with what others have read/observed?

The clock rate for the DSPI is described on page 971 of the reference manual: SCK baud rate = (fSYS/PBR) x [(1+DBR)/BR]

I was thinking it might be convenient to represent one bit to the 2811 as 8 SPI bits (one byte) as this makes the math convenient.

1.25 us / 8 = 156.25 ns per SPI bit.

At 48 Mhz with a clock divider of 8 would give an error of ~10 ns. This is about 60 LEDS given the tolerance of 600ns.

(1 / 48 Mhz) * 8 = 166.66 ns.

At 96 Mhz, a prescaler of 5 (PBR=0b10) and a divisor of 3 (BR=6 or 0b0010 according to table 43-34, and DBR=1), gives 156.25 ns per bit and 8 bits would give 1.25 us:

96,000,000 / 5 * (2 / 6) = 6,400,000 = 156.25ns * 8 = 1.25 us.

Code:
To send :   We'd write:
             +---------+---------+---------+---------+---------+---------+---------+---------+
0            |    1    |     1   |     0   |     0   |     0   |     0   |     0   |     0   | 
1            |    1    |     1   |     1   |     1   |     1   |     1   |     0   |     0   |
             +-- 0.15--+-- 0.15--+-- 0.15--+-- 0.15--+-- 0.15--+-- 0.15--+-- 0.15--+-- 0.15--+
(excuse the ascii art.)


Am I reading the description of the clock rate calculation correctly?

So, I'm thinking of using

Code:
FCPU=960000000
and
               DBR = 1     LSBFE=1    PBR = 0b10   BR = 0b0010
SPI0_CTAR0 = (1 << 31) | (1 << 24) | (0b10 << 22) | 0b0010;

Does this make sense? Is there some better timing option?

Thanks,

-c
 
68 LEDs per meter ws2811 light strips!

I love how fast the chinese light strip manufacturers are raising the bar on the WS2811 light strips.
It seems like only a few months ago, 30 LED's per meter was the best you could get for addressable light strips.

The WS2811 light strips I currently have are GreeLed GE60RGB2811C which are 60 LEDs/m on white flexible circuit and IP67 waterproof silicone sleeve.

I see that they now have a new product with 68 LEDs/m GE68RGB2811x which is available in black or white, water proof or non water proof.
Here's a Link: GE68RGB2811

By the way, GreeLed also has an LPD8806 based strip with 52 LED/m if you prefer that type. I have one of these also.

If I can get these WS2811 strips working well on my Teensy 3.0 soon, I'd consider setting up a group buy on some of the 68LED/m rolls.
They come in 5M reels.

PS. I'm not affiliated with GreeLed in any way.
I'm just a customer that's satisfied with their product.
 
Last edited:
I have a plan for a library that will drive 8 strips simultaneously, using DMA so the CPU isn't tied up bit-bashing the waveform. That will allow it to generate animations or communicate by USB or serial while also updating the LEDs. The idea is to support up to 2000 LEDs with double buffering or 4000 LEDs with single buffering, at 60 Hz update rate.

At this point, it's in the planning phase......
 
First Light

I have a plan for a library that will drive 8 strips simultaneously, using DMA so the CPU isn't tied up bit-bashing the waveform. That will allow it to generate animations or communicate by USB or serial while also updating the LEDs. The idea is to support up to 2000 LEDs with double buffering or 4000 LEDs with single buffering, at 60 Hz update rate.

At this point, it's in the planning phase......

I really can't wait to see that...

So the good news for me is that I've had first light with my 60LED/m WS2811 light strips!
Here's a photo of the first light.
Teensy3 and WS2811.jpg

After reloading the Teensy 3.0 Beta11 software, and reshuffling some stuff around on my hard disks.

I downloaded the modified Teensy3.0 Adafruit Neopixel Library

It compiled and ran perfectly first try.
I'm already creating new patterns, and working on my bluetooth interface.
Thanks Paul...Your awesome!
 
Has anyone noticed color variation on their light strips?

I have two different light strips, one is based on LPD8806 chips, and the other is based on WS2811s which are integral with the RGB-LEDs.

I've been using the LPD8806 strip for some time, but only yesterday got the WS2811 strip to work.
Now that I can reliably control the WS2811 strips, I notice that when it's set to pure white (255,255,255) that there is quite a bit of variation in perceived color of the individual LEDs
Some appear slightly pinkish, and others appear slightly bluish and greenish. I can also notice it when set to orange.

On my LPD2811 based strip, they all appear identical in color.

I'll try and capture this in a photo this afternoon, but I've found that these strips are difficult to photograph accurately.
But it looks a little like this:
Colors.jpg

I'm wondering if this has to do with the binning of the LEDs on this particular light strip, or if it's an issue with WS2811 in general.

Does anyone else see this in their WS2811 based strips?
 
Last edited:
Considering how cheaply these LED strips are made in China, it seems pretty amazing any of them have good color balance.

The only "strip" (actually 4 of them) I have are actually a cluster of 6 LEDs for each WS2811, inside a plastic housing with a translucent white dome on top. They run on 12 volts. Earlier today Robin and I had a conversation about how PJRC might need to buy a lot of LEDs (thousands).... of course only for software compatibility testing!!! ;)
 
Status
Not open for further replies.
Back
Top