SimpleIDE program for Neopixels 2811 through 6812RGBW

I started with David Betz's ws2812 program that was already set up to easily support other strips and seeing that that program was based on JonnyMac's Spin code that ws recently updated to support RGBW strips I was able to get something working pretty quickly.

I'm having a couple issues with what I have so far.

If you have a strip of pixels that is longer than the quantity of pixels you are trying to run some of the pixels outside that range are turning on to a random color.
example: 24 strip of pixels, code is set to run only 10 pixels. Pixels 14 and 15 might turn green or pink and not change.

The other part is that I was hoping to be able to have the driver be able to use RGB 0xRRGGBB format or RGBW 0xRRGGBBWW format automatically so that other drivers like color pickers or color sensors wouldn't need to be changed.

It seems like older RGB programs do pack the 24bit information into 32bit longs but do it as 0x00RRGGBB format. I made a few attempts at trying to shift the bits around in programming but never got what I wanted. Even went back and studied JonnyMac's Nut and Volts article for the original code and how it moves bits around but still no luck yet.

I settled on 0xRRGGBBWW for now.
"Keep moving forward" - Meet the Robinsons
«1

Comments

  • 38 Comments sorted by Date Added Votes
  • If you have a strip of pixels that is longer than the quantity of pixels you are trying to run some of the pixels outside that range are turning on to a random color.

    These low-cost pixels aren't perfect, and occasionally subject to "glitches," especially if you try to drive the data too fast. This is why my latest driver allows the developer to set the rest time between refresh cycles.

    My latest driver uses $RRGGBBWW format for all pixel types. If you have 24-bit pixels the LSB is never shifted out, hence irrelevant. I don't know what happens to Spin/PASM when it gets translated to C, but it always looks like a train wreck. This is why I develop in Spin.
    Jon McPhalen
      *It's "Jon" or "JonnyMac" -- please don't call me "Jonny"
  • JonnyMac wrote: »
    I don't know what happens to Spin/PASM when it gets translated to C, but it always looks like a train wreck. This is why I develop in Spin.
    Thanks for the compliment.

  • JonnyMacJonnyMac Posts: 5,799
    edited July 24 Vote Up0Vote Down
    My comment wasn't a personal attack -- I assumed that code was translated using an application. It would be nice if C was as easy to follow as Spin, but I don't think that will ever be the case. Spin was designed for multicore and has an elegance to its approach; this is not true of C (vis-a-vis the Propeller).
    Jon McPhalen
      *It's "Jon" or "JonnyMac" -- please don't call me "Jonny"
  • Spin that is translated with spin2cpp does come out looking like a "train wreck". But that is because spin2cpp has to handle features that are unique to the way Spin was implemented. One of the main complications is that Spin code can access method parameter as a long array. This requires that spin2cpp copy the calling parameters to an array, and it accesses them from the array.

    The nice thing about Spin is it's simplicity and limited features. This makes it easy for newbies to learn it, and people can master it in a month or two.

    Spin really only has a couple of features that handle the multicore nature of the Prop. The multicore support basically consists of cognew/coginit and the lock instructions. The rest of Spin is really only relevant to a single core. The C libraries contain a significant amount of support for multicore and multitasking. Of course, it's harder to learn and master because of the flexibility it provides.
  • JonnyMac wrote: »
    My comment wasn't a personal attack -- I assumed that code was translated using an application. It would be nice if C was as easy to follow as Spin, but I don't think that will ever be the case. Spin was designed for multicore and has an elegance to its approach; this is not true of C (vis-a-vis the Propeller).
    I'm not sure I really see much difference between the C code I wrote and your original Spin code except that the Spin code included the PASM driver in the same file.
  • JonnyMac wrote: »
    It would be nice if C was as easy to follow as Spin, but I don't think that will ever be the case. Spin was designed for multicore and has an elegance to its approach; this is not true of C (vis-a-vis the Propeller).

    Are you trying to start another language war? You do know that that is an opinion, right? At best you could argue that, in a hypothetical world where no one knows either C or Spin, Spin is easier to learn. But that's a moot point because we clearly don't live in that world.

    My question is (mostly) rhetorical. I know (am pretty darned sure) you weren't trying to start a language war. But you do know statements like "It would be nice if C was as easy to follow as Spin" are surefire ways to trigger such a thread...
    David
    PropWare: C++ HAL (Hardware Abstraction Layer) for PropGCC; Robust build system using CMake; Integrated Simple Library, libpropeller, and libPropelleruino (Arduino port); Instructions for Eclipse and JetBrain's CLion; Example projects; Doxygen documentation
  • DavidZemon wrote: »
    JonnyMac wrote: »
    It would be nice if C was as easy to follow as Spin, but I don't think that will ever be the case. Spin was designed for multicore and has an elegance to its approach; this is not true of C (vis-a-vis the Propeller).

    Are you trying to start another language war? You do know that that is an opinion, right? At best you could argue that, in a hypothetical world where no one knows either C or Spin, Spin is easier to learn. But that's a moot point because we clearly don't live in that world.

    My question is (mostly) rhetorical. I know (am pretty darned sure) you weren't trying to start a language war. But you do know statements like "It would be nice if C was as easy to follow as Spin" are surefire ways to trigger such a thread...
    The one big advantage that Spin has that I can see is that you can mix Spin and PASM in the same file. That, for some, is a huge advantage and may be the main reason for many claiming that Spin is superior. It's hard to argue with that short of providing a preprocessor for C that allows you to embed PASM code in a .c file. That would, of course, be possible but then programs written using that facility wouldn't really be C programs anymore. There is also the argument that Spin does not require every function to be defined twice, once in a .c file and once in a .h file. This is also a valid criticism.

  • David, I played around with the idea of using a preprocessor, but I didn't see much advantage in using it. The preprocessor was pretty easy to write. I tried writing a few programs with it. However, it was just as easy for me to use separate C and assembly files than it was to combine them. The only minor advantage is to pre-populate variables with values in the hub image before starting a cog. That can be done in other ways either by having a known offset where all the variables reside, or by just passing a pointer to a struct containing all the values needed when starting up the cog. Personally, I don't see that combining Spin and PASM into one file is much of an advantage.
  • JonnyMacJonnyMac Posts: 5,799
    edited July 24 Vote Up0Vote Down
    Are you trying to start another language war?
    Of course not. But to prevent any further possibility of causing offense, I will bow out of participating in forum threads, and stop posting code in ObEx.
    Jon McPhalen
      *It's "Jon" or "JonnyMac" -- please don't call me "Jonny"
  • Three Davids against one Jon is not fair. I suggest we declare a truce and join our forces against the dark side of the Forth. :)
  • Jon, please don't.

    The C crowd is just thin skinned, because of lack of support. Neither Parallax nor a lot of us Spin/Pasm users even try to use such goodies as Spin2Cpp.

    I think Dave, David and Eric put a lot of effort into this 'and nobody notices, nobody cares' like Carlin used to say.

    I personally really enjoy reading your code, and over the years learned a lot from you. Not just about Spin and Pasm, but the art of coding.

    You are one of the lucky persons, able to use the Propeller, Spin and Pasm in your work environment, so you have gratification for what you are doing, not just financial, but also thru happy customers and customers(visitors?) of them.

    But David, Dave & Co do all of this in there spare time and -hmm - seem to feel that nobody wants it and that even a strong wind is blowing against them.

    Which is sad, but understandable.

    My understanding is, that C/C++ was supposed to run on the P2, but got used on the P1 for the lack of a P2. And the P1 is quite restrained in Memory, so getting C/C++ running there was the second choice.

    On the P2 however, C/C++ will be way more important and also way more usable. So @Ken's decision to go the PropGCC route is correct by all means, and all of us Spinners will have Spin2 to move on to the next bigger, faster, Propeller without much hassle. At least I hope so.

    So please Jon, don't.

    Mike

    I am just another Code Monkey.

    A determined coder can write COBOL programs in any language. -- Author unknown.

    The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this post are to be interpreted as described in RFC 2119.
  • Dave Hein wrote: »
    Three Davids against one Jon is not fair. I suggest we declare a truce and join our forces against the dark side of the Forth. :)
    I'm certainly not against Jon. He has made many wonderful contributions both in code and advice over many years. I was just surprised by his comment.

    Jon: Please don't hold back on my account. I'll try to thicken my skin a bit in the future. :-)

  • David BetzDavid Betz Posts: 11,472
    edited July 25 Vote Up0Vote Down
    Dave Hein wrote: »
    Three Davids against one Jon is not fair. I suggest we declare a truce and join our forces against the dark side of the Forth. :)
    Forth is on the dark side? Maybe I haven't looked closely enough at it yet. Time to dive into Tachyon. It must be doing *something* right! :-)

  • Dave Hein wrote: »
    David, I played around with the idea of using a preprocessor, but I didn't see much advantage in using it. The preprocessor was pretty easy to write. I tried writing a few programs with it. However, it was just as easy for me to use separate C and assembly files than it was to combine them. The only minor advantage is to pre-populate variables with values in the hub image before starting a cog. That can be done in other ways either by having a known offset where all the variables reside, or by just passing a pointer to a struct containing all the values needed when starting up the cog. Personally, I don't see that combining Spin and PASM into one file is much of an advantage.
    I don't see it as a big advantage either but I think others do. In fact, it eliminates some possibilities for errors if everything is in a single file. Spin allows high level code and assembly in the same file and as a bonus doesn't require header files. That means what might be three files in C (a foo.c, foo.h, foo.s) can be a single file in Spin with no possibility of the files getting out of sync with each other.
  • David Betz wrote: »
    Dave Hein wrote: »
    David, I played around with the idea of using a preprocessor, but I didn't see much advantage in using it. The preprocessor was pretty easy to write. I tried writing a few programs with it. However, it was just as easy for me to use separate C and assembly files than it was to combine them. The only minor advantage is to pre-populate variables with values in the hub image before starting a cog. That can be done in other ways either by having a known offset where all the variables reside, or by just passing a pointer to a struct containing all the values needed when starting up the cog. Personally, I don't see that combining Spin and PASM into one file is much of an advantage.
    I don't see it as a big advantage either but I think others do. In fact, it eliminates some possibilities for errors if everything is in a single file. Spin allows high level code and assembly in the same file and as a bonus doesn't require header files. That means what might be three files in C (a foo.c, foo.h, foo.s) can be a single file in Spin with no possibility of the files getting out of sync with each other.

    Well, I have to admit that I am able to get Spin and Pasm out of sync, even if in one file. But the header files are something I never really got used to. Seems to be so unneeded to type the same stuff again. And -hmm- the way GCC handles Assembler is quite ugly compared to the way it is integrated into Spin.

    On the other hand I was finally able to run GCC under Ubuntu on Win10 and hope to be able to get all those goodies to run in Windows. Not sure what to do with the serial port issue of this WSL thing.

    Mike

    I am just another Code Monkey.

    A determined coder can write COBOL programs in any language. -- Author unknown.

    The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this post are to be interpreted as described in RFC 2119.
  • msrobots wrote: »
    Well, I have to admit that I am able to get Spin and Pasm out of sync, even if in one file. But the header files are something I never really got used to. Seems to be so unneeded to type the same stuff again. And -hmm- the way GCC handles Assembler is quite ugly compared to the way it is integrated into Spin.
    I think one of the big reasons for separate header files in C is that you don't have to have the source code for libraries in order to use them. This allows for proprietary libraries where only the binary library and header files are included in the distribution. It also means you don't have to parse the entire source file if you're linking a library with other code. This isn't an issue with Spin since there is no such thing as a binary library or even object files that can be separately linked. This works for Spin because programs tend to be small. It doesn't work as well on larger computers where C is often used because building everything from source every time would be too time consuming.

    And, yes, the inline assembler in GCC is quite ugly. Some of the ugliness is to allow efficient optimization of embedded code and some seems to be there for no good reason like the need to put all of the code in quotes. I believe this is mainly done to make the parser easier but it certainly results in ugly code. However, inline assembly is hardly ever used in C since the C source tends to compile efficiently enough in most cases. This may be true on P2 as well with hub exec. It isn't true on P1 because of the layer of interpretation that is required due to the tiny code space of the P1 COG.
  • Dave HeinDave Hein Posts: 5,295
    edited July 25 Vote Up0Vote Down
    Function prototypes in header files are nice because they tell the compiler what the parameter types are. This allows the compiler to issue warnings or errors if the wrong type is used, which is a very useful feature for novices and expert programmers. Another nice use for headers is to hide ugly macro definitions from the programmer. However, these hidden macros can cause confusion sometimes if they play around with the C syntax.

    Finally, C header files are a good place to put common definitions that are used by many source files. Something like this would be a nice addition to Spin.
  • Dave Hein wrote: »
    Function prototypes in header files are nice because they tell the compiler what the parameter types are. This allows the compiler to issue warnings or errors if the wrong type is used, which is a very useful feature for novices and expert programmers.
    Yes but Spin and Java get this by just parsing the source file to extract the prototypes. They only have to be in one place.

  • The point is that function prototypes provide a way to do error checking. Spin lacks that feature because it doesn't have types. Many novice problems occur when string pointers aren't properly used, or a floating point value is used incorrectly. I'm not suggesting that types be added to Spin (though I have suggested this in the past), but Spin will continue to lack the error checking that other languages provide.
  • Dave Hein wrote: »
    The point is that function prototypes provide a way to do error checking. Spin lacks that feature because it doesn't have types. Many novice problems occur when string pointers aren't properly used, or a floating point value is used incorrectly. I'm not suggesting that types be added to Spin (though I have suggested this in the past), but Spin will continue to lack the error checking that other languages provide.
    Ah yes, that's true. While the Spin compiler can verify that the correct number of arguments are passed to a function, it can't check the argument types. Good point. Anyway, Java has this solved and does support types. I had a strange idea just now that C could be "fixed" by having .h files be generated automatically when compiling .c files. You'd have to do a first pass through the C file to extract the prototype information and then use that to compile that .c file as well as any that refer to it. The point is, the .h file would be a generated file not one the user has to write themself. Of course, again, that wouldn't be standard C anymore.
  • msrobotsmsrobots Posts: 1,675
    edited July 26 Vote Up0Vote Down
    I know we are way off topic with this thread, but since this is the most serious and friendliest language war ever, we might get some constructive information out of it.

    David is right, that the prototypes can be extracted from the source file in a early pass of the compiler, I guess this is what happens in C#. So a separate .h file may be just needed if you want to use precompiled binary libraries without source access. But even that seems possible without .h files, I can without problems use external libraries in C# and VS extracts the needed prototypes out of the provided .dll. So there seem to be a way to do that.

    Dave is also right by stating that Spin lacks types, pushing the type-checking right back to the programmer. As I started to move from VB6 to the net-framework I HATED C# but had no way around it.

    VS does generate some files automagically, not prototypes, but design files containing the visual elements. Sometimes a hassle when getting out of sync, but usually it works pretty well. Same goes for the need of make files. Sure VS does it behind your back, but you do not need to care about it at all, usually.

    But this is a IDE thing, some people swear on using vim and command line tools, some people like the use of IDEs, to make the life easier.

    Coming from COBOL in the first place, I am not afraid of large lines of code. Source codes with 50.000 lines per file are not really rare there. Sure, the C# projects I worked on in the last 20+ years have rarely that size per file, but more files. OK COBOL is a bad example because it is the most verbose language I ever worked with and the philosophy of C was in part to get rid of that verbosity and shrink down the source code immensely.

    a for (i=1;i++;i>10) in C would look like this in COBOL

    PERFORM VARYING i FROM 1 TO 10...., besides you would not find any commercial COBOL program using a variable "i" in the first place. That is because COBOL does not have local variables as used in other languages, and you HAVE TO use longer and more descriptive names.

    All of this is moot on a micro controller like the P1or even the P2. So a lot of features of C/C++ make - in my opinion - not much sense for small targets.

    One part of the success of the Arduino was to strip down the language so far that they even do not mention it is C++. And normal people where able do combine stuff to use it without even knowing they program C++.

    On the other hand, if we can get some POSIX layer on the P2, introduce dynamic loading of modules from external storage, and some minimalistic Memory Management the amount of code you could run on a P2 might extend to the need of.

    we will find out.

    Mike
    I am just another Code Monkey.

    A determined coder can write COBOL programs in any language. -- Author unknown.

    The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this post are to be interpreted as described in RFC 2119.
  • msrobots wrote: »
    David is right, that the prototypes can be extracted from the source file in a early pass of the compiler, I guess this is what happens in C#. So a separate .h file may be just needed if you want to use precompiled binary libraries without source access. But even that seems possible without .h files, I can without problems use external libraries in C# and VS extracts the needed prototypes out of the provided .dll. So there seem to be a way to do that.
    The problem with that approach is that the binary form of a compiled program would have to be standardized across platforms. That would probably be difficult. It would be much easier to have the compiler produce a .h file that could be used by users of precompiled libraries. The .h file syntax is already standardized.
  • msrobotsmsrobots Posts: 1,675
    edited July 26 Vote Up0Vote Down
    I like the way you think, but if you have the .so (or what a dll equivalent is) for say 'solaris' running on sparc, shouldn't the sparc-c-compiler/ide be able to know the used calling convention? It will definitely need to now that at link time?

    Say in windows, I can peek into a dll, because it is a windows-specific dll and in a PExx format. Else it would not work in my actual system. VS knows that so it can do that for me.

    I am pretty sure that the same goes for Linux/BSD/other. Each system has a common used convention how the binary and the entry points are defined.

    Or is the type information already lost at that point?

    just curious,

    Mike
    I am just another Code Monkey.

    A determined coder can write COBOL programs in any language. -- Author unknown.

    The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this post are to be interpreted as described in RFC 2119.
  • msrobots wrote: »
    I like the way you think, but if you have the .so (or what a dll equivalent is) for say 'solaris' running on sparc, shouldn't the sparc-c-compiler/ide be able to know the used calling convention? It will definitely need to now that at link time?

    Say in windows, I can peek into a dll, because it is a windows-specific dll and in a PExx format. Else it would not work in my actual system. VS knows that so it can do that for me.

    I am pretty sure that the same goes for Linux/BSD/other. Each system has a common used convention how the binary and the entry points are defined.

    Or is the type information already lost at that point?

    just curious,

    Mike
    I think the type information is still there in GCC generated ELF files at least when they include debugging information. I'm not sure about the file formats that other compilers generate. I'm not sure whether #define constants or macros are part of the debugging information though.
  • jmgjmg Posts: 10,465
    msrobots wrote: »
    .... But the header files are something I never really got used to. Seems to be so unneeded to type the same stuff again.
    One historic reason for separate headers in many languages, is the primary source does not have to be C.

    Headers allow name and param info for Assembler routines, or any other language that follows the param convention rules.
    Way, way back, header files also meant you did not need to parse all source files - these days of GHz CPU, GB RAM and TB HDD, that's more a 'who cares'.

    It could be relatively easy to have C (or variant) tolerate no header files, if someone decided that was worth the effort.
    msrobots wrote: »
    And -hmm- the way GCC handles Assembler is quite ugly compared to the way it is integrated into Spin.
    Well, yes, that's an historic kludge, and partly because GCC is so generic.
    Thus a simple way to 'push code lines' into the following assembler was done, but most other languages these days have cleaner ASM..ENDASM or similar.

    If you want the best performance from in-line ASM, those in-line pieces should ideally have full ASM ability, including macros.

  • jmgjmg Posts: 10,465
    msrobots wrote: »
    I like the way you think, but if you have the .so (or what a dll equivalent is) for say 'solaris' running on sparc, shouldn't the sparc-c-compiler/ide be able to know the used calling convention? It will definitely need to now that at link time?

    Say in windows, I can peek into a dll, because it is a windows-specific dll and in a PExx format. Else it would not work in my actual system. VS knows that so it can do that for me.

    I am pretty sure that the same goes for Linux/BSD/other. Each system has a common used convention how the binary and the entry points are defined.

    Or is the type information already lost at that point?
    Some languages allow Run Time Type Checks, but that has a code size and time overhead - rather less microcontroller space friendly.

    To have the most compact run-times, the Type/Calling Checks are best done at Link time, which does mean you need at a full OBJECT file collection.

    Or is P2 going to be general enough, that people will brave DLL-Hell, and allow mix-and-match binary files ?

  • @msrobots: C# has a mechanism called reflection as a native part of the language itself. All types are derived from a base class, and the information about the type can be queried by the runtime, even the program itself. C/C++ have no such facility.

    A compiled library doesn't have any mechanism to expose this information. It could be done, but producing such a thing would require support from the compiler to produce an extra blob of information in the library, or a "sidecar" file, but that's pretty much the same as a header.
  • Kednerpo wrote: »
    I started with David Betz's ws2812 program that was already set up to easily support other strips and seeing that that program was based on JonnyMac's Spin code that ws recently updated to support RGBW strips I was able to get something working pretty quickly.

    I'm having a couple issues with what I have so far.

    If you have a strip of pixels that is longer than the quantity of pixels you are trying to run some of the pixels outside that range are turning on to a random color.
    example: 24 strip of pixels, code is set to run only 10 pixels. Pixels 14 and 15 might turn green or pink and not change.

    The other part is that I was hoping to be able to have the driver be able to use RGB 0xRRGGBB format or RGBW 0xRRGGBBWW format automatically so that other drivers like color pickers or color sensors wouldn't need to be changed.

    It seems like older RGB programs do pack the 24bit information into 32bit longs but do it as 0x00RRGGBB format. I made a few attempts at trying to shift the bits around in programming but never got what I wanted. Even went back and studied JonnyMac's Nut and Volts article for the original code and how it moves bits around but still no luck yet.

    I settled on 0xRRGGBBWW for now.

    This thread seems to have gotten way off track. May I ask where you got the code you started with? I'd like to propose that I adopt your modification of the code and that we remove any reference to JonnyMac as he requested and repost it to wherever you found it. I don't recall ever posting it anywhere myself. I'd be happy to have your modified version become the official version. Thanks for adding the RGBW support!
  • Hi David,

    The original was from a post you made a few years ago.

    forums.parallax.com/discussion/152504/c-code-to-work-with-ws2812-neopixel-leds/p1

    I started with the latest version you posted. It would be great if you could post the updated code there once the changes you proposed are made.

    I will edit my original post to this thread to add a link to yours.

    There is a bug in the code where additional LEDs are being lit unintentionally. I was wondering if the following code from the rgbx.h file was correct.
    #define COLOR(r, g, b, w)      (((r) <<32) | ((g) << 16)| ((b) << 8) | (w))
    #define SCALE(x, l)         ((x) * (l) / 255)
    #define COLORX(r, g, b, w, l)  ((SCALE(r, l) << 32) | (SCALE(g, l) << 16) | SCALE(b, l) << 8| SCALE(b, l))
    

    I wasn't sure if (r)<<32 should instead be (r)<<24

    Thank you much for your work on the original code and for looking at adopting the modified version.
    "Keep moving forward" - Meet the Robinsons
  • Kednerpo wrote: »
    Hi David,

    The original was from a post you made a few years ago.

    forums.parallax.com/discussion/152504/c-code-to-work-with-ws2812-neopixel-leds/p1

    I started with the latest version you posted. It would be great if you could post the updated code there once the changes you proposed are made.

    I will edit my original post to this thread to add a link to yours.

    There is a bug in the code where additional LEDs are being lit unintentionally. I was wondering if the following code from the rgbx.h file was correct.
    #define COLOR(r, g, b, w)      (((r) <<32) | ((g) << 16)| ((b) << 8) | (w))
    #define SCALE(x, l)         ((x) * (l) / 255)
    #define COLORX(r, g, b, w, l)  ((SCALE(r, l) << 32) | (SCALE(g, l) << 16) | SCALE(b, l) << 8| SCALE(b, l))
    

    I wasn't sure if (r)<<32 should instead be (r)<<24

    Thank you much for your work on the original code and for looking at adopting the modified version.
    Shifting by 32 will always result in zero of course. You're correct that it should be 24. In looking at JonnyMac's original PASM code I think the license requires that I leave his copyright in the PASM source. I can remove his name from the C code though since I wrote that myself. I'll work on cleaning this up and then I'll put it in OBEX and probably also GitHub.

Sign In or Register to comment.