Go Down

Topic: 8x8x8 multiplexed LED cube with an Arduino Mega 2560 (Read 41 times) previous topic - next topic

Un4Seen

#185
Feb 19, 2013, 03:55 pm Last Edit: Feb 19, 2013, 03:58 pm by Un4Seen Reason: 1
Hi CrossRoads!

Yes, the N+1 shift registers (where N is the size of the cube in one dimension) are daisy chained, one for the anode planes and N for the cathode columns. The first shift register on the line controls the anode planes and the rest of N shift registers control the cathode columns.

Indeed, this only writes out one byte:
Code: [Select]

digitalWrite (PIN_SS, LOW); //Start transferring data
SPI.transfer (0xFF);  //Turn off the current plane (in fact all planes)(all 1s)
digitalWrite (PIN_SS, HIGH); //Done transferring data

That should be enough to turn everything off, because the value (all 1s) gets into the first shift register and turns off all the anode planes, so it does not matter what is left in the next N shift registers, which control the cathode columns. Or at least, that's how I imagine it...

cubeData is a matrix consisting of NxN bytes. The first index is the plane index, the second index is the row index inside the plane. Each element of the matrix contains one byte, which holds the data for one column inside the horizontal plane. In other words cubeData has NxN elements and each element contains N bits (obviously N cannot exceed 8 ).

Did I understand correctly that when you have X pieces of shift registers daisy chained, the first byte sent out via SPI.tansfer() goes into the first shift register, then the second SPI.transfer() pushes it into the second shift register, and so on?

Un4Seen

#186
Feb 19, 2013, 04:39 pm Last Edit: Feb 19, 2013, 04:46 pm by Un4Seen Reason: 1
Actually, if the data goes live only when the SS pin is turned back HIGH, then I think this should be enough to switch to the next horizontal LED plane (next multiplexing step):
Code: [Select]

void displayCurrentPlane ()
{
    digitalWrite (PIN_SS, LOW); //Start transferring data

   for (byte i = N - 1; i >= 0; --i) //Set up the LEDs inside the current plane
   {
       SPI.transfer (cubeData[currentPlaneIndex][i]);
   }

   SPI.transfer (~(1 << currentPlaneIndex)); //Turn on the current plane and turn off all other planes (current plane's bit is set to 0, all other bits are set to 1)

   digitalWrite (PIN_SS, HIGH); //Done transferring data
}

Un4Seen

Tonight I've "fired up" the LED cube. For about 2 hours it did not work at all. Turned out I had one short plus some misunderstanding about how my solderless breadboard's +/- rails work. I've solved these and the cube started working :D

Unfortunately it doesn't quite work as I would have expected it to. There are some mysteries that I can't explain:
1. In theory we have discussed that a cathode column can be turned on by setting its bit to 1. This works as expected. We have also discussed that an anode plane can be turned on by setting its bit to 0. Instead of this it turns on when I set its bit to 1, not to 0. I have followed CrossRoads circuit design 100%.
2. When I turn an anode plane on (by setting its bit to 1) some other planes also turn on (one or two planes above/below it), but much more faintly than the plane that actually needs to be turned on.
3. When I set all anode planes to off (by setting all bits to 0), the middle two planes turn on at full brightness.

CrossRoads

For the anode/layer, writing a 1 into the shift register bit makes the output go low & turns on the PNP to make the anodes High.
For each cathode, writing a 1 into the shift register bit to make the output go low and turn on the LED.

Can you seperate the SS for the anode from the SS for the cathodes?

Instead of your funny << shift thing, pull the data from an array:
Code: [Select]

for (layer = 0 to 7){
// turn off all layers
digitalWrite(AnodeSS, LOW);
  SPI.transfer(0x00);
digitalWrite(AnodeSS, HIGH);

// write cathode - I suppose this could be the array structure you have above too
digitalWrite(CathodeSS, LOW);
  SPI.transfer(cathodeData[2*layer]);        // 0,2,4,6,8,10,12,14
  SPI.transfer(cathodeData[(2*layer)+1]); // 1,3,5,7,9,11,13,15
digitalWrite(CathodeSS, HIGH);
// this seems simpler to me tho - just 2 bytes per layer

// turn on anode
digitalWrite(AnodeSS, LOW);
  SPI.transfer(anodeData[layer]);
digitalWrite(AnodeSS, HIGH);

}
Designing & building electrical circuits for over 25 years. Check out the ATMega1284P based Bobuino and other '328P & '1284P creations & offerings at  www.crossroadsfencing.com/BobuinoRev17.
Arduino for Teens available at Amazon.com.

Un4Seen

Ok, so in order to turn on an LED situated at the intersection of the layer X and column Y, you need to write 1 into the Xth bit of the anode shift register and 1 into the appropriate bit of the appropriate cathode shift register. The main idea is that both the anode and cathode shift registers need to receive a 1 bit in order to turn on the LED. That's nice. It seems that I misunderstood it earlier, but now everything is clear.

I'm not so worried at the moment about how exactly I write those bits into the shift registers, as that seems to be working. On the other hand I'm very much worried about the fact that turning a layer on also turns on  1 or 2 other layers below and/or above it, but not as brightly as the targeted layer. Also, if I turn off all the layers, the two middle layers turn on at full brightness. That's very worrying... seems like a hardware bug...

For testing purposes I have disabled the whole multiplexing and everything that can make debugging hard. My whole loop() function is empty now, I just test things in the setup() function.

For example, if my setup() contains this:
Code: [Select]

void setup ()
{
    pinMode (PIN_MOSI, OUTPUT);
    pinMode (PIN_SCK, OUTPUT);
    pinMode (PIN_SS, OUTPUT);

    SPI.begin ();
    SPI.setBitOrder (MSBFIRST);
    SPI.setClockDivider (SPI_CLOCK_DIV4);

    digitalWrite (PIN_SS, LOW); //start transferring data
    SPI.transfer (B00000000); //turn off cathode columns 8-15
    SPI.transfer (B00000001); //turn on cathode column 0, turn off cathode columns 1-7
    SPI.transfer (B00000001); //turn on the first anode plane (anode plane 0)
    digitalWrite (PIN_SS, HIGH); //done transferring data
}


The code cannot get simpler than this. There's clearly no error in it and yet anode planes 1 and 2 also turn on in a dim manner next to anode plane 0 which turns on at full brightness, as instructed.

If in the last SPI.transfer(), which sets the anode planes, I transfer all 0 bits, the two middle anode planes (1 and 2) turn on.

Remember that I have a 4x4x4 cube driven by 3 daisy chained shift registers. The first 4 outputs of the first shift register on the line control the 4 anode layers through the MOSFETS and the next two shift registers on the line use all their 8 outputs to control the 16 cathode columns.

At the moment I don't have the slightest clue, what can be wrong, but it smells like a hardware problem to me...
Let me know if you suspect anything.

Thanks!

Go Up