Shop OBEX P1 Docs P2 Docs Learn Events
TLC5940/41 Driver — Parallax Forums

TLC5940/41 Driver

mhm21mhm21 Posts: 14
edited 2014-01-19 19:23 in Propeller 1
Hello all, I am starting this thread for constructive feedback on my TLC5940 driver. Currently it have written the vast majority in assembly so that I might quickly index through a large LED matrix (32x32). This chip seemed like a wonderful place to learn about the counter modules as it requires a grey scale clock pulse to be emitted and monitored at as high a frequency as possible. I am using the counterA in NCO mode to generate a 3MHz square wave (max SPI frequency supported by the chip) and counter B in rising edge detection mode to determine when 4096 pulses have elapsed.

Within the grey scale timing window, a counter is monitored for changes to any individual channel. If a change is detected, it is written and latched to the chip. This data then becomes valid on the next grey scale cycle. As it stands, the grey scale timing and channel update runs at 7.3kHz. Not terrible, but I suppose there is room for improvement. Extensions for multiple chips can be realized by changing the number of channels in the constant block. I have yet to test beyond two chips in series, but I suspect that the driver might need to be changed to support larger number of chips.

I had hoped this module would be useful for others, so I plan to upload it to OBEX if it is well received. What changes should be made to make it more useful/usable/better/faster/stronger/etc. ? Is there a more elegant way to do the initial channel declarations? I feel like these are using up a lot of valuable space.
Con

  _clkmode = xtal1 + pll16x
  _xinfreq = 5_000_000

CHANNELS = 16

VAR

LONG    SIN,SCLK,XLAT,BLANK,GSCLK,SOUT
LONG    REFRESH,CHANNEL_IN[CHANNELS]

BYTE    COG

PUB Start(SIN_,SCLK_,XLAT_,BLANK_,GSCLK_,SOUT_) : Pass

'Pin declarations
SIN := SIN_
SCLK := SCLK_
XLAT := XLAT_
BLANK := BLANK_
GSCLK := GSCLK_
SOUT := SOUT_

'Starts new cog and returns true if successful

Stop

cog := cognew(@START_TLC,@SIN)
Pass := @refresh

PUB Set_Channel(chan,val)

CHANNEL_IN[chan] := val
refresh ++

PUB Stop

if COG
  cogstop(COG~)

DAT

org     0

START_TLC

                        mov     P1,par
                        rdlong  dummy,P1
                        mov     SIN_MASK,#1
                        shl     SIN_MASK,dummy

                        add     P1,#4
                        rdlong  dummy,P1
                        mov     SCLK_MASK,#1
                        shl     SCLK_MASK,dummy

                        add     P1,#4
                        rdlong  dummy,P1
                        mov     XLAT_MASK,#1
                        shl     XLAT_MASK,dummy

                        add     P1,#4
                        rdlong  dummy,P1
                        mov     BLANK_MASK,#1
                        shl     BLANK_MASK,dummy

                        add     P1,#4
                        rdlong  dummy,P1
                        mov     GSCLK_MASK,#1
                        shl     GSCLK_MASK,dummy
                        add     ctra_,dummy             ' Setup counter pins
                        add     ctrb_,dummy

                        andn    dira,GSCLK_MASK         ' Set pin directions
                        or      dira,BLANK_MASK
                        or      dira,SCLK_MASK
                        or      dira,SIN_MASK
                        or      dira,XLAT_MASK

                        mov     ctra,ctra_              ' Start counters in correct mode
                        mov     frqa,frqa_              ' Counter A is in NCO mode at 3 MHz (max SPI frequency of TLC5940)
                        mov     ctrb,ctrb_              ' Counter B is in rising edge detection mode, used to count to 4096 for the grey scale clock
                        mov     frqb,frqb_              ' Counter B adds 1 to PHSB on every rising edge
                        
'---------------------------------------------------------
MAIN_LOOP

        :Loop
                        mov     ti,cnt
                        mov     phsb,#0                 ' Reset counter
                        or      dira,GSCLK_MASK         ' Turn on 3 MHz output waveform
                        call    #READ_ARRAY             ' If new data, update channels
        :gs_loop
                        cmp     resolution,phsb     wc  ' If PHSB is => 4096, turn off and strobe blanking pin
              if_nc     jmp     #:gs_loop
                        andn    dira,GSCLK_MASK

                        or      outa,BLANK_MASK
                        andn    outa,BLANK_MASK

                        sub     ti,cnt
                        wrlong  ti,p1
                        jmp     #:Loop

MAIN_LOOP_RET           ret                        

'---------------------------------------------------------
READ_ARRAY
                        mov     p1,par
                        add     p1,#(6*4)
                        mov     RFRSH,#0                ' Clear refresh count
                        wrlong  RFRSH,p1
                        add     p1,#4
                        mov     array_count,CC          ' Number of longs to read, sequentially
                        
                        or      outa,SCLK_MASK          ' Drive SCLK high, mysterious 193'rd pulse in data sheet
                        andn    outa,SCLK_MASK          ' Drive SCLK low                             
                        
 :read_loop             
                        mov     mask,twelve_bit_mask    ' Setup masks 
                        mov     bits,#12                ' Loop counter
                        rdlong  channel,p1              ' Reads channel values sequentially 
                        add     p1,#4                   ' Increment pointer to next long in memory (channels)
                         
 :Sin_loop
                        
                        test    channel,mask         wz
               if_nz    or      outa,SIN_MASK           ' Toggle data pin  
               if_z     andn    outa,SIN_MASK 
                        or      outa,SCLK_MASK          ' Drive SCLK high
                        andn    outa,SCLK_MASK          ' Drive SCLK low
                        
                        shr     mask,#1                 ' Shift mask to next bit, 12 bit total resolution
                        
                        djnz    bits,#:SIN_LOOP                        
                        djnz    array_count,#:read_loop                        

                        or      outa,XLAT_MASK
                        andn    outa,XLAT_MASK
                        
READ_ARRAY_RET          ret


'Variables
'-----------------------------------------------------------------------------------
P1                      LONG    0
ti                      LONG    0

SIN_MASK                LONG    0
SCLK_MASK               LONG    0
XLAT_MASK               LONG    0
BLANK_MASK              LONG    0
GSCLK_MASK              LONG    0
SOUT_MASK               LONG    0

mask                    LONG    0                       ' Used as 12 bit channel mask
twelve_bit_mask         LONG    1<<12
resolution              LONG    4096                    ' Used for grey scale counter
bits                    LONG    0
array_count             LONG    0                       ' Determines how many channels to read
channel                 LONG    0
CC                      LONG    CHANNELS
RFRSH                   LONG    0                       ' Determines update interval

dummy                   LONG    0

ctra_                   LONG    %00100 << 26            ' NCO mode
ctrb_                   LONG    %01010 << 26            ' Rising edge detection mode
frqa_                   LONG    1610612736              ' 30 MHz
frqb_                   LONG    1                       ' 1 increment for each edge

FIT 496      
Sign In or Register to comment.