Jump to content
43oh

TLC5940 - "Full Implementation"


Recommended Posts

hi there, as i already said in another thread i was working on the code for controlling the TLC5940. here it is!

 

100% working. specification-sheet i used to code this: http://www.ti.com/lit/sw/slvc106/slvc106.pdf

 


  • [*:1o0bnvvd]supports DC
    [*:1o0bnvvd]supports Grayscale
    [*:1o0bnvvd]recommendet implementation from the Programming Flow Chart
    [*:1o0bnvvd]does not support EEPROM-programming (cause you will need 22 Volts for this)
    [*:1o0bnvvd]actually does not support "Use DC from EEPROM-mode"
    [*:1o0bnvvd]LOD-Check not implemented for now ... but i think i will do this soon if i find more literature on this

 

/***
TLC5940
***/

#include "msp430g2553.h"
#include "stdbool.h"


// How many TLC's daisy-chained
#define n 2

/***
Ports
***/

// STATUS-LED
#define PORT_STATUS_LED P1OUT
#define PIN_STATUS_LED BIT0

// BLANK - to pin 23 of every TLC5940
#define PORT_BLANK P1OUT
#define PIN_BLANK BIT3

// XLAT - to pin 24 of every TLC5940
#define PORT_XLAT P1OUT
#define PIN_XLAT BIT4

// SCLK - to pin 25 of every TLC5940
#define PORT_SCLK P1OUT
#define PIN_SCLK BIT5

// SIN - to pin 26 of first TLC5940
#define PORT_SIN P1OUT
#define PIN_SIN BIT6

// GSCLK - to pin 18 of every TLC5940
#define PORT_GSCLK P1OUT
#define PIN_GSCLK BIT7

// DCPRG - to pin 19 of every TLC5940
#define PORT_DCPRG P2OUT
#define PIN_DCPRG BIT3

// VPRG - to pin 27 of every TLC5940
#define PORT_VPRG P2OUT
#define PIN_VPRG BIT4

/***
DO NOT EDIT BELOW
***/

#define x (n * 16)

/***
Brightness-Correction
***/

const int pwm_table[256] = {
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,26,28,30,32,34,36,38,40,42,
44,46,48,50,52,55,58,61,64,67,70,73,76,79,82,85,88,91,94,97,100,103,106,110,114,118,122,126,130,
134,138,142,146,150,154,158,162,166,170,174,178,182,186,190,195,200,205,210,215,220,225,230,235,
240,245,250,255,260,265,270,275,280,285,290,297,304,311,318,325,332,339,346,353,360,367,374,381,
388,395,402,409,416,423,430,437,444,451,458,467,476,485,494,503,512,521,530,539,548,557,566,575,
584,593,602,611,626,641,656,671,686,701,716,731,746,761,776,791,806,821,836,851,866,881,896,916,
936,956,976,996,1016,1036,1056,1076,1096,1116,1136,1156,1176,1196,1221,1246,1271,1296,1321,1346,
1371,1396,1421,1446,1471,1496,1526,1556,1586,1616,1646,1676,1706,1736,1766,1796,1826,1856,1886,
1921,1956,1991,2026,2061,2096,2131,2166,2201,2236,2271,2306,2341,2376,2411,2446,2481,2516,2551,
2586,2621,2656,2691,2726,2761,2796,2832,2868,2904,2940,2976,3012,3048,3084,3120,3156,3192,3228,
3266,3304,3342,3380,3418,3456,3494,3532,3572,3612,3652,3692,3737,3782,3827,3872,3917,3962,4007,4095
};

// holds the actual DC-data for each channel
char dc_data[x] = {63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63};

/***
Variables
***/

// first PWM-cycle after Dot Correction Data has changed?
bool FirstCycleFlag;

// holds the actual PWM-data for each channel
int gs_data[x];

/***
small userdefined Functions
***/

// useful macros
#define setLow(port, pin) { port &= ~pin; }
#define setHigh(port, pin) { port |= pin; }
#define pulse(port, pin) { setHigh(port, pin); setLow(port, pin); }
#define toggle(port, pin) { port ^= pin; }

/***
transfer DC-data to our TLC5940's
***/

void send_DC() {
// DCPRG - dont use DC-EEPROM
setHigh(PORT_DCPRG, PIN_DCPRG);

// VPRG - set Dot Correction Input
setHigh(PORT_VPRG, PIN_VPRG);

// Reset Counter
int Counter = 0;

// clock in Dot Correction Data
for (; {
	// Counter > n * 96 - 1
	// 6 Bits * 16 Channels = 96
	if (Counter > (n * 96 - 1)) {
		pulse(PORT_XLAT, PIN_XLAT);
		break;
	}
	else {
		// Set SIN to DC Data[Counter]
		// MSB first
		if ((dc_data[Counter / 6] >> (5 - (Counter % 6))) & 0x01) {
			setHigh(PORT_SIN, PIN_SIN);
		}
		else {
			setLow(PORT_SIN, PIN_SIN);
		}

		pulse(PORT_SCLK, PIN_SCLK);

		Counter++;
	}
}

// dont save to EEPROM - so we finish here

// set FirstCycleFlag to true
FirstCycleFlag = true;
}

/***
transfer PWM-data to our TLC5940's
***/

void send_GS() {
if (FirstCycleFlag == true) {
	setLow(PORT_VPRG, PIN_VPRG);
}

// Reset Counters
int GSCLK_Counter = 0;
int Data_Counter = 0;

setLow(PORT_BLANK, PIN_BLANK);

// clock in PWM Data
for (; {
	if (GSCLK_Counter > 4095) {
		setHigh(PORT_BLANK, PIN_BLANK);
		pulse(PORT_XLAT, PIN_XLAT);

		if (FirstCycleFlag == true) {
			pulse(PORT_SCLK, PIN_SCLK);
		}

		FirstCycleFlag = false;

		break;
	}
	else {
		// 12 Bit * 16 Channels = 192
		if (Data_Counter > (n * 192 - 1)) {
			pulse(PORT_GSCLK, PIN_GSCLK);
			GSCLK_Counter++;
		}
		else {
			// Set SIN to GS Data[Counter]
			// MSB first
			if ((gs_data[Data_Counter / 12] >> (11 - (Data_Counter % 12))) & 0x01) {
				setHigh(PORT_SIN, PIN_SIN);
			}
			else {
				setLow(PORT_SIN, PIN_SIN);
			}

			pulse(PORT_SCLK, PIN_SCLK);

			Data_Counter++;

			pulse(PORT_GSCLK, PIN_GSCLK);

			GSCLK_Counter++;
		}
	}
}
}

/***
Our main program
***/

void main(void) {
// stop WDT - WDTPW is the password needed for every write and then tell watchdog to hold
WDTCTL = WDTPW | WDTHOLD;

BCSCTL1 = CALBC1_16MHZ;
DCOCTL = CALDCO_16MHZ;

// initialize the ports connected to the TLC's
// set ports to output-direction
P1DIR |= (PIN_STATUS_LED|PIN_BLANK|PIN_XLAT|PIN_SCLK|PIN_SIN|PIN_GSCLK);
P1OUT = 0x00;
P2DIR |= (PIN_DCPRG|PIN_VPRG);
P2OUT = 0x00;

// initialize TLC5940
setLow(PORT_GSCLK, PIN_GSCLK);
setLow(PORT_SCLK, PIN_SCLK);
setLow(PORT_DCPRG, PIN_DCPRG);
setHigh(PORT_VPRG, PIN_VPRG);
setLow(PORT_XLAT, PIN_XLAT);
setHigh(PORT_BLANK, PIN_BLANK);

// force first cycle
send_DC();
send_GS();

// enable interrupts
__bis_SR_register(GIE);

while(1) {
	// load gs-data here 

	// update PWM-data permanently
	send_GS();
}
}

Link to post
Share on other sites
  • 3 months later...

ok, i build it but i only have 6 leds lighting up, i have not connected the out0 as well as 15.

any suggestions`?

 

edit: it works perfectly, just had some weird short ^^. also your code does not seem to initiate the gs_data array, so its full of signed ints, some positive, some negative

Link to post
Share on other sites

have a look on these lines:

 

 while(1) {
     // load gs-data here 

     // update PWM-data permanently
     send_GS();
  }

 

you should load the gs-data before calling send_GS() ;)

 

you can also initialize the gs-data some lines before - before the comment "force first cycle" with some code like this:

 

for (i=0;i<16;i++) {
     gs_data[i]=0;
}

Link to post
Share on other sites

The TLC5940 has no so called "Auto Display Repeat Function" - so you always need to send the color-data to the chip ;)

 

this is done within the main-loop in my implementation and test-program ;)

 

if you really need this this function (because you need the mcu for other tasks/calculations) have a look on the TLC5971 ;)

 

edit: or maybe this one: TLC5943

Link to post
Share on other sites

I have now implemented my RTC, but the problem is that the TLC5940 now started to heavily flicker and light up led's that are not supposed to light up. my question would be how often i need to refresh the tlc5940 in order to supress flickering. thjis way i could have a timer interrupt for the second increment and another interuppt to controll the tlc5940.

 

you current code polls it, so it refreshes the tlc as often as possible. how often is enough?

 

-lastaid

Link to post
Share on other sites

ok i found a way to get nice results with the tlc5940. i set the timer keeping time to 100Hz [ after i tried 16hz but this flickered ] and increment subseconds as well as sending data to the tlc. with this i get flicker free results but my seconds seem to be a little of. this raises the question how many cycles sending data to 1 or 2 ics. the problem would be much easier to fix if we would figure out a way how to send data to the tcl and keep it.

after going through the datasheet i looked at the blank pin. could this be the problem? if i blank shortly after i enabled the tcl this would explain why it appears only on if i just pushed data.

i still have no idea why it is not working, the 100hz is just a workaround, but having my main timer setup with 100hz is a little wasteful in means of power management.

 

any ideas?

Link to post
Share on other sites
you current code polls it, so it refreshes the tlc as often as possible. how often is enough?

 

If you can get a ~120kHz clock output to GSCLK(unused timer?) you can update it 30 times a second. As it stands this thing needs updated a lot... And I put in this code to see just how fast the program was running and it isn't very quick as is. I don't know if it's eating up a bunch of clock cycles with the for loop or what, but it only goes through 255 updates in about 2-2.5 seconds.

 

for(i = 0; i < 16; i++) gs_data[i] = whileCount;
whileCount++;
if(whileCount > 255) whileCount = 0;

 

100 updates per second isn't terrible, but since that's the only thing it's doing it leaves no room for the poor MSP to do other things.

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...