tlc5920 16x8 led driver/controller
Pavel Hudecek
edizon na seznam.cz
Pátek Srpen 31 17:07:16 CEST 2018
Tak tohle bych považoval za tak nějak samozřejmé:-) Ze všech obrázků i
tabulek v DS též plyne, že CSEL má čistě statickou funkci, tzn. po celou
dobu svitu tam musí být daná kombinace.
Ale uznávám, že ani samozřejmé věci někdy zas tak samozřejmé nejsou:-)
Zrovna koukám sem:
http://www.farnell.com/datasheets/2625486.pdf
A z grafů 8/13 a 9/13 to vypadá, že s CE se v rámci běžného čtení a zápisu
musí "cvičit", což patří do kategorie "to by mě ani ve snu nenapadlo":-)
Jsem zvyklý, že tuhle nohu (není-li zvláštní důvod k jinému použití) dávám
natvrdo na GND. Navíc v aplikaci, pro kterou jsem to chtěl, by to chtělo,
aby ke čtení stačilo mít trvale aktivní OE a jen měnit adresy, což je u RAM
s tímto rozhraním též normální, ale tady to asi taky nepůjde.
PH
-----Původní zpráva-----
From: David Belohrad
uz jsem to rozjel. problemu bylo vic, ale ten hlavni bylo casovani signalu
csel. nejak jsem nepochopil, ze csel by mel byt na jedne hodnote 'dost
dlouho', a ze je to prave csel, ktery dela tu sloupcovou obnovovaci
frekveni. takze jsem musel kod cely predelat. Kdyby nekdo potreboval FPGA
implementaci, tady je. Zapojeni je v jednom z predchozich emailu (mam tam 2
tlc drivery a vsechny signaly krome vstupnich dat jsou stejne. data jsou
kazdemu TLC predavana v display.data1_o a display.data2_o). Prilozeny kod je
informativni (chybi deklarace ckrs_t, implementace clock_divider ...). pokud
nekdo chce cely kod, rad preposlu.
import CKRSPkg::*;
module tlc5920
#(
// clock divider. Set to zero when ClkRs_ix provides 40MHz
// stream. For all faster clocks give division ratio to get to
// lower speeds
parameter g_divider = 4
)
(
// 40 MHz clock reset stream
input ckrs_t ClkRs_ix,
// data input. Logic '1' turns the particular led on (= emits
// light). The vector data are as follows:
// [column][row][red/green]
input logic [3:0][15:0][1:0] data_ib,
// interface to the chip
display_x display
);
// clock enable
logic enable,
onems = 0,
enabledly = 0;
logic sclk = 0,
latch = 0;
// counting 32bits to be shifted in one go into both registers
localparam CBITS = 7;
logic [CBITS-1:0] counter_b = '0;
logic frame;
// first index is DRIVER, second index is data to be shifted in
logic [1:0][15:0] data_b;
// first we get clock enable out of division, get maximum speed,
// which is 10MHz. This is clock into serial register
clock_divider
#(.g_divider(g_divider))
i_clock_divider_ms
(.enable_o(enable),
.*);
// millisecond counting (roughly)
logic [14:0] cntms = '0;
always_ff @(posedge ClkRs_ix.clk)
if (enable) begin
if (cntms == 15'd10000)
cntms <= '0;
else
cntms <= cntms + 15'd1;
onems <= (|cntms) ? '0 : '1;
end
typedef enum logic[5:0] {IDLE, LOAD, SHIFTSTART,
SHIFTSTOP, LATCH} state_t;
state_t state;
always_ff @(posedge ClkRs_ix.clk)
enabledly <= enable;
logic [2:0] next_csel;
always_ff @(posedge ClkRs_ix.clk)
if (onems && enable)
next_csel <= display.csel_ob3 + 3'd1;
// translate current column into next data slice
logic [1:0] nextidx;
logic nextcolor;
assign nextidx = next_csel[1:0];
logic [31:0] compact_b;
// these are 32 bits corresponding to row/color
assign compact_b = data_ib[nextidx];
// we use currentout data slice to cast the data to the led diodes
outputs
always_ff @(posedge ClkRs_ix.clk)
if (state == LOAD && enabledly) begin
data_b[1] <= compact_b[31:16];
data_b[0] <= compact_b[15:0];
end else if (state == SHIFTSTOP && enable) begin
data_b[1] <= {data_b[1][14:0], 1'b0};
data_b[0] <= {data_b[0][14:0], 1'b0};
end
// simple counter to count the states
always_ff @(posedge ClkRs_ix.clk)
if (state == LOAD)
counter_b <= (CBITS)'(16);
else if (enabledly && sclk && (|counter_b))
counter_b <= counter_b - (CBITS)'(1);
// counter for columns:
always_ff @(posedge ClkRs_ix.clk or posedge ClkRs_ix.reset)
if (ClkRs_ix.reset)
display.csel_ob3 <= '0;
else if (frame && enable)
display.csel_ob3 <= display.csel_ob3 + 3'd1;
always_ff @(posedge ClkRs_ix.clk or posedge ClkRs_ix.reset) begin
if (ClkRs_ix.reset) begin
state <= IDLE;
end else if (enable) begin
frame <= '0;
sclk <= '0;
latch <= '0;
display.blank_o <= '0;
case(state)
IDLE: begin
display.blank_o <= '0;
if (onems) begin
display.blank_o <= '1;
state <= LOAD;
end
end
LOAD: begin
display.blank_o <= '1;
frame <= 1;
state <= SHIFTSTART;
end
SHIFTSTART: begin
display.blank_o <= '1;
sclk <= 1;
state <= SHIFTSTOP;
end
SHIFTSTOP: begin
display.blank_o <= '1;
sclk <= 0;
if (~(|counter_b))
state <= LATCH;
else
state <= SHIFTSTART;
end
LATCH: begin
display.blank_o <= '1;
latch <= 1;
state <= IDLE;
end
endcase // case (state)
end
end
initial begin
$display("Size of input vector: %d", $bits(data_ib));
end
assign display.latch_o = latch;
assign display.sclk_o = sclk;
assign display.data1_o = data_b[0][15];
assign display.data2_o = data_b[1][15];
endmodule // tlc5920
Daniel Valuch <balu na k-net.fr> writes:
> pisal som to pred 10 rokmi, ale reverznut by nemalo byt tazke :-)
>
> hodiny equ 30h ;aktualny cas
> minuty equ 32h
> sekundy equ 34h
> medzi_low equ 36h
> medzi_high equ 37h
> GPS_status equ 38h
> sek_tmp1 equ 39h
> sek_tmp2 equ 3Ah
>
> timeshift bit 7Ch ;time shift with respect to GMT. 0 = GMT+1, 1 = GMT+2
> timeshift_in bit p3.5 ;timeshift input
>
> text equ 40h ; zaciatok 32B bloku s aktualnym textom
>
> disp equ 40h ;zaciatok pamate s datami pre displej
> disp1 equ 40h ; znak1 H displeja 1
> disp2 equ 48h ; znak1 H displeja 2
> disp3 equ 50h ; znak1 H displeja 3
> disp4 equ 58h ; znak1 H displeja 4
> disp5 equ 60h ; znak1 H displeja 5
> disp6 equ 68h ; znak1 H displeja 6
> disp7 equ 70h ; znak1 H displeja 7
> disp8 equ 78h ; znak1 H displeja 8
>
>
> znak1 equ 80h ; zaciatok dat (bit 0) pre znak1
> znak2 equ 90h ; zaciatok dat (bit 0) pre znak2
> znak3 equ 0A0h ; zaciatok dat (bit 0) pre znak3
> znak4 equ 0B0h ; zaciatok dat (bit 0) pre znak4
>
> latch bit P2.7
> blank bit P2.5
> sclk bit P2.6
> csel0 bit P2.4
> csel1 bit P2.3
> csel2 bit P2.2
>
> RCAP2H equ 0CBh
> RCAP2L equ 0CAh
> T2MOD equ 0C9H
> T2CON equ 0C8H
> TR2 bit 0C8h.2
>
> task1flag bit 78h
> task2flag bit 79h
> task3flag bit 7Ah
> task4flag bit 7Bh
>
>
> pocet_znakov equ 32 ; pocet znakov na displeji
>
>
> org 0
>
> jmp init
>
> ;interrupt handles
> org 0bh ;------- timer 0 interrupt handle
> mov TL0,#Low T0_const
> mov TH0,#High T0_const
> push 0h ;push registra R0
> push 1h ;push registra R1
>
> jb task1flag,task1
> jb task2flag,task2
> jb task3flag,task3
> jb task4flag,task4
>
> setb task1flag
> clr task2flag
> clr task3flag
> clr task4flag
> jmp von_z_int
>
> task1:
> clr task1flag
> setb task2flag
> clr task3flag
> clr task4flag
>
> ;
> mov R0,#znak1
> mov R1,#16
>
> ; setb blank
>
> loop3: mov P0, na R0
> setb sclk
> inc R0
> clr sclk
> djnz R1,loop3
>
> setb latch
> clr latch
>
> clr csel0
> clr csel1
> clr csel2
> ; clr blank
>
> jmp von_z_int
>
> task2:
> clr task1flag
> clr task2flag
> setb task3flag
> clr task4flag
>
> ;
> mov R0,#znak2
> mov R1,#16
>
> ; setb blank
>
> loop4: mov P0, na R0
> setb sclk
> inc R0
> clr sclk
> djnz R1,loop4
>
> setb latch
> clr latch
>
> setb csel0
> clr csel1
> clr csel2
> ; clr blank
>
> jmp von_z_int
>
> task3:
> clr task1flag
> clr task2flag
> clr task3flag
> setb task4flag
>
> mov R0,#znak3
> mov R1,#16
>
> ; setb blank
>
> loop5: mov P0, na R0
> setb sclk
> inc R0
> clr sclk
> djnz R1,loop5
>
> setb latch
> clr latch
>
> clr csel0
> setb csel1
> clr csel2
> ; clr blank
>
> jmp von_z_int
>
> task4:
> setb task1flag
> clr task2flag
> clr task3flag
> clr task4flag
>
> ;
> mov R0,#znak4
> mov R1,#16
>
> ; setb blank
> loop6: mov P0, na R0
> setb sclk
> inc R0
> clr sclk
> djnz R1,loop6
>
> setb latch
> clr latch
>
> setb csel0
> setb csel1
> clr csel2
> ; clr blank
>
> jmp von_z_int
>
>
>
> von_z_int:
> clr blank
> pop 1h ;pop registra R1
> pop 0h ;pop registra R1
> reti
>
>
> On 27/08/2018 21:58, David Belohrad wrote:
>> Ahojte,
>>
>> ma prosim nekdo zkusenosti s tl5920?
>>
>> www.ti.com/lit/ds/symlink/tlc5920.pdf
>>
>>
>> nevim jak spravne formulovat muj dotaz. ... nefunguje to a asi nerozumim,
>> jak to ma fungovat. Datasheet je velice skoupy na informace. a at delam
>> co delam, led matrix zobrazuje hovadiny. Vyrobil jsem kus systemverilog
>> kodu, ktery dava 'blank' signal trvale na log. L. Necham vzdy do 16
>> bitoveho registru nacist pro dany radek tu 16-bitovou informaci, po
>> kazdych 16 bitech vytvorim puls na LATCH (transision L->H->L), a na
>> kazdych 16-bitech cykluji csel vzdy dvakrat (tedy mezi dvema latch
>> impulzy ma csel hodnotu 0,1 pak 2,3 pak 4,5), a tedy jeden 'frame'
>> vyzaduje 4x latch - celkove 64 bitu poslanych na kazdy frame, ktery
>> cykluje csel od nuly do sedmi.
>>
>> Kdyz to spustim a divam se na data na SIN/SOUT, vsechno vypada perfektne,
>> logicky. Ovsem diody si delaji co chteji. nektere z nich slabe sviti,
>> nektere silne, skoro to vypada, jako kdyby nebyl dostatecny proud tema
>> diodama, nebo dochazelo k nejakemu mixu mezi logikou CSEL pinu a seriove
>> linky. Napada me jenom, ze signal BLANK proste z nejakeho neznameho
>> duvodu musi byt take pouzivan. Ja jej mam trvale na nule, protoze chci
>> mit ty diody neustale zapnute.
>>
>> Tak me napadlo, nema k tomuto driveru nekdo kod napsany pro ... cokoliv?
>> arduino/jakykoliv mikrokontroler, abych si mohl proverit jestli casuji
>> jak mam? K cemu je BLANK?
Další informace o konferenci Hw-list