I created a LEDDriver class. I have some #ifdefs in the code for testing. When I compile using XCode I define TESTING. This enables code that outputs data to a file for debugging on the PC before uploading to the arduino. Befor eI upload to the arduino I undefine TESTING so that code won't execute.
I based the code off the tlc5947's datasheet and the octobright code. It contains two arrays: temp_data[NUM_PINS] and led_data[NUM_PINS]. led_data gets pushed out to the tlc. temp_data gets pushed to led_data if it is different than led_data. This way I am not pushing led_data to the tlc if I don't need to.
LEDDriver.h
#ifndef LEDDriver_H
#define LEDDriver_H
#include <stdint.h>
#include "led_config.h"
#ifdef TESTING
#include <iostream> //remove for AVR
#include <fstream>
using namespace std;
#endif
class LEDDriver
{
public:
LEDDriver();
~LEDDriver();
void SetPins(uint8_t pClock_pin, uint8_t pData_pin, uint8_t pBlank_pin, uint8_t pLatch_pin);
void Update(); //this should set pLED_data to tempLedData, then compare with led_data to see if need to update.
//if need to update then update led_data and SetLatch(). This will minimize flickering. Only latch if needed.
void SetClock();
void SetLatch();
void BlankToggle();
void ClearLEDS();
void SetLED(uint16_t led, uint16_t red, uint16_t green, uint16_t blue);
private:
#ifdef TESTING
ofstream fp_out;
#endif
uint16_t temp_data[NUM_PINS];
uint16_t led_data[NUM_PINS];
uint8_t blank_status;
uint8_t clock_pin;
uint8_t data_pin;
uint8_t blank_pin;
uint8_t latch_pin;
void _WriteChannel(uint16_t value);
void _UpdateLEDS();
};
#endif
LEDDriver.cpp
#include "led_config.h"
#include "LEDDriver.h"
#include "wiring.h"
#include "HardwareSerial.h"
#ifdef TESTING
#include <iostream> //remove for AVR
#include <fstream>
using namespace std;
#endif
LEDDriver::LEDDriver()
{
blank_status = LOW;
#ifdef TESTING
fp_out.open("myfile.txt");
#endif
}
LEDDriver::~LEDDriver()
{
#ifdef TESTING
fp_out.close();
#endif
}
void LEDDriver::SetPins(uint8_t pClock_pin, uint8_t pData_pin, uint8_t pBlank_pin, uint8_t pLatch_pin)
{
clock_pin = pClock_pin;
data_pin = pData_pin;
blank_pin = pBlank_pin;
latch_pin = pLatch_pin;
}
void LEDDriver::Update()
{
//compare with led_data to see if need to update.
//if need to update then update led_data and SetLatch(). This will minimize flickering. Only latch if needed.
uint8_t updateleds = 0;
int i = 0;
//Check if we need updating first TODO
//The function shoudl transfer tempData if needed
for(i = (NUM_PINS - 1); i >= 0; i--)
{
if(led_data[i] != temp_data[i])
{
updateleds++;
led_data[i] = temp_data[i];
}
}
//Check if leds need to be updates then push the update
if(updateleds > 0)
{
#ifdef TESTING
fp_out << " Update " << endl;
#endif
#ifdef SERIAL_DEBUG
Serial.println(" Update ");
#endif
_UpdateLEDS();
SetLatch();
}
#ifdef TESTING
else
{
fp_out << " No update " << endl;
}
for(i = (NUM_PINS - 1); i >= 0; i--)
{
fp_out << "l " << i << ": " << led_data[i] << endl;
}
fp_out << flush;
#endif
}
void LEDDriver::SetClock()
{
digitalWrite(clock_pin, HIGH);
digitalWrite(clock_pin, LOW);
}
void LEDDriver::SetLatch()
{
digitalWrite(latch_pin, HIGH);
delay(1);
digitalWrite(latch_pin, LOW);
}
void LEDDriver::ClearLEDS()
{
for(int i = (NUM_PINS - 1); i >= 0; i--)
{
temp_data[i] = 0;
}
}
void LEDDriver::BlankToggle()
{
if(blank_status == LOW)
{
blank_status = HIGH;
}
else
{
blank_status = LOW;
}
}
void LEDDriver::SetLED(uint16_t led, uint16_t red, uint16_t green, uint16_t blue)
{
temp_data[(led*PINS_PER_LED)+RED] = red;
temp_data[(led*PINS_PER_LED)+GREEN] = green;
temp_data[(led*PINS_PER_LED)+BLUE] = blue;
}
void LEDDriver::_WriteChannel(uint16_t value)
{
int bit;
// Write value, MSB first
for (bit=11; bit>=0; --bit)
{
if (value & (1<<bit))
{
digitalWrite(data_pin, HIGH);
}
else
{
digitalWrite(data_pin, LOW);
}
// We need to wait 30ns after writing data before clocking it in.
// Fortunately, our AVR is slow enough that we don't need to
// do an explicit wait here
digitalWrite(clock_pin, HIGH);
digitalWrite(clock_pin, LOW);
}
}
void LEDDriver::_UpdateLEDS()
{
//Check if we need updating first TODO
//The function should transfer tempData if needed
for(int i = (NUM_PINS - 1); i >= 0; i--)
{
_WriteChannel(led_data[i]);
#ifdef SERIAL_DEBUG
Serial.print("write led pin ");
Serial.print(i);
Serial.print(": ");
Serial.println(led_data[i]);
#endif
#ifdef TESTING
fp_out << "write led pin " << i << ": " << led_data[i] << endl;
fp_out << flush;
#endif
}
SetClock();
}