LED Strip uC controlling with MSP430

Discussion in 'Embedded Systems and Microcontrollers' started by tindel, Jan 2, 2015.

  1. tindel

    Thread Starter Active Member

    Sep 16, 2012
    568
    193
    http://moderndevice.com/new-products/new-product-serial-led-strips/

    http://www.mikroshop.ch/pdf/UCS1903.pdf

    I received a couple meters of the above led strip to play with for Christmas... for the life of me I can't figure out how to program it with the MSP430G2553... the software they have is for an AVR. When I asked for this for Christmas I thought it was suppose to use a SPI bus which is easy enough to program - turns out it uses a discrete signal not conforming to any serial bus that I'm aware of.

    The difficulty comes from the timing diagram shown in the second link. To transmit a 0 there has to be 0.5us high followed immediately by 2.0us of low, and a 1 has to have 2.0us of high followed by 0.5us of low signal. At 16MHz, the 0.5us pulse is only 8 clock cycles. Which makes this tough... to add to the difficulty, I believe this strip uses the high speed mode decreasing the minimum clock cycle interval to 4.

    I'm not sure how to do this with any accuracy. It's not conforming to a serial protocol of any type that I'm aware of. I'm guessing there is a way to use the timer on the MSP430, but I'm not quite sure how to attack it... any tips? Maybe I just set the IO bit and then delay the desired clock cycles before then return changing the state again?
     
  2. joeyd999

    AAC Fanatic!

    Jun 6, 2011
    2,675
    2,720
    Yes, this looks like a (proprietary?) one-wire signalling protocol. I've not seen it before, and, IMHO, it's pretty silly -- there are better ways to do it.

    There is only 150 ns allowable error for the edge times. This is going to be tough by bit-banging.

    Perhaps there is a driver IC as a companion to convert a more standard stream (UART, SPI, IIC) into this protocol?
     
    Last edited: Jan 2, 2015
  3. joeyd999

    AAC Fanatic!

    Jun 6, 2011
    2,675
    2,720
    Ok...been thinking about this. I might approach it like this:

    Use the on-chip uart, clocked at 4Mbaud (slow version) or 8Mbaud (fast version), and set for 1 start bit (high) and 1 stop bit (low).

    Each code sent to the LED chip will have the pattern serialized as b'1xxxxxxxx0', where the x's are the codes below, and each bit time will be 0.25uS (or 0.125uS in fast mode):

    Each byte is sent as eight consecutive transfers of the following pattern:

    To send a 0 bit, write b'10000000' to the transmit register
    To send a 1 bit, write b'11111110' to the transmit register

    You'll only have 2.5 microseconds between successive writes, so all your data will need to be pre-packaged in an array, and the data shifted out in a tight loop.

    The hardware will take care of the edge times, so you shouldn't have a problem.

    Good Luck!

    Edit: Oh, a reset can be done by pausing data transmission.
     
  4. joeyd999

    AAC Fanatic!

    Jun 6, 2011
    2,675
    2,720
    Also, using 1/2 the baud rate detailed above, you could pack 2 bits into one byte transfer, using these codes:

    00 - b'00001000'
    01 - b'00001111'
    10 - b'11101000'
    11 - b'11101111'
     
  5. joeyd999

    AAC Fanatic!

    Jun 6, 2011
    2,675
    2,720
    As a sanity check, I wanted to see if I could do this on a PIC. The answer is yes, but only with a 64Mhz clock, and the 2 bits per byte transfer.
     
  6. joeyd999

    AAC Fanatic!

    Jun 6, 2011
    2,675
    2,720
    In PIC18 asm, here is how I would do it (the code to set up the USART is not shown):

    Code (Text):
    1.  
    2.  
    3. txdata  lfsr    0,array         ;point to array of data
    4.  
    5.     movlw   low (-bytecount)    ;load number of bytes to send
    6.     movwf   bytectr
    7.     movlw   high (-bytecount)
    8.     movwf   bytectr+1
    9.  
    10. dobyte  movlw   4       ;send 4 doublets per byte
    11.     movwf   dblctr
    12.  
    13. dublet  rlncf   indf0,f     ;simultaneously shift bytes,
    14.     rlncf   indf0,f     ;   and multiply least 2 by 4 for jump
    15.  
    16.     movf    indf0,w     ;bits 2 & 3 are important
    17.     andlw   b'1100'     ;mask them
    18.     addwf   pcl,f       ;and use as index into jump table
    19.  
    20. c00 movlw   b'00001000' ;code for doublet '00'
    21.     bra load
    22.  
    23. c01 movlw   b'00001111' ;code for doublet '01'
    24.     bra load
    25.  
    26. c10 movlw   b'11101000' ;code for doublet '10'
    27.     bra load
    28.  
    29. c11 movlw   b'11101111' ;code for doublet '11'
    30.     bra load
    31.  
    32. load    btfss   pir1,txif   ;txreg empty?
    33.     bra load        ;  no, wait
    34.  
    35.     movwf   txreg       ;yes, send new code
    36.  
    37.     decfsz  dblctr,f    ;all doublets done?
    38.     bra dublet      ;no, do more
    39.  
    40.     movf    postinc0,f  ;point to next byte
    41.  
    42.     incfsz  bytectr,f   ;do for all bytes
    43.     bra dobyte
    44.     incfsz  bytectr+1,f
    45.     bra dobyte
    46.  
    47.     return          ;done.
    48.  
     
    Last edited: Jan 2, 2015
  7. joeyd999

    AAC Fanatic!

    Jun 6, 2011
    2,675
    2,720
    I got the codes wrong (my stupid head forgot LSBs are sent first). The proper codes are:

    00 - b'00010000'
    01 - b'00010111'
    10 - b'11110000'
    11 - b'11110111'
     
  8. joeyd999

    AAC Fanatic!

    Jun 6, 2011
    2,675
    2,720
    Also, I had an error in my bit shifting. Here is a fully corrected version:

    Code (Text):
    1.  
    2. txdata  lfsr    0,array         ;point to array of data
    3.  
    4.     movlw   low (-bytecount)    ;load number of bytes to send
    5.     movwf   bytectr
    6.     movlw   high (-bytecount)
    7.     movwf   bytectr+1
    8.  
    9.     rlncf   indf0,f     ;pre-align lsbs for jump table
    10.     rlncf   indf0,f
    11.  
    12. dobyte  movlw   4       ;send 4 doublets per byte
    13.     movwf   dblctr
    14.  
    15. dublet  movf    indf0,w     ;bits 2 & 3 are important
    16.     andlw   b'1100'     ;mask them
    17.     addwf   pcl,f       ;and use as index into jump table
    18.  
    19. c00 movlw   b'00010000' ;code for doublet '00'
    20.     bra load
    21.  
    22. c01 movlw   b'00010111' ;code for doublet '01'
    23.     bra load
    24.  
    25. c10 movlw   b'11110000' ;code for doublet '10'
    26.     bra load
    27.  
    28. c11 movlw   b'11110111' ;code for doublet '11'
    29.     bra load
    30.  
    31. load    btfss   pir1,txif   ;txreg empty?
    32.     bra load        ;  no, wait
    33.  
    34.     movwf   txreg       ;yes, send new code
    35.  
    36.     rrncf   indf0,f     ;shift for next two bits
    37.     rrncf   indf0,f
    38.  
    39.     decfsz  dblctr,f    ;all doublets done?
    40.     bra dublet      ;no, do more
    41.  
    42.     movf    postinc0,f  ;point to next byte
    43.  
    44.     incfsz  bytectr,f   ;do for all bytes
    45.     bra dobyte
    46.     incfsz  bytectr+1,f
    47.     bra dobyte
    48.  
    49.     return          ;done.
    50.  
     
  9. tindel

    Thread Starter Active Member

    Sep 16, 2012
    568
    193
    Wow - ask and I'll receive! Thanks joeyd999. A couple reasons I don't think this will work with an MSP430:
    • Maximum clock rate is 16MHz (on the G2553) so I don't think you could get the bit shifting through fast enough between UART writes.
    • Start bit is always LOW. You could probably go through an inverting buffer to make it work and invert all of the logic but at 8Mbaud - maybe not...
    • You have to hold the bit in reset for 24us for the data to be asserted... UART is nominally high.
    Regardless - I've decided to pursue sending this back in favor of an SPI bus driven one that will be more friendly to the MSP430 family... I don't feel like experimenting and being out 50 bucks... or it laying around collecting dust.
     
Loading...