//includes
#include <SPI.h>
//constants
#define ANODE_LEVELS 8 //currently only supported up to 8 anode layers, untested anything lower than 8 but should technically work...maybe with a tweak or two
#define REFRESH_RATE 500
//instance variables
//Timer anodeTimer;
//THESE PIN NUMBERS CANNOT BE CHANGED, THERE ARE HARDWARE DEDICATED TO SPI
#define dataPin 11
#define clockPin 13
#define latchPin 10 //this one can be any pin
#define LATCH (1<<2) //SS (RCK), pin 10 is port B2
//Anode Layers begin at:
//brightness bit 0: 0:[0][0] 1:[24][0] 2:[48][0] 3:[72][0] 4:[96][0] 5:[120][0] 6:[144][0] 7:[168][0]
//brightness bit 1: 0:[0][1] 1:[24][1] 2:[48][1] 3:[72][1] 4:[96][1] 5:[120][1] 6:[144][1] 7:[168][1]
//brightness bit 2: 0:[0][2] 1:[24][2] 2:[48][2] 3:[72][2] 4:[96][2] 5:[120][2] 6:[144][2] 7:[168][2]
//brightness bit 3: 0:[0][3] 1:[24][3] 2:[48][3] 3:[72][3] 4:[96][3] 5:[120][3] 6:[144][3] 7:[168][3]
// 0: GRBGRBGR 22111000
// 1: RBGRBGRB 54443332
// 2: BGRBGRBG 77766655
//...: ........ ........
volatile byte anodeLevel = 0;
volatile byte bamCounter = 0;
volatile byte bamBit = 0;
volatile unsigned long count = 0;
volatile long led[64][4];
#define clearMatrix() memset(led, 0, sizeof(led));
//functions
void setup()
{
Serial.begin(115200);
Serial.println('\n');
SPI.setBitOrder(MSBFIRST);//Most Significant Bit First
SPI.setDataMode(SPI_MODE0);// Mode 0 Rising edge of data, keep clock low
SPI.setClockDivider(SPI_CLOCK_DIV2);//Run the data in at 16MHz/2 = 8MHz
//noInterrupts();// kill interrupts until everybody is set up
//We use Timer 1 to refresh the cube, its the only 16 bit timer
TCCR1A = B00000000;//Register A all 0's since we're not toggling any pins
TCCR1B = B00001011;//bit 3 set for CTC mode, will call interrupt on counter match, bits 0 and 1 set to divide clock by 64, so 16MHz/64=250kHz
//TIMSK1 = B00000010;//bit 1 set to call the interrupt on an OCR1A match
OCR1A = (unsigned int)((250000UL / (REFRESH_RATE * ANODE_LEVELS)) - 1UL);//our clock runs at 250kHz, which is 1/250kHz = 4us, with OCR1A set to 30, the interrupt will be called every (30+1)x4us=124us (8kHz)
pinMode(dataPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(latchPin, OUTPUT);
SPI.begin();//start up the SPI library
interrupts();//let the show begin, this lets the multiplexing start
}
//volatile byte x2 = 7, y2 = 7, z2 = 7, r2 = 15, g2 = 15, b2 = 15;
void loop()
{
count = micros();
//derp();
//setLED(x2, y2, z2, r2, g2, b2);
setLED(0, 0, 0, 0, 0, 0);
count = micros() - count;
Serial.println(count);
while(1);
}
//a background running interrupt when the clock matches
//ISR(TIMER1_COMPA_vect) //Interrupt Service Routine, Timer/Counter1 Compare Match A
void derp()
{
volatile signed char x, z;
//each output cycle takes ANODE_LEVELS executions and each brightness bit's numerical representation is the length of time it remains on
//then the 1st bit stays on for 1 cycle (ANODE_LEVELS executions), the 2nd bit stays on for 2 cycles (ANODE_LEVELS * 2 executions), then 4 cycles, and so forth
//but since we never* reset bamCounter, we must check for the previous bit's cycles, ie: check the 4th bit for (ANODE_LEVELS + ANODE_LEVELS * 2 + ANODE_LEVELS * 4)
//which is why you see the (x0 default implied), x1, x3, x7, higher resolution would continue x15, x31, x63, x127, or (compareTo = ANODE_LEVELS * ((1 << (bit - 1)) - 1))
if(bamCounter == ANODE_LEVELS || bamCounter == (ANODE_LEVELS * 3) || bamCounter == (ANODE_LEVELS * 7)) //hardcoded a 4 bit resolution
{
bamBit++;
}
bamCounter++;
//Anode Shift Register
SPI.transfer(0xFF - (1 << anodeLevel));
//The other 24 Shift Registers
for(z = ANODE_LEVELS - 1; z >= 0 ; z--)
{
for(x = ANODE_LEVELS - 1; x >= 0 ; x--)
{
}
}
//Toggle latch to copy data to the storage register
PORTB |= LATCH;//Latch pin (pin 10, port B2) HIGH
PORTB &= ~LATCH;//Latch pin (pin 10, port B2) LOW
if(bamCounter >= ANODE_LEVELS * 15) //4 bit resolution
{
bamCounter = 0;
bamBit = 0;
}
anodeLevel = (anodeLevel + 1) % ANODE_LEVELS;
}
// 0 1 2 3 4 5 6 7
//0 R,G,B R,G,B R,G,B R,G,B R,G,B R,G,B R,G,B R,G,B
//1 R,G,B R,G,B R,G,B R,G,B R,G,B R,G,B R,G,B R,G,B
//2 R,G,B R,G,B R,G,B R,G,B R,G,B R,G,B R,G,B R,G,B
//3 R,G,B R,G,B R,G,B R,G,B R,G,B R,G,B R,G,B R,G,B
//4 R,G,B R,G,B R,G,B R,G,B R,G,B R,G,B R,G,B R,G,B
//5 R,G,B R,G,B R,G,B R,G,B R,G,B R,G,B R,G,B R,G,B
//6 R,G,B R,G,B R,G,B R,G,B R,G,B R,G,B R,G,B R,G,B
//7 R,G,B R,G,B R,G,B R,G,B R,G,B R,G,B R,G,B R,G,B
void setLED(byte x, byte y, byte z, byte r, byte g, byte b)
{
int loc = (y << 3) + z;
led[loc][0] = (( (r & 1L) << (x * 3)) + ( (g & 1L) << (x * 3 + 1)) + ( (b & 1L) << (x * 3 + 2))) | (led[loc][0] & ~(7L << (x * 3)));
led[loc][1] = (((long)!!(r & 2L) << (x * 3)) + ((long)!!(g & 2L) << (x * 3 + 1)) + ((long)!!(b & 2L) << (x * 3 + 2))) | (long)(led[loc][1] & ~(7L << (x * 3)));
led[loc][2] = (((long)!!(r & 4L) << (x * 3)) + ((long)!!(g & 4L) << (x * 3 + 1)) + ((long)!!(b & 4L) << (x * 3 + 2))) | (long)(led[loc][2] & ~(7L << (x * 3)));
led[loc][3] = (((long)!!(r & 8L) << (x * 3)) + ((long)!!(g & 8L) << (x * 3 + 1)) + ((long)!!(b & 8L) << (x * 3 + 2))) | (long)(led[loc][3] & ~(7L << (x * 3)));
/*Serial.print(loc);
Serial.println(" = ");
for(int i = 31; i >= 0; i--){if((i + 1) % 8 == 0)Serial.print(" "); Serial.print(!!(led[loc][0] & (1L << i)));}
Serial.println();
for(int i = 31; i >= 0; i--){if((i + 1) % 8 == 0)Serial.print(" "); Serial.print(!!(led[loc][1] & (1L << i)));}
Serial.println();
for(int i = 31; i >= 0; i--){if((i + 1) % 8 == 0)Serial.print(" "); Serial.print(!!(led[loc][2] & (1L << i)));}
Serial.println();
for(int i = 31; i >= 0; i--){if((i + 1) % 8 == 0)Serial.print(" "); Serial.print(!!(led[loc][3] & (1L << i)));}
Serial.println();*/
}