Multi Strip sk6812(RGBW)/ws2812b driver demo
Kednerpo
Posts: 46
in Propeller 1
I've been working on a driver that will run multiple strips of Adafruit's NeoPixels. I started by making a few changes to JonnyMac's ws2812 driver to make it run a single RGB or RGBW strip. Once I got that working I starting adding the ability to control multiple strips. I also added a few more controls and features.
This first version is definitely a work in progress but it offers the following features.
Default set to 8 strips
I set the default to 8 strips so it would be directly compatible with Adafruits OctoWS2811 driver, which is basically a 74HCT245-based level shifter.
The default 8 can be changed by changing the STRIP_QTY constant in the demo object and in the sk6812 driver object.
256 LEDs per strip
It looked like JonnyMac's ws2812 driver still had a limit per strip of 256 LEDs. I kept to that. It also seemed that 2048 LEDs (8 strips * 256 LEDs) was still within the propeller's capabilities.
Divide a single txpin output into different "strips"
O.k. I'm not sure exactly why this works but I think it is a cool feature. You can wire a string of LEDs together then divide it into multiple "strips;"
for instance a 30 LED string connected to pin P0 could be set up with:
Strip#0 is LEDs 0 thru 10, Strip#1 is LEDs 11 thru 15, Strip#2 is LEDs 16 thru 23, and Strip#3 is LEDs 24 thru 29 (I believe the strips need to be consecutive).
You can then use the Set_Strip method to change just the LEDs defined in the "strip."
Mix and Match RGB and RGBW
Any strip can be either RGB or RGBW. This also works with the the above feature of dividing a strip into multiple strips. So on one txpin output you could run a string of RGB LEDs then wire in a string of RGBW then go back to RGB. Define it as 3 different strips on the same txpin and the driver will run them correctly.
Note: this feature does not do any RGBW to RGB math conversion. The white channel is just dropped off of the RGB strip.
Setup and change the direction of each strip
When running a method like a chase or color wipe this feature lets you change the direction of any or all strips. Instead of reading the RGBW buffer from the first to the last channel of the strip this will read it from last to first channel effectively reversing the direction.
When defining the default direction of the strip in Strip_Params use fwrd or rvrs.
When changing the direction in programming use strip.dir or strip.dir_all methods fwrd(normal), rvrs(backwards), tggl(toggle direction), or dflt(set back to default).
example: strip.dir_all (dflt) ' sets all strips to default direction
example: strip.dir (0, tggl) ' toggles strip#0's direction
Lastly and the part that needs the most work: Fading
Fading each pixel from any color to another. i.e. Fade to black
This is a system that sets a target RGBW value and compares it with the current RGBW value per channel. If they are not equal it compares each byte of the target and current R,G,B and W values and increments or decrements each byte of the current R,G,B,and W channel to eventually make the current RGBW and the target RGBW the same. The amount incremented or decremented can each be set for slower or faster transitions. I made it two different variables so that the fade in could be different than the fade out value.
Calling the strip.fade, strip.fade_fill, strip.fade_strip, or strip.fade_all methods only executes the compare and adjust method once, so you need repeat the method multiple times to see any change. The strip.fade_fill, strip.fade_strip, or strip.fade_all will return a value of how many LEDs were changed when running the compare method. This way you can choose to repeat those methods a certain number of times or until the amount of LEDs changed is zero; in other words all the LEDs current RGBW are the same as their target RGBW values.
Example:
repeat
time.pause(10)
until strip.fade_strip (0,$20_00_00_00, 1,2) == 0 'repeats loop until leds_chngd = 0
this will repeat the strip.fade_strip method until all of strip#0 LEDs are at $20_00_00_00. The increments the value is 1 the decrements value is 2
This is all working but I hope to make a few improvements.
Shorter strips of LEDs fade from one color to another faster than longer ones for obvious reasons; fewer LEDs to process.
On the short term I would like to implement a system that would make the processing of LEDs take the same amount of time whether the strip was long or short. I don't know enough about the clock and how long it takes to process each LED to fully implement this feature at this time.
Ultimately I would love to be able to set a target RGBW value and set how long I want it to take to get there and have the system compare and determine a pause time and increment/decrement value to reach that value.
I very much welcome any feedback. I am trying to get better at programming and would love to hear about any areas of my programming that need improvement, or just simpler ways of doing things.
This first version is definitely a work in progress but it offers the following features.
Default set to 8 strips
I set the default to 8 strips so it would be directly compatible with Adafruits OctoWS2811 driver, which is basically a 74HCT245-based level shifter.
The default 8 can be changed by changing the STRIP_QTY constant in the demo object and in the sk6812 driver object.
256 LEDs per strip
It looked like JonnyMac's ws2812 driver still had a limit per strip of 256 LEDs. I kept to that. It also seemed that 2048 LEDs (8 strips * 256 LEDs) was still within the propeller's capabilities.
Divide a single txpin output into different "strips"
O.k. I'm not sure exactly why this works but I think it is a cool feature. You can wire a string of LEDs together then divide it into multiple "strips;"
for instance a 30 LED string connected to pin P0 could be set up with:
Strip#0 is LEDs 0 thru 10, Strip#1 is LEDs 11 thru 15, Strip#2 is LEDs 16 thru 23, and Strip#3 is LEDs 24 thru 29 (I believe the strips need to be consecutive).
You can then use the Set_Strip method to change just the LEDs defined in the "strip."
Mix and Match RGB and RGBW
Any strip can be either RGB or RGBW. This also works with the the above feature of dividing a strip into multiple strips. So on one txpin output you could run a string of RGB LEDs then wire in a string of RGBW then go back to RGB. Define it as 3 different strips on the same txpin and the driver will run them correctly.
Note: this feature does not do any RGBW to RGB math conversion. The white channel is just dropped off of the RGB strip.
Setup and change the direction of each strip
When running a method like a chase or color wipe this feature lets you change the direction of any or all strips. Instead of reading the RGBW buffer from the first to the last channel of the strip this will read it from last to first channel effectively reversing the direction.
When defining the default direction of the strip in Strip_Params use fwrd or rvrs.
When changing the direction in programming use strip.dir or strip.dir_all methods fwrd(normal), rvrs(backwards), tggl(toggle direction), or dflt(set back to default).
example: strip.dir_all (dflt) ' sets all strips to default direction
example: strip.dir (0, tggl) ' toggles strip#0's direction
Lastly and the part that needs the most work: Fading
Fading each pixel from any color to another. i.e. Fade to black
This is a system that sets a target RGBW value and compares it with the current RGBW value per channel. If they are not equal it compares each byte of the target and current R,G,B and W values and increments or decrements each byte of the current R,G,B,and W channel to eventually make the current RGBW and the target RGBW the same. The amount incremented or decremented can each be set for slower or faster transitions. I made it two different variables so that the fade in could be different than the fade out value.
Calling the strip.fade, strip.fade_fill, strip.fade_strip, or strip.fade_all methods only executes the compare and adjust method once, so you need repeat the method multiple times to see any change. The strip.fade_fill, strip.fade_strip, or strip.fade_all will return a value of how many LEDs were changed when running the compare method. This way you can choose to repeat those methods a certain number of times or until the amount of LEDs changed is zero; in other words all the LEDs current RGBW are the same as their target RGBW values.
Example:
repeat
time.pause(10)
until strip.fade_strip (0,$20_00_00_00, 1,2) == 0 'repeats loop until leds_chngd = 0
this will repeat the strip.fade_strip method until all of strip#0 LEDs are at $20_00_00_00. The increments the value is 1 the decrements value is 2
This is all working but I hope to make a few improvements.
Shorter strips of LEDs fade from one color to another faster than longer ones for obvious reasons; fewer LEDs to process.
On the short term I would like to implement a system that would make the processing of LEDs take the same amount of time whether the strip was long or short. I don't know enough about the clock and how long it takes to process each LED to fully implement this feature at this time.
Ultimately I would love to be able to set a target RGBW value and set how long I want it to take to get there and have the system compare and determine a pause time and increment/decrement value to reach that value.
I very much welcome any feedback. I am trying to get better at programming and would love to hear about any areas of my programming that need improvement, or just simpler ways of doing things.
Comments
This driver allows you to have as may strips as you have pins; you simply define an array and point to it. For example, if you have a string of 20 LEDs with the colors stored in a long array called strip1, you could do something like this
The first line sets the buffer to use and the number of pixels in it -- these are required by other methods in the driver
The second line fills that buffer with $FF_00_00
The final line sends that buffer to pixels connected to P15 on the Propeller.
Advantages:
-- no wasted RAM; app specifies size of array (I may update my standard driver to do this)
-- same array can be output to multiple strips
-- multiple arrays can be output to same strip (e.g., double-buffering for animation)
I'll get everything updated and into ObEx as soon as I can.
I see you've added an additional level of user-friendliness by letting us specify the color as #RED instead of having to look it up in the table.
Looking forward to it.
I'm glad you found the fade functionality useful. It was fun to write.
The ability to specify a color instead of having to look it up is already in the current demo
This demo is modified from one of Jon's (JohnnyMac's) other ws-2812 drivers so a lot of the functionality is similar.
You can change the color wipe to:
For fade to black try this: