Forum: Mikrocontroller und Digitale Elektronik TLC5940 Code


von Peter (Gast)


Lesenswert?

Hallo Leute,

ich bin scho seit Ewigkeiten auf der Suche nach einem passenden Code für 
die Ansteuerung eines/mehrer Tlcs 5940 mit einem Atmega8. Leider sind 
die Codes die ich gefunden habe nicht sehr gut dokumentiert bzw. 
funktionieren nicht einwandfrei (Basiccode aus Ledstyles-forum). Leider 
bin ich nicht gerade der Softwaremensch sondern eher der Hardwarler.
Hat vielleicht jemand ne Ansteuerungsroutine für den Tlc5940 rumliegen 
oder kann einer eine proggen. gerne auch gegen bares!

von Peter (Gast)


Lesenswert?

up

von Kai F. (kai-) Benutzerseite


Lesenswert?

hallo,
da ließe sich bestimmt was machen
schreib mir einfach mal ne Mail (einfach auf meinen Namen klicken)

Grüße
Kai

von Mike123 (Gast)


Lesenswert?

Hi,

wo liegen denn genau die Probleme bei der Ansteuerung?
wie weit bist du denn?
hast du denn überhaupt schon was gemacht?
oder willst du fertigen Code?


Gruß,

Michel

von Patrick S. (patrick22285)


Lesenswert?

Ich hab das Gleiche Problem bekomme das irgendwie nicht hin mit 
flowchart und Demystify, wäre echt dankbar wenn mir jemannd einen Code 
Schicken würde
will über ein STK500 mit einem Atmega8515 einem TLC5940 ansprechen

von Karl H. (kbuchegg)


Lesenswert?

Und die gleiche Frage.
Woran scheitert es denn?

von Christian D. (neo87)


Lesenswert?

Ich arbeite derzeit an einem ähnlichen Projekt. Allerdings verwende ich 
den TLC 5941 und einen Xmega. Ich kann dir heute Nachmittag den Code mal 
Posten wenn's dir hilft. Solltest du leicht für nen atmega umschreiben 
können.
 Der PWM-Takt kommt bei mir von einem externen Ozsillator. Dieser hängt 
am T1-Pin vom xmega und erzeugt das Blank-Signal im PWM-Mode.

von Patrick S. (patrick22285)


Lesenswert?

Christian Dreihsig schrieb:
> Ich arbeite derzeit an einem ähnlichen Projekt. Allerdings verwende ich
> den TLC 5941 und einen Xmega. Ich kann dir heute Nachmittag den Code mal
> Posten wenn's dir hilft. Solltest du leicht für nen atmega umschreiben
> können.
>  Der PWM-Takt kommt bei mir von einem externen Ozsillator. Dieser hängt
> am T1-Pin vom xmega und erzeugt das Blank-Signal im PWM-Mode.

Das wäre echt Super nett von dir.
der Takt erzeugt das blank signal??

wie hast du das mit dem GSCLK Takt gelöst?

von Christian D. (neo87)


Lesenswert?

So endlich Feierabend :)

Patrick S. schrieb:
> wie hast du das mit dem GSCLK Takt gelöst?

Also, der GSCLK kommt bei mir, wie schon erwähnt, von einem 
Quarzoszillator (25Mhz). Der Oszillator hängt gleichzeitig noch am Xmega 
und zählt dort einen Timer hoch. Der Timer wiederrum läuft im PWM-Mode 
und erzeugt alle 4096 GSCLK-Takte den BLANK-Impuls. Die Datenübertragung 
zum TLC5941 läuft ganz Normal über Hardware-SPI nur das ich das XLAT mit 
dem BLANK-Impuls syncronisiere. Macht man das nicht flackern die LEDs 
beim ändern der Werte manchmal auf weil die Register des TLC5941 nich 
gebuffert sind und der Zähler sonst weiter ist als der Wert auf den man 
ihn setzt->Folge: Die LED bleibt einen ganzen Zyklus lang an.

So und jetzt zum Code. Ist noch lange nicht fertig, das LOD wird noch 
nicht ausgewertet. Außerdem wollte ich das Array mit den GS/DC-Werten 
noch ändern und mit nem Getter drauf zugreifen da das so doch ne 
ganzschöne Platzverschwendung ist.

Zuerst der Init für den Timer zur Erzeugung des BLANK-signals:
1
void timer_init(void){
2
  //Port für BLANK setzen O->
3
  PORTC.DIRSET = TLC5941_BLANK;
4
  
5
  //Port für GSCK setzen & Triggern 0<-
6
  PORTD.DIRCLR = TLC5941_GSCK;
7
  PORTD.PIN0CTRL = PORT_ISC_RISING_gc;
8
  
9
  //Setze PD0 als Eventchannel
10
  EVSYS.CH0MUX = EVSYS_CHMUX_PORTD_PIN0_gc;
11
  
12
  //Clocksource -> Event Channel0
13
  TCC0.CTRLA = TC_CLKSEL_EVCH0_gc;
14
  
15
  //SingleSlope-PWM-mode & OC0A aktivieren
16
  TCC0.CTRLB |= TC_WGMODE_SINGLESLOPE_gc | TC0_CCAEN_bm;//0xF3;
17
  
18
  //Legt Timer Topwert und damit auch fest
19
  //bei wievielen Impulsen die Interrupt Routine
20
  //ausgeführt wird
21
  TCC0.PER = 4095;
22
  TCC0.CCA = 1;
23
}

Jetzt das SPI-initieren
1
void SPI_init(void) {
2
  //SPI-ports festlegen
3
  PORTC.DIRSET = TLC5941_Sin | TLC5941_SCK | TLC5941_XLAT | TLC5941_MODE;
4
  PORTC.DIRCLR = TLC5941_Sout | TLC5941_XERR;
5
  
6
  //SPI konfigurien: MASTER, 8Mhz, Mode0
7
  SPIC.CTRL |= SPI_MASTER_bm | SPI_PRESCALER_DIV4_gc | SPI_MODE_0_gc;
8
  
9
  //Keinen interrupt auslösen,
10
  //SPIC.INTCTRL = SPI_INTLVL_MED_gc;
11
  SPIC.INTCTRL = SPI_INTLVL_OFF_gc;
12
  
13
  //SPI aktivieren
14
  SPIC.CTRL |= SPI_ENABLE_bm;
15
  
16
  //XERR aktivieren
17
  PORTC.PIN2CTRL = PORT_OPC_PULLUP_gc | PORT_ISC_FALLING_gc; //PIN configurieren Pullup & Fallende Flanke
18
  PORTC.INTCTRL |= PORT_INT0LVL_MED_gc; // PortC interrupt0 -> medium-level setzen
19
  PORTC.INT0MASK |= PIN2_bm; // Pin2 für Interrupt0 freigeben
20
  PMIC.CTRL |= PMIC_MEDLVLEN_bm; // Medium-Level Interrupts aktivieren
21
  sei(); // Interrupts global freigeben
22
}

und jetzt die Routiene zum senden der DC & GS-Werte.
Die Routine zum Senden der der 6bit und 12bit Werte stammt von Falk 
Brunner hier aus dem Forum, Ich hoffe er ist mir nich böse das ich das 
hier nochmal veröffentliche.
1
//THX to Falk Brunner @ microcontroller.net
2
void TLC5941_SET_DC(uint8_t array[]) {
3
  PORTC.OUTSET = TLC5941_MODE;//MODE 1 = DC
4
5
  uint8_t bit_count_in; // Zähler für Bits in den Eingangsdaten 6Bit/Segment
6
  uint8_t bit_count_out=0; // Zähler für Bits in den Ausgangsdaten 8Bit/SPI Byte
7
  uint8_t dot_count; // Zähler für Arrayindex der EIngangsdaten
8
  uint8_t byte_in; // Eingangsdaten
9
  uint8_t byte_out = 0; // Ausgangsdaten
10
  uint8_t mask_out = 0x80; // Bitmaske für Ausgangsdaten
11
12
    for (dot_count = 0; dot_count < 32; dot_count++) { // Schleife über Eingangsarray
13
        byte_in = array[31-dot_count]; // nächstes Element laden
14
         // Schleife über 6 Bit/Eingangsbyte
15
        for (bit_count_in=0; bit_count_in < 6; bit_count_in++) {    
16
            if (byte_in & 0x20) byte_out |= mask_out; // Prüfe Bit #5, wenn ja in den Ausgangsdaten setzen
17
            byte_in <<= 1; // nächstes Bit hinschieben
18
            mask_out >>= 1; // Maske auf nächsten Ausgangsbit schieben
19
            bit_count_out++; // Bitzähler für Ausgang++
20
            if (bit_count_out == 8) { // 8 Bits erreich, Ausgangsbyte voll?
21
                bit_count_out=0; // Zähler rücksetzen
22
                SPI_send(byte_out); // senden
23
                byte_out = 0; // Zähler rücksetzen
24
                mask_out = 0x80; // Maske rücksetzen
25
            }
26
    }
27
  }
28
  PORTC.OUTSET = TLC5941_XLAT; //XLAT kurz auf 1 um daten zu übernehmen
29
  PORTC.OUTCLR = TLC5941_XLAT;
30
  PORTC.OUTCLR = TLC5941_MODE; //wieder auf GS-mode zurücksetzten
31
}
1
//THX to Falk Brunner @ microcontroller.net
2
void TLC5941_SET_GS(uint16_t array[]) {
3
  PORTC.OUTCLR = TLC5941_MODE;//MODE 0 = GS mode
4
5
  uint8_t bit_count_in; // Zähler für Bits in den Eingangsdaten 6Bit/Segment
6
  uint8_t bit_count_out=0; // Zähler für Bits in den Ausgangsdaten 8Bit/SPI Byte
7
  uint8_t dot_count; // Zähler für Arrayindex der Eingangsdaten
8
  uint16_t byte_in; // Eingangsdaten
9
  uint8_t byte_out = 0; // Ausgangsdaten
10
  uint16_t mask_out = 0x80; // Bitmaske für Ausgangsdaten
11
12
    for (dot_count = 0; dot_count < 32; dot_count++) { // Schleife über Eingangsarray
13
        byte_in = array[31-dot_count]; // nächstes Element laden
14
        // Schleife über 6 Bit/Eingangsbyte
15
        for (bit_count_in=0; bit_count_in < 12; bit_count_in++) {    
16
            if (byte_in & 0x0800) byte_out |= mask_out; // Prüfe Bit #12, wenn ja in den Ausgangsdaten setzen
17
            byte_in <<= 1; // nächstes Bit hinschieben
18
            mask_out >>= 1; // Maske auf nächsten Ausgangsbit schieben
19
            bit_count_out++; // Bitzähler für Ausgang++
20
            if (bit_count_out == 8) { // 8 Bits erreich, Ausgangsbyte voll?
21
                bit_count_out=0; // Zähler rücksetzen
22
                SPI_send(byte_out); //senden
23
                byte_out = 0; // Zähler rücksetzen
24
                mask_out = 0x80; // Maske rücksetzen
25
      }            
26
    }          
27
  }    
28
  
29
  while(TCC0.CNT < 4095); //auf Blank-Flanke warten
30
  
31
  PORTC.OUTSET = TLC5941_XLAT; //XLAT kurz auf 1 um daten zu übernehmen
32
  PORTC.OUTCLR = TLC5941_XLAT;
33
}

Die beiden Arrays sehen übrigens so aus und da steckt auch die 
Platzverschwendung ;)
1
uint8_t DC[32] = {
2
63,  //1
3
63,  //2
4
...
5
63};
6
uint16_t GS[32] = {
7
4095,  //1
8
4095,  //2
9
...
10
4095};

So, das wars erstmal, wie gesagt alles noch Baustelle und die LOD fehlt 
auch noch aber du willst ja auch noch was zu tun haben ;)

Ich hoffe das ich dir helfen konnte.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.