Fast Updates (frame rates) of Color Effect G35 Grids

It’s the time of the year to start playing around with Christmas Light hardware and software. Lately, I’m focusing more on simpler (i.e, less light strings) displays and more on incorporating my “mini mega light tree“.

As described in previous posts (Driving GE G-35 Light String with Digilent Uno32GE G35 ColorEffects Christmas Tree), this consists of a tree made from multiple GE G35 ColorEffects LED light strings. I adapted my light sequencing program to drive the addressable bulbs, using a Digilent ChipKit Uno32 ‘Arduino-compatible’ microcontoller as a protocol converter more or less. The PC software sends serial commands to the Uno32, and it in turn sends commands to the G35 strings via digital out pins. The software essentially treats the tree as a pixel grid which it can load bitmap to; transforms (scrolls and fades) can then be applied to the grid.

One problem that has plagued me, though, is that refreshes get bogged down when sending lots of commands to multiple strings. The effect is pretty severe when trying to do things like fade the whole tree, load an entire bitmap, or scroll a bitmap with lots of different-colored pixels around the tree (bitmaps with just a few pixel variations aren’t so bad, since I only have to update those pixels that change, not every single pixel). This year, I decided to take a stab at improving it.

Until now, I thought that my problem was shoveling a lot of data across the serial line, while also doing the work of sending the custom protocol out to various strings – possibly due to serial handling producing a lot of interrupts. Some other blog entries had misled me (or I misinterpreted them :-) to believe that controlling multiple strings at once with high refresh rates should be possible with Arduino-class hardware. Turns out this isn’t exactly true…or at least isn’t simple. There’s an interesting thread on the topic here.

Thinking maybe I just needed to reduce the serial data burden, I started down the path of offloading more of the work to the  microcontroller in order to reduce the data going over the USB serial line. It turns out this is NOT the reason it get’s bogged down. Even when no info is sent via serial (like during the all-string-fades I currently have during setup() execution) the delay between the update of each string increases as I increase the number of strings. One string is very fast, with no significant delay…five is noticeably bogged down. This led me to calculate how much time it takes to send a single color/intensity to every bulb on five strings based on the µSec delays built into protocol functions in the sketch. Turns out it takes over 1/20th of a second to update an entire string! Throw in some overhead for logic and serial handling and it’s nearly a quarter of a second to update five strings! I really should have calculated this sooner (or should have read that thread mentioned above :-).

It’s clear that to get faster updates, more horsepower won’t necessarily help -I need parallel string addressing. Even with more horsepower, I’d still spend too much time blocked, waiting on delay functions.  I think in that forum jwhite describes provides an implementation and provides code where he uses some kind of “ring buffer” and can theoretically update 6 strings simultaneously – I think by constantly looping through a timing cycle and writing the bits representing the ‘current’ color into six pins at once during each cycle? – effectively implementing a true raster rendering? The C code is actually over my head, so I’m kind of speculating here.

Since my C skills are probably too weak to take something like that on, it occurred to me that I could get the parallelism I want using multithreading. By driving each string from a separate thread, less time could be spent by the main thread being blocked by delay functions in the protocol implementation.  As a result, I just ordered a NetDuino Plus. I’m hopeful that this will allow me to take advantage of the multhreading support in the .Net Micro framework, not to mention giving me an easy way to port a lot of the display logic to run on the microcontroller instead of the PC. It even includes ethernet support and an SD card, so I’m thinking I should be able to put all the bitmaps in the SD and move from USB tethering to a simple network-based protocol over Ethernet. Watch here for an update :-)

UPDATE: (11/27/2013) Dang, just realized the Thread.sleep() only has millisecond precision (and even then it’s not exact) – and although there are techniques for getting microsecond timing accuracy, they appear to be not very accurate, plus they just use loops which would probably not free up the cpu when sleeping. Going to have to think on this one some more…

About these ads
This entry was posted in Uncategorized. Bookmark the permalink.

6 Responses to Fast Updates (frame rates) of Color Effect G35 Grids

  1. Beach Bum says:

    Love it! Great posts on these lights! Thanks!

    I HATE Darco, his posts got me into these lights also. For Burning Man this year, I did 32 strings of these lights with 1,600 lights total, synced to music like Katy Perry’s Firework, Aerosmith’s Pink is Kink, Sammy Hagar’s Red, Night Ranger’s You Can (Still) Rock in America with red/white/blue blasting down the strings, and about 80 more songs. 80′ diameter lights canopy, with a 16′ tall center pole and 32 10′ tall poles radially around the perimeter of the circle.

    I solved the update frequency problem by switching to a LeafLab’s Maple ARM M3 processor, and outputting the data for many strings in parallel. There’s no way to do it with an Arduino Uno or Mega due to the size of the arrays that need to be held in memory. If the Arduino Due was out a year ago, I would have used that uP instead of the Maple, since the kids at LeafLabs did a fantastic job on the Maple, but they went onto more profitable lives. Buffer and 3.3V -> 5V the data with a 74LS541 buffer/driver chip with the Due. I used a Raspberry Pi in Python to output the songs in sync with the lights.

    For sh__s & grins, description, code and schematics are at:
    http://dougisagod.com/html/armlightsproj.html

    Thanks for doing your blog and your infectious enthusiasm for this stuff! Merry Christmas!

    • Andy Coulson says:

      Wow, pretty awesome. This season ColorEffects strings seem pretty rare, so I don’t know if I’ll be adding anymore..none at Costco, very expensive online :-( I’ll check out your project – I’ve pretty much come to the conclusion that parallel is the best/only option. I’m kind of de-motivated by that, though, since it means a big rewrite – I hope your project might help!

  2. Beach Bum says:

    Thanks, cool! Wish the Color Effects were still being produced in the same fashion. Costco, with their great return policies, had to be losing money – if any one light connection broke, the rest of the string died. I wonder if the different forms of Color Effects lights at Home Depot or Lowes have the same addressing and bit usage, I haven’t seen details on-line. If anyone knows, could you kindly reply here?

    If you like, you’re welcome to pull the code, of course. The whole trick is to fill the color array, generate the arrays in parallel bit order (short routine, as you see, but takes some bit twiddling – works great forever after first debug), and then output the strings in parallel (also a short routine). It requires at least 20KB of SRAM, which was the limit on the Maple, so I had to make some compromises. Yep, it takes that, along with a couple weeks of free time for the hardware and software ;-) Great project for a high-school Maker-type fair.

    I love the Maple (though iffy for new projects), and the Du-e (du-EY) has the same setup() and loop(), so the code ports very easily. People just need to realize that 3.3V->5V buffering is a fact of life.

    Great blog, thanks!

    • Andy Coulson says:

      Hmm..struggling with your code a little here..this stuff is really forcing me to learn more C ..all this C and bit-twiddling makes my head hurt :-) But I think I get it… For simplicity sake, let’s say I have 8 strings and I want to display a ‘grid’ that is 8×50. A ‘frame’ is basically held in a 26×50 array of bytes, where each bit in a byte maps to a pin (and string)? My raster update therefor consists of an outer loop for each bulb (0 to 49) and an inner loop of 0-26 (26 bits required to encode the RGB for each bulb) and I bang all 8 bits (for 8 strings) into my processors port register at once. So, a complete frame update takes 50*26*70uSec = .091 Sec; a full frame update about 10 times a second? This sounds pretty good and might be less of a re-design of my approach for using bitmaps than I thought – I just have to represent my ‘current frame bitmap’ in a 26 x 50 array and make a draw() function similar to your output_array() and related functions.

      • Beach Bum says:

        Wow, you got the concept, not easy. Nice!

        Some items:
        - I didn’t catch before that you were using a Uno32, which is a MIPS architecture (probably M3 also), with 16 KB of SRAM. Yep, you can do it with this. Very similar to the Maple. I didn’t even know this board existed, nice!

        - Yep, you can do a draw() function, with the bit twiddling placing the color and intensity directly in the 26×50 array, without going through the intermediate step of placing the color in a colors[8][50]. I hadn’t thought about doing it that way, but it works, nice. I did a lot of code where the lights moved +1 or -1, so the colors[][] array was extremely helpful in simplifying the mental gymnastics to do this.

        - “So, a complete frame update takes 50*26*70uSec = .091 Sec; a full frame update about 10 times a second?” – Actually, it’s about double that speed. You have the 10us low/20us high (or vice-versa) per bit, times 26 bits, with the >30us reset-low only after all 26 bits are output, resulting in about 20 Hz.

        - The function that outputs a byte or word to a port, as well as the setup for it, may be hardware dependent. So, you may want to check the Uno32 docs & Microchip library docs on this call. You may also want to verify that all your strings are actually on the same port. It took me several days of debug to get the bit-twiddling correct, it’s so easy to make a mistake by rushing and not quadruple-checking the bit-twiddling and masking.

        - I kept all the lights to the same intensity, which was globally changeable. Saved the space of an intensity[][] array.

        Congrats again on your project, and on your lights, beautiful work!!!!!! :-)

  3. Andy Coulson says:

    Oh, right…missed the 40us being outside the loop. I thought my calculation was coming up kind of slow!

    Yep, already started down the path of identifying the correct port(s). Actually, I’ll probably use the uC32 which has more memory but I guess is otherwise pretty equivalent. Anyway, I started out trying to dig through the Microchip docs and that probably would have worked, but on a whim I took a peek at the wiring_digital.c lib which comes in the customized Arduino IDE Digilent distributes and discovered some code in wiring_digital.c (and also described here http://chipkit.net/forum/viewtopic.php?f=6&t=654) for setting or clearing port bits directly via masks…not quite banging a whole byte or two in directly, but close. I’m blinking leds that way now, and intend to investigate further.

    Do you have any video of the Burning Man setup? It sounds awesome and I have a friend (and burning man attendee) who would be particularly interested.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s