LEDs uneven brightness with 4x4x4 LED cube

Hey,
i built a 4x4x4 LED Cube, the Anodes of the LEDs are connected Vertical, and the Kathods are connected Horizontal. The Kathods are controlled by 4x Transistors which are controlled by 3 Shift Registers which are also controlling the Anodes.

But now the LEDS have an uneven brightness depending on how many are lighten up.

Here´s a schematic, but only with 4 LEDs for the sake of simplicity.

The Anodes strands have each a 220 Ohm Resistors, the Transistors a 1k Ohm.

74HC595 is only good for 35mA max on their outputs. The limits that to 12 mA or so - now you are sharing that 12mA over 1 to 8 LEDs, you can see why the brightness varies.
Try putting a MIC2981 after each shift register to provide more current drive.
You could also lower the 1K so the transistors turn on more fully (into saturation, so Vce is lower).

What is the forward voltage of the LEDs? If you don't know, at least tell us the colour.

Assuming red LEDs, which have a forward voltage of 1.8V, and a 0.7V drop across your transistors, there will be 5-1.8-0.7=2.5V across the series resistors, so the current will be 2.5/200=12.5mA.

If all 8 LEDs are lit, this will be 100mA in total for a shift register. The data sheet indicates this must be kept under 70mA, so that is a possible cause of the uneven brightness.

If the LEDs are blue, with a forward voltage of 3.2V, then the current per resistor will be 5mA and 40mA for the SR if all 8 LEDs are lit. No problem.

I think it is more likely that your uneven brightness is a software issue, so please post your code using code tags. For even brightness, it is important that each led is lit for the same length of time, regardless of how many LEDs are lit at once.

So at first, i have Blue LEDs,

the Voltage of 1 Layer is ~1.9V, the Amperage is ~ 7mA

the Voltage of 1 and 2 Layer is ~1.9V, the Amperage is ~ 3.1mA

the Voltage of 1, 2 and 3 Layer is ~1.9V, the Amperage is ~ 2.4mA

the Voltage of 1,2 ,3 and 4 Layer is ~1.9V, the Amperage is ~ 1.8mA

And for example when i turn on the 1st and 4th Layer each has about 7mA

now when I turn on the 1st and the 4th and some of the LEDs in the 2nd and 3rd Layer each has about 3.1mA

Some ppl said also a Capacitator would help.

Try putting a MIC2981 after each shift register to provide more current drive.

You mean replacing the 74HC595 with the MIC2981 right ?

rechscheibfeler:
So at first, i have Blue LEDs

OK. And later?

rechscheibfeler:
the Voltage of 1 Layer is ~1.9V, the Amperage is ~ 7mA

the Voltage of 1 and 2 Layer is ~1.9V, the Amperage is ~ 3.1mA

the Voltage of 1, 2 and 3 Layer is ~1.9V, the Amperage is ~ 2.4mA

the Voltage of 1,2 ,3 and 4 Layer is ~1.9V, the Amperage is ~ 1.8mA

I do not understand what you are measuring here. What are you using to measure, and where are you placing the two probes of the measuring device to take the measurements? Are you measuring these with a multimeter? A multimeter may not be reliable for measuring values which are not steady/constant.

rechscheibfeler:
Some ppl said also a Capacitator would help.

You should indeed have capacitors. One 0.1uF ceramic bypass cap for each shift register, plus a larger electrolytic cap, e.g. 10~100uF would be a good idea.

rechscheibfeler:
You mean replacing the 74HC595 with the MIC2981 right ?

No, in addition to the '595. The '595 cannot source very much current, around 70mA as I said before. The MIC2981 would boost up the current. But as you are using blue leds, I don't think the 70mA limit of the '595 is a problem.

If you are only going to build a 4 by 4 by 4 cube and not larger, then the sensible way to do it is to use a MAX7219. :roll_eyes:

Im planing to to an 8x8x8 Cube, but at first i want to have a solution for the brightness, because i think its a harder contrast if i have an 8x8x8 Cube.

And now i have also Blue LEDs,

The ceramic bypass Capacitator parallel to the Shift Registers right ? And the electrolytic is placed where ?

Im not that good at electronics heheh.

The 0.1uF caps should be close the power pins of each chip. The larger cap can be anywhere, across the 5V and ground.

I think these caps are necessary, but I'm not sure they will correct your brightness problem. You should post your code so that we can check it. If your code is too long to post, it would be best if you make a short version, which shows the problem and nothing more.

// Connections
int mreset = 10;
int shift = 11;
int store = 12;
int data = 13;
int taster = 9;
int a, tasterstatus = 0;

/ Delays
int tasterdelay = 250;

int fast = 8;
int stage1 = 150;
int stage2 = 150;
int stage3_1 = 400;
int stage3_2 = 750;
int stage4 = 150;

unsigned long time_now = 0;

// Pattern

int leftside[24]    = {1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int ndleftside[24]  = {1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int ndrightside[24] = {1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0};
int rightside[24]   = {1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0};

btw can i do these Numbers as Hex ?

void setup() {
  pinMode(shift , OUTPUT);
  pinMode(store , OUTPUT);
  pinMode(data , OUTPUT);
  pinMode(mreset , OUTPUT);
  pinMode(taster , INPUT);

  Serial.begin(9600);
  randomSeed(analogRead(0));

  digitalWrite(mreset, LOW);
  digitalWrite(store, HIGH);
  digitalWrite(mreset, HIGH);
  digitalWrite(store, LOW);

}
void loop() {
  tasterstatus = digitalRead(taster);
  if (tasterstatus == HIGH) {
    a++;
    delay(tasterdelay);
  }
  switch (a) {
    case 1:
      pattern1();
      break;
    case 2:
      pattern2();
      break;
    case 3:
      pattern3();
      break;
    case 4:
      pattern4();
      break;
    default:
      if (a != 0)
        a = 1;
      break;
  }
}

void pattern1() {
  time_now = millis();
  for (int i = 0; i < 24; i++) {
    digitalWrite(shift, LOW);
    digitalWrite(data, leftside[i]);
    digitalWrite(shift, HIGH);
  }
  digitalWrite(store, HIGH);
  digitalWrite(store, LOW);

  while (millis() < time_now + stage1) {
    tasterstatus = digitalRead(taster);
    if (tasterstatus == HIGH) {
      delay(tasterdelay);
      a++;
      loop();
      return;
    }
  }
  digitalWrite(mreset, LOW);
  digitalWrite(store, HIGH);
  digitalWrite(mreset, HIGH);
  digitalWrite(store, LOW);

  time_now = millis();
  for (int i = 0; i < 24; i++) {
    digitalWrite(shift, LOW);
    digitalWrite(data, ndleftside[i]);
    digitalWrite(shift, HIGH);
  }
  digitalWrite(store, HIGH);
  digitalWrite(store, LOW);

  while (millis() < time_now + stage1) {
    tasterstatus = digitalRead(taster);
    if (tasterstatus == HIGH) {
      delay(tasterdelay);
      a++;
      loop();
      return;
    }
  }
  digitalWrite(mreset, LOW);
  digitalWrite(store, HIGH);
  digitalWrite(mreset, HIGH);
  digitalWrite(store, LOW);

  time_now = millis();
  for (int i = 0; i < 24; i++) {
    digitalWrite(shift, LOW);
    digitalWrite(data, ndrightside[i]);
    digitalWrite(shift, HIGH);
  }
  digitalWrite(store, HIGH);
  digitalWrite(store, LOW);

  while (millis() < time_now + stage1) {
    tasterstatus = digitalRead(taster);
    if (tasterstatus == HIGH) {
      delay(tasterdelay);
      a++;
      loop();
      return;
    }
  }
  digitalWrite(mreset, LOW);
  digitalWrite(store, HIGH);
  digitalWrite(mreset, HIGH);
  digitalWrite(store, LOW);

  time_now = millis();
  for (int i = 0; i < 24; i++) {
    digitalWrite(shift, LOW);
    digitalWrite(data, rightside[i]);
    digitalWrite(shift, HIGH);
  }
  digitalWrite(store, HIGH);
  digitalWrite(store, LOW);

  while (millis() < time_now + stage1) {
    tasterstatus = digitalRead(taster);
    if (tasterstatus == HIGH) {
      delay(tasterdelay);
      a++;
      loop();
      return;
    }
  }
  digitalWrite(mreset, LOW);
  digitalWrite(store, HIGH);
  digitalWrite(mreset, HIGH);
  digitalWrite(store, LOW);

  time_now = millis();
  for (int i = 0; i < 24; i++) {
    digitalWrite(shift, LOW);
    digitalWrite(data, ndrightside[i]);
    digitalWrite(shift, HIGH);
  }
  digitalWrite(store, HIGH);
  digitalWrite(store, LOW);

  while (millis() < time_now + stage1) {
    tasterstatus = digitalRead(taster);
    if (tasterstatus == HIGH) {
      delay(tasterdelay);
      a++;
      loop();
      return;
    }
  }
  digitalWrite(mreset, LOW);
  digitalWrite(store, HIGH);
  digitalWrite(mreset, HIGH);
  digitalWrite(store, LOW);

  time_now = millis();
  for (int i = 0; i < 24; i++) {
    digitalWrite(shift, LOW);
    digitalWrite(data, ndleftside[i]);
    digitalWrite(shift, HIGH);
  }
  digitalWrite(store, HIGH);
  digitalWrite(store, LOW);

  while (millis() < time_now + stage1) {
    tasterstatus = digitalRead(taster);
    if (tasterstatus == HIGH) {
      delay(tasterdelay);
      a++;
      loop();
      return;
    }
  }
  digitalWrite(mreset, LOW);
  digitalWrite(store, HIGH);
  digitalWrite(mreset, HIGH);
  digitalWrite(store, LOW);

  time_now = millis();
  for (int i = 0; i < 24; i++) {
    digitalWrite(shift, LOW);
    digitalWrite(data, leftside[i]);
    digitalWrite(shift, HIGH);
  }
  digitalWrite(store, HIGH);
  digitalWrite(store, LOW);

  while (millis() < time_now + stage1) {
    tasterstatus = digitalRead(taster);
    if (tasterstatus == HIGH) {
      delay(tasterdelay);
      a++;
      loop();
      return;
    }
  }
  digitalWrite(mreset, LOW);
  digitalWrite(store, HIGH);
  digitalWrite(mreset, HIGH);
  digitalWrite(store, LOW);
}

Hopefully you understand, the pattern1 is basically the same every time

When I said a short version of your code, I meant one that compiles and runs, demonstrating the problem you need help with.

Paul__B:
If you are only going to build a 4 by 4 by 4 cube and not larger, then the sensible way to do it is to use a MAX7219. :roll_eyes:

I can think of a way you could build an 8x8x8 cube using max7219. You could build a tower, 4x2 base, 8 high, controlled by a max chip. Build 7 more and space them as an 8x8x8 cube, chaining the chips. I don't know how practical or sturdy this would be without something to brace the towers and keep them spaced apart without making electrical contact. Perhaps wire could be used as bracing between the towers, soldering the wire to one tower, but using clear glue blobs to attach each wire to the adjacent tower. Perhaps that UV-setting glue. A blob of glue on the end of the wire could be allowed/made to set first, insulating the tip of the wire, then a second blob to fix it to the adjacent tower.

PaulRB:
I can think of a way you could build an 8x8x8 cube using max7219.

Indeed it is a plausible way to construct the cube and would have immensely better performance than multiplexing by layer.

The limitation is the need to run 16 wires to each layer; you would want to alternate the sides so the 8 wires for each layer row could alternate between sides so that there were only four sets on each side and so for the columns. Since these are also the supports, you probably want to run alternate row connections on alternate sides.

Can't say I have the enthusiasm right now to wrangle 512 LEDs. :roll_eyes:

If you look at the 8X8 cube by Jolli-Cube they have a real good step by step on building a cube.
As Paul_ _B stated, soldering 512 led's can be quite tedious, but if you make a proper jig it's not too bad.

tbh, i like this idea more, how to solder the LEDs together

When you post some working code which demonstrates the dimming problem, I'm sure we can help with that.

The Code above should Work, its Just shortend

rechscheibfeler:
The Code above should Work, its Just shortend

You mean from post #8? I don't have to try it, I can see from reading it that it's not going to compile/verify.

// Connections
int mreset = 10;
int shift = 11;
int store = 12;
int data = 13;
int taster = 9;
int a, tasterstatus = 0;

// Delays
int tasterdelay = 250;

int fast = 8;
int stage1 = 150;
int stage2 = 150;
int stage3_1 = 400;
int stage3_2 = 750;
int stage4 = 150;

unsigned long time_now = 0;

// Pattern

int leftside[24]    = {1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int ndleftside[24]  = {1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int ndrightside[24] = {1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0};
int rightside[24]   = {1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0};

void setup() {
  pinMode(shift , OUTPUT);
  pinMode(store , OUTPUT);
  pinMode(data , OUTPUT);
  pinMode(mreset , OUTPUT);
  pinMode(taster , INPUT);

  Serial.begin(9600);
  randomSeed(analogRead(0));

  digitalWrite(mreset, LOW);
  digitalWrite(store, HIGH);
  digitalWrite(mreset, HIGH);
  digitalWrite(store, LOW);

}
void loop() {
  tasterstatus = digitalRead(taster);
  if (tasterstatus == HIGH) {
    a++;
    delay(tasterdelay);
  }
  switch (a) {
    case 1:
      pattern1();
      break;
  }
}

void pattern1() {
  time_now = millis();
  for (int i = 0; i < 24; i++) {
    digitalWrite(shift, LOW);
    digitalWrite(data, leftside[i]);
    digitalWrite(shift, HIGH);
  }
  digitalWrite(store, HIGH);
  digitalWrite(store, LOW);

  while (millis() < time_now + stage1) {
    tasterstatus = digitalRead(taster);
    if (tasterstatus == HIGH) {
      delay(tasterdelay);
      a++;
      loop();
      return;
    }
  }
  digitalWrite(mreset, LOW);
  digitalWrite(store, HIGH);
  digitalWrite(mreset, HIGH);
  digitalWrite(store, LOW);

  time_now = millis();
  for (int i = 0; i < 24; i++) {
    digitalWrite(shift, LOW);
    digitalWrite(data, ndleftside[i]);
    digitalWrite(shift, HIGH);
  }
  digitalWrite(store, HIGH);
  digitalWrite(store, LOW);

  while (millis() < time_now + stage1) {
    tasterstatus = digitalRead(taster);
    if (tasterstatus == HIGH) {
      delay(tasterdelay);
      a++;
      loop();
      return;
    }
  }
  digitalWrite(mreset, LOW);
  digitalWrite(store, HIGH);
  digitalWrite(mreset, HIGH);
  digitalWrite(store, LOW);

  time_now = millis();
  for (int i = 0; i < 24; i++) {
    digitalWrite(shift, LOW);
    digitalWrite(data, ndrightside[i]);
    digitalWrite(shift, HIGH);
  }
  digitalWrite(store, HIGH);
  digitalWrite(store, LOW);

  while (millis() < time_now + stage1) {
    tasterstatus = digitalRead(taster);
    if (tasterstatus == HIGH) {
      delay(tasterdelay);
      a++;
      loop();
      return;
    }
  }
  digitalWrite(mreset, LOW);
  digitalWrite(store, HIGH);
  digitalWrite(mreset, HIGH);
  digitalWrite(store, LOW);

  time_now = millis();
  for (int i = 0; i < 24; i++) {
    digitalWrite(shift, LOW);
    digitalWrite(data, rightside[i]);
    digitalWrite(shift, HIGH);
  }
  digitalWrite(store, HIGH);
  digitalWrite(store, LOW);

  while (millis() < time_now + stage1) {
    tasterstatus = digitalRead(taster);
    if (tasterstatus == HIGH) {
      delay(tasterdelay);
      a++;
      loop();
      return;
    }
  }
  digitalWrite(mreset, LOW);
  digitalWrite(store, HIGH);
  digitalWrite(mreset, HIGH);
  digitalWrite(store, LOW);

  time_now = millis();
  for (int i = 0; i < 24; i++) {
    digitalWrite(shift, LOW);
    digitalWrite(data, ndrightside[i]);
    digitalWrite(shift, HIGH);
  }
  digitalWrite(store, HIGH);
  digitalWrite(store, LOW);

  while (millis() < time_now + stage1) {
    tasterstatus = digitalRead(taster);
    if (tasterstatus == HIGH) {
      delay(tasterdelay);
      a++;
      loop();
      return;
    }
  }
  digitalWrite(mreset, LOW);
  digitalWrite(store, HIGH);
  digitalWrite(mreset, HIGH);
  digitalWrite(store, LOW);

  time_now = millis();
  for (int i = 0; i < 24; i++) {
    digitalWrite(shift, LOW);
    digitalWrite(data, ndleftside[i]);
    digitalWrite(shift, HIGH);
  }
  digitalWrite(store, HIGH);
  digitalWrite(store, LOW);

  while (millis() < time_now + stage1) {
    tasterstatus = digitalRead(taster);
    if (tasterstatus == HIGH) {
      delay(tasterdelay);
      a++;
      loop();
      return;
    }
  }
  digitalWrite(mreset, LOW);
  digitalWrite(store, HIGH);
  digitalWrite(mreset, HIGH);
  digitalWrite(store, LOW);

  time_now = millis();
  for (int i = 0; i < 24; i++) {
    digitalWrite(shift, LOW);
    digitalWrite(data, leftside[i]);
    digitalWrite(shift, HIGH);
  }
  digitalWrite(store, HIGH);
  digitalWrite(store, LOW);

  while (millis() < time_now + stage1) {
    tasterstatus = digitalRead(taster);
    if (tasterstatus == HIGH) {
      delay(tasterdelay);
      a++;
      loop();
      return;
    }
  }
  digitalWrite(mreset, LOW);
  digitalWrite(store, HIGH);
  digitalWrite(mreset, HIGH);
  digitalWrite(store, LOW);
}

this code is working, i tried it.

Thanks, I can believe that would compile.

But what it would do... My brain is melting a little bit trying to predict that. Why? Because loop() calls pattern1() and pattern1() calls loop(). This is what is named, if I remember correctly, "mutual recursion". Something an expert coder would only use only in rare circumstances and with very careful planning. If a beginner uses it, is a clear sign of confusion or error.

So I'm more convinced than ever that your dimming problem is a software error.

The other alarm bell that rings in my head is the bit patterns your code is sending out to the shift registers. I would expect this to light only one layer of the cube at any instant. But the data does not indicate that is what is happening. Can you explain what the strategy is for driving your cube? If you are truly trying to light more than one layer of the cube at the same instant, this is why you are getting the uneven dimming, I think. The '595s can support the current requirements of your blue LEDs and 220R series resistors for one layer at a time, but if you try to light more than one layer at once, they will be dimmer, no question.

Yes, im doing it with Shift Registers,

the Strategy is, that 3 Shift Register are controlling the LED´s and 4 Capacitators,

each Capacitators(1-4 on the Pattern Numbers) are controlling the Height,
the other 16 are Controlling the Column.

Because you can only light up 1 Layer, it switches between these Layers, so it looks like they are lighting together.

Ill call the loop back, because now you can press the button at any state of the pattern to go to the next pattern.