Now however, I've changed the code to this, and it's not working:
class LED {
public:
static int MODULES; // Number of LED modules connected. Defined in config.txt.
static byte * data; // LED data is stored as a string of 12 bit LED values. There are 3 bytes for every two LEDs. We store it this way because the data does not need to be altered when we are shifting it out to the TLC5947s. Modifying the data with bit shifts would be very expensive and there is a lot of data to move.
static byte * scale; // Scaling factor for LED brightness. Used when say, you want to be able to adjust the brightness of the powercell without changing all the code that assumes the max desired brightness is 1.0. Value stored here is scaling_factor*255, where scaling factor is 0..1.
void set(int, float, float);
float get(int);
private:
};
// Class global variable declatations:
int LED::MODULES;
byte * LED::data;
byte * LED::scale;
Inside setup():
// Configure LEDs:
LED::MODULES = 2; // Eventually this will be defined in config.txt.
LED::data = (byte *) malloc(LED::MODULES*36 * sizeof(byte));
LED::scale = (byte *) malloc(LED::MODULES*24 * sizeof(byte));
for (int x = 0; x < (LED::MODULES * 36); x++) { LED::data[x] = 0; }
for (int x = 0; x < (LED::MODULES * 24); x++) { LED::scale[x] = 255; } // Set LED brightness scale factor to default, then adjust only those which are defined in config.txt.
/*
This function sets the value of the LED at the specified index. (value = 0..4095 - 0 is first index)
*/
void setLED(int index, int value) { // Could change this to take a floating point argument! Also may want to change so index 1 is first LED.
int firstBit, firstByte;
// index * 12 = first bit of LED value.
// (index * 12) / 8 = byte containing first bit.
// Format of data:
// Bit order -> 76543210
// [5]=33333333 [4]=33332222 [3]=2222222 [2]=11111111 [1]=11110000 [0]=00000000 <- Array starts here.
// Note that the data is shifted out starting with the last byte in the array and moving back to the first, and it is shifted out in MSB order.
// (index * 12) / 8 = start byte
// (0 * 12) / 8 = 0
// (1 * 12) / 8 = 1
// (index * 12) % 8 = start bit (will be 0 or 4)
//( 1 * 12) % 8 = 4
firstBit = index * 12;
firstByte = firstBit / 8;
if ((firstBit % 8) == 0) { // LEDs 0, 2, 4...
LED::data[firstByte] = value; // Place bits 7..0 in first byte.
LED::data[firstByte+1] = (LED::data[firstByte+1] & 0b11110000) | (value >> 8); // Place bits 11..8 in bits 3..0 of second byte.
} else { // LEDs 1, 3, 5...
LED::data[firstByte] = (LED::data[firstByte] & 0b00001111) | ((value & 0b1111) << 4); // Place bits 3..0 in bits 7..4 of first byte.
LED::data[firstByte+1] = value>>4; // Place bits 11..4 in second byte.
}
}
/*
This function shifts all the LED data out to the TLC5947's.
*/
#define NOP __asm__ __volatile__ ("nop\n");
#define WAIT NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP // 10 NOPs
void updateLEDs() {
const int LEDFrameTime = 1000 / 30; // The number of milliseconds between each update of the LEDs. 1000 / 24 = 24fps.
static unsigned long nextLEDFrameTime = 0;
//uint8_t *thisLED;
//uint8_t *lastLED;
byte *thisLED;
byte *lastLED;
if (time >= nextLEDFrameTime) { // If it is time for an LED update...
//unsigned int time = micros();
thisLED = &LED::data[LED::MODULES*36]; // The first operation is to decrement this pointer, so the first time we write thisLED it will be array index LEDMODULES*36-1
lastLED = &LED::data[0];
cli(); // Halt interrupts.
do {
SPDR = *--thisLED; WAIT;
//while (!(SPSR & _BV(SPIF))); SPDR = *thisLED--; // Wait for transfer of byte over SPI bus to complete, then transfer *thisLED into SPDR register, and decrement address of *thisLED.
} while (thisLED != lastLED); // thisLED is decremented one last time before we hit the end of the loop, so after byte 0 transfers, the loop exits.
WAIT; // Wait for last byte to finish transfer.
SPSR = SPSR & ~_BV(SPIF); // Clear transfer flag.
//while (!(SPSR & _BV(SPIF))); // Wait for last byte to finish transfer.
// 15 nops and:
// 6x unroll = 276us
// 12x unroll = 256us
// 24x unroll = 252us
// This may be leaving the SPIF flag set.
// Clear SPIF flag:
//while (!(SPSR & _BV(SPIF))); // Wait for last byte to finish transfer.
// 340 microseconds
// The trick which makes the above so fast is that we decrement the pointer and do the conditional jump while we are waiting for the previous byte transfer to complete.
// Move data from shift register into latch register:
LATPORT &= ~(1 << LATPIN); // Set LATCH pin low. It is important to do this first, just before transitioning high! I don't know why, but the LED modules won't work right otherwise!
LATPORT |= (1 << LATPIN); // Set LATCH pin high. Transitioning from low to high moves all data from the shift register into the latch registers.
ENAPORT |= (1 << ENAPIN); // Set BLANK pin high. Turn all outputs off, and reset grayscale timer. Blanking reduces flicker, but it does not seem to matter if it is before, after, or in the middle of latching.
ENAPORT &= ~(1 << ENAPIN); // Set BLANK pin low. Turn all outputs on.
sei(); // Reenable interrupts.
//time = micros() - time;
//Serial1.println(time,DEC);
nextLEDFrameTime = time + LEDFrameTime; // Set the time of the next update.
}
}
Where have I gone wrong here?