Jump to content
Sign in to follow this  
pillum

Controlling TLC5940 with MSP430G2553 doesn't work

Recommended Posts

That's a good point, I have had issues with male-female jumper wires that I got from eBay.

Also, your LEDs are powered from another source, is the GND connected? I know it's silly but there were cases where people forgot to connect GNDs.

Share this post


Link to post
Share on other sites

Lol, well...I removed everything and connected everything from scratch the dunno maybe like 10th time and now it works..

This time I used Launchpad's Vcc for the LEDs, though. Trying with external power source now.

 

Thanks all for your help, especially kylej1050, cde and RobG ! :clap:

 

 

edit: Tried external power source, works too! Since I changed all wires and reconnected them from scratch, i think there was some fault in the wiring.

 

edit2: strange, it works sometimes and sometimes not.... :eh: . now its not working anymore :( it blinks sometimes and sometimes its off and then on for a long time

 

edit3: i think the led is broken..used a different led, its not blinking

Share this post


Link to post
Share on other sites

Sounds like a wire connection issue.

You may want to use 3 male headers with soldered wires, that will eliminate flaky jumper wires.

I do that all the time, saved me some headaches :)

 

post-197-135135557206_thumb.jpeg

Share this post


Link to post
Share on other sites

Could also be a bad breadboard? The contacts in breadboards can lose their springyness and stop making contact properly. And double check that you connected the grounds between the launchpad and external power supplies.

Share this post


Link to post
Share on other sites
...Your code keeps the processor very busy. I would recommend using a timer to output your clock signal while the MSP goes about other business...

You could also output your SMCLK to one pin and use timer to count to 0xFFF and pulse BLANK on interrupt.

 

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

Share this post


Link to post
Share on other sites

Doesn't the clock signal need to be synchronized then?

Because now I'm resetting the PWM counter after 4095 rounds of gsdata upload and not after 4095 cycles.

Isn't the MSP430G2553 also able to use the USCI HW to control the TLC5940 via SPI?

 

Also, how do I change the Grayscale data with an USB connection to my PC?

Is there already a lib for serial connection like with arduino?

Share this post


Link to post
Share on other sites

No, GSCLK and SCLK are two independent clock signals and do not have to be synchronized.

Use P1.4 (SCLK out) for GSCLK, set timer to upmode, 1:1 SMCLK, and CCR to 0xFFF.

In timer's ISR, pulse BLANK, P1.3 for example.

P1.0 -> XLAT

P1.5 (USCI SCLK) -> SCLK

P1.7 (SIMO) -> SIN

P1.6 (SOMI) -> SOUT (optional)

P1.1 UART RX

P2.0 -> VPRG (optional)

P2.1 -> DCPRG (optional)

 

Use UCA0 in UART mode to receive data from PC, UCB0 in SPI mode to send data to TLC.

Share this post


Link to post
Share on other sites
No, GSCLK and SCLK are two independent clock signals and do not have to be synchronized.

Use P1.4 (SCLK out) for GSCLK, set timer to upmode, 1:1 SMCLK, and CCR to 0xFFF.

I should use SCLK pin for GSCLK? I'm not sure I understand what you want to do..

 

In timer's ISR, pulse BLANK, P1.3 for example.

but XLAT isn't? Is pulsing BLANK really so resource intensive that you need an timer interrupt for it?

 

In the flowchart they pulse GSCLK only after data transfer is complete, does this really not need to be synchronized or

was this just arbitrary that they made it like this?

Share this post


Link to post
Share on other sites

Here is the implementation of what I was suggesting.

Send byte through UART to light up the LED.

Upper nibble controls LED #, lower nibble brightness (0-15)

So, to set LED#1 to max, you send 0x1F, LED#16 to 50%, send 0xF7

LED#4 '0' = 0%, '7' = 50%, '?' = 100%

LED#5 '@ = 0%, 'G' = 50%, 'O' = 100%

LED#6 'P' = 0%, 'W' = 50%, '_' = 100%

and so on.

 

BTW, DCPRG and VPRG are grounded.

 

#include 

#define RX_PIN		BIT1
#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 UCA0
P1SEL |= RX_PIN;
P1SEL2 |= RX_PIN;

UCA0CTL1 |= UCSSEL_2;
UCA0BR0 = 0x82; // 9600@16MHz
UCA0BR1 = 0x06;
UCA0MCTL = UCBRS_6;
UCA0CTL1 &= ~UCSWRST;
IE2 |= UCA0RXIE;

// 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();

_bis_SR_register(GIE);
}

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?
}

P1OUT |= XLAT_PIN;
P1OUT &= ~XLAT_PIN;
}

#pragma vector=USCIAB0RX_VECTOR
__interrupt void USCI0RX_ISR(void) {
u_char byte = UCA0RXBUF;	// copy RX buffer
u_char led = byte >> 4;		// upper 4 bits are LED #
leds[led] = byte & 0x0F;	// lower 4 bits are brightness 0-15
// update TLC
updateTLC();
}

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

Share this post


Link to post
Share on other sites
No, GSCLK and SCLK are two independent clock signals and do not have to be synchronized.

Use P1.4 (SCLK out) for GSCLK, set timer to upmode, 1:1 SMCLK, and CCR to 0xFFF.

I should use SCLK pin for GSCLK? I'm not sure I understand what you want to do..

MSP430 SMCLK out -> TLC GSCLK

MSP430 UCB0 SCLK -> TLC SCLK

 

 

In timer's ISR, pulse BLANK, P1.3 for example.

but XLAT isn't? Is pulsing BLANK really so resource intensive that you need an timer interrupt for it?

GSCLK and BLANK are used for PWM. GSCLK clocks the PWM counter, BLANK turns LEDs off and sets PWM counter to 0.

When PWM counter reaches 0xFFF, it stops. If you do not pulse BLANK at that time, LEDs will remain off. Pulsing BLANK will restart PWM count.

Instead of pulsing GSCLK and keeping track in code, you use timer module.

4096 pulses would require 20k+ clock cycles per PWM cycle!

This way, you need only ~20 of them (per PWM cycle.)

 

In the flowchart they pulse GSCLK only after data transfer is complete, does this really not need to be synchronized or was this just arbitrary that they made it like this?

XLAT is used for latching data. Since new data replaces old one when XLAT goes high, latching should happen when PWM counter is inactive (BLANK is 1.)

You could move updateTLC() and XLAT to timer's ISR, but I think the effect of latching in the middle of PWM cycle is not significant. Doing it that way means new data will be sent to TLC every PWM cycle, where my original code sends data only when something changes.

 

Something like this:

 

#include 

 

#define RX_PIN

Share this post


Link to post
Share on other sites
Here is the implementation of what I was suggesting.

Send byte through UART to light up the LED.

Upper nibble controls LED #, lower nibble brightness (0-15)

So, to set LED#1 to max, you send 0x1F, LED#16 to 50%, send 0xF7

LED#4 '0' = 0%, '7' = 50%, '?' = 100%

LED#5 '@ = 0%, 'G' = 50%, 'O' = 100%

LED#6 'P' = 0%, 'W' = 50%, '_' = 100%

and so on.

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?
}

Now you're confusing me more. I thought this is serial and not random access.

I update the grayscale data serially, that means one after another.

But you're specify WHICH led to update. Where you got that from? You got any documentation on that?

 

Also you're transmitting 3 bytes per LED (counting last '\0'), I only do 12bits.

Share this post


Link to post
Share on other sites
Now you're confusing me more. I thought this is serial and not random access.

I update the grayscale data serially, that means one after another.

But you're specify WHICH led to update. Where you got that from? You got any documentation on that?

 

Also you're transmitting 3 bytes per LED (counting last '\0'), I only do 2 bytes.

 

Brightness data for all LEDs is stored in leds[]. In this example, I am only using 4 bits for 16 levels of brightness.

Sending one byte via UART updates data in leds[] for only one LED.

updateTLC() updates all LEDs, sends 192 bits.

 

TLC's GS register is 12 bits, UCB0 can only send 8 bits at a time. In my code, I am sending GS data for 2 LEDs in each iteration, 24 bits, 3 bytes. Total of 8 iterations.

So for example, LED 15 and 14 is at max, 0x0F in leds[]. 00001111 and 00001111

First byte, I am taking leds[15] and shifting it 4 times to the left (basically multiplying it by 16 to get 12 bit value.) 11110000

Next byte contains 4 lower bits of LED 15 and 4 upper bits of LED 14. Since we have only 16 levels, 4 lower bits are always 0, so we send only leds[14] (we don't have to shift it because they are in the right position. 00001111

Last byte, all 0s since we have 16 levels only. In the end, we send: 111100000000 111100000000. Repeat that 7 more times for the remaining 14 LEDs

 

If you want to have more levels, for example 256, all you need to do is change updateTLC()

 

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

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

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

Share this post


Link to post
Share on other sites

Ah ok, I get it now. I was just confused by the fact that you're counting 8 leds with ledcounter and sending 3 bytes each.

 

Thanks for explaining

Share this post


Link to post
Share on other sites

Cr*p...happens again. This time everythings soldered so no flaky breadboard connection.

Do I need to update DC register before updating GS register? Also, do I need the first cycle flag when not updating it?

 

VPRG and DCPRG are grounded and not controlled by MSP this time since I'm using the DC data from EEPROM.

 

Sniffer tells me, that there is a (clocked) current flowing through OUTn (strangely also on TLCs not connected to the MSP).

But the LEDs are pretty dark to off using the same old resistor with value of 1.91kOhm

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×