Go Down

Topic: Shift Register Multiplexing - 8x8x8 - Code Efficiency? (Read 1 time) previous topic - next topic

kriogenic

Hey there,

I have several other micro controllers to play around with but this time I thought I would try build an 8x8x8 on the arduino and see if it would be possible to not use LED drivers such as the TLC5940.
I decided to go with shift registers and for an 8x8x8 cube that required 9 registers.
8, 8 bit registers to control the 64 anodes of the matrix
1, 8 bit register to control the 8 cathodes of the matrix

With this circuit it means each shift register can have all 8 LEDS on at once without over drawing any IO pins or the registers itself.

I have some code which works to light up the lights I want, but when adding this into a loop, the loop is rather large and I THINK it takes too long to execute. Which is why the Persistence of Vision is messed up and the lights are not changing fast enough.

Here is some of the code.

Light Array in Hex and Ground Layer Init.
Code: [Select]

int CubeAnimationArray [8] [8]= {
  {255,255,255,255,255,255,255,255},
  {255,129,129,129,129,129,129,255},
  {255,129,129,129,129,129,129,255},
  {255,129,129,129,129,129,129,255},
  {255,129,129,129,129,129,129,255},
  {255,129,129,129,129,129,129,255},
  {255,129,129,129,129,129,129,255},
  {255,255,255,255,255,255,255,255}
};

int PinArray[8] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};


Function which is meant to display the above as a solid frame it is in hex so it SHOULD be the outline of the 8x8x8 cube.
Code: [Select]

void RunAnim(int Array[8][8]){ //Array becomes the frame which should be displayed on the 8x8x8
  for(int j = 0; j <= 7; j++){ //for all layers in Array (Array[x][])
    digitalWrite(latchPin, 0);  //Pull Low
    for(int k = 0; k<=7; k++){
      shiftOut(dataPin, clockPin, Array[j][k]); //shiftOut the 8 bytes of data to the 8 registers to control anodes
    }
      digitalWrite(latchPin, 1); // Pull High
      digitalWrite(glatchPin,0); // Pull Ground Low
       shiftOut(negdatapin, clockPin, PinArray[j]); //shiftOut the byte for which cathode should be enabled
       digitalWrite(glatchPin,1); // Pull Ground High
  }


This code works perfectly fine. However the time in lighting up the layers is too slow which means it more looks like an animation scrolling up the layers then it does a solid outline.

Anyone have some ideas on how I may do this a little more efficiently?

Thanks,
Kriogenic.

marklar

These posts may help ..

shiftOutFast using direct port manipulation ..
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1254488619

shiftOutEvenFaster :) - using SPI.  Here is a final version for RGBs but it would work for single LEDs as well.
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1278251011

Hope that helps

CrossRoads

So your 8x8x8 cube, you've basically got 1 long string of 8 shift registers sourcing current, each output connected to 8 LEDS #1-8 say, with the cathode of all the #1s connected, all the #2s connected and each cathode group all sunk by a big transistor controlled by 9th shift register? So you do the 8 shiftouts (or SPI.transfers) into the serial-in register, do the latchout & enable the cathode, while the next set of 8 are being shifted into the serial-in register, and after the display time turn off the cathode, do the the latchout & enable the cathode for the next layer.

I had always envisioned the cubes as being two shift register per layer with anodes on one side and cathodes on the other, write the 8 anode shift registers, turn on the cathode, next set of anodes, next cathode, etc. But since its set up as 8 layers of 8x8 vs 8 layers of 64, can get away with smaller cathode drivers, each sinking 8 LEDs vs 64. 16 shift registers vs 9.

I could see the 1x64 being easier to build up than 8x8s and having to keep each layer totally isolated, while the eight 1x64s only the anodes need to be isolated, all the cathodes in each layer being connected. Eight SPI transfers per row would be really quick too.
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.

kriogenic

Hey thanks for the replies.

@marklar
I took a look at shiftOutEvenFaster, but unfortunately I don't understand a great deal about SPI.
I tried to use the code given and tried to understand it but I still don't quite get it.
It was not on my priority list but if I could keep PWM like in the code posted to allow brightness changes then I would like to keep so...
Any more help regarding SPI would be great.

@CrossRoads, yes you are right there are 8 registers in a string (3 outputs on arduino) and then I have the ground register (2 new inputs Data and Latch, sharing same clock)
I have tried using SPI from a few example but have had no luck getting any lights on my matrix to display using SPI.
Same here, anymore help regarding SPI would be awesome.

Thanks,
Kriogenic.

CrossRoads

Okay, I'm kinda winging the use of arrays here, might be a little jumbled still
Code: [Select]


#include <SPI.h>
// must use the SPI pins
// MOSI to shift Reg SER In line on chip #1
// SCK goes to all shift registers
// MISO (if reading back), is tied up by SPI library otherwise
// define a chip select pin
spiCS = 10; // for example, can  be any pin


void setup(){
// must include this
pinMode (spiCS, OUTPUT);
digitalWrite (spiCS, HiGH);  // off state
}

void loop(){
// to output the date, take CS low, do the SPI transfers, bring CS high - the low to hi moves the data to the output register
// loop within a loop to select the layer, then load the array
for (y = 0; y<9; y=y+1){
digitalWrite (layer[y], LOW);  // assumes you have 8 CSs from arduino outputs -
// redo that as needed for your shift register to walk a 1 across the outputs
for (x = 0; x<8; x=x+1){
array_index = (y*8)+x; 
SPI.transfer (data_array[array_index]); // 1st pass 0-7, 2nd 8-15, 3rd 9-23, etc
} // next x
digitalWrite (spiCS, HIGH); // moves data into output register
digitalWrite (layer[y], HIGH); // assumes need a high out to drive NPN transistor to bring cathode low
} // next y
// maybe use blink without delay scheme if only want to update the layers at defined times


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.

kriogenic

Ahh I see what needs to be done.

Thanks for the clarification it makes perfect sense now.

Seems to be working fine, now its just connection problems in my circuit somewhere

Thanks for all the help,
Kriogenic.


Okay, I'm kinda winging the use of arrays here, might be a little jumbled still
Code: [Select]


#include <SPI.h>
// must use the SPI pins
// MOSI to shift Reg SER In line on chip #1
// SCK goes to all shift registers
// MISO (if reading back), is tied up by SPI library otherwise
// define a chip select pin
spiCS = 10; // for example, can  be any pin


void setup(){
// must include this
pinMode (spiCS, OUTPUT);
digitalWrite (spiCS, HiGH);  // off state
}

void loop(){
// to output the date, take CS low, do the SPI transfers, bring CS high - the low to hi moves the data to the output register
// loop within a loop to select the layer, then load the array
for (y = 0; y<9; y=y+1){
digitalWrite (layer[y], LOW);  // assumes you have 8 CSs from arduino outputs -
// redo that as needed for your shift register to walk a 1 across the outputs
for (x = 0; x<8; x=x+1){
array_index = (y*8)+x; 
SPI.transfer (data_array[array_index]); // 1st pass 0-7, 2nd 8-15, 3rd 9-23, etc
} // next x
digitalWrite (spiCS, HIGH); // moves data into output register
digitalWrite (layer[y], HIGH); // assumes need a high out to drive NPN transistor to bring cathode low
} // next y
// maybe use blink without delay scheme if only want to update the layers at defined times




kriogenic

On a similar topic,

I have gone with Marklars' ShiftOutEvenFaster,
I don't really understand it and that is a problem.

I have tried reading up on PortManipulation but dont get a couple of the functions.

Code: [Select]

//--- Used to setup SPI based on current pin setup
//    this is called in the setup routine;
void setupSPI(){
  byte clr;
  SPCR |= ( (1<<SPE) | (1<<MSTR) ); // enable SPI as master
  SPCR &= ~( (1<<SPR1) | (1<<SPR0) ); // clear prescaler bits
  clr=SPSR; // clear SPI status reg
  clr=SPDR; // clear SPI data reg
  SPSR |= (1<<SPI2X); // set prescaler bits
  delay(10);
}


//--- The really fast SPI version of shiftOut
byte spi_transfer(byte data)
{
  SPDR = data;   // Start the transmission
  loop_until_bit_is_set(SPSR, SPIF);
  return SPDR;   // return the received byte, we don't need that
}


A nice explanation on this would be nice as I would like to do something similar but with PORTD for my one ground layer shift register, to switch layers quicker.

Thanks,
Kriogenic.

Go Up