Jump to content


Photo

MSP430G2553 and 3-wire SPI RGB LED timing help

msp430 TM1809

  • Please log in to reply
15 replies to this topic

#1 m0nk37

m0nk37

    Member

  • Members
  • PipPip
  • 22 posts

Posted 22 January 2017 - 06:36 PM

Hello,

 

Im working with TM1809 RGB LEDs on an MSP430G2553 over SPI (3-wire) data transfer.

 

Im running into issues with timing and im not sure if its due to voltage or something else, and could really use some help.

 

https://www.deskontr...eets/TM1809.pdf on page 2 says that these lights require 4.5-5.5V, and i know the MSP430 is at 3.3V, is this the reason? 

 

My code below achieves the ability to set the RGB LEDs with about 95% success rate, i run into issues attempting to animate the colors or if i send it the same color over and over it will send bad data 5% of the time and fail.

 

If its not the voltage, can someone take a look at my code and let me know if they have any ideas?

 

Thanks for your time! :)

 

 

Attached Files

  • Attached File  main.c   4.1KB   2 downloads


#2 LiviuM

LiviuM

    Level 1

  • Members
  • 53 posts

Posted 22 January 2017 - 07:03 PM

Hi,

have you seen the @Fmilburn's topic about controlling WS2812B LEDs using MSP430G2553 LP and SPI?


  • m0nk37 likes this

#3 m0nk37

m0nk37

    Member

  • Members
  • PipPip
  • 22 posts

Posted 22 January 2017 - 07:55 PM

Hi @LiviuM

 

Thanks, yes i have seen that post actually. Fmilburn gave me some help previously and now im stuck again.



#4 chicken

chicken

    Level 4

  • Members
  • 854 posts

Posted 22 January 2017 - 09:03 PM

Just the other day, there was an article on hackaday that may give you some workarounds
http://hackaday.com/...3-3v-data-line/

Alternatively, a level shifter like SN74HCT125 could be used.
  • m0nk37 likes this

#5 LiviuM

LiviuM

    Level 1

  • Members
  • 53 posts

Posted 22 January 2017 - 09:10 PM

I've used some (4) WS2812B powered at 3.3 V and they worked OK. Never used TM1809, though.


  • m0nk37 likes this

#6 m0nk37

m0nk37

    Member

  • Members
  • PipPip
  • 22 posts

Posted 22 January 2017 - 09:53 PM

@chicken thanks for that, i will give it a read.

 

I also had another question if someone can help, i wanted to make sure i understand this part correctly. On page 4 here: https://www.deskontr...eets/TM1809.pdf, it shows the wave form timings.

 

It shows High speed mode, and Low speed mode. How are these modes determined?

 

Second, how should the timings supplied in the datasheet be applied to the code? Are the timing values per bit sent, or byte? The data sheet shows a 72bit data structure and is confusing me.

 

Example:

 

T0H 0,high-level time , min=450 , typ=600, max=750 ns

T1H 1,high-level time , min=1050, typ=1200, max=1350 ns

 

How does this correlate to the 72bit data structure, and just in general, to the bits i should be sending?

 

 The timing is per byte. 


Edited by m0nk37, 22 January 2017 - 10:43 PM.


#7 chicken

chicken

    Level 4

  • Members
  • 854 posts

Posted 22 January 2017 - 11:03 PM

Looking at the data sheet:
- Hi/lo speed is determined by the voltage on the SET pin. See page 2
- The timing waveform on page 4 is describing 1 bit. Repeat it 72 times to transmit 72 bits of data (8/8/8 bit RGB for 3 LEDs), times the number of chained ICs.

From what I understand, the SPI trick uses multiple bits of SPI data to match a single LED bit's timing. E.g. you'd use 100 to transmit a 0 and 110 to transmit a 1. You just have to make sure that SPI runs at roughly 600ns / bit, i.e. 1.666 MHz, with 1.6 probably being close enough. The trickier question is how to get the color data into that format and feeding it to the SPI peripheral. That's where the library comes in.

@Fmilburn to the rescue :-)
  • m0nk37 likes this

#8 m0nk37

m0nk37

    Member

  • Members
  • PipPip
  • 22 posts

Posted 23 January 2017 - 12:25 AM

Thank you for the suggestion! I will try those settings and see what happens. 

 

This is currently what ive got so far (not in the code i supplied, did this afternoon). It seems to work about 90-95% of the time, there is always one random pixel that wants to act up. It was exciting because it ran for a few minutes without messing up.

 

 

16MHz / MOD 3.2 = 5MHz DCO, which is 200ns per cycle

TM1809 requires
LONG = 1050ns to 1350ns per byte
SHORT = 450ns to 750ns per byte
RESET = 24us (microseconds), 1 us = 1000ns (based on cycle per MHz)

My Script is currently (8/8/8 bit RGB for 3 LEDs)
LONG = 1000ns, 5 bits on in the byte. (5 * 200ns)
SHORT = 400ns, 2 bits on in the byte. (2 * 200ns)
RESET = 48 cycles


Edited by m0nk37, 23 January 2017 - 12:27 AM.


#9 m0nk37

m0nk37

    Member

  • Members
  • PipPip
  • 22 posts

Posted 23 January 2017 - 01:55 AM

Looking at the data sheet:
- Hi/lo speed is determined by the voltage on the SET pin. See page 2
- The timing waveform on page 4 is describing 1 bit. Repeat it 72 times to transmit 72 bits of data (8/8/8 bit RGB for 3 LEDs), times the number of chained ICs.

From what I understand, the SPI trick uses multiple bits of SPI data to match a single LED bit's timing. E.g. you'd use 100 to transmit a 0 and 110 to transmit a 1. You just have to make sure that SPI runs at roughly 600ns / bit, i.e. 1.666 MHz, with 1.6 probably being close enough. The trickier question is how to get the color data into that format and feeding it to the SPI peripheral. That's where the library comes in.

@Fmilburn to the rescue :-)

I tried these configuration settings but unfortunately it didnt work. It was outside the ranges for it to work right i guess. 

 

I did 16Mhz / 10 to get 1.6MHz for 625ns. With LONG having 2 bits on, and SHORT having 1.

 

The LEDs just turned on (white) even though i was sending it colors, so it was to far outside the range.



#10 Fmilburn

Fmilburn

    Level 3

  • Members
  • 525 posts
  • LocationSeattle

Posted 23 January 2017 - 07:53 AM

 

I tried these configuration settings but unfortunately it didnt work. It was outside the ranges for it to work right i guess. 

 

I did 16Mhz / 10 to get 1.6MHz for 625ns. With LONG having 2 bits on, and SHORT having 1.

 

The LEDs just turned on (white) even though i was sending it colors, so it was to far outside the range.

I have learned not to comment on devices I haven't worked with before but here goes anyway ;)

 

How did you set the clock and are you sure you got that correct?  If it is 625 ns then it would appear to be OK with LONG and SHORT as you have described it.  Did you post your code?  I didn't see it.

 

What code are you using that gives 90-95% correct?  The schematic in the datasheet shows a capacitor between Vcc and GND - did you place that in your circuit?  Could possibly be something flaky because of that.

 

It is really useful to have a logic analyzer for this type work, unfortunately mine isn't working at the moment.


  • m0nk37 likes this

#11 m0nk37

m0nk37

    Member

  • Members
  • PipPip
  • 22 posts

Posted 23 January 2017 - 03:38 PM

 

 

How did you set the clock and are you sure you got that correct?  If it is 625 ns then it would appear to be OK with LONG and SHORT as you have described it.  Did you post your code?  I didn't see it.

 

New code posted in this reply. Line 47 in void relay(), is where the bits are specified. And inside void main() is where the DCO is configured.

I am configuring the DCO by taking the 16MHz clock and setting the DCO speed divider to obtain 5MHz for the seemingly working copy, and 1.6MHz for the copy which doesnt seem to work.

I dont know how to fully set the DCO by taking the rsel/mod.

 

 

 

What code are you using that gives 90-95% correct?  The schematic in the datasheet shows a capacitor between Vcc and GND - did you place that in your circuit?  Could possibly be something flaky because of that.

 

I have attached it. I do not have any capacitor between VCC and GND, the only thing going to the LEDs from the board (MSP430) is the Data/Logic Line In. The LEDs have an external 5V power supply.

 

 

 

It is really useful to have a logic analyzer for this type work, unfortunately mine isn't working at the moment.

 

I think you should fix it :D

 

I also attached an old school Oscilloscope reading of the "working" copy, i dont think it will help much but i think its cool anyways :)

 

If you need me to explain the code I can, i think its fairly straight forward.

Attached Files



#12 m0nk37

m0nk37

    Member

  • Members
  • PipPip
  • 22 posts

Posted 23 January 2017 - 09:12 PM

@chicken

 

I narrowed it down to 1.666MHz (12MHz / MOD 7.2), sending 2 bits LONG and 1 bit SHORT, this time i am seeing the proper colors, however it is not as tight as the 5MHz ive posted. I assume this is what you were referring to using a library, how would one fix the timing outside of SPI? Could i use a timer and force it not to send unless its at the correct time frame perhaps?



#13 Fmilburn

Fmilburn

    Level 3

  • Members
  • 525 posts
  • LocationSeattle

Posted 23 January 2017 - 09:17 PM

I had a quick look at your code and I suspect there are multiple problems.  For example, in main_working_95.c

    // DCO Speed Divider
    UCB0BR0 = 3.2;

You can't put a floating point number into a register and I don't think this is doing what you want it to.  If you are new to registers on microcontrollers I suggest The TI workshop at http://processors.wi...ops_and_Modules

 

I think you can modify the CCS code I posted in the link @LiviuM referred to and make it work.  Here is my quick edit of the code:

// Runs on G2553 at 8 MHz
// Output is on pin P1_2 (MOSI)

#include <msp430.h>

#define SPIDIV     0x02                         // 8 MHz/2 gives ~250 ns for each on bit in byte       <=====
#define SPILONG    0b11111000                   // 1250 ns on, 750 ns off                              <=====
#define SPISHORT   0b11100000                   // 750 ns on, 1250 ns off                              <=====

void initClock();
void initSPI();
void initWS2812();
void sendByte (unsigned char b);
void sendPixel (unsigned char r, unsigned char g, unsigned char b);
void show();

int main(void)
{
  WDTCTL = WDTPW + WDTHOLD;                     // Stop watchdog timer

  initClock();
  initSPI();
  initWS2812();

  while(1){
      sendPixel(0xFF, 0xFF, 0xFF);               // show all ones                                     <======
//    sendPixel(0x00, 0x00, 0x00);               // show all zero                                     <======
      show();
  }
}

void initClock(){
    BCSCTL1 = CALBC1_8MHZ;                       // load calibrated data for 8 MHz                    <======
    DCOCTL = CALDCO_8MHZ;                        //                                                   <======
}

void initSPI(){
    P1SEL = BIT1 + BIT2 + BIT4;
    P1SEL2 = BIT1 + BIT2 + BIT4;
    UCA0CTL0 |= UCCKPL + UCMSB + UCMST + UCSYNC;  // 3-pin, 8-bit SPI master
    UCA0CTL1 |= UCSSEL_2;                         // SMCLK
    UCA0BR0 |= SPIDIV;                            // clock divider
    UCA0BR1 = 0;                                  //
    UCA0MCTL = 0;                                 // No modulation
    UCA0CTL1 &= ~UCSWRST;                         // **Initialize USCI state machine**
    IE2 |= UCA0RXIE;                              // Enable USCI0 RX interrupt
}

// Sends one byte to the LED strip by SPI.
void sendByte (unsigned char b){
    unsigned char bit;
    for (bit = 0; bit < 8; bit++){
      if (b & 0x80) // is high-order bit set?
          UCA0TXBUF = SPILONG;     // long on bit defined for each clock speed
      else
          UCA0TXBUF = SPISHORT;    // short on bit defined for each clock speed
      b <<= 1;                     // shift next bit into high-order position
    }
}

// Send a single pixel worth of information.  Turn interrupts off while using.
void sendPixel (unsigned char r, unsigned char g, unsigned char b){
    sendByte (g);        // NeoPixel wants colors in green-then-red-then-blue order
    sendByte (r);
    sendByte (b);
}

// latch the colors
void show(){
    __delay_cycles(72);            // 18 micro seconds
}

void initWS2812(){
    show ();                       // in case MOSI went high, latch in whatever we sent
    sendPixel (0, 0, 0);           // now change back to black
    show ();                       // and latch that
}

The main changes I made are:

  • In the function initClock() the clock speed is set to 8 MHz using the factory stored defaults.  The workshop linked above has a good overview of how to do this for the MSP430 family.
  • At the very top SPIDIV is set to 2 which means it is ticking at 4 MHz - a period of 250 ns.
  • Accordingly, the bytes defined in the next two lines will have the on/off periods that are shown - these happen to fall within the specifications given by the datasheet.

You can test this with your oscilloscope.  In main() there is a line that sends all ones and another (commented out) that sends all zeros. This is what I see on my oscilloscope when the output is set to all ones:

Attached File  SDS00009.jpg   75.36KB   0 downloads

The time divisions are set to 250 ns and  you can see that the wiggles are high for 1250 ns and then low for 750 ns.  Right on the money.  There is a lot of overshoot - that is why a 0.1 uF capacitor between the signal and ground is probably a good idea.  You can check your scope to see if it is doing what it should.


  • m0nk37 likes this

#14 m0nk37

m0nk37

    Member

  • Members
  • PipPip
  • 22 posts

Posted 23 January 2017 - 10:56 PM

@Fmilburn

 

Thank you! :D

 

I tested your code, and the output on P1.2 in my scope. It looks pretty much identical as yours. There is a problem though, the lights arent functioning with these setting. I realize your example is only setup for 1 LED, and the first LED in the strip just kind of strobes. Im going to attempt to modify the code and account for the 72bit structure these LEDs want, i think that may be why its not turning on/off.

 

You used UCA0 in your example, whats the difference between it and UCB0? If i take your configuration settings and apply it to my code as UCB0 on P1.7, it *seems* to work, but eventually messes up. Could it be because my device isnt calibrated properly? or would it be because of the capacitor you mentioned.

 

In any event, this is great thank you for your help once again.



#15 Fmilburn

Fmilburn

    Level 3

  • Members
  • 525 posts
  • LocationSeattle

Posted 24 January 2017 - 04:11 AM

 

You used UCA0 in your example, whats the difference between it and UCB0? If i take your configuration settings and apply it to my code as UCB0 on P1.7, it *seems* to work, but eventually messes up. Could it be because my device isnt calibrated properly? or would it be because of the capacitor you mentioned

 

From the family user guide, slau144j, pg 436:

 

The USCI_Ax modules support:
• UART mode
• Pulse shaping for IrDA communications
• Automatic baud rate detection for LIN communications
• SPI mode
The USCI_Bx modules support:
• I2C mode
• SPI mode

I tried USCI B in my code just now and it looked OK on the oscilloscope.  The timing is just on the edge of what the datasheet for your part allows but I would expect it to be OK.  You can adjust the clock further if necessary.  For example:  http://forum.43oh.co...co-calibration/ and there are other examples of adjusting DCO on 43oh as well as other places.  I have never had reason to do much of that though.

 

The datasheet calls for the capacitor - I would put it in especially if I was experiencing problems.


  • m0nk37 likes this

#16 m0nk37

m0nk37

    Member

  • Members
  • PipPip
  • 22 posts

Posted 25 January 2017 - 01:25 AM

@Fmilburn

 

Alright thank you and everyone else very much for all of your help. Ill try the capacitor and then further clock calibration if need be, im sure the code you've posted works. It has to be one of those other things. Ill post a follow up once its working :).







Also tagged with one or more of these keywords: msp430, TM1809

0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users