tlc5920 16x8 led driver/controller

David Belohrad david na belohrad.ch
Středa Srpen 29 09:25:54 CEST 2018


diky vsem,

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?
>>
>> ztratil jsem s tou hovadinou cely den
>>
>> diiky.
>>
>> .d.
>> _______________________________________________
>> HW-list mailing list  -  sponsored by www.HW.cz
>> Hw-list na list.hw.cz
>> http://list.hw.cz/mailman/listinfo/hw-list
>
>
> _______________________________________________
> HW-list mailing list  -  sponsored by www.HW.cz
> Hw-list na list.hw.cz
> http://list.hw.cz/mailman/listinfo/hw-list


Další informace o konferenci Hw-list