Jump to content
43oh

TLC5940 examples


Recommended Posts

TLC5940 code examples.

1. UART to TLC

2. Chasing light, useful for your next Knight Rider project :smile:

#include

#define SCLK_PIN BIT5
#define MOSI_PIN BIT7

#define GSCLK_PIN BIT4
#define BLANK_PIN BIT0
#define XLAT_PIN BIT2

typedef unsigned char u_char;

u_char leds[16] = { 0, };

void updateTLC();

void main(void) {

    WDTCTL = WDTPW + WDTHOLD; // disable WDT
    BCSCTL1 = CALBC1_16MHZ; // 16MHz clock
    DCOCTL = CALDCO_16MHZ;

    P1OUT &= ~(BLANK_PIN + XLAT_PIN);
    P1DIR |= BLANK_PIN + XLAT_PIN;

    P1DIR |= GSCLK_PIN; // port 1.4 configured as SMCLK out
    P1SEL |= GSCLK_PIN;

    // setup timer
    CCR0 = 0xFFF;
    TACTL = TASSEL_2 + MC_1 + ID_0; // SMCLK, up mode, 1:1
    CCTL0 = CCIE; // CCR0 interrupt enabled

    // setup UCB0
    P1SEL |= SCLK_PIN + MOSI_PIN;
    P1SEL2 |= SCLK_PIN + MOSI_PIN;

    UCB0CTL0 = UCCKPH + UCMSB + UCMST + UCSYNC; // 3-pin, 8-bit SPI master
    UCB0CTL1 |= UCSSEL_2; // SMCLK
    UCB0BR0 |= 0x01; // 1:1
    UCB0BR1 = 0;
    UCB0CTL1 &= ~UCSWRST; // clear SW

    updateTLC();
    P1OUT |= XLAT_PIN;
    P1OUT &= ~XLAT_PIN;

    _bis_SR_register(GIE);

    leds[0] = 0x0F;
    u_char counter = 0;
    u_char direction = 0;
    while (1) {
        _delay_cycles(500000);
        if (direction) {
            counter--;
            leds[counter] = 0x0F;
            leds[counter + 1] = 0;
            if (counter == 0)
                direction = 0;
        } else {
            counter++;
            leds[counter] = 0x0F;
            leds[counter - 1] = 0;
            if (counter == 15)
                direction = 1;
        }
    }
}

void updateTLC() {

    u_char ledCounter = 8;

    while (ledCounter-- > 0) {

        UCB0TXBUF = leds[(ledCounter << 1) + 1] << 4;
        while (!(IFG2 & UCB0TXIFG))
            ; // TX buffer ready?

        UCB0TXBUF = leds[ledCounter << 1];
        while (!(IFG2 & UCB0TXIFG))
            ; // TX buffer ready?

        UCB0TXBUF = 0;
        while (!(IFG2 & UCB0TXIFG))
            ; // TX buffer ready?
    }
}

#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A0(void) {
    P1OUT |= BLANK_PIN;
    P1OUT |= XLAT_PIN;
    P1OUT &= ~XLAT_PIN;
    P1OUT &= ~BLANK_PIN;
    updateTLC();
}


Link to post
Share on other sites
  • 4 weeks later...
  • Replies 35
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

Popular Posts

TLC5940 code examples. 1. UART to TLC 2. Chasing light, useful for your next Knight Rider project #include #define SCLK_PIN BIT5 #define MOSI_PIN BIT7 #define GSCLK_PIN BIT4 #define BLANK_PIN B

Yes, I am using 4bit data and multiplying it by 256 when sending. To be exact, since TLC requires 12bit GS data, I am sending 3 SPI bytes in each iteration with GS data for 2 LEDs and the only thing I

Here are some 2231 examples   #include <msp430g2231.h> #include "pattern.h" #define SCLK_PIN BIT5 #define MOSI_PIN BIT7 #define GSCLK_PIN BIT4 #define BLANK_PIN BIT2 #define XLAT_PIN BIT1 #

GS PWM cycle takes 4096 clock cycles, at 16MHz, that's 256us.

GS cycle (updateTLC()) takes about 900 clock cycles, ~56us (that's for two TLCs.)

The delay between GS cycle and data latch is ~200us and the frame rate is ~4000/s.

GS PWM & GS cycles happen at the same time, so there's practically no "dead" space between PWM cycles (maybe 1us.)

New data should not be latched during PWM, it should be latched either before or after.

The problem with latching before is that you will introduce relatively long delay between PWM cycles (56us) and all LEDs would be off during that time (you could use slower PWM clock, but then you have to come up with a way to track it.)

In my code, I am sending new data during PWM, then calculating next data, then waiting until PWM cycle is done to latch new data.

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

Thanks RobG for your example code, it worked the first time :D

But i was trying to modify the code to dim the leds in a range from 0 to 255, but it isn't working. I just set the value of the led in the array, so leds[0] = 0 to leds[0] = 255, there is some difference, but it's not smooth, and no 256 steps. What am i doing wrong :oops:?

Link to post
Share on other sites

Yes, I am using 4bit data and multiplying it by 256 when sending. To be exact, since TLC requires 12bit GS data, I am sending 3 SPI bytes in each iteration with GS data for 2 LEDs and the only thing I have to multiply is first LEDs value by 16 (first SPI byte.)

0-15
leds[0] = 00001111
leds[1] = 00001111

12bit
LED0         LED1
111100000000 111100000000

SPI 3 bytes
11110000 00001111 00000000

 

Here's 8bit version with LPM instead of delay.

 

#include 

#define SCLK_PIN	BIT5
#define MOSI_PIN	BIT7

#define GSCLK_PIN	BIT4
#define BLANK_PIN	BIT2
#define XLAT_PIN	BIT1
#define DCPRG_PIN	BIT0
#define VPRG_PIN	BIT0

typedef unsigned char u_char;

#define NUMBER_OF_LEDS 32

u_char leds[NUMBER_OF_LEDS] = { 0, };
u_char timerCounter = 0;

void updateTLC();

void main(void) {

WDTCTL = WDTPW + WDTHOLD; // disable WDT
BCSCTL1 = CALBC1_16MHZ; // 16MHz clock
DCOCTL = CALDCO_16MHZ;

P1OUT &= ~(VPRG_PIN);
P1DIR |= VPRG_PIN;

P1DIR |= GSCLK_PIN; // port 1.4 configured as SMCLK out
P1SEL |= GSCLK_PIN;

P2OUT &= ~(BLANK_PIN + XLAT_PIN + DCPRG_PIN);
P2DIR |= BLANK_PIN + XLAT_PIN + DCPRG_PIN;

// setup timer
CCR0 = 0xFFF;
TACTL = TASSEL_2 + MC_1 + ID_0; // SMCLK, up mode, 1:1
CCTL0 = CCIE; // CCR0 interrupt enabled

// setup UCB0
P1SEL |= SCLK_PIN + MOSI_PIN;
P1SEL2 |= SCLK_PIN + MOSI_PIN;

UCB0CTL0 = UCCKPH + UCMSB + UCMST + UCSYNC; // 3-pin, 8-bit SPI master
UCB0CTL1 |= UCSSEL_2; // SMCLK
UCB0BR0 |= 0x01; // 1:1
UCB0BR1 = 0;
UCB0CTL1 &= ~UCSWRST; // clear SW

updateTLC();
P2OUT |= XLAT_PIN;
P2OUT &= ~XLAT_PIN;

_bis_SR_register(GIE);

leds[0] = 0x0F;
u_char counter = 0;
u_char direction = 0;
u_char first = 0;
u_char firstDirection = 0;
u_char brightness = 0xFF;
while (1) {
	if (direction) {
		counter--;
		leds[counter] = brightness;
		leds[counter + 1] = 0;
		if (counter == first) {
			direction = 0;
			// first
			if (firstDirection) {
				first--;
				if (first == 0)
					firstDirection = 0;
			} else {
				brightness -= 16;
				leds[first - 1] = brightness;
				first++;
				if (first == (NUMBER_OF_LEDS - 2))
					firstDirection = 1;
			}
		}

	} else {
		counter++;
		leds[counter] = brightness;
		leds[counter - 1] = 0;
		if (counter == (NUMBER_OF_LEDS - 1)) {
			direction = 1;
		}
	}
	// sleep
	_bis_SR_register(LPM0_bits);
}
}

void updateTLC() {

u_char ledCounter = NUMBER_OF_LEDS >> 1;

while (ledCounter-- > 0) {

	u_char i = ledCounter << 1;

	UCB0TXBUF = leds[i + 1];
	while (!(IFG2 & UCB0TXIFG))
		; // TX buffer ready?

	UCB0TXBUF = leds[i] >> 4;
	while (!(IFG2 & UCB0TXIFG))
		; // TX buffer ready?

	UCB0TXBUF = leds[i] << 4;
	while (!(IFG2 & UCB0TXIFG))
		; // TX buffer ready?
}
}

#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A0(void) {
P2OUT |= BLANK_PIN;
P2OUT |= XLAT_PIN;
P2OUT &= ~XLAT_PIN;
P2OUT &= ~BLANK_PIN;
updateTLC();

timerCounter++;
if (timerCounter == 0x40) { // 0x40 - 256us * 64 = 16.384ms, ~61Hz
	timerCounter = 0;
	_bic_SR_register_on_exit(LPM0_bits);
}
}

 

Finally, here's full 12bit GS version

 

#include 

#define SCLK_PIN	BIT5
#define MOSI_PIN	BIT7

#define GSCLK_PIN	BIT4
#define BLANK_PIN	BIT2
#define XLAT_PIN	BIT1
#define DCPRG_PIN	BIT0
#define VPRG_PIN	BIT0

typedef unsigned char u_char;
typedef unsigned int u_int;

#define NUMBER_OF_LEDS 32

u_int leds[NUMBER_OF_LEDS] = { 0, };
u_char timerCounter = 0;

void updateTLC();

void main(void) {

WDTCTL = WDTPW + WDTHOLD; // disable WDT
BCSCTL1 = CALBC1_16MHZ; // 16MHz clock
DCOCTL = CALDCO_16MHZ;

P1OUT &= ~(VPRG_PIN);
P1DIR |= VPRG_PIN;

P1DIR |= GSCLK_PIN; // port 1.4 configured as SMCLK out
P1SEL |= GSCLK_PIN;

P2OUT &= ~(BLANK_PIN + XLAT_PIN + DCPRG_PIN);
P2DIR |= BLANK_PIN + XLAT_PIN + DCPRG_PIN;

// setup timer
CCR0 = 0xFFF;
TACTL = TASSEL_2 + MC_1 + ID_0; // SMCLK, up mode, 1:1
CCTL0 = CCIE; // CCR0 interrupt enabled

// setup UCB0
P1SEL |= SCLK_PIN + MOSI_PIN;
P1SEL2 |= SCLK_PIN + MOSI_PIN;

UCB0CTL0 = UCCKPH + UCMSB + UCMST + UCSYNC; // 3-pin, 8-bit SPI master
UCB0CTL1 |= UCSSEL_2; // SMCLK
UCB0BR0 |= 0x01; // 1:1
UCB0BR1 = 0;
UCB0CTL1 &= ~UCSWRST; // clear SW

updateTLC();
P2OUT |= XLAT_PIN;
P2OUT &= ~XLAT_PIN;

_bis_SR_register(GIE);

leds[0] = 0x0F;
u_char counter = 0;
u_char direction = 0;
u_char first = 0;
u_char firstDirection = 0;
u_int brightness = 0xFFF;
while (1) {
	if (direction) {
		counter--;
		leds[counter] = brightness;
		leds[counter + 1] = 0;
		if (counter == first) {
			direction = 0;
			// first
			if (firstDirection) {
				first--;
				if (first == 0)
					firstDirection = 0;
			} else {
				brightness -= 0x8F;
				leds[first - 1] = brightness;
				first++;
				if (first == (NUMBER_OF_LEDS - 2))
					firstDirection = 1;
			}
		}

	} else {
		counter++;
		leds[counter] = brightness;
		leds[counter - 1] = 0;
		if (counter == (NUMBER_OF_LEDS - 1)) {
			direction = 1;
		}
	}
	// sleep
	_bis_SR_register(LPM0_bits);
}
}

void updateTLC() {

u_char ledCounter = NUMBER_OF_LEDS >> 1;

while (ledCounter-- > 0) {

	u_char i = ledCounter << 1;

	UCB0TXBUF = leds[i + 1] >> 4;
	while (!(IFG2 & UCB0TXIFG))
		; // TX buffer ready?
	u_char unib = leds[i + 1] << 4;
	u_char lnib = (leds[i] >> 8) & 0x0F;
	UCB0TXBUF = unib | lnib;
	while (!(IFG2 & UCB0TXIFG))
		; // TX buffer ready?

	UCB0TXBUF = leds[i];
	while (!(IFG2 & UCB0TXIFG))
		; // TX buffer ready?
}
}

#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A0(void) {
P2OUT |= BLANK_PIN;
P2OUT |= XLAT_PIN;
P2OUT &= ~XLAT_PIN;
P2OUT &= ~BLANK_PIN;
updateTLC();

timerCounter++;
if (timerCounter == 0x40) { // 0x40 - 256us * 64 = 16.384ms, ~61Hz
	timerCounter = 0;
	_bic_SR_register_on_exit(LPM0_bits);
}
}

Link to post
Share on other sites

Improved version. 12bit grayscale level.

SMCLK is now divided by 8 to slow PWM clock down to 2MHz (2ms PWM cycle.)

TLCs GS data is updated only once per 8 PWM cycles, right before wake up.

 

#include 

#define SCLK_PIN	BIT5
#define MOSI_PIN	BIT7

#define GSCLK_PIN	BIT4
#define BLANK_PIN	BIT2
#define XLAT_PIN	BIT1
#define DCPRG_PIN	BIT0
#define VPRG_PIN	BIT0

typedef unsigned char u_char;
typedef unsigned int u_int;

#define NUMBER_OF_LEDS 32

u_int leds[NUMBER_OF_LEDS] = { 0, };
u_char timerCounter = 0;

void updateTLC();

void main(void) {

WDTCTL = WDTPW + WDTHOLD; // disable WDT
BCSCTL1 = CALBC1_16MHZ; // 16MHz clock
DCOCTL = CALDCO_16MHZ;
BCSCTL2 |= DIVS_3; // divide clock by 8

P1OUT &= ~(VPRG_PIN);
P1DIR |= VPRG_PIN;

P1DIR |= GSCLK_PIN; // port 1.4 configured as SMCLK out
P1SEL |= GSCLK_PIN;

P2OUT &= ~(BLANK_PIN + XLAT_PIN + DCPRG_PIN);
P2DIR |= BLANK_PIN + XLAT_PIN + DCPRG_PIN;

// setup timer
CCR0 = 0xFFF;
TACTL = TASSEL_2 + MC_1 + ID_0; // SMCLK, up mode, 1:1
CCTL0 = CCIE; // CCR0 interrupt enabled

// setup UCB0
P1SEL |= SCLK_PIN + MOSI_PIN;
P1SEL2 |= SCLK_PIN + MOSI_PIN;

UCB0CTL0 = UCCKPH + UCMSB + UCMST + UCSYNC; // 3-pin, 8-bit SPI master
UCB0CTL1 |= UCSSEL_2; // SMCLK
UCB0BR0 |= 0x01; // 1:1
UCB0BR1 = 0;
UCB0CTL1 &= ~UCSWRST; // clear SW

updateTLC();
P2OUT |= XLAT_PIN;
P2OUT &= ~XLAT_PIN;

_bis_SR_register(GIE);

leds[0] = 0x0F;
u_char counter = 0;
u_char direction = 0;
u_char first = 0;
u_char firstDirection = 0;
u_int brightness = 0xFFF;

while (1) {
	//
	if (direction) {
		counter--;
		leds[counter] = brightness;
		leds[counter + 1] = 0;
		if (counter == first) {
			direction = 0;
			// first
			if (firstDirection) {
				first--;
				if (first == 0)
					firstDirection = 0;
			} else {
				leds[first - 1] = brightness;
				first++;
				if (first == (NUMBER_OF_LEDS - 2))
					firstDirection = 1;
			}
		}
	} else {
		counter++;
		leds[counter] = brightness;
		leds[counter - 1] = 0;
		if (counter == (NUMBER_OF_LEDS - 1)) {
			direction = 1;
		}
	}

	//update all leds
	u_char c = 0;
	while(c < NUMBER_OF_LEDS) {
		if(leds[c] > 0) leds[c] = brightness;
		c++;
	}
	//update brightness
	brightness -= 0x02;

	// sleep
	_bis_SR_register(LPM0_bits);
}
}

void updateTLC() {

u_char ledCounter = NUMBER_OF_LEDS >> 1;

while (ledCounter-- > 0) {

	u_char i = ledCounter << 1;

	UCB0TXBUF = leds[i + 1] >> 4;
	while (!(IFG2 & UCB0TXIFG))
		; // TX buffer ready?
	u_char unib = leds[i + 1] << 4;
	u_char lnib = (leds[i] >> 8) & 0x0F;
	UCB0TXBUF = unib | lnib;
	while (!(IFG2 & UCB0TXIFG))
		; // TX buffer ready?

	UCB0TXBUF = leds[i];
	while (!(IFG2 & UCB0TXIFG))
		; // TX buffer ready?
}
}

#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A0(void) {
P2OUT |= BLANK_PIN;
P2OUT |= XLAT_PIN;
P2OUT &= ~XLAT_PIN;
P2OUT &= ~BLANK_PIN;

timerCounter++;
if (timerCounter == 0x08) { // 0x08 - 2ms * 8 = 16.384ms, ~61Hz
	updateTLC();
	timerCounter = 0;
	_bic_SR_register_on_exit(LPM0_bits);
}
}

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

Here are some 2231 examples

 

#include <msp430g2231.h>
#include "pattern.h"
#define SCLK_PIN BIT5
#define MOSI_PIN BIT7
#define GSCLK_PIN BIT4
#define BLANK_PIN BIT2
#define XLAT_PIN BIT1
#define DCPRG_PIN BIT7 //P2
#define VPRG_PIN BIT0
typedef unsigned char u_char;
typedef unsigned int u_int;
#define NUMBER_OF_LEDS 16
u_char timerCounter = 0;
// 16 levels of brightness
const u_int lut[16] = { 0, 30, 60, 100, 200, 300, 400, 600, 800, 1000, 1200, 1500, 1800, 2100, 2400, 2550 }; // range is 0-4095 (12bit)
u_char patternIndex = 0;
u_char patternCounter = 0;
void updateTLC();
void sendData(u_int data);
void main(void) {
WDTCTL = WDTPW + WDTHOLD; // disable WDT
DCOCTL |= DCO0 + DCO1; // DCO = 15.25MHz
BCSCTL1 |= RSEL0 + RSEL1 + RSEL2 + RSEL3; // as above
BCSCTL2 |= DIVS_3; // divide clock by 8
P1OUT &= ~(VPRG_PIN + BLANK_PIN + XLAT_PIN + SCLK_PIN + MOSI_PIN);
P1DIR |= VPRG_PIN + BLANK_PIN + XLAT_PIN + SCLK_PIN + MOSI_PIN;
P1DIR |= GSCLK_PIN; // port 1.4 configured as SMCLK out
P1SEL |= GSCLK_PIN;
P2SEL &= ~(BIT6 | BIT7);
P2OUT &= ~DCPRG_PIN;
P2DIR |= DCPRG_PIN;
// setup timer
CCR0 = 0xFFF;
TACTL = TASSEL_2 + MC_1 + ID_0; // SMCLK, up mode, 1:1
CCTL0 = CCIE; // CCR0 interrupt enabled
updateTLC();
P1OUT |= XLAT_PIN;
P1OUT &= ~XLAT_PIN;
_bis_SR_register(GIE);
while (1) {
//
// logic goes here
// patternIndex is used for pattern selection
// patternCounter is used for timeline
if(patternCounter < 16) {
patternIndex++;
patternCounter++;
} else {
patternIndex--;
patternCounter++;
}
// sleep
_bis_SR_register(LPM0_bits);
}
}
void updateTLC() {
u_char ledCounter = NUMBER_OF_LEDS >> 1;
while (ledCounter-- > 0) {
u_char i = ledCounter << 1;
sendData(lut[pattern[patternIndex][i + 1]]);
sendData(lut[pattern[patternIndex][i]]);
}
}
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A0(void) {
P1OUT |= BLANK_PIN;
P1OUT |= XLAT_PIN;
P1OUT &= ~XLAT_PIN;
P1OUT &= ~BLANK_PIN;
patternIndex &= 0x0F; // mask patternCounter to get 0-15 range
timerCounter++;
if (timerCounter == 0x08) { // 0x08 - 2ms * 8 = 16.384ms, ~61Hz
updateTLC();
timerCounter = 0;
_bic_SR_register_on_exit(LPM0_bits);
}
}
void sendData(u_int data) {
u_char c = 0;
while (c < 12) {
(data & 0x0800) ? (P1OUT |= MOSI_PIN) : (P1OUT &= ~MOSI_PIN);
P1OUT |= SCLK_PIN;
P1OUT &= ~SCLK_PIN;
data <<= 1;
c++;
}
}

 

Pattern.h

#ifndef PATTERN_H_
#define PATTERN_H_
// 16 patterns, 16 LEDs, 16 brightness levels
const char pattern[16][16] = {
//
{ 1, 3, 5, 7, 9, 11, 13, 15, 14, 12, 10, 8, 6, 4, 2, 0 }, //
{ 0, 1, 3, 5, 7, 9, 11, 13, 15, 14, 12, 10, 8, 6, 4, 2 }, //
{ 2, 0, 1, 3, 5, 7, 9, 11, 13, 15, 14, 12, 10, 8, 6, 4 }, //
{ 4, 2, 0, 1, 3, 5, 7, 9, 11, 13, 15, 14, 12, 10, 8, 6 }, //
{ 6, 4, 2, 0, 1, 3, 5, 7, 9, 11, 13, 15, 14, 12, 10, 8 }, //
{ 8, 6, 4, 2, 0, 1, 3, 5, 7, 9, 11, 13, 15, 14, 12, 10 }, //
{ 10, 8, 6, 4, 2, 0, 1, 3, 5, 7, 9, 11, 13, 15, 14, 12 }, //
{ 12, 10, 8, 6, 4, 2, 0, 1, 3, 5, 7, 9, 11, 13, 15, 14 }, //
{ 14, 12, 10, 8, 6, 4, 2, 0, 1, 3, 5, 7, 9, 11, 13, 15 }, //
{ 15, 14, 12, 10, 8, 6, 4, 2, 0, 1, 3, 5, 7, 9, 11, 13 }, //
{ 13, 15, 14, 12, 10, 8, 6, 4, 2, 0, 1, 3, 5, 7, 9, 11 }, //
{ 11, 13, 15, 14, 12, 10, 8, 6, 4, 2, 0, 1, 3, 5, 7, 9 }, //
{ 9, 11, 13, 15, 14, 12, 10, 8, 6, 4, 2, 0, 1, 3, 5, 7 }, //
{ 7, 9, 11, 13, 15, 14, 12, 10, 8, 6, 4, 2, 0, 1, 3, 5 }, //
{ 5, 7, 9, 11, 13, 15, 14, 12, 10, 8, 6, 4, 2, 0, 1, 3 }, //
{ 3, 5, 7, 9, 11, 13, 15, 14, 12, 10, 8, 6, 4, 2, 0, 1 }, //
};
#endif /* PATTERN_H_ */

 

Another example

#include <msp430g2231.h>
#define SCLK_PIN BIT5
#define MOSI_PIN BIT7
#define GSCLK_PIN BIT4
#define BLANK_PIN BIT2
#define XLAT_PIN BIT1
#define DCPRG_PIN BIT7 //P2
#define VPRG_PIN BIT0
typedef unsigned char u_char;
typedef unsigned int u_int;
#define NUMBER_OF_LEDS 16
u_int leds[NUMBER_OF_LEDS] = { 0, };
u_char timerCounter = 0;
void updateTLC();
void sendData(u_int data);
void main(void) {
WDTCTL = WDTPW + WDTHOLD; // disable WDT
DCOCTL |= DCO0 + DCO1; // DCO = 15.25MHz
BCSCTL1 |= RSEL0 + RSEL1 + RSEL2 + RSEL3; // as above
BCSCTL2 |= DIVS_3; // divide clock by 8
P1OUT &= ~(VPRG_PIN + BLANK_PIN + XLAT_PIN + SCLK_PIN + MOSI_PIN);
P1DIR |= VPRG_PIN + BLANK_PIN + XLAT_PIN + SCLK_PIN + MOSI_PIN;
P1DIR |= GSCLK_PIN; // port 1.4 configured as SMCLK out
P1SEL |= GSCLK_PIN;
P2SEL &= ~(BIT6 | BIT7);
P2OUT &= ~DCPRG_PIN;
P2DIR |= DCPRG_PIN;
// setup timer
CCR0 = 0xFFF;
TACTL = TASSEL_2 + MC_1 + ID_0; // SMCLK, up mode, 1:1
CCTL0 = CCIE; // CCR0 interrupt enabled
updateTLC();
P1OUT |= XLAT_PIN;
P1OUT &= ~XLAT_PIN;
_bis_SR_register(GIE);
leds[0] = 0x0F;
u_char counter = 0;
u_char direction = 0;
u_char first = 0;
u_char firstDirection = 0;
u_int brightness = 0xFFF;
while (1) {
//
if (direction) {
counter--;
leds[counter] = brightness;
leds[counter + 1] = 0;
if (counter == first) {
direction = 0;
// first
if (firstDirection) {
 first--;
 if (first == 0)
 firstDirection = 0;
} else {
 leds[first - 1] = brightness;
 first++;
 if (first == (NUMBER_OF_LEDS - 2))
 firstDirection = 1;
}
}
} else {
counter++;
leds[counter] = brightness;
leds[counter - 1] = 0;
if (counter == (NUMBER_OF_LEDS - 1)) {
direction = 1;
}
}
//update all leds
u_char c = 0;
while(c < NUMBER_OF_LEDS) {
if(leds[c] > 0) leds[c] = brightness;
c++;
}
//update brightness
brightness -= 0x02;
// sleep
_bis_SR_register(LPM0_bits);
}
}
void updateTLC() {
u_char ledCounter = NUMBER_OF_LEDS >> 1;
while (ledCounter-- > 0) {
u_char i = ledCounter << 1;
sendData(leds[i + 1]);
sendData(leds[i]);
}
}
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A0(void) {
P1OUT |= BLANK_PIN;
P1OUT |= XLAT_PIN;
P1OUT &= ~XLAT_PIN;
P1OUT &= ~BLANK_PIN;
timerCounter++;
if (timerCounter == 0x08) { // 0x08 - 2ms * 8 = 16.384ms, ~61Hz
updateTLC();
timerCounter = 0;
_bic_SR_register_on_exit(LPM0_bits);
}
}
void sendData(u_int data) {
u_char c = 0;
while (c < 12) {
(data & 0x0800) ? (P1OUT |= MOSI_PIN) : (P1OUT &= ~MOSI_PIN);
P1OUT |= SCLK_PIN;
P1OUT &= ~SCLK_PIN;
data <<= 1;
c++;
}
}

Link to post
Share on other sites

Hi, thanks for posting so quickly.

I've had a look at your first 2231 example and there's a couple of things that I don't understand.

- I dont know what "MOSI" is, and how there are 2 ports being used when there is only P1?

- Which pin from the uC goes to the "SIN" pin of the TLC?

I tried running it, but again I dont get any output - probably because I dont have a clue what I'm doing :(

Cheers

GD

Link to post
Share on other sites

MOSI (Master Out, Slave In) means data out pin from MCU (SDO) is connected to data in (SIN) on TLC.

2231 has two P2 pins, P2.6 (13) and P2.7 (14.)

If you look at defines, BITx refers to P1.x, except DCPRG which is P2.x

#define SCLK_PIN BIT5
#define MOSI_PIN BIT7
#define GSCLK_PIN BIT4
#define BLANK_PIN BIT2
#define XLAT_PIN BIT1
#define DCPRG_PIN BIT7 //P2
#define VPRG_PIN BIT0

Link to post
Share on other sites

Hi, thanks for your reply - that cleared that up for me.

I think I must be doing something horribly wrong because I'm not getting any output from the chip.

This is everything I have wired up:

  • VPRG - P1.0
  • SIN - P1.7 (although when I checked the MSPG2231 data sheet, P1.6 has SDO as its secondary function so i'm not sure about that)
  • SCLK - P1.5
  • XLAT - P1.1
  • BLANK - P1.2
  • GND - Ground
  • VCC - to Vcc
  • IREF - to Ground through 2k resistor
  • DCPRG - XOUT (on the MCU data sheet it shows that XOUT is P2.7)
  • OUTPUTS 0-2 - RGB anodes of a common cathode RGB LED

I'm sorry to keep bothering you but I am really, really stuck with this - I'm starting to think that TI have sent me 4 TLCs that are all broken because I cannot get any output with all 4.

 

Thanks

GD

Link to post
Share on other sites
SIN - P1.7 (although when I checked the MSPG2231 data sheet, P1.6 has SDO as its secondary function so i'm not sure about that)

 

Right, if I was using hardware SPI, then P1.6 would be used. I am doing software SPI and using P1.7, which is MOSI on 2553.

 

 

OUTPUTS 0-2 - RGB anodes of a common cathode RGB LED

I'm sorry to keep bothering you but I am really, really stuck with this - I'm starting to think that TI have sent me 4 TLCs that are all broken because I cannot get any output with all 4.

 

Well, this could be your problem, TLC5940 is a sink driver, meaning outputs should be connected to cathodes and anodes are common.

Try connecting a single LED, anode to Vcc and cathode to TLC, and see if it lights up.

Link to post
Share on other sites

Hi

 

Thanks for that last post, it was really helpful. I did what you said and connected a single LED to the TLC but still no light.

But I started testing what was causing this so when i pulled out the DCPRG wire - connected to XOUT and pin 18 of TLC - the LED was brightening then dimming very quickly. So at least now i know that my chip isn't broken which is good.

Do you know why this would be happening?

 

Cheers

GD

Link to post
Share on other sites

This is odd. When DCPRG is low (as it is in my example,) TLC uses EEPROM for dot correction. When DCPRG is high, it uses DC register. EEPROM is pre-programmed with 0x3F, DC register is random. I will try my code tonight to verify there are no typos.

BTW, pin 18 is GSCLK, not DCPRG.

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...