mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik TLC5940 Code


Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
up

Autor: Kai Franke (kai-) Benutzerseite
Datum:

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

Grüße
Kai

Autor: Mike123 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Patrick S. (patrick22285)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und die gleiche Frage.
Woran scheitert es denn?

Autor: Christian Dreihsig (neo87)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Patrick S. (patrick22285)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Christian Dreihsig (neo87)
Datum:

Bewertung
0 lesenswert
nicht 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:
void timer_init(void){
  //Port für BLANK setzen O->
  PORTC.DIRSET = TLC5941_BLANK;
  
  //Port für GSCK setzen & Triggern 0<-
  PORTD.DIRCLR = TLC5941_GSCK;
  PORTD.PIN0CTRL = PORT_ISC_RISING_gc;
  
  //Setze PD0 als Eventchannel
  EVSYS.CH0MUX = EVSYS_CHMUX_PORTD_PIN0_gc;
  
  //Clocksource -> Event Channel0
  TCC0.CTRLA = TC_CLKSEL_EVCH0_gc;
  
  //SingleSlope-PWM-mode & OC0A aktivieren
  TCC0.CTRLB |= TC_WGMODE_SINGLESLOPE_gc | TC0_CCAEN_bm;//0xF3;
  
  //Legt Timer Topwert und damit auch fest
  //bei wievielen Impulsen die Interrupt Routine
  //ausgeführt wird
  TCC0.PER = 4095;
  TCC0.CCA = 1;
}

Jetzt das SPI-initieren
void SPI_init(void) {
  //SPI-ports festlegen
  PORTC.DIRSET = TLC5941_Sin | TLC5941_SCK | TLC5941_XLAT | TLC5941_MODE;
  PORTC.DIRCLR = TLC5941_Sout | TLC5941_XERR;
  
  //SPI konfigurien: MASTER, 8Mhz, Mode0
  SPIC.CTRL |= SPI_MASTER_bm | SPI_PRESCALER_DIV4_gc | SPI_MODE_0_gc;
  
  //Keinen interrupt auslösen,
  //SPIC.INTCTRL = SPI_INTLVL_MED_gc;
  SPIC.INTCTRL = SPI_INTLVL_OFF_gc;
  
  //SPI aktivieren
  SPIC.CTRL |= SPI_ENABLE_bm;
  
  //XERR aktivieren
  PORTC.PIN2CTRL = PORT_OPC_PULLUP_gc | PORT_ISC_FALLING_gc; //PIN configurieren Pullup & Fallende Flanke
  PORTC.INTCTRL |= PORT_INT0LVL_MED_gc; // PortC interrupt0 -> medium-level setzen
  PORTC.INT0MASK |= PIN2_bm; // Pin2 für Interrupt0 freigeben
  PMIC.CTRL |= PMIC_MEDLVLEN_bm; // Medium-Level Interrupts aktivieren
  sei(); // Interrupts global freigeben
}

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.
//THX to Falk Brunner @ microcontroller.net
void TLC5941_SET_DC(uint8_t array[]) {
  PORTC.OUTSET = TLC5941_MODE;//MODE 1 = DC

  uint8_t bit_count_in; // Zähler für Bits in den Eingangsdaten 6Bit/Segment
  uint8_t bit_count_out=0; // Zähler für Bits in den Ausgangsdaten 8Bit/SPI Byte
  uint8_t dot_count; // Zähler für Arrayindex der EIngangsdaten
  uint8_t byte_in; // Eingangsdaten
  uint8_t byte_out = 0; // Ausgangsdaten
  uint8_t mask_out = 0x80; // Bitmaske für Ausgangsdaten

    for (dot_count = 0; dot_count < 32; dot_count++) { // Schleife über Eingangsarray
        byte_in = array[31-dot_count]; // nächstes Element laden
         // Schleife über 6 Bit/Eingangsbyte
        for (bit_count_in=0; bit_count_in < 6; bit_count_in++) {    
            if (byte_in & 0x20) byte_out |= mask_out; // Prüfe Bit #5, wenn ja in den Ausgangsdaten setzen
            byte_in <<= 1; // nächstes Bit hinschieben
            mask_out >>= 1; // Maske auf nächsten Ausgangsbit schieben
            bit_count_out++; // Bitzähler für Ausgang++
            if (bit_count_out == 8) { // 8 Bits erreich, Ausgangsbyte voll?
                bit_count_out=0; // Zähler rücksetzen
                SPI_send(byte_out); // senden
                byte_out = 0; // Zähler rücksetzen
                mask_out = 0x80; // Maske rücksetzen
            }
    }
  }
  PORTC.OUTSET = TLC5941_XLAT; //XLAT kurz auf 1 um daten zu übernehmen
  PORTC.OUTCLR = TLC5941_XLAT;
  PORTC.OUTCLR = TLC5941_MODE; //wieder auf GS-mode zurücksetzten
}
//THX to Falk Brunner @ microcontroller.net
void TLC5941_SET_GS(uint16_t array[]) {
  PORTC.OUTCLR = TLC5941_MODE;//MODE 0 = GS mode

  uint8_t bit_count_in; // Zähler für Bits in den Eingangsdaten 6Bit/Segment
  uint8_t bit_count_out=0; // Zähler für Bits in den Ausgangsdaten 8Bit/SPI Byte
  uint8_t dot_count; // Zähler für Arrayindex der Eingangsdaten
  uint16_t byte_in; // Eingangsdaten
  uint8_t byte_out = 0; // Ausgangsdaten
  uint16_t mask_out = 0x80; // Bitmaske für Ausgangsdaten

    for (dot_count = 0; dot_count < 32; dot_count++) { // Schleife über Eingangsarray
        byte_in = array[31-dot_count]; // nächstes Element laden
        // Schleife über 6 Bit/Eingangsbyte
        for (bit_count_in=0; bit_count_in < 12; bit_count_in++) {    
            if (byte_in & 0x0800) byte_out |= mask_out; // Prüfe Bit #12, wenn ja in den Ausgangsdaten setzen
            byte_in <<= 1; // nächstes Bit hinschieben
            mask_out >>= 1; // Maske auf nächsten Ausgangsbit schieben
            bit_count_out++; // Bitzähler für Ausgang++
            if (bit_count_out == 8) { // 8 Bits erreich, Ausgangsbyte voll?
                bit_count_out=0; // Zähler rücksetzen
                SPI_send(byte_out); //senden
                byte_out = 0; // Zähler rücksetzen
                mask_out = 0x80; // Maske rücksetzen
      }            
    }          
  }    
  
  while(TCC0.CNT < 4095); //auf Blank-Flanke warten
  
  PORTC.OUTSET = TLC5941_XLAT; //XLAT kurz auf 1 um daten zu übernehmen
  PORTC.OUTCLR = TLC5941_XLAT;
}

Die beiden Arrays sehen übrigens so aus und da steckt auch die 
Platzverschwendung ;)
uint8_t DC[32] = {
63,  //1
63,  //2
...
63};
uint16_t GS[32] = {
4095,  //1
4095,  //2
...
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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.