WS2801 LED Strip with SPI

Hi,
i’am trying to get my WS2801 LED strip to work with the spark core. There is already an arduino library available for it. https://github.com/adafruit/Adafruit-WS2801-Library

I’ve tried playing around with the library to make it run on the spark core, but i’m still not been successful with it. I’m not sure about the ClockDivider on the spark core. The system clock is 72MHz? So there’s no suitable Clock Division Factor to make a clock speed of 2 MHz out of it. Has someone any suggestions how to deal with this?

WS2801 Datasheet: http://www.adafruit.com/datasheets/WS2801.pdf
Thanks

Looks like from the datasheet that it can handle a Maximum input clock frequency 25MHz

But later on it says The transmit the data over long distance by cascading, the WS2801 integrates push-pull output stage with strong driving capability which enables the data and clock can be transmitted up to 6 meters at 2MHz clock frequency.

A SPI divider of 36 sounds like what you want, but 32 is pretty close. If in fact it’s 72MHz / 32 = 2.25MHz. Based on the docs that say which sets the SPI clock to one-quarter the frequency of the system clock. it should be correct. I would think 2.25MHz should work for the first pixel no problem, but if it doesn’t work for the whole string, try a divider of 64 and your SPI will be 1.125MHz. That should work fine.

If you are not getting anything to respond you probably have some issues with the port/use of the library. You can also try posting your code here (highlight it all and press CTRL+K to format it), or a link to your code up on Pastebin.com or Github.com

The NEOpixels are probably going to be another interesting item to get working with the Core, but that library is bit-banged… so we’ll need some more control over the low level I/O before attempting that.

If you’re not controlling a lot of pixels it might be best to bit-bang the clock and data to the WS2801; they are very tolerant of timing. The WS2812 (used in NeoPixels), on the other hand, is single-wire and very finicky; pulse width (fractional microseconds) is used to control bit value and it’s darned difficult to do with a traditional micro.

I have written drivers for both using the Parallax Propeller chip. It’s fast, the assembly code is easy, and the drivers work flawlessly. My personal goal is to use the Spark Core for wireless connectivity and the Propeller for specialty IO – a serial bridge will link the two.

For you fans of Limp Bizkit, have a look at this video which features guitarist Wes Borland (comes in just after the 5 minute mark). He’s wearing a costume built by Steve Wang (“Predator” and lots of other cool movie monsters) and his team, with electronics and programming by me. There are about 290 WS2801 pixels in the costume, all are being updated every 3ms by the Propeller (this is the advantage of multi-core). Limp Bizkit is on tour now and Wes has a button on the helmet that lets him change animations – most are more colorful that the code created for the League of Legends event.

Wow! Epic :slight_smile: That costume is definitely sweet as hell. If you don’t mind me asking, how did you get hooked up working with Wes?

Even though I’ve never used a Parallax Propeller chip for any projects, I understand the multi-core design is very useful for high speed parallel operations. It’s a shame though that you don’t expect a similar processing power from the Spark Core, and only wish to use it like a Wifi dongle.

Right now there is no way to easily bit bang the digital outputs faster than 250kHz. You can use digitalWrite(D0,HIGH) and digitalWrite(D0,LOW) repeatedly to generate a 250kHz clock, but as soon as you start adding in data and supporting code, your clock speed will drop dramatically.

Hopefully we can gain access to direct port manipulation from the sketch to utilize the speed and power of this STM32 running at 72MHz.

Good news. I’m done with customizing the WS2801 library for the spark core. It was quite easy. The divider of 32 was the right suggestion. The second thing i forgot was to hold down the clock pin for 1 milliscond. Now it’s working fine. :slight_smile:

The option for using the library with a SoftSPI is not working yet. Maybe you could give me some advice to make it run.

As you can see in the library, you can manually set a clock and data pin. If you set this, the data will be written directly to the output register.
How do i set the register with the spark to write data to it directly?

So here is the library:

1 Like

That event was the League of Legends championship for Riot Games. They hired Wes to be part of the music. Riot also hires my friend, Steve Wang, to build character displays for them – like this one which is the first time I used WS2801 LEDs (this is not the final code – just a test).

http://www.youtube.com/watch?v=YuSMKciw0J8

It was Riot that contracted Steve to build the costume. He calls me whenever electronics are involved.

I just got my Spark Core today so I’m hoping to get it up and running shortly. That said, my Android phone is not compatible with the Spark app; I don’t know if this is a deal breaker.

The Spark Core and Propeller are not Apples and Apples. I like the Propeller for its simplicity and raw horsepower. It’s not fancy, but I like that. As I said, I think combing the two into a system may be a way for me to leverage the specialty things I do. I could be wrong, but I doubt the Spark Core could do constant updating of several hundred WS2812 LEDs like I do in the Propeller. It takes a lot of speed, a lot of RAM (probably not an issue), and precise timing, hence that process runs in a devoted core. Attempting to run WS2812 code in an interrupt is not practical, IMHO.

1 Like

@Roadrunner I have a WS2801 at home too and would like to use it with the spark.

Thanks for porting the library!

Is there another way to use it than to building my own firmware? could I just copy/paste the class definition into the main program in spark’s web IDE?
I tried it like this:
http://tny.cz/b7b14b14

but getting errors:
http://tny.cz/de75d798

Guys @Roadrunner @JonnyMac @kwyjib0!

Please give this port for the WS2801 a try:

I have the speed set to SPI_CLOCK_DIV128 (562.5kHz) here: https://gist.github.com/technobly/8339548#file-sparkcorews2801-cpp-L201

Please try changing it to each of these:

SPI_CLOCK_DIV64 (1.125MHz)
SPI_CLOCK_DIV32 (2.25MHz)
SPI_CLOCK_DIV16 (4.5MHz)
SPI_CLOCK_DIV8 (9MHz)
SPI_CLOCK_DIV4 (18MHz)

And see how fast it works up to! Thanks :smile:

Also JonnyMac, please try my WS2812 port on your several hundred LED strip if you can! Thanks!!
GitHub - technobly/Particle-NeoPixel: An Implementation of Adafruit's NeoPixel Library for Particle devices: Core, Photon, P1, Electron, Argon, Boron, Xenon and RedBear Duo.

I want to do the entire 24-bit routine with assembly when I learn a bit more Cortex M3 assembly.. there is some assembly in there already for timing though.

1 Like

@BDub thanks so much for your work! really appreciate it.

haven’t tried it out with the strip as I realized that I need to solder some connectors to my ws2801 strip first… but I pasted your code in the web ide and it compiled!

Can you please tell me what I did wrong in my code? So that way I can learn something for the future…

@BDub just wanted to show you how nicely my WS2801 strip is working with the spark :smiley:

w00t! that’s awexome @kwyjib0. Any chance you played with the other SPI_DIVIDERs? I’m curious if it can really be driven up to 25MHz or not… thanks for your help. I’ll see what I can do about figuring out what’s different in your code vs. mine. I know I had to get in and chop out the software driven SPI cases because that was all ASM stuff for AVR and won’t compile for the Spark.

@BDub I finally had some time to play around. couldn’t really tell a difference with settings SPI_CLOCK_DIV128, SPI_CLOCK_DIV64 and SPI_CLOCK_DIV32.
but at SPI_CLOCK_DIV16 it started flickering in the rainbow part. solid colors were fine though.

Will run it at SPI_CLOCK_DIV64, or what would you suggest?

Interesting… well then I would suggest keeping it at SPI_CLOCK_DIV32 (2.25MHz). Somewhere in the datasheet it talks about 2Mhz data rate… but in another place it talks about 25MHz. So you’ve answered the question!

I recently tried doing what the code said: copying directly into the Spark online editor. I got the following error:

../84d69444e34cc0565b92767e3962ed304abd089941dbb04b429932459add/the_user_app.cpp:3:1: error: 'RGB' does not name a type
make: *** [../84d69444e34cc0565b92767e3962ed304abd089941dbb04b429932459add/the_user_app.o] Error 1

Error: Could not compile. Please review your code.

Any idea as to what I’ve done wrong?

@bandgeek80001
Did you paste the following code in the web IDE?
https://github.com/technobly/SparkCore-NeoPixel/blob/master/SparkPixel.cpp

It seems to compile just fine. Maybe you didn’t paste the entire code?

@Dave I do see the error myself as well, even copying the RAW version of the code.

the_user_app.cpp:3:1: error: 'RGB' does not name a type make: *** [the_user_app.o] Error 1

RGB is not used as a type anywhere… so this must be a compiler parsing error. There are plenty of comments with RGB in them though.

EDIT: It’s definitely one of the comments. I changed all of the RGB in comments to REDGREENBLUE and now the error reports that as the type that’s not defined.

Found it… it’s line 370. If you remove the single quotes around conventional it compiles
https://gist.github.com/technobly/8339548#file-sparkcorews2801-cpp-L370

// optional extra parameter: WS2801_RGB is 'conventional' RGB order

1 Like

Awesome find, looking into this now

Edit: Thanks for calling me by my username, sends the thread straight to the top of my inbox :slight_smile:

By eliminating the single quotes around 'conventional' in the above-posted code, it works!

3 Likes