Shop OBEX P1 Docs P2 Docs Learn Events
C code to work with WS2812 NeoPixel LEDs — Parallax Forums

C code to work with WS2812 NeoPixel LEDs

David BetzDavid Betz Posts: 14,516
edited 2015-06-04 19:53 in Propeller 1
Here is a sample program that uses the ws2812 LED control C code that I wrote based on JonnyMac's Spin code. Actually, the PASM driver is nearly identical to Jon's. I don't have anywhere near as many effects as he does but they're relatively easy to add. I'm planning to expand this to support my WS2812 Christmas ornament project.

I'll also attach a zip file containing all of the code and a Makefile to build it.

Old version with PropGCC Makefile: ws2812.zip
Newer version as a Simple Library for use with SimpleIDE: libws2812.zip (obsolete, use the one below)
Updated version that supports suppressing R/G swapping for use with the ws2811 as well as the ws2812: libws2812.zip
Yet another update switching to JonnyMac's "one shot" driver with some corresponding API changes: libws2812.zip <<< use this version
#include <propeller.h>
#include "ws2812.h"

// led chain
#define LED_PIN     13
#define LED_COUNT   4

// 4 Parallax WS2812B Fun Boards
uint32_t ledColors[LED_COUNT];

// LED driver state
ws2812_t driver;

// pattern for chase
uint32_t pattern[] = {
    COLOR_RED,
    COLOR_ORANGE,
    COLOR_YELLOW, 
    COLOR_GREEN,
    COLOR_BLUE,
    COLOR_INDIGO
};

#define pattern_count  (sizeof(pattern) / sizeof(pattern[0]))

// ticks per millisecond
int ticks_per_ms;

// forward declarations
void alternate(int count, int delay);
void chase(int count, int delay);
void pause(int ms);

int main(void)
{
    // calibrate the pause function
    // CLKFREQ is the clock frequency of the processor
    // typically this is 80mhz
    // dividing by 1000 gives the number of clock ticks per millisecond
    ticks_per_ms = CLKFREQ / 1000;
    
    // load the LED driver
    if (ws2812b_init(&driver) < 0)
        return 1;
        
    // repeat the patterns
    for (;;) {
    
        // alternate inner and outer colors
        alternate(8, 500);
        
        // chase
        chase(32, 200);
    }
           
    return 0;
}

void alternate(int count, int delay)
{
    // start with the outer two LEDs green and the inner two red
    ledColors[0] = COLOR_GREEN;
    ledColors[1] = COLOR_RED;
    ledColors[2] = COLOR_RED;
    ledColors[3] = COLOR_GREEN;

    // repeat count times or forever if count < 0
    while (count < 0 || --count >= 0) {
    
        // swap the inner and outer colors
        ledColors[0] = ledColors[1];
        ledColors[1] = ledColors[3];
        ledColors[2] = ledColors[3];
        ledColors[3] = ledColors[0];
    
        // update the LED chain
        ws2812_refresh(&driver, LED_PIN, ledColors, LED_COUNT);
            
        // delay between frames
        pause(delay);
    }
}

// the chase effect was translated from Spin code by Jon MacPhalen
void chase(int count, int delay)
{
    int base = 0;
    int idx, i;
    
    // repeat count times or forever if count < 0
    while (count < 0 || --count >= 0) {
    
        // fill the chain with the pattern
        idx = base;                             // start at base
        for (i = 0; i < LED_COUNT; ++i) {       // loop through connected leds
            ledColors[i] = pattern[idx];        // update channel color
            if (++idx >= pattern_count)              // past end of list?
                idx = 0;                        // yes, reset
        }
        if (++base >= pattern_count)            // update the base for the next time
            base = 0;
    
        // update the LED chain
        ws2812_refresh(&driver, LED_PIN, ledColors, LED_COUNT);
            
        // delay between frames
        pause(delay);
    }
}

void pause(int ms)
{
    waitcnt(CNT + ms * ticks_per_ms);
}
«1345

Comments

  • RetrobitsRetrobits Posts: 46
    edited 2013-12-20 17:58
    I also used spin2cpp on JonnyMac's spin files (driver and demo code), and it worked flawlessly.

    - Earl
  • David BetzDavid Betz Posts: 14,516
    edited 2013-12-20 18:12
    Retrobits wrote: »
    I also used spin2cpp on JonnyMac's spin files (driver and demo code), and it worked flawlessly.

    - Earl
    I know you can do that but I'd rather have a native C implementation.
  • JonnyMacJonnyMac Posts: 9,105
    edited 2013-12-21 08:32
    I also used spin2cpp on JonnyMac's spin files (driver and demo code), and it worked flawlessly.

    That's interesting to know -- may have to give it a try. That said... I understand David's point-of-view and agree with it; when I finally commit to C, I want to be writing code as it is intended to be written in that language.

    BTW... I'm thrilled so many people are having fun with the WS28xx drivers I've written. I was just in Steve Wang's ("Predator") shop yesterday working with his team trying to simulate fire with high intestity LEDs and steam (we have a working solution) -- controlled with a Propeller, of course. Who says LEDs aren't cool?
  • David BetzDavid Betz Posts: 14,516
    edited 2013-12-21 09:20
    JonnyMac wrote: »
    That's interesting to know -- may have to give it a try. That said... I understand David's point-of-view and agree with it; when I finally commit to C, I want to be writing code as it is intended to be written in that language.
    Partly I wanted to do it myself so that I could understand how it works. The spin2cpp approach is good if you just want to use an object as a black box.
  • jazzedjazzed Posts: 11,803
    edited 2013-12-21 09:26
    David Betz wrote: »
    The spin2cpp approach is good if you just want to use an object as a black box.
    Exactly.

    While it is nice that the tool works well in so many cases which is a great achievement, the resulting code in no way reflects the way C source should be written.

    There was one guy here who tried using spin2cpp output as source to be managed by source control and be a test subject for a review process. Certainly not an appropriate use.
  • skylightskylight Posts: 1,915
    edited 2013-12-21 12:31
    JonnyMac wrote: »

    BTW... I'm thrilled so many people are having fun with the WS28xx drivers I've written. I was just in Steve Wang's ("Predator") shop yesterday working with his team trying to simulate fire with high intestity LEDs and steam (we have a working solution) -- controlled with a Propeller, of course. Who says LEDs aren't cool?
    I've just purchased a neoPixel Ring and can't wait till I have time to try out your driver, The mention about simulating fire sounds very interesting and I hope you can get a video that would show the effect,you mention steam I'm presuming the hot stuff and wondered if those ultrasonic fogger discs might do the same trick without the danger of the heat?
  • JonnyMacJonnyMac Posts: 9,105
    edited 2013-12-21 13:06
    Thanks to David you can try the driver in Spin or C!

    We shot some test video on phones which looks better than real life! We're using 1W amber LEDs with a few reds through in, and I have a simple flame algorithm that I'm running on multiple channels (from an EFX-TEK HC-8+). I wish I could use WS2812s on this but I don't think they're bright enough, and we'd have to build special boards to achieve the required density. That said, I may order a couple of those Adafruit strips and try them when the shop re-opens in a couple weeks.
  • skylightskylight Posts: 1,915
    edited 2013-12-21 13:25
    Not sure if you can achieve the same effect with Leds but we used to simulate fire with lamps on dimmers and using sound to light, we found the best sound input was from radio discussion programmes as the speech is rather random.
  • RetrobitsRetrobits Posts: 46
    edited 2013-12-21 14:20
    David Betz wrote: »
    Partly I wanted to do it myself so that I could understand how it works. The spin2cpp approach is good if you just want to use an object as a black box.

    I completely understand. Auto-generated code, especially translating between languages, is rarely optimal, and is often hard to read. That said, I had a NeoPixel ring in my hot little hands, and time restrictions - I wanted to make a Christmas ornament. The protocol requirements for the WS2812 are pretty exacting, and I'm a PropGCC newb, so the black-box approach was the way to go. Not advocating that way in every case - just wanted to let people know it worked.

    - Earl
  • David BetzDavid Betz Posts: 14,516
    edited 2013-12-21 15:01
    Retrobits wrote: »
    I completely understand. Auto-generated code, especially translating between languages, is rarely optimal, and is often hard to read. That said, I had a NeoPixel ring in my hot little hands, and time restrictions - I wanted to make a Christmas ornament. The protocol requirements for the WS2812 are pretty exacting, and I'm a PropGCC newb, so the black-box approach was the way to go. Not advocating that way in every case - just wanted to let people know it worked.

    - Earl
    My project is to make a Christmas ornament as well. What code did you end up using? I know you used JonnyMac's Spin object but what code did you add on top of that to create your ornament effect?

    Actually, I think if I was just planning to use JonnyMac's object as-is I would probably have just left it in Spin. I did run his Spin code and Duane Degn's and both were impressive.
  • RetrobitsRetrobits Posts: 46
    edited 2013-12-22 14:36
    David Betz wrote: »
    My project is to make a Christmas ornament as well. What code did you end up using? I know you used JonnyMac's Spin object but what code did you add on top of that to create your ornament effect?

    I wrote a couple of my own routines to:

    - Do a red/green swirl color comet tail chase
    - Blink 3-5 random lights in the ring with white, doing a gradual up/down ramp on the intensity
    - Do a red/green full ring color mix with alternating colors

    The routines aren't that good :-) But if there's interest, I'll post them.

    - Earl
  • JonnyMacJonnyMac Posts: 9,105
    edited 2013-12-22 17:08
    This is the season of giving, Earl -- don't tease, post! We get better seeing how others have solved problems.
  • SRLMSRLM Posts: 5,045
    edited 2014-01-10 22:59
    Hey, this is pretty cool. I'm going to have to get some to play around with. Would you mind if I included a version of this code into libpropeller?

    BTW, most of the objects in libpropeller with ASM were converted with spin2cpp, including the same FFDS1 that the "one guy" tried converting. I did do quite a bit of work after the conversion to make sure things ran smoothly, but it's still in the pedigree. I think the objects turned out ok.

    spin2cpp converted objects:
    MCP3208
    PWM32
    FSRW
    FFDS1
  • David BetzDavid Betz Posts: 14,516
    edited 2014-01-11 08:30
    SRLM wrote: »
    Hey, this is pretty cool. I'm going to have to get some to play around with. Would you mind if I included a version of this code into libpropeller?
    If you're talking about my C interface to JonnyMac's PASM code for NeoPixels then you are welcome to use it in libpropeller. If I were going to release it, I'd probably try to improve my API a bit and I guess you'll want a C++ interface anyway. Do you have any guidelines for code in libpropeller? I'd be happy to morph my code to match your standards.
  • pmrobertpmrobert Posts: 673
    edited 2014-09-24 05:47
    Thank you, David, stuff like this is greatly appreciated!
  • NWCCTVNWCCTV Posts: 3,629
    edited 2014-09-24 21:26
    I'll also attach a zip file containing all of the code and a Makefile to build it.
    II have never done this before. How do I use the makefile to "build" the project?
  • David BetzDavid Betz Posts: 14,516
    edited 2014-09-25 06:00
    NWCCTV wrote: »
    II have never done this before. How do I use the makefile to "build" the project?
    You have to create a command window and run the command line tools. However, maybe instead I should just make a SimpleIDE project for this. I can try making the project tonight but I don't have any WS2812 LEDs with me at the moment so I don't be able to verify it until I get home on Friday night.
  • DavidZemonDavidZemon Posts: 2,973
    edited 2014-09-25 06:10
    NWCCTV wrote: »
    II have never done this before. How do I use the makefile to "build" the project?

    As David Betz mentioned, it needs to be done from the command prompt (quite easy!). Since this is your first time though, there's one quick step involved first: telling the command prompt where PropGCC and Make are located.

    Instructions for this are all over the internet, including plastered right onto the Google search results: https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#safe=off&q=how to set environment variables windows
    The variable name you need to add is "PATH" and the value needs to be set to wherever propeller-elf-gcc.exe is installed. For instance, I have PropGCC installed to C:\propgcc, so I would set it like so:

    Capture.PNG


    IF there is already a variable called path, simply add your value to end of it with a single semicolon separating your value from the old one (no spaces)

    Woohoo! All done with setup.

    Now, open a file browser navigate to the contents of that zip file. Hold "shift" and right click in the window (not on top of a file or folder). There should be an option in the menu that says "Open command window here". Click it. Type "make" and press enter. All done :)
    431 x 505 - 63K
    418 x 495 - 62K
  • NWCCTVNWCCTV Posts: 3,629
    edited 2014-09-25 09:48
    Where can I download PropGCC from?
  • David BetzDavid Betz Posts: 14,516
    edited 2014-09-25 09:50
    NWCCTV wrote: »
    Where can I download PropGCC from?
    The easiest way is just to install SimpleIDE which includes release_1_0 of PropGCC. You then just need to set your PATH to point to the directory containing propeller-elf-gcc.exe and you should be able to use the command line tools.
  • NWCCTVNWCCTV Posts: 3,629
    edited 2014-09-25 10:04
    Thanks David. I just figured that one out as I already have SimpleIDE installed.
  • PublisonPublison Posts: 12,366
    edited 2014-09-25 10:12
    NWCCTV wrote: »
    Where can I download PropGCC from?

    https://code.google.com/p/propgcc/
  • DavidZemonDavidZemon Posts: 2,973
    edited 2014-09-25 10:15
    Thanks David - that's an important correction regarding propeller-elf-gcc.exe. I've fixed my post accordingly
  • NWCCTVNWCCTV Posts: 3,629
    edited 2014-09-25 10:26
    I am getting a "make is not recognized as an internal or external command, operable program or batch file" error.
  • DavidZemonDavidZemon Posts: 2,973
    edited 2014-09-25 10:33
    NWCCTV wrote: »
    I am getting a "make is not recognized as an internal or external command, operable program or batch file" error.

    A few possibilities....
    If you changed the environment variable (or created it) after opening the terminal, that won't work. You'll need to close the terminal and then reopen it.

    Can you show us the output of
    echo %PATH%
    
    ?
  • NWCCTVNWCCTV Posts: 3,629
    edited 2014-09-25 13:08
    Microsoft Windows [Version 6.1.7601]
    Copyright (c) 2009 Microsoft Corporation. All rights reserved.
    C:\Users\Andyn.NWUPGRADESPLUS>echo %PATH%
    C:\Program Files\Common Files\Microsoft Shared\Windows Live;C:\windows\system32;
    C:\windows;C:\windows\System32\Wbem;C:\windows\System32\WindowsPowerShell\v1.0\;
    C:\Program Files\WIDCOMM\Bluetooth Software\;C:\Program Files\Windows Live\Share
    d;;C:\Program Files\SimpleIDE\propeller-gcc\bin;C:\Program Files\Microsoft SQL S
    erver\100\Tools\Binn\;C:\Program Files\Microsoft SQL Server\100\DTS\Binn\;C:\Pro
    gram Files\SimpleIDE\propeller-gcc\bin
    C:\Users\Andyn.NWUPGRADESPLUS>
  • DavidZemonDavidZemon Posts: 2,973
    edited 2014-09-25 13:24
    NWCCTV wrote: »
    Microsoft Windows [Version 6.1.7601]
    Copyright (c) 2009 Microsoft Corporation. All rights reserved.
    C:\Users\Andyn.NWUPGRADESPLUS>echo %PATH%
    C:\Program Files\Common Files\Microsoft Shared\Windows Live;C:\windows\system32;
    C:\windows;C:\windows\System32\Wbem;C:\windows\System32\WindowsPowerShell\v1.0\;
    C:\Program Files\WIDCOMM\Bluetooth Software\;C:\Program Files\Windows Live\Share
    d;;C:\Program Files\SimpleIDE\propeller-gcc\bin;C:\Program Files\Microsoft SQL S
    erver\100\Tools\Binn\;C:\Program Files\Microsoft SQL Server\100\DTS\Binn\;C:\Pro
    gram Files\SimpleIDE\propeller-gcc\bin
    C:\Users\Andyn.NWUPGRADESPLUS>

    I notice a newline that probably shouldn't be there following the PropGCC installation - also, no semicolon following it. You should closely inspect the value of the PATH variable and fix it. To make this easier, you might copy the value and paste it into Notepad or your favorite text editor, make the modifications, and then paste it back into the value box.
  • NWCCTVNWCCTV Posts: 3,629
    edited 2014-09-25 14:12
    Here is the actual output. The first one was incorrect. I see nothing different.

    C:\Users\Andyn.NWUPGRADESPLUS>echo %PATH%
    C:\Program Files\Common Files\Microsoft Shared\Windows Live;C:\windows\system32;
    C:\windows;C:\windows\System32\Wbem;C:\windows\System32\WindowsPowerShell\v1.0\;
    C:\Program Files\WIDCOMM\Bluetooth Software\;C:\Program Files\Windows Live\Share
    d;;C:\Program Files\SimpleIDE\propeller-gcc\bin;C:\Program Files\Microsoft SQL S
    erver\100\Tools\Binn\;C:\Program Files\Microsoft SQL Server\100\DTS\Binn\;C:\Pro
    gram Files\SimpleIDE\propeller-gcc\bin
  • DavidZemonDavidZemon Posts: 2,973
    edited 2014-09-25 15:01
    NWCCTV wrote: »
    Here is the actual output. The first one was incorrect. I see nothing different.

    C:\Users\Andyn.NWUPGRADESPLUS>echo %PATH%
    C:\Program Files\Common Files\Microsoft Shared\Windows Live;C:\windows\system32;
    C:\windows;C:\windows\System32\Wbem;C:\windows\System32\WindowsPowerShell\v1.0\;
    C:\Program Files\WIDCOMM\Bluetooth Software\;C:\Program Files\Windows Live\Share
    d;;C:\Program Files\SimpleIDE\propeller-gcc\bin;C:\Program Files\Microsoft SQL S
    erver\100\Tools\Binn\;C:\Program Files\Microsoft SQL Server\100\DTS\Binn\;C:\Pro
    gram Files\SimpleIDE\propeller-gcc\bin

    Looks reasonable to me. Is "make.exe" in that folder? It should be. But with PATH being set correctly, I can't imagine any other reason why cmd wouldn't find it.

    I don't know why make.exe wouldn't be in C:\Program Files\SimpleIDE\propeller-gcc\bin. It should be. If it isn't. try downloading a new version of PropGCC (i have a package with 1.9.0 here) and replace C:\Program Files\SimpleIDE\propeller-gcc with the new version. Make sure the folder is still named the same thing of course.
  • NWCCTVNWCCTV Posts: 3,629
    edited 2014-09-25 17:46
    Now I get the following error:

    C:\Users\Andyn.NWUPGRADESPLUS\Downloads\ws2812>make
    process_begin: CreateProcess(NULL, spin2cpp --dat -o ws2812_driver.dat ws2812_dr
    iver.spin, ...) failed.
    make (e=2): The system cannot find the file specified.
    make: *** [ws2812_driver.dat] Error 2
Sign In or Register to comment.