5x5x5 LED cube - can't get the refresh rate up enough

Hey guys,

I am trying to build a 5x5x5 LED cube. I familiarised myself with the necessary concepts and made the first plane of the cube for testing. I am using a 3-to-8 line demultiplexer (a 74HC238 to be precise: http://www.nxp.com/documents/data_sheet/74HC_HCT238.pdf) for, well, demultiplexing.

My problem is the following:
I can achieve a 200 Hz refresh rate without flickering on a single LED, which would be fine for this project. But when I try to cycle through one row, the 200 Hz refresh rate drops significantly. Meaning that I can make 2 LEDs appear at once whithout flickering but thats it. When I add a third into the cycle, it is not flicker-free any more.

I don’t know if my problem is hardware-based or software-based.

As for the hardware:
I use the 74HC238 demux IC, I connect the cathodes of the 25 LEDs to the demultiplexer and I connect the common anode to the microcontroller. And that’s that. There are resistors (of 100 Ohms) between the LEDs and the demux, and the microcontroller’s pin goes to the gate of a transistor. The supply votage is 3.3 V. (a little later on the why). So I go with some basic stuff. Maybe I am missing something here.

As for the software:
I use Energia as my coding software. That is, because I use an MSP430 as the microcontoller (this is why I use a 3.3V voltage source). I know this is an arduino forum, but a lot of you have built a LED cube, even bigger than mine, and as I read the posts, this is a helpful community with a lot of knowledgable members. And my problem is not microcontroller-based. Also, it is very similar to any arduino board, it has a 16 MHz CPU, so computation should not be a problem.
Back to the software. I use binary representation of the decimal numbered pins of the IC to turn on each LED - 000 for 0, 001 for 1, 010 for 2, etc) If I use the in-built fuction of Energia to convert decimals to binary, with a delay/sleep function of 1 miliseconds, I only get up to 2 LED without flickering. If I program the pins directly with the necessary binary numbers (so there is no need for conversion), it goes up to 3. But that is the highest, and frankly, I need to convert decimals to binaries. And 3 is not good enough for a 5x5x5 LED cube, not to mention a bigger one.

Here is my test code:

//the input pins for the demultiplexer
int const Ax{8};
int const Bx{9};
int const Cx{10};

// the pin for the anode of the first plane
int const currentSink{2};

//
int demuxInA{0};
int demuxInB{0};
int demuxInC{0};

void setup()
{
  Serial.begin(9600); // starting serial communication

// setting pins as OUTPUTs and INPUTs
  pinMode(currentSink, OUTPUT);
  
  pinMode(Ax, OUTPUT);
  pinMode(Bx, OUTPUT);
  pinMode(Cx, OUTPUT);
  
// these are the 4 demux ICs ON/OFF switch
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);
  pinMode(14, OUTPUT);
  
// setting everything to default value
  digitalWrite(Ax, LOW);
  digitalWrite(Bx, LOW);
  digitalWrite(Cx, LOW);
  digitalWrite(currentSink, HIGH);
  
  digitalWrite(11, HIGH);
  digitalWrite(12, HIGH);
  digitalWrite(13, HIGH);
  digitalWrite(14, HIGH);
}

void loop()
{
//cycleing through the first 3 LEDs
  for (int i{}; i < 3; i++)
  {
// converting decimals to microcontroller/IC terms  
  if (i <= 7)
  { 
    digitalWrite(11, LOW);
    digitalWrite(12, HIGH);
    digitalWrite(13, HIGH);
    digitalWrite(14, HIGH);
  }
  else if ((i >= 8) && (i <= 15))
  {
    digitalWrite(11, HIGH);
    digitalWrite(12, LOW);
    digitalWrite(13, HIGH);
    digitalWrite(14, HIGH);
  }
  else if ((i >= 16) && (i <= 23))
  {
    digitalWrite(11, HIGH);
    digitalWrite(12, HIGH);
    digitalWrite(13, LOW);
    digitalWrite(14, HIGH);
  }
  else if ((i >= 24) && (i <= 31))
  {
    digitalWrite(11, HIGH);
    digitalWrite(12, HIGH);
    digitalWrite(13, HIGH);
    digitalWrite(14, LOW);
  } 
    
// converting i, a decimal into binary, and feeding it to the demultiplexer
  demuxInA = bitRead(i, 0);
  demuxInB = bitRead(i, 1);
  demuxInC = bitRead(i, 2);

  digitalWrite(Ax, demuxInA);
  digitalWrite(Bx, demuxInB);
  digitalWrite(Cx, demuxInC); 

// printing the numbers (i and its binary representation) on the screen
  Serial.println(i);
  Serial.print(demuxInC);
  Serial.print(demuxInB);
  Serial.println(demuxInA);

// refresh rate of 1 ms    
  sleep(1);
  }
}

I was trying to solve the problem with codes posted on the internet, but I could not find a solution for this problem so far.

Robert

Suggest you remove the sleep and also the Serial.print and see if that makes a difference.

I use the 74HC238 demuc IC, connect the cathodes of the 25 LEDs to the demultiplexer, connect the common anode to the microcontroller. And that's that. There are resistors (of 100 Ohms) between the LEDs and the demux, and the microcontroller's pin goes to the gate of a transistor.

The 238 has only 8 outputs. Maybe you are using 4 of them to light your 25 leds?

Assuming I am correct, your hardware design is bad. You can not achieve better than a 1 in 25 multiplex ratio, which may be too dim in addition to being too slow. I would aim for a 1 in 5 multiplex ratio, which means lighting up to all 25 leds on a layer simultaneously, perhaps using shift registers such as 74hc595 or better still tpic6c595.

marco_c: Suggest you remove the sleep and also the Serial.print and see if that makes a difference.

Hey Marco,

thanks for the tip, I tried them. Also with the delay function instead of sleep. Without any improvement.

Robert

PaulRB: The 238 has only 8 outputs. Maybe you are using 4 of them to light your 25 leds?

Assuming I am correct, your hardware design is bad. You can not achieve better than a 1 in 25 multiplex ratio, which may be too dim in addition to being too slow. I would aim for a 1 in 5 multiplex ratio, which means lighting up to all 25 leds on a layer simultaneously, perhaps using shift registers such as 74hc595 or better still tpic6c595.

Hey Paul,

thanks for your response. You are correct in assuming I use 4 ICs. I was thinking that the problem is with the demux chip, but the datasheet states that it has a nanosecond response time. So, switching between outputs should not be causing any delays.

Could you please elaborate on why the hardware design is bad? I will look into the shift registers you suggested. I simply want to understand what concept I am not getting. Is it that demultiplexers are not suited for LED cubes altogether? It is just that a lot of instructables use them (I have chosen one of those for my design, unfortunately it is a quite old article, can't ask for help there), and it seems that nobody has this kind of problem.

Robert

Hi Robert.

Before I explain my problem your hardware design, there are a few things about the code you posted that need to be pointed out.

There are a lot of lines like this one:

int const Ax{8};

What did you expect that line to do? Set the variable Ax to the value 8? Declare an array of length 8? I'm not entirely sure if it will do either of those things, but even if it does, its not the "normal" way.

To set the value of a variable, use:

int const Ax = 8;

To declare and array, use:

int const Ax[8];

Also, this line:

 sleep(1);

won't even compile for me. Did it for you?

OK, so onto the hardware design. Can you post a schematic please? I am struggling to imagine how you have it wired.

But it sounds to me like perhaps you can only light up to 5 leds in the same column at any instant in time? Your code then has to visit each of the 25 columns in turn, to refresh the cube once. Switching columns 25 times could be made to happen quite quickly. You are correct to point out that the chips can switch in a very short time and it is the code that is limiting how quickly this happens. But speed of column switching is not the biggest problem. The problem is from the point of view of any single led in your cube, it can only be lit for 1 period, followed by 24 periods of being off. This greatly lowers the average current and so the brightness of your whole cube. So even if you can speed up the switching, you can't make the cube very bright. This is what we call the multiplex ratio. 1:25 means on for one period out of every 25 periods, whatever length of time a "period" is.

If you switch to using 4 x shift registers, you can change from multiplexing column-by-column to multiplexing layer-by-layer. This would give you a 1:5 multiplex ratio and a much brighter cube. As up to 25 leds would be lit at once, you would need to use 5x transistors, one to drive each layer, because obviously an Arduino output can't drive 25 leds at once. You would also have to have series resistors for each column, so 25 resistors rather than just one for each layer.

One more tip for you: Instructables have a very bad reputation on this forum. So many questions get asked here by people who have tried to follow them and there is some problem or they don't work in some way. Many Instructables are published by well meaning people who don't have any training in electronics or programming, and they are full of bad designs and mistakes. Even if 100 Instructables do something, that does not mean it is right.

I hope I have explained a little better this time. Please ask about anything you are unsure of.

Hi Paul,

As for the hardware:

I will draw up a schematic. But you described it quite well.

First of all, I linked a different datasheet that I use (just noticed the mistake, sorry). Here is the correct one, it is for a SN74LV4051A multiplexer/demultiplexer, this is what I use: http://www.produktinfo.conrad.com/datenblaetter/1000000-1099999/001048020-da-01-en-IC_MUX_DEMU_8X1_SN74LV4051AN_PDIP_16_TID.pdf

In short: Let's take a look at the demux IC's connection. - I connect the INH port to the microcontroller. If it is HIGH, there is no signal to the output channels. So I use the microcontroller to select which demultiplexer I want to send the signal to. In my code I refer to this as the ON/OFF switch. - I connect 3 other ports of the IC to the microcontroller, the A, B and C ports. These controll which output is HIGH, so basically if I connect 8 LEDs to a demux chip, which one will be lit. I refer to these in my code as demuxInA, demuxInB, demuxInC. - I connect the output ports to the LEDs (ports Y0-Y7). Between the output ports and the LEDs there is one 100 Ohms resistor for each LED (so there is one between Y0 and its LED, between Y1 and its LED, etc.) - I connect the COM port to be it a demultiplexer (it goes to 3.3V if I remember correctly, sorry, not at home to check) - I connect 1 GND port to the ground - I connect the VCC to 3.3V

As for the planes, I decided to hook up each to a different pin on the microcontroller, so I can enable all 5 at once.

Let's assume I use 5 demux chips for the 5 rows I have in one plane, controlling 5 LEDs with one chip. With the above configuration, I can light up the same LED in each row at once, turning the INH port of all the demux ICs to LOW (hence switching them ON). So with this, I only need a 1/5 duty cycle, since I need the persistance of vision for 5 LEDs only (for the LEDs in one row, sice I can enable the rows all at once, no need for the POV there). This goes for the whole cube, since the planes can be enabled all at once too.

But I guess you are right, it is not an accident that most desings use shift registers for a LED cube, so I get my hand on a couple of them, and start to get familiar with them.

To be honest my main problem was that if I take one LED, hook it up as it was an LED in a cube (IC and transistor and everything), the program I quoted will work on it for a 1/5 duty cycle, meaning that if I run the main loop function once, than wait for 4 milliseconds (so 5 miliseconds passes in each cycle, but only one is 'useful'), it works perfectly. I thought that I can hook up 4 other LEDs for the other 4 milliseconds, to make this work. And I cannot.

But maybe I will get that later in my embedded systems or programming studies. For now, I stick to shift registers.

As for the software:

int const Ax{8};

this is an initialization, and is equal to int const Ax = 8; I study C++ (from the internet, just for myself), I was told that this is the preferred way to initialize a variable, so I use this. Both works.

 sleep(1);

The sleep fuction is for sending the microcontroller into sleep mode for the amount of milliseconds specified between the parenthesis. It was suggested that I use sleep(1); for stability even when I don't want any delay. It is equal to the delay fuction (which delays running the main loop function of the program for the amount of milliseconds sepcified) for this case. I tried it with the delay function, same result. Since sleep is more energy consumption friendly, I decided to use that.

The MSP430 is not an arduino board, and its IDE, Energia was designed to accept a code very similar to the arduino programming, but apparently they are not interchangable. This must be the reason the sleep function won't compile for you.

As with the Instructables: thanks, I will be cautious with them. I like to get an idea and basic implementation from one place, and figure it out myself. But I guess I should get the concepts from a place where people know what they are doing and why.

Thanks again for taking the time for my questions, problems.

Robert

The MSP430 is not an arduino board, and its IDE, Energia was designed to accept a code very similar to the arduino programming, but apparently they are not interchangable.

So why are you posting on an Arduino Forum? At best it is a bit cheeky and at worst it is downright dishonest.

It was suggested that I use sleep(1); for stability even when I don't want any delay.

Sounds like rubbish to me.

Sleep on an Arduino is a very different concept due to the processor architecture.

Hey Mike,

allow me a quote from my first post: 'I use Energia as my coding software. That is, because I use an MSP430 as the microcontoller (this is why I use a 3.3V voltage source). I know this is an arduino forum, but a lot of you have built a LED cube, even bigger than mine, and as I read the posts, this is a helpful community with a lot of knowledgable members. And my problem is not microcontroller-based. Also, it is very similar to any arduino board, it has a 16 MHz CPU, so computation should not be a problem.'

I don't believe my question offfends anyone, and if you don't feel it appropriate here, please report it to a moderator.

As for sleep function, it is possible that using it for proper code execution is rubbish, I have no idea. I don't see any disadvantage using it, so I do. Think of it as a delay function instead.

Robert

please report it to a moderator.

OK