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!
hallo, da ließe sich bestimmt was machen schreib mir einfach mal ne Mail (einfach auf meinen Namen klicken) Grüße Kai
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
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
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.
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?
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.