Flickering problem when emulating PWM (sometimes!) with RGB LEDs

Hi Folks,

I've got a small problem with a 3 dimensional 8x8x8 RGB led cube that I've built related to flickering when blending colors. The theory of the cube (seen done many ways on the internet) is that you quickly display 8 layers in sequence (horizontal usually) sufficiently fast that you get a clear image because of the persistence of vision effect. In an LED, each color element (r,g,b) is on at some percentage to blend together and result in a composite color for the given LED. The way folks tend to do this is to hook up a set of chips to allow multiplexing of output from a microcontroller, load up a layer (64 x 3 = 192 bits) and then latch the chips. There's various ways to do this with common anode & common cathode leds, sourcing and sinking current chips.

For context, I successfully designed an 8x8x8 monocube with a circuit of my own design and have a set of fun animations I've created. In this project, I've hooked up my cube to an Arduino Uno running at 16mhz. I'm running the display routine in an interrupt firing ~1000/second. With an 8 layer cube, this gives a smooth 125hz frame rate for the cube. The IC's I'm using are DM13a's along with common anode LED's. To blend colors, I treat the display of all 8 layers as a "frame" and will turn off some percentage of the frames for that color. I've got 4 interesting states for an led-color: off, half, "more," on. So, it turns out that when the red elements are "on" fully, they make it such that you cannot see the blue or green elements--go figure. That said, half-red (~63hz of red) + (125hz)green provides a perfectly respectable yellow as you'd expect and half-red + blue provides a reasonable purple. This is basically emulating pulse width modulation and while it would be nice, I don't really care about 8 bit color depth through bit angle modulation and such. That is, I'm pretty okay with "half" as one of a few states. The issue I've got is making the color Orange. In RGB land, orange is ~"twice" the red than green. Where I'm at, the best way to go is to just dial up a bit more red beyond "half" to "more." The way I implemented half is to count up to 8 frame displays and have a color on during 1,3,5,7 and off the other counts. If I allow red to be on for 2-3 more of the counts I do get a decent orange. The problem I'm experiencing is that as soon as I dial up the frequency of red's "oscillation" beyond half, I get a pronounced flicker with the resulting orange. I don't get it. It's not intuitive to me what's happening. I wouldn't have thought a higher cycle of moving red from ~63hz to, say, ~90hz or ~110hz would cause flickering.

Does anyone have an appropriate background in signals, electronics, something that might help me gain insight into this?

My current hope is that I can attach a chipkit uno that has an 80 mhz chip and cycle the whole thing faster than it's possible to see problems. I don't know if that will work, but I'd still like to understand what's happening here.

Regards,

David

Two things:

  1. I like the LED array, 8 x 8 wow! Some patience putting that lot together! Looks pretty (apart from the flickering orange)

  2. I don't know the answer but, as you seem to be aware, the traditional method of controlling light output is not through frequency per se, but via mark/space ratio of a constant frequency aka PWM.

So when you talk about 63Hz frequency (which is only switched part of the time) I would have thought flickering would have been a problem more of the time - but maybe I don't fully understand your technique.

Using PWM at a much higher frequency (eg kHz not Hz) for each of the colours would ensure no flickering at anytime, but I fully appreciate this is not a route you might want to take. I'm hoping others understand better what you are describing and can assist further as this is not the way I would have implemented it, that's all.

If you try and get Orange for just one LED (not in your array) does that flicker too?

But it sure looks nice, nonetheless.

Frequency shifting instead of PWM? Interesting. I wrote a bit of code to control RGB color transitions for Neopixels. The loop logic might work for your project also.

/**
Scetch ColorFade is a color fade routine for Adafruit Neo-Pixels
to be run on the Arduino Uno development platform. Colors transition
through green, aqua, blue, violet, red, orange, yellow. Change define
values to suit output pin (PIN) number of Neo-Pixels (PIXEL_NUM)
and delay interval (DELAY_TIME).
@author Mike Tonge
@date 032316
*/
// Required header (Adafruit_Neopixel_Master library)
#include <Adafruit_NeoPixel.h>
// Definitions (change to suit)
#define PIN            6 // Data output pin (Arduino)
#define PIXEL_NUM      2 // Number of Neo-Pixels in series
#define DELAY_TIME   100 // Delay value (miliseconds)
// Setup the NeoPixel library, tell it how many pixels, and which pin to use to send data.
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(PIXEL_NUM, PIN, NEO_GRB + NEO_KHZ800);
// Variable declarations
int redVal; // Red value
int greenVal; // Green value
int blueVal; // Blue value
int pixelIndex; // Loop counter to address pixels in series
// Run once
void setup() {
  pixels.begin(); // Initialize the NeoPixel library.
  Serial.begin(9600); // Serial monitor used for diagnostics
} // End setup
// Main method (non-terminating) loop
void loop() { // Begin 'main' loop
  for (int i = 0; i <= 765; i = i + 5) { // Loop counter 'i' used to set RGB values
    // Red off, Green down, Blue up
    if (i < 255) { // If 'i' is less than 255
      redVal = 0; // Red is off
      greenVal = 255 - i; // Green decreases as 'i' increases
      blueVal = i; // Blue increases as 'i' increases
    }
    // Red up, Green off, Blue down
    if (i > 255) { // If 'i' is greater than 255
      redVal = i - 255; // Red increases as 'i' increases
      greenVal = 0; // Green is off
      blueVal = 510 - i; // Blue decreases as 'i' increases
    }
    // Red down, Green up, Blue off
    if (i > 510) { // If 'i' is greater than 510
      redVal = 765 - i; // Red decreases as 'i' increases
      greenVal = i - 510; // Green increases as 'i' increases
      blueVal = 0; // Blue is off
    }
    // Loop address each Neo-Pixel and updates RGB values
    for (pixelIndex = 0; pixelIndex < PIXEL_NUM; pixelIndex++) {
      pixels.setPixelColor(pixelIndex, pixels.Color(redVal, greenVal, blueVal));
      pixels.show(); // Send the updated RGB values to pixel
    }// End 'for' loop
    delay(DELAY_TIME); // Loop delay interval

    // Diagnostic output to Serial Monitor
    /**
    Serial.print(i);
    Serial.print(" , ");
    Serial.print(redVal);
    Serial.print(" , ");
    Serial.print(greenVal);
    Serial.print(" , ");
    Serial.print(blueVal);
    Serial.println();
    */
  }// End 'for' loop
}// End 'main' loop

I hope this helps.

The errant flickering might be caused by some circuit noise. Poster Ralph_S_Bacon might be able to provide you with a capacitor value to dampen unwanted spikes at that frequency (~63hz).

Hi Ralph,

As a guy with a computer science background that picked this up as a hobby, I probably lack the precise language to describe the technique I'm using. I believe that I've implemented PWM and am describing the amount of time an LED (set) is on as a frequency as a function of the number of hardware interrupt cycles that the LED is on. That is, ~1000 interrupts/second, 1 horizontal plane per interrupt or 8 interrupts to draw the cube, allowing for a maximum of ~125 cube "frames" to be drawn per second. So, when I'm describing a color being on at a certain frequency, or saying red is on for ~63hz, I've got red on for say: frame draw 1 off for frame draw 2, on for frame draw 3 and so on. Based on quickly reading, I believe this is a mark-space ratio of 1:1 or "on" for 50% of the possible time.

Any thoughts on how you could get a lowly arduino to give you PWM in the khz range as you suggest noting that I've got to multiplex out to a set of chips to get 64 outputs and can't rely on the hardware PWM built into the arduino pins. This is my hope for the chipkit -- just cycle it faster.

Quite stymied by why red being on for > 50% of the available time can flicker when 50% itself does not.

Best,

David

David, are you using the Arduino's SPI hardware to send data to those led drivers? Does your code use SPI.transfer() or shiftOut() or neither? If using SPI, have you requested the highest possible frequency?

Paul

Hi Paul,

I'm use direct port manipulation (way faster than the digital writes). I implemented both SPI and direct port manipulation and found direct PORT manipulation faster, but it could be that I didn't configure the SPI correctly from a clocking perspective. Is it generally understood the SPI must be faster if done properly? I admit that I haven't revisited that part of my code in some time.

David