TLC5940/41 Driver
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.
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
spin
17K
