0

Sorry for my code is long and my English is not good.

I'm working with 8x8x8 LED cube project using Arduino nano. I tried to understand code, but I don't understand how cube[][] data write on pins.

I just want to know, how write the data from cube[8][8] to hardware using SPI. code download using this link.

Thanks in advance.

My code is here :

#define AXIS_X 1
#define AXIS_Y 2
#define AXIS_Z 3
#define REFRESH_RATE 120

int CUBE_SIZE = 8;
int SPI_CS = 10;// This SPI Chip Select pin controls the MAX72xx
byte value[8];

volatile unsigned char cube[8][8];
volatile int current_layer = 0;

void setup()
{
  Serial.begin (115200);
  Serial.println("jolliFactory 8x8x8 jolliCube Demo example 1.0");              

  pinMode(SPI_CS, OUTPUT);

  SPI.begin();

  maxTransferAll(0x0F, 0x00);   // 00 - Turn off Test mode
  maxTransferAll(0x09, 0x00);   // Register 09 - BCD Decoding  // 0 = No decoding
  maxTransferAll(0x0B, 0x07);   // Register B - Scan limit 1-7  // 7 = All LEDS
  maxTransferAll(0x0C, 0x01);   // 01 = on 00 = Power saving mode or shutdown
  maxTransferAll(0x0A, 0x0F);   // Set Brightness Intensity

  setUpInterrupts();
}

// Get the current status of a voxel
unsigned char getvoxel(int x, int y, int z)
{
    if (inrange(x,y,z))
    {
        if (cube[z][y] & (1 << x))
        {
            return 0x01;
        } else
        {
            return 0x00;
        }
    } else
    {
        return 0x00;
    }
}

void maxTransferAll(uint8_t address, uint8_t value)
{
  digitalWrite(SPI_CS, LOW); 

    for ( int c=1; c<= CUBE_SIZE;c++) {
        SPI.transfer(address);
        SPI.transfer(value);
    }

  digitalWrite(SPI_CS, HIGH); 
}

void maxTransferOne(uint8_t whichMax, uint8_t address, uint8_t value)
{
  byte noop_reg = 0x00;    //max72xx No op register
  byte noop_value = 0x00;  //value

  digitalWrite(SPI_CS, LOW); 

  for (int i=CUBE_SIZE; i>0; i--)   // Loop through our number of Max72xx ICs 
  {
    if (i==whichMax)
    {
      SPI.transfer(address);
      SPI.transfer(value);
    }
    else
    {
      SPI.transfer(noop_reg);
      SPI.transfer(noop_value);
    }
  }

  digitalWrite(SPI_CS, HIGH);
}

void maxTransferLEDCube(uint8_t address)
{
  digitalWrite(SPI_CS, LOW); 

  for (int i=0; i<CUBE_SIZE; i++)   // Loop through our number of Max72xx ICs 
  {
      SPI.transfer(address);
      SPI.transfer(value[CUBE_SIZE-i-1]);
  }

  digitalWrite(SPI_CS, HIGH);
}

void setUpInterrupts()
{
  cli();//stop interrupts while we set them up
  //set up an interrupt with timer1
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1  = 0;
  OCR1A = (16000000/REFRESH_RATE/1024/CUBE_SIZE -1);
  TCCR1B |= (1 << WGM12);
  // Set to CS10 and CS12 so we have the 1024
  TCCR1B |= (1 << CS12) | (1 << CS10);  
  TIMSK1 |= (1 << OCIE1A);
  sei();//re-allow interrupts 
}

ISR(TIMER1_COMPA_vect)
{   
  for(byte y = 0 ; y < CUBE_SIZE ; y++)
  {
    byte b = 0;

    for(byte x = 0 ; x < CUBE_SIZE ; x++)
    {
      //form data byte
      b = b << 1;

      if (getvoxel(x,y,current_layer)==1)
      {
        b |= 1;        
      }
    }
        value[y] = b;    
  }

  maxTransferLEDCube(CUBE_SIZE - current_layer);

  current_layer++;

  if (current_layer == 8)
    current_layer = 0;
}

1 Answer 1

1

First, you need to know how the LEDs are arranged. There are 8 layers, each with 8 rows, each with 8 LEDs.

Each LED is represented as a single bit inside unsigned char cube[8][8]; - the first [8] is the array of layers, the second [8] is the array of rows, and the unsigned char holds 8 bits to represent the state of the 8 LEDs in that row.

Each LED layer has one MAX7219 8x8 LED Matrix Controller. To tell it what to do you need to give it a Command byte and a Data byte. So to tell it to light up LEDs 1, 2, and 7 on the fourth row, you need to tell it 0x04 0x86. You send this command by setting CS LOW, sending the 16 bits of the Command+Data, then setting CS HIGH.

Each MAX7219 is connected one after the other in an SPI string. To command all of them at once you need to set CS LOW, send 16 bits for each MAX7219 (128 bits in all), then set CS HIGH. If you only want to command one MAX7219, you need to send a NOP Command+Data (0x00 0x00) to all the others.

The way the program works is:

  1. setup()

    a. Initialise the Serial port, and print a message.
    b. Set the CS pin as an OUTPUT, then initialise SPI.
    c. Initialise all the MAX7219 chips by sending a series of commands -
    the same Command+Data to each of them (maxTransferAll()).
    d. Initialise the Timer interrupt (setUpInterrupts()).

  2. loop()
    This isn't shown in the code. Presumably it alters the cube[8][8] array to make the special effects.

  3. TIMER1_COMPA_vect (the interrupt handler)
    Every time the timer ticks, the handler will command all of the MAX7219s to show the next row of LEDs. This will last until the next timer tick, when the next row will be displayed. If this is done fast enough, the human eye's "persistence of vision" will not see the rows flickering.

    For each row (`y`) in the `cube` array
       Set `b` to 0
       For each bit ('x') in the `cube` data
          If the bit is set (`getvoxel(...)`) set a bit in `b`.
       Store `b` in the `value[y]` array
    

value now holds the bytes needed as Data for the next row for each of the MAX7219 chips.

    Send value over SPI using `maxTransferLEDCube(...)`

Since the cube displays the same row for each layer simultaneously, the Command doesn't have to change, only the Data does. That's what the value array holds: the Data to be sent to each MAX7219 chip.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.