Jump to content
Rickta59

[Energia Library] WS2811Driver LED Controller Class

Recommended Posts

@@MORA99 - This lib is very MSP430 asm dependent.  The CC3200 uses an M4, so there is no chance of a direct port.  You might have some luck looking into a Tiva WS2811 library since it's the same core, but I doubt it would be a simple port.  Once I get my hands on a CC3200 LP I'll probably try to make a compatible WS2811 library for it, or expand this one to work with it as well.

I think SPI is often used for the higher-speed parts.  @@Rickta59 may have more experience with that :)

Share this post


Link to post
Share on other sites

I think SPI is often used for the higher-speed parts.  @@Rickta59 may have more experience with that :)

 

Ya, I just looked up the WS2811 lib on the Stellaristi forum, and it's SPI based.  Someone with more experience would have to make a new one for the CC3200 since the devices don't share a serial coms peripheral.

 

It would be really cool to have WiFi controlled LED strips though.  I might just have to get a CC3200LP and start working on this anyway.

Share this post


Link to post
Share on other sites

Sorry for derailing this, I am not that familiar with TI to realise which family cc3200 belongs to.

 

It is probaly possible with SPI, a lesser wifi enabled device uses that to control ws2811, but you would be taking up a hardware SPI port, which is a pretty limited resource, maybe an analog switch could multiplex it.

One could use a secondary 8bit mcu to offload the timing as long as fast updates are not needed.

 

I see the adafruit avr code is assembler too, ofcause being ~16mhz theres fewer cycles to waste than at 80-120mhz, but 80mhz is still nowhere near enough to do it in c, I tried 2 inline asm sleeps with digitalWrite and its way off, maybe a direct bit manipulation could work, acording to the datasheet the leds dont really require perfect timing, theres +/-150ns on both high and low pulse, so +/-12cycles at 80mhz.

Share this post


Link to post
Share on other sites

Sorry for derailing this, I am not that familiar with TI to realise which family cc3200 belongs to.

 

It is probaly possible with SPI, a lesser wifi enabled device uses that to control ws2811, but you would be taking up a hardware SPI port, which is a pretty limited resource, maybe an analog switch could multiplex it.

One could use a secondary 8bit mcu to offload the timing as long as fast updates are not needed.

 

I see the adafruit avr code is assembler too, ofcause being ~16mhz theres fewer cycles to waste than at 80-120mhz, but 80mhz is still nowhere near enough to do it in c, I tried 2 inline asm sleeps with digitalWrite and its way off, maybe a direct bit manipulation could work, acording to the datasheet the leds dont really require perfect timing, theres +/-150ns on both high and low pulse, so +/-12cycles at 80mhz.

Yeah, barring that a PWM timer peripheral with tight code for updates would be necessary I think.

Share this post


Link to post
Share on other sites

I think SPI is often used for the higher-speed parts.  @@Rickta59 may have more experience with that :)

I implemented a version of this stuff using SPI on an LPC1114 (Cortex-M0). I'm sure you could use the concepts described in this post: http://forum.43oh.com/topic/3756-my-time-with-the-lpc1114-dip28/?p=34414

to do the same thing with the Tiva chips and their SPI peripheral.

 

-rick

Share this post


Link to post
Share on other sites

I just got my hands on a MSP430 Launchpad and a 1m 60 leds per meter ws2811 led stripe.

I downloaded the libraries run it on energy and uploaded to the Launchpad , plug to a 5V power source the Launchpad and the stripe + the communication line to the P1.7.

When I turn it on, nothing happens.

Actually the first led (closer to the cables) shine a little red, that's it.

Am I missing something?

 

Thanks for the patient and appreciate any insights.

angelo

Share this post


Link to post
Share on other sites

I have a 15 led ledstrip. I tried to program it. I tried like 4 hours and all the ledstrip is doing is showing some random (this how it looks to me). I added some code I uploaden to my MSP430. I tried to program it to display green and then turn of and so on but it's behaving as in the video below. 
 
https://www.youtube.com/watch?v=-rSzRfCvNME&list=UUV-uWfvEunXHUINAUfiqBHQ

 

This is the actual code I uploaded to the MSP430

// blink_strip - ws2811 led strip blink example
// 11-15-2012 Initial Version 0.1

#include <WS2811Driver.h>

// 24 bits of color data stored GGRRBB
const uint8_t leds0[] = { 0x00,0xff,0x00}; 
const uint8_t leds1[] = { 0x00,0x00,0x00}; 

WS2811Driver ledStrip; // uses P1_7 as datapin connect to DIN on strip

void setup(void)
{
    ledStrip.setLEDCount(15); // setup for 4 leds on a strip
    ledStrip.begin();        // configure P1.7 for output
}

void loop() {
    ledStrip.write(leds0,15);               // set leds to red,green,blue,white
    delay(500);
    ledStrip.write(leds1,15); // turn off all 4 leds
    delay(500);
}

Share this post


Link to post
Share on other sites

I have a 15 led ledstrip. I tried to program it. ...

I'm assuming you are using the zip file from the first post in this thread and using an msp430g2553 running at 16 MHz, yes?

 

Does the blink_strip example work?

 

-rick

Share this post


Link to post
Share on other sites

Assuming the blink_strip example works, let's look at why your code is giving the results you are getting.

 

If you read a little about how the ws2811 works on oPossums's original posting you can see each pixel takes 3 bytes (8bits of Green, 8 bits of R, 8 bits of Blue). In your code you are only providing data for one pixels worth of data. Because you made that a const uint8_t it will end up in flash memory ( this is important later as we will see ). However when you call the ledStrip.write(led0,15) you are telling the write function to expect 15 bytes of led data. This will never work correctly, as you need to provide 3 bytes for each pixel. You have only created 3 bytes of valid data but you are telling the function that there is 15 bytes there.

 

This is the actual implementation of write(const uint8_t *, uint16_t len):

 

void WS2811Driver::write(const uint8_t *data, uint16_t len) {
disableWatchDog();
write_ws2811_hs(data, len, _pin_mask);
enableWatchDog();
}

The code just disables the watchdog interrupt as cycle counting is used in this code to achieve timing, then it calls the low level asm code. passing the address of data, the number of bytes at that address and the pin_mask so it can toggle the correct output pin.

 

Let's go back to what you are seeing in the video. I see it toggling 2 leds on and off. One seems to have a color (although I can't tell what it is, and the other pixel is off and then the rest of the pixels are white. I said earlier that the fact that your leds bytes are in flash is important to understanding why you are seeing white. When you load a new program on your msp430g2553, the first thing the mspdebug does is erase memory. For the msp430 erased memory has a value of 0xFF hex. So lets look at some disassembled code of when you actually call the WS2811:write call:

 

0000c088<loop>:

c088: 3d 40 0f 00 mov #15, r13 ;#0x000f <<< this is the length #15

c08c: 3e 40 de c2 mov #-15650,r14 ;#0xc2de <<< note this address of the data array

c090: 3f 40 00 02 mov #512, r15 ;#0x0200 <<< this is the pin mask

c094: b0 12 dc c0 call #0xc0dc <<< this is the address of the ::write function

c098: 3e 40 f4 01 mov #500, r14 ;#0x01f4

c09c: 0f 43 clr r15

c09e: b0 12 12 c2 call #0xc212

c0a2: 3d 40 0f 00 mov #15, r13 ;#0x000f

c0a6: 3e 40 e1 c2 mov #-15647,r14 ;#0xc2e1 <<< note this address

c0aa: 3f 40 00 02 mov #512, r15 ;#0x0200

c0ae: b0 12 dc c0 call #0xc0dc

c0b2: 3e 40 f4 01 mov #500, r14 ;#0x01f4

c0b6: 0f 43 clr r15

c0b8: b0 12 12 c2 call #0xc212

c0bc: 30 41 ret

[code=auto:0]

 

When you pass 15 to the low-level write and the address of data array at 0xc2de, the low level function performs a buffer read outside of its bounds, it should really stop after 3 bytes because that is all there is for valid data. However, you told it there are 15 bytes of data starting at address 0xc2de. It reads your 3 valid bytes and then gets the value of 0xFF for each byte past the end of the array. Because the flash memory has been erased it contains 0xff,0xff,0xff for each pixel data you did't define.

 

So the solution is to define more valid pixel data and provide the proper number of bytes to the write call.

 

-rick

 

I have a 15 led ledstrip. I tried to program it. I tried like 4 hours and all the ledstrip is doing is showing some random (this how it looks to me). I added some code I uploaden to my MSP430. I tried to program it to display green and then turn of and so on but it's behaving as in the video below. 

 

https://www.youtube.com/watch?v=-rSzRfCvNME&list=UUV-uWfvEunXHUINAUfiqBHQ

Share this post


Link to post
Share on other sites

First a big thank you to help me. It now makes sense to me. So in my case when the led strip is 15 leds long I'll should define 45 RGB values, if I want to light them all up of course. I'll give that a try! I thought the len in the write function was how long the led strip actually was. I also tried to use the extra layer library (also in this post of ILAMtitan). I also tried to run the code of bobnova but got the same uncontrollable feeling.

 

Assuming the blink_strip example works, let's look at why your code is giving the results you are getting.

 

If you read a little about how the ws2811 works on oPossums's original posting you can see each pixel takes 3 bytes (8bits of Green, 8 bits of R, 8 bits of Blue). In your code you are only providing data for one pixels worth of data. Because you made that a const uint8_t it will end up in flash memory ( this is important later as we will see ). However when you call the ledStrip.write(led0,15) you are telling the write function to expect 15 bytes of led data. This will never work correctly, as you need to provide 3 bytes for each pixel. You have only created 3 bytes of valid data but you are telling the function that there is 15 bytes there. That is never going to work properly.

 

...

 

-rick

Share this post


Link to post
Share on other sites

There are 2 write functions:

 

void WS2811Driver::write(const uint8_t *data, uint16_t len) {
    disableWatchDog();
    write_ws2811_hs(data, len, _pin_mask);
    enableWatchDog();
}

void WS2811Driver::write(const uint8_t *data) {
    write(data,_led_cnt * 3);
}
The one you are using expects you to pass the proper number of bytes. The second one write(led_data), doesn't expect a length in bytes, it uses the number of leds you provided to the setLEDCount() function (stored internally in _led_cnt) and multiplies it by 3 to get an expected byte length of the led data. It then calls the write(data,len) function.

 

-rick

Share this post


Link to post
Share on other sites

So if I change @@bobnova s code a bit it would become for my 15 led strip

#include <WS2811Driver.h>

byte leds0[45];       //15x3 per led
WS2811Driver ledStrip; // uses P1_7 as datapin connect to DIN on strip

void setup(void)
{
ledStrip.setLEDCount(15); // setup for 15 leds on a strip
ledStrip.begin();	 // configure P1.7 for output
for (byte x = 0 ; x < 45 ; x++){
	 leds0[x] = 0; //turn all pixels off
}
}

void loop() {
//Modified the code, want to make the led strip one color ... red
leds0[0] = 50;
leds0[1] = 0;
leds0[2] = 0;
//
for(byte x = 0; x <= 42 ; x+3){
leds0[x] = leds0[0];
leds0[x+1] = leds0[1];
leds0[x+2] = leds0[2];
}
ledStrip.write(leds0);			 // write to the LEDs
delay(100);

}

However if I execute this code, I still get really weird behavior... It's really driving me crazy  ^_^

Share this post


Link to post
Share on other sites

it is GRB not RGB

 

Does the sample work? That is where you should start with any library. If the blink_strip example doesn't work then you might have a wiring problem, or a power problem or your 16MHz DCO value might be off.

 

-rick

Share this post


Link to post
Share on other sites

I was a bit busy with my exams but found some time to run the sample code and filmed what happened. I just modified the code a bit so that it used 15 leds. 
 

// blink_strip - ws2811 led strip blink example
// 11-15-2012 Initial Version 0.1

#include <WS2811Driver.h>

// 24 bits of color data stored GGRRBB
const uint8_t leds0[] = { 0x00,0xff,0x00, 0x00,0xff,0x00, 0x00,0xff,0x00, 0x00,0xff,0x00, 0x00,0xff,0x00, 0x00,0xff,0x00, 0x00,0xff,0x00, 0x00,0xff,0x00, 0x00,0xff,0x00, 0x00,0xff,0x00, 0x00,0xff,0x00, 0x00,0xff,0x00, 0x00,0xff,0x00, 0x00,0xff,0x00, 0x00,0xff,0x00 }; // R,G,B,W
const uint8_t leds1[] = { 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00, 0x00,0x00,0x00 }; 
// 0,0,0,0

WS2811Driver ledStrip; // uses P1_7 as datapin connect to DIN on strip

void setup(void)
{
    ledStrip.setLEDCount(15); // setup for 4 leds on a strip
    ledStrip.begin();        // configure P1.7 for output
}

void loop() {
    ledStrip.write(leds0);               // set leds to red
    delay(500);
    ledStrip.write(leds1,sizeof(leds1)); // turn off all 15 leds
    delay(500);
}

https://www.youtube.com/watch?v=4m9zJ1Ft3fk&spfreload=10

 

You can see clearly the led sometimes does what it's asked to, turn all red and then turn off. But it's like only able to do this one time and then it starts "freestyling" again. I'm far from an expert but my intuition tells me the msp430 isn't timing (or clocking) correctly, or can it be the ws2812 chips who are processing the signals wrongly? If the DCO of the MSP430 isn't function properly, is changing the microcontroller the only option?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×