SirZusa 34 Posted October 11, 2011 Share Posted October 11, 2011 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(); } } fj604, larsie, pillum and 4 others 7 Quote Link to post Share on other sites
bluehash 1,581 Posted October 12, 2011 Share Posted October 12, 2011 Thanks for sharing your code, SirZusa. lastaid 1 Quote Link to post Share on other sites
lastaid 15 Posted January 31, 2012 Share Posted January 31, 2012 Gonna try it now Only question is: i have common cathode rbg leds, so i need to source, not to sink them. will it still work? Quote Link to post Share on other sites
lastaid 15 Posted January 31, 2012 Share Posted January 31, 2012 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 Quote Link to post Share on other sites
SirZusa 34 Posted January 31, 2012 Author Share Posted January 31, 2012 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; } Quote Link to post Share on other sites
larsie 121 Posted February 1, 2012 Share Posted February 1, 2012 Didn't know about this chip. Nice... Sooo many projects one should test... Quote Link to post Share on other sites
SugarAddict 227 Posted February 1, 2012 Share Posted February 1, 2012 Looks cleaner than mine :thumbup: Quote Link to post Share on other sites
lastaid 15 Posted February 3, 2012 Share Posted February 3, 2012 its works as of now, i have a few funny timer issues with my rtc, and i am not sure yet how to have the tlc _hold_ the state and still display the leds. this way i don't have to refresh it all the time. but this hopefully work in a few hours ^^ Quote Link to post Share on other sites
SirZusa 34 Posted February 3, 2012 Author Share Posted February 3, 2012 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 Quote Link to post Share on other sites
lastaid 15 Posted February 4, 2012 Share Posted February 4, 2012 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 Quote Link to post Share on other sites
SirZusa 34 Posted February 5, 2012 Author Share Posted February 5, 2012 Did you have a look in the datasheet? I have no clue on how often it should be refreshed but you can try it out. Just place the send_GS() in an timer-interrupt and experimant a little bit Quote Link to post Share on other sites
lastaid 15 Posted February 7, 2012 Share Posted February 7, 2012 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? Quote Link to post Share on other sites
SirZusa 34 Posted February 7, 2012 Author Share Posted February 7, 2012 did you have a look on my last post on the first page? -> viewtopic.php?f=10&t=1700#p16617 the TLC5940 has no "Auto Display Repeat Function" - this is what you are looking for - so you need to do this manually Quote Link to post Share on other sites
kylej1050 27 Posted February 7, 2012 Share Posted February 7, 2012 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. Quote Link to post Share on other sites
SugarAddict 227 Posted February 7, 2012 Share Posted February 7, 2012 When I did mine I had to go with 10 bit greyscale data instead of 12 bit, so use values <1024 for your brightness and change if (GSCLK_Counter > 4095) { into if (GSCLK_Counter > 1023) { That should fix your fickering problems. Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.