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

C code to work with WS2812 NeoPixel LEDs

124

Comments

  • NWCCTVNWCCTV Posts: 3,629
    edited 2014-10-11 20:15
    So I got the loop problem resolved. Now, in the code in post# 80, where exactly are the below commands pulling the colors from? For the last command I understand, but not this part.
    // ws2812_fill_wheel_continuous_dim(colors, LED_COUNT, LED_COUNT+5, 128, 100);// ws2812_fill_wheel_continuous(colors, LED_COUNT, LED_COUNT+5, 100);
    
  • David BetzDavid Betz Posts: 14,516
    edited 2014-10-12 03:57
    NWCCTV wrote: »
    So I got the loop problem resolved. Now, in the code in post# 80, where exactly are the below commands pulling the colors from? For the last command I understand, but not this part.
    // ws2812_fill_wheel_continuous_dim(colors, LED_COUNT, LED_COUNT+5, 128, 100);// ws2812_fill_wheel_continuous(colors, LED_COUNT, LED_COUNT+5, 100);
    
    Those functions use ws2812_wheel_dim to generate a color from an 8 bit value from 0-255 that covers the color spectrum.
  • NWCCTVNWCCTV Posts: 3,629
    edited 2014-10-12 09:17
    So how do I change them?
  • David BetzDavid Betz Posts: 14,516
    edited 2014-10-12 10:03
    NWCCTV wrote: »
    So how do I change them?
    What kind of effect are you trying to achieve? The only thing these functions really do is stuff values in the colors array, one for each LED. You can get any effect you want by just storing into that array. The functions are just easy ways to get particular effects.
  • NWCCTVNWCCTV Posts: 3,629
    edited 2014-10-12 13:15
    I just want to get different colors.
  • David BetzDavid Betz Posts: 14,516
    edited 2014-10-12 13:21
    NWCCTV wrote: »
    I just want to get different colors.
    Have you experimented with just storing different RGB values into the colors array to see if you can create the effect you want? You can get any RGB color by using the COLOR or COLORX macros. To do animations just create a loop that changes the RGB values in the colors array and then executes a ws2812_pause before the next iteration. You can control the "frame rate" by adjusting the length of that pause. For a simple example, just fill the colors array with COLOR(255, 0, 0) to get all red or COLOR(0, 255, 0) to get all green or COLOR(0, 0, 255) to get all blue.
  • TubularTubular Posts: 4,702
    edited 2014-10-12 15:17
    Most leds are "RGB" in terms of bit order, but a few (WS2812 and clones) are GRB
  • David BetzDavid Betz Posts: 14,516
    edited 2014-10-12 15:20
    Tubular wrote: »
    Most leds are "RGB" in terms of bit order, but a few (WS2812 and clones) are GRB
    Are those the only bit orders you know of? Is there any need to support anything other than RGB and GRB? No, for instance, BGR LEDs out there?
  • NWCCTVNWCCTV Posts: 3,629
    edited 2014-10-12 15:45
    I am confused as to where the "colors array" is located.
  • David BetzDavid Betz Posts: 14,516
    edited 2014-10-12 16:02
    The array called "colors" in the code below. Each entry in that array is the RGB value sent to the corresponding LED in the chain. For example, colors[0] will be the RGB color of the first LED in the chain, colors[1] will be the RGB value of the second LED in the chain, etc. If you want the first LED to be red, then set colors[0] to COLOR(255, 0, 0) and so on.
    #include <stdint.h>
    #include <propeller.h>
    #include "ws2812.h"
    
    #define LED_PIN 15
    #define LED_COUNT 16
    
    int main(void)
    {
        uint32_t colors[LED_COUNT];
        int cog;
    
        ws2812_clock_init();
    
        memset(colors, 0, sizeof(colors));
        if ((cog = ws2812_init(LED_PIN, colors, LED_COUNT, SWAP_NONE)) < 0)
            return 1;
    
        for (;;) {
            // do whatever you want to change the values in colors[]
            ws2812_pause(500);
        }
    
        cogstop(cog);
    
        return 0;
    }
    
  • TubularTubular Posts: 4,702
    edited 2014-10-13 00:59
    David Betz wrote: »
    Are those the only bit orders you know of? Is there any need to support anything other than RGB and GRB? No, for instance, BGR LEDs out there?

    They're the only two I've seen so far David.

    I need to do some broader research on these leds and variants for a few presentations soon, so will let you know if I find otherwise
  • NWCCTVNWCCTV Posts: 3,629
    edited 2014-10-13 17:45
    I am confused as to exactly where the following statement goes in the code.
    colors[0]  COLOR(255, 0, 0)
    
  • David BetzDavid Betz Posts: 14,516
    edited 2014-10-21 17:33
    How do people feel about C vs. C++? I know many of you like Spin and that is fine but you are served well by JonnyMac's driver. I'm trying to decide whether to concentrate on a C or a C++ interface to Jon's PASM driver. Parallax seems to favor C for their Learn tutorials but I think that C++ matches the Spin object model better. Some will say that C++ is too memory intensive for the Propeller but if used judiciously it can be just as compact as C. Look at what SwimDude0614 has done with PropWare. Of course, I can provide both a C and a C++ interface but I'm interested to hear which people think they would be more likely to use. Any opinions?
  • mindrobotsmindrobots Posts: 6,506
    edited 2014-10-21 17:57
    David Betz wrote: »
    Some will say that C++ is too memory intensive for the Propeller but if used judiciously it can be just as compact as C.

    If using C++ judiciously is not easily done by a novice C or C++ programmer, then I've go for C if it can keep more people out of trouble,If common practices in C++ can lead people to memory abuse and frustration and then abandonment of the Propeller because they didn't know the few "easy" tricks that veteran C++ programmers know will lead to judicious memory use, then the benefits of C++ doesn't outweigh the potential cost.

    If it is obvious to someone new to C++ how to use it judiciously, then go for it because the model is nicer even though it strays from Learn.
  • David BetzDavid Betz Posts: 14,516
    edited 2014-10-21 18:10
    mindrobots wrote: »
    If using C++ judiciously is not easily done by a novice C or C++ programmer, then I've go for C if it can keep more people out of trouble,If common practices in C++ can lead people to memory abuse and frustration and then abandonment of the Propeller because they didn't know the few "easy" tricks that veteran C++ programmers know will lead to judicious memory use, then the benefits of C++ doesn't outweigh the potential cost.

    If it is obvious to someone new to C++ how to use it judiciously, then go for it because the model is nicer even though it strays from Learn.
    The fact is, it is easy to misuse C as well if you make use of large libraries and floating point. I think one needs to learn the limitations of an MCU platform to use pretty much any language. Maybe that is one area where Spin has an advantage. Since it isn't available for any other platform, by definition all Spin code will run on the Propeller. This can't be said of C or C++ or even Basic or any "standard" language that has implementations on platforms with larger amounts of memory. I guess I can't say for sure if it is easy to teach beginners to stick with a memory-efficient subset of C++ since I've never taught beginners. Certainly, you could provide a set of guidelines that would keep beginners out of a lot of trouble like avoiding the standard C++ library (like Parallax has suggested that they avoid the C standard library) and avoid any construct that allocates memory from the heap. That is what I did with the C++ library for RGB LEDs that I mentioned in a post a while back. What you can't prevent is beginners or anyone from dredging the internet for sample code that was intended to run on a PC and trying to shoehorn it into a Propeller. That usually won't work in either C or C++.
  • DavidZemonDavidZemon Posts: 2,973
    edited 2014-10-21 18:11
    mindrobots wrote: »
    If using C++ judiciously is not easily done by a novice C or C++ programmer...

    That's a question I haven't asked before... but I think a very very good one. This is way off topic, but I think I'll start another page in the PropWare docs that contains some dos and don'ts of C++ coding. There isn't much... but some simple stuff like "don't use anything from the std namespace. avoid new. if using inheritance, only use virtual when required." I don't want to start a whole brainstorming session here - but David, what do you think? Could a simple docs page help solve the problem of novice C++ programmers hitting code bloat?
  • David BetzDavid Betz Posts: 14,516
    edited 2014-10-21 18:18
    That's a question I haven't asked before... but I think a very very good one. This is way off topic, but I think I'll start another page in the PropWare docs that contains some dos and don'ts of C++ coding. There isn't much... but some simple stuff like "don't use anything from the std namespace. avoid new. if using inheritance, only use virtual when required." I don't want to start a whole brainstorming session here - but David, what do you think? Could a simple docs page help solve the problem of novice C++ programmers hitting code bloat?
    I think it could but I'm not sure my intuition is necessarily accurate. I have a hard time putting myself in the place of a beginner. While I'm certainly no C++ expert, I know enough about how the language works to avoid using constructs that will get me into trouble. Actually, that brings up something that has bugged me. It doesn't seem like modern programmers have much of a concept of how a language maps to the hardware so they have very little idea how much overhead any particular language construct might introduce. Aren't programming languages and compilers that generate machine code taught anymore?
  • David BetzDavid Betz Posts: 14,516
    edited 2014-10-21 18:24
    David Betz wrote: »
    IActually, that brings up something that has bugged me. It doesn't seem like modern programmers have much of a concept of how a language maps to the hardware so they have very little idea how much overhead any particular language construct might introduce. Aren't programming languages and compilers that generate machine code taught anymore?

    (hmmm... talking to myself!)

    Now that I think more about this, it isn't really relevant to this discussion. We're probably not talking about CS majors here. We're talking about "makers" who want to build something with LEDs and a Propeller board. They will probably just cut/paste code from some sample and hack it to get it to do what they want. They may never fully understand how it works. In that case, I guess the guidelines document is probably the best approach.
  • DavidZemonDavidZemon Posts: 2,973
    edited 2014-10-21 18:28
    David Betz wrote: »
    (hmmm... talking to myself!)

    Now that I think more about this, it isn't really relevant to this discussion. We're probably not talking about CS majors here. We're talking about "makers" who want to build something with LEDs and a Propeller board. They will probably just cut/paste code from some sample and hack it to get it to do what they want. They may never fully understand how it works. In that case, I guess the guidelines document is probably the best approach.

    I was seconds away from posting exactly that. We're not talking about professional or educated programmers.
  • David BetzDavid Betz Posts: 14,516
    edited 2014-10-21 18:36
    I've been enticed by Jon's alternate version of his driver that does "single shot" updates of LED chains. In fact, I'd like to move to that model entirely since it seems more flexible. However, I'm wondering if it might be good to take one more step in that direction than Jon has so far. His single-shot driver takes all of the timing parameters during COG initialization and they remain in effect until the COG is reloaded. I'm wondering if it might make sense to pass those in on each update so that a single COG could drive more than one chain of LEDs each of which requires different timing. I'm thinking that you might want to use some of the Parallax "fun boards" along with some of the through-hole RGB LEDs that are RGB rather than GRB and may require different timing as well. I guess you could handle that with Jon's driver by just loading a separate COG with each different set of timing parameters so that a single COG only has to handle one type of LED but passing these parameters on each update call doesn't introduce that much overhead and makes it possible to drive different types of LED with the same COG.
  • David BetzDavid Betz Posts: 14,516
    edited 2014-10-25 18:17
    David Betz wrote: »
    I've been enticed by Jon's alternate version of his driver that does "single shot" updates of LED chains. In fact, I'd like to move to that model entirely since it seems more flexible. However, I'm wondering if it might be good to take one more step in that direction than Jon has so far. His single-shot driver takes all of the timing parameters during COG initialization and they remain in effect until the COG is reloaded. I'm wondering if it might make sense to pass those in on each update so that a single COG could drive more than one chain of LEDs each of which requires different timing. I'm thinking that you might want to use some of the Parallax "fun boards" along with some of the through-hole RGB LEDs that are RGB rather than GRB and may require different timing as well. I guess you could handle that with Jon's driver by just loading a separate COG with each different set of timing parameters so that a single COG only has to handle one type of LED but passing these parameters on each update call doesn't introduce that much overhead and makes it possible to drive different types of LED with the same COG.
    I guess I've decided not to add this additional level of abstraction. As has been pointed out to me, it is unlikely that someone will use multiple types of LEDs in the same project. And, even if they do, they can always use another COG for the LEDs that use different parameters.
  • David BetzDavid Betz Posts: 14,516
    edited 2014-10-25 18:35
    Here is that basic C++ API I've setup to work with chains of WS2812 LEDs. I have two main classes: ws2812 and ws2812b for the two types of LEDs that I've had experience using. I also have a base class called ws2812x where it is possible to specify all of the timing parameters and the RGB/GRB settings directly for handling other types of LEDs that might require different settings. This mirrors what Jon did in his Spin code.
    class ws2812x {
    public:
        enum {
            kRGB,
            kGRB    // for WS2812 and WS2812B
        };
        ws2812x(int usreset, int ns0h, int ns0l, int ns1h, int ns1l, int type);
        ~ws2812x();
        bool running() { return m_cog != -1; }
        void refresh(ws2812_Chain &chain);
    private:
        volatile uint32_t m_command;
        int m_cog;
    };
    
    class ws2812 : public ws2812x {
    public:
        ws2812() : ws2812x(50, 350, 800, 700, 600, kGRB) {}
        ~ws2812() {}
    };
    
    class ws2812b : public ws2812x {
    public:
        ws2812b() : ws2812x(50, 350, 900, 900, 350, kGRB) {}
        ~ws2812b() {}
    };
    
    Here is a simple program that uses these classes:
    #include <propeller.h>
    #include "ws2812.h"
    
    /* led chain */
    #define LED_PIN     13
    #define LED_COUNT   4
    
    int main(void)
    {
        // create an LED driver object and load the driver into a COG
        ws2812b driver;
        
        // make sure the driver actually started successfully
        if (!driver.running())
            return 1;
    
        // 4 Parallax WS2812B Fun Boards
        uint32_t ledColors[LED_COUNT];                      // array to hold the colors of each LED in the chain
        ws2812_Chain leds(LED_PIN, ledColors, LED_COUNT);   // chain object
        
        // 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;
        
        // animate the LED colors
        for (;;) {
        
            // 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
            driver.refresh(leds);
                
            // delay between frames
            waitcnt(CNT + CLKFREQ);
        }
               
        return 0;
    }
    

    Here is a zip file containing the source code. The example above is in the file test2.cpp.

    ws2812.zip
  • David BetzDavid Betz Posts: 14,516
    edited 2014-10-26 09:13
    Here is a C version of the code in message #113:
    #include <propeller.h>
    #include "ws2812.h"
    
    /* led chain */
    #define LED_PIN     13
    #define LED_COUNT   4
    
    int main(void)
    {
        
        uint32_t ledColors[LED_COUNT];  // 4 Parallax WS2812B Fun Boards
        ws2812_t driver;
        
        // load the LED driver
        if (ws2812_init(&driver) < 0)
            return 1;
            
        // 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;
        
        // animate the LED colors
        for (;;) {
        
            // 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
            waitcnt(CNT + CLKFREQ);
        }
               
        return 0;
    }
    

    Here is a zip file containing the source code. The example above is in the file test2.c.

    ws2812-c.zip
  • David BetzDavid Betz Posts: 14,516
    edited 2014-10-26 14:17
    Here is a more complicated example that shows how Jon's "single shot" driver can handle more than one chain of LEDs at the same time. This controls a 16 LED ring using the algorithm I used last year for my Christmas tree ornament as well as four of the Parallax WS2812B modules. Notice that both chains of LEDs are handled by the same driver by separate calls to the ws2812_refresh functions for each chain.
    #include <propeller.h>
    #include "ws2812.h"
    
    /* fun board chain */
    #define FUN_LED_PIN         13
    #define FUN_LED_COUNT       4
    
    /* led ring */
    #define RING_LED_PIN        15
    #define RING_LED_COUNT      16
    
    /* animation settings */
    #define RING_SAMPLE_COUNT    (RING_LED_COUNT + 5)
    #define RING_BRIGHTNESS      128
    
    /* delay between animation frames */
    #define DELAY               (CLKFREQ / 6)
    
    int main(void)
    {
        uint32_t ringColors[RING_LED_COUNT];
        uint32_t funColors[FUN_LED_COUNT];
        ws2812_t driver;
        int i = 0, di = 1;
        int j = 0;
        
        // load the LED driver
        if (ws2812_init(&driver) < 0)
            return 1;
            
        // start the Parallax WS2812B boards with the outer two LEDs green and the inner two red
        funColors[0] = COLOR_GREEN;
        funColors[1] = COLOR_RED;
        funColors[2] = COLOR_RED;
        funColors[3] = COLOR_GREEN;
        
        // start the ring with all black
        memset(ringColors, 0, sizeof(ringColors));
        
        // animate the LED colors
        for (;;) {
        
            // swap the inner and outer colors of the Parallax WS2812B boards
            funColors[0] = funColors[1];
            funColors[1] = funColors[3];
            funColors[2] = funColors[3];
            funColors[3] = funColors[0];
        
            // fill in the next ring color
            ringColors[i] = ws2812_wheel_dim(j * (255 / RING_SAMPLE_COUNT), RING_BRIGHTNESS);
    
            // setup for the next frame
            i += di;
            if (i >= RING_LED_COUNT) {
                di = -1;
                --i;
            }
            else if (i < 0) {
                di = 1;
                ++i;
            } 
            if (++j >= RING_SAMPLE_COUNT)
                j = 0;    
            
            // update the LED fun boards
            ws2812_refresh(&driver, FUN_LED_PIN, funColors, FUN_LED_COUNT);
    
            // update the LED ring
            ws2812_refresh(&driver, RING_LED_PIN, ringColors, RING_LED_COUNT);
                
            // delay between frames
            waitcnt(CNT + DELAY);
        }
               
        return 0;
    }
    
  • David BetzDavid Betz Posts: 14,516
    edited 2014-10-29 04:14
    I just posted an update to the code in the top post of this thread along with some sample code that will work with an array of the new Parallax WS2812B boards.
  • NWCCTVNWCCTV Posts: 3,629
    edited 2015-01-25 13:02
    So with the Super Bowl fast approaching I have decided to honor our Seahawks by throwing a party. I have several strips of the WS2811 and WS 2812B LED's. I will be controlling them via Prop Demo Boards. All the power issues, etc. are all figured out. What is not figured out is some really cool sequences of the Blue and Green of the RGB LED's. I currently have them so they can blink all 33 LED's on and off in Green and Blue but I would also like to make the Blue chase the Green and vice versa and possibly some other cool blink and chase modes. I am currently using code from post # 83 but I can only use the last part of the program and that is what is running to blink Blue and Green. Any suggestions?
  • NWCCTVNWCCTV Posts: 3,629
    edited 2015-01-25 14:20
    When attempting to run the code in post #114, I get this error: libws2812.c:18:5: error: too few arguments to function 'ws2812_init'

    Any suggestions? My main program for the RGB LED's does not have an issue with the ws21812_init command.
  • David BetzDavid Betz Posts: 14,516
    edited 2015-01-25 15:39
    NWCCTV wrote: »
    When attempting to run the code in post #114, I get this error: libws2812.c:18:5: error: too few arguments to function 'ws2812_init'

    Any suggestions? My main program for the RGB LED's does not have an issue with the ws21812_init command.
    What code are you using? There is no file called libws2812.c in the zip file attached to post #114.
  • NWCCTVNWCCTV Posts: 3,629
    edited 2015-01-25 15:51
    Just the code in post #114. The libws2812.c is the name of the project. Also, please see post #117 as this is what I am trying to do. I have been messing with this all day and can not get a grip on it. I even tried to modify Jonny Mac's ws2812 driver to only show Blue and Green but I can not figure that out either.
  • David BetzDavid Betz Posts: 14,516
    edited 2015-01-25 15:57
    NWCCTV wrote: »
    Just the code in post #114. The libws2812.c is the name of the project. Also, please see post #117 as this is what I am trying to do. I have been messing with this all day and can not get a grip on it. I even tried to modify Jonny Mac's ws2812 driver to only show Blue and Green but I can not figure that out either.
    Can you post a zip file containing all of your sources?
Sign In or Register to comment.