www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik AtMega 48 Timmer


Important announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Nova (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Morgen,

ich habe ein IC von TI TLC5941 (16xLED Dimmen per PWM 12Bit)
Controller AtMega48-20PU ... der LED Treiber will 196 Bit Daten für die 
PWM (12 Bit pro LED).

nach dem man dem IC alle 196 Bit geschickt hat brauch man ein PWM Ref 
CLK...das IC Zählt die Clocks und sobald der Wert für den jeweiligen 
Kanal erreicht ist schaltet er sie ein.
nach 4096 clocks jedoch brauche ich ein blank Signal um den Zähler 
zurück zusetzen... logisch und eigentlich auch kein Problem...oder? 
...also aus meinem Standpunkt schon....

am liebsten würde ich denn Ref. CLK über ein PWM out erzeugen da ich den 
nur einmal setzen muss und mich das keine Prozessorzeit kostet.... nur 
brauch ich im Endeffekt ein Interrupt nach 4096 Clocks um dann die PWM 
abzuschalten den Black zuschicken und wieder anzufangen.

meine Überlegung war:
wenn ich ne 100Hz PWM will muss ich 100 mal neu Anfangen d.h. 4069 
Clocks mal 100 => 4096 KHZ die ich als Ref CLK brauche eigentlich etwas 
mehr da ich zwischendrin immer noch den blank brauche ... sagen wir 
0,5MHz ist eine runde Sache ....

kann ich irgendwie auswerten wann 4096 Clocks aus einem  PWM Ausgang 
rausgekommen sind?

ohne gleich 50% Cpu time zu verlieren?

oder hat da einer eine bessere Idee (das ist meine Hoffnung^^)


mfg Nova

Autor: Falk Brunner (falk)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
@  Nova (Gast)

>CLK...das IC Zählt die Clocks und sobald der Wert für den jeweiligen
>Kanal erreicht ist schaltet er sie ein.

Eher aus.

>am liebsten würde ich denn Ref. CLK über ein PWM out erzeugen da ich den
>nur einmal setzen muss und mich das keine Prozessorzeit kostet.... nur

Genau.

>brauch ich im Endeffekt ein Interrupt nach 4096 Clocks um dann die PWM
>abzuschalten den Black zuschicken und wieder anzufangen.

>wenn ich ne 100Hz PWM will muss ich 100 mal neu Anfangen d.h. 4069
>Clocks mal 100 => 4096 KHZ die ich als Ref CLK brauche eigentlich etwas

nein, eher 100 Hz * 4096, macht 409,6 kHz.

>kann ich irgendwie auswerten wann 4096 Clocks aus einem  PWM Ausgang
>rausgekommen sind?

>ohne gleich 50% Cpu time zu verlieren?

Man braucht hier zwei Timer. Einer macht den Takt von 400 kHz, der 
andere die 100 Hz.

MFG
Falk

Autor: Nova (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
du meinst also ich lasse die einfach immer laufen .... naja die idee ist 
nicht dumm... das SPI interface ist getrennt d.h. auch wenn die pwm 
gerade läuft kann ich daten nachschieben.
der Blank muss aber ein kurzer strob sein ... das würde ich über ein 
compare machen ... den pin kurz toggeln (12ns reichen) joar... is ne 
gute idee ...

kostet mich 1 8-bit timmer + OCA pin und 1 16-bit timmer naja nicht 
schön aber was besseres ist mir auch nicht eingefallen^^

danke aufjedenfall erstmal

Autor: Falk Brunner (falk)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
@  Nova (Gast)

>der Blank muss aber ein kurzer strob sein ... das würde ich über ein
>compare machen ... den pin kurz toggeln (12ns reichen) joar... is ne
>gute idee ...

Nöö, vollkommen unsinnig. Den Strobe machst du schlicht per Software, 
nachdem du neue Daten geladen hast.

>kostet mich 1 8-bit timmer + OCA pin und 1 16-bit timmer naja nicht
>schön aber was besseres ist mir auch nicht eingefallen^^

Wird hier auch nicht besser.

MFG
Falk

Autor: Nova (Gast)
Datum:
Angehängte Dateien:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
ich meine nicht den Strob sondern den blank... den Strob braucht man 
natürlich für das SPI Interface aber nicht für den PWM Cycle

soweit ich das im Datenblatt richtig verstanden habe wird mit dem gclk, 
der mit dem PWM Pin erzeugt wird, der interne Counter hochgezählt mit 
dem an verglichen wird,  um den Counter wieder auf 0 zusetzen brauche 
ich ein blank da er das nicht von alleine macht.

d.h. für jeden PWM Durchgang brauche ich 4096 GCLK’Ss dann ein Blank und 
dann wieder 4096 GCLK’s und dann ein Blank ... und so weiter ...

bei 100 Hz PWM brauch ich auch 100 Blanks egal ob ich was an den Dimm 
werten der einzelnen Kanäle änder oder nicht ... wenn ich das richtig 
verstanden habe ist das SPI Interface unabhängig von der eigentlichen 
PWM Erzeugung ...

Autor: Falk Brunner (falk)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Stimmt alles soweit.

Autor: Nova (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
humm ... dann wird das wohl auf ein versuch ankommen ^^

Autor: Nova (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
So also die Timmer sind am laufen...420KHz und 100,2Hz passt ganz gut 
aber

hat einer ne Idee wie ich 16 x 5bit in 8 bit Packete verpacke?

meine Idee ist:
uint8_t byte_count = 0;
uint8_t dot_count = 0;
int8_t frei = 8;
uint8_t send_byte = 0;

while ( dot_count <= 15)
{ 
   send_byte |= dot_array[dot_count]>>frei;

   byte_count++;
   dot_count++;
   frei = byte_count*8 - dot_count*5;

   while (frei > 0)
   {
       send_byte |= dot_array[dot_count] << (8 - frei);
       frei = byte_count*8 - (dot_count+1)*5;
       if (frei >= 0) dot_count++;
       else           frei = frei * -1;         
   }

   SPI_SEND(send_byte);
   send_byte = 0;
}

kann das so gehen? oder hat da mal wieder wer ne bessere idee^^

gruß Sascha

Autor: Falk Brunner (falk)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
@  Nova (Gast)

>hat einer ne Idee wie ich 16 x 5bit in 8 bit Packete verpacke?

Wieso 16x5? Das Ding hat 6 Bit/Punkt. Ist aber auch etwas doof, weil 
eben nicht 8 :-0

>kann das so gehen? oder hat da mal wieder wer ne bessere idee^^

Ohne das Programm jetzt im Detail geprüft zu haben würde ich sagen dass 
es zwar prinzipiell läuft, auf dem AVR aber relativ viel Zeit braucht. 
Keine Ahung wieviel, aber Bitschieben mit variabler Stellenzahl kostet 
viel Zeit.
Besser ist es, feste Bitmasken zu verwenden. etwa so.

uint8_t bit_count_in;
uint8_t bit_count_out=0;
uint8_t dot_count;
uint8_t send_byte = 0;
uint8_t mask_in;
uint8_t mask_out = 0x80;

for (dot_count = 0; dot_count < 16; dot_count++) {
    mask_in = 0x20;
    for (bit_count_in=0; bit_count_in < 6; bit_count_in++) {
        if (dot_array[dot_count] & mask_in) send_byte |= mask_out;
        mask_in >= 1;
        mask_out >= 1;
        bit_count_out++;
        if (bit_count_out == 8) {
            bit_count_out=0;
            SPI_SEND(send_byte);
            send_byte = 0;
            mask_out = 0x80;
        }
    }
}

Das sollte recht flott laufen, weil nur eine feste Maske geschoben wird, 
das dauert jeweils 1 Takt ;-)

>Nova (Gast)
>gruß Sascha

Soviel zum Thema Geschlechterzuordnung von Nicknames im Internet . . . 
;-)

Mfg
Falk

Autor: Maik Fox (sabuty) Benutzerseite
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Ich habe das mal so gelöst, indem ich GSCLK und die Daten-Clock beide an 
die SPI-Clock gehängt habe. Dann einen Zustandsautomaten in den 
SPI-Interrupt, der sich um den Datenversand (erst Dummydaten, am Ende 
richtige Daten + Blank/Strobe) kümmert. Damit läuft die ganze 
Ansteuerung eines TLC5940 nebenher ab und man braucht sich nicht weiter 
drum kümmern.

Geht allerdings nur, wenn man die SPI-Schnittstelle nicht noch für was 
anderes braucht.

Autor: Nova (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
joar äää^^
naja and der spi hängt noch ein FRAM ein FLASH eine SD karte ein RFM12 
eine RTC und porterwieterung + Front Board ^^

den SPI ist im dauer Stress ;-)

meine lösung sieht jetzt mal so aus:
    while ( dot_count <= 15)
    { 
        send_byte |= dot_array[dot_count]>>frei;
      PORTA = send_byte;
         byte_count++;
         dot_count++;
         frei = byte_count*8 - dot_count*5;

         while (frei > 0)
         {
             send_byte |= dot_array[dot_count] << (8 - frei);
        PORTA = send_byte;
             frei = byte_count*8 - (dot_count+1)*5;
             if (frei >= 0)   dot_count++;                       
         }

    if (frei < 0)   frei = 5 - (frei * -1);         
       SPI_Transfer(send_byte);
       send_byte = 0;
       }

die Variante von Falk habe ich wenn ich erlichbin bei ersten 
drübergucken nicht verstanden ... muss mir das mal im Simulator angucken 
...
aber nur vom einwürf im endeffect brach ich ein bitstrom von 96bit nur 
für die Stromeinstellung.

aber danke schon mal^^
das besste ist amanfang hatte ich keine Idde und bei ab tippen von dem 
code vom Schmirpapier ins Forum habe ich schon 3 Fehler gefunden...

Autor: Nova (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
edit:

also laut AVR Studio kommt da kein einziges Bit in der SPI rutine an ...
hattes du das schon mal getestet oder frei schnautze mal runter getippt?

Autor: Nova (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
edit2:  (sry fürs spammen)

in meinem code ist noch meine debug ausgabe drin
    while ( dot_count <= 15)
    { 
        send_byte |= dot_array[dot_count]>>frei;
         byte_count++;
         dot_count++;
         frei = byte_count*8 - dot_count*5;

         while (frei > 0)
         {
             send_byte |= dot_array[dot_count] << (8 - frei);
             frei = byte_count*8 - (dot_count+1)*5;
             if (frei >= 0)   dot_count++;                       
         }

    if (frei < 0)   frei = 5 - (frei * -1);         
       SPI_Transfer(send_byte);
       send_byte = 0;
       }

gruß Sascha

Autor: Falk Brunner (falk)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
War nur so mal fix hingeschrieben, ist aber korrekt, bis auf zwei 
vergessene ">" Zeichen bei den Schiebeoperationen. Hier nochmal etwas 
aufgeräumt und simulationsfreundlich.

#include <stdint.h>

// Datenfeld für Segmente
uint8_t dot_array[16] = {0x10, 0x15, 0x3f, 0x30, 0x00, 0x00, 0x3F, 0xFF,
                         0x10, 0x15, 0x3f, 0x30, 0x00, 0x00, 0x3F, 0xFF};

void send_tlc5941(uint8_t dot_array[]) {
 
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 < 16; dot_count++) {      // Schleife über Eingangsarray
        byte_in = dot_array[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
            }
        }   
    }
}

int main (void) {

    send_tlc5941(dot_array);
    while(1);
}

MfG
Falk

Autor: Nova (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
ja fettes DANKE!!!!

du schiebst dir das einafch zurecht... sag ich jetzt mal so ... du 
maskirst immer nur ein Bit und schiebst das dann in das Ausgangsbyte 
rein ... saubere Idee ... und ja du ahst recht das ist schneller^^

mfg Sascha

Autor: Nova (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
so da bin ich mal wieder^^

wenn ich das richtig verstanden habe muss ich dein Code so ändern damit 
er mir die 12 bit PWM in 8 bit Packete verpackt:
void send_tlc5941_pwm(uint16_t pwm_array[]) {
 
  TLC5941_PORT  &=  ~(1<<TLC5941_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 = 0x0400; // Bitmaske für Ausgangsdaten

    for (dot_count = 0; dot_count < 16; dot_count++) {      // Schleife über Eingangsarray
        byte_in = pwm_array[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 & 0x0200) 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_Transfer(byte_out);                     // senden
                byte_out = 0;                               // Zähler rücksetzen
                mask_out = 0x0400;                          // Maske rücksetzen
            }
        }   
    }
  TLC5941_PORT  |=   (1<<TLC5941_LOAD);
  TLC5941_PORT  &=  ~(1<<TLC5941_LOAD);
  TLC5941_PORT  |=   (1<<TLC5941_MODE);
}

richitg?

Autor: Falk Brunner (falk)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
@  Nova (Gast)

>richitg?

Leider nein. Deine Ausgangsdaten sind immer noch nur 8 Bit, dort also 
keine Änderung. LEdiglich die EIngangsdaten wachsen von 6 auf 12 Bit, es 
ändert sich nur byte_in und die Maske für byte_in. Einfacher als du 
denkst ;-)
Siehe unten.
void send_tlc5941_pwm(uint16_t pwm_array[]) {
 
  TLC5941_PORT  &=  ~(1<<TLC5941_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
  uint8_t mask_out = 0x80;    // Bitmaske für Ausgangsdaten

    for (dot_count = 0; dot_count < 16; dot_count++) {      // Schleife über Eingangsarray
        byte_in = pwm_array[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 & 0x0200) 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_Transfer(byte_out);                     // senden
                byte_out = 0;                               // Zähler rücksetzen
                mask_out = 0x80;                            // Maske rücksetzen
            }
        }   
    }
  TLC5941_PORT  |=   (1<<TLC5941_LOAD);
  TLC5941_PORT  &=  ~(1<<TLC5941_LOAD);
  TLC5941_PORT  |=   (1<<TLC5941_MODE);
}

MfG
Falk

Autor: Nova (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
jo sehr cool ... das ding geht ja^^

wenn ich fertig bin soll das mal ein rgb folienleier werden mit den ic's 
auf dem folien leiter und mir ist aufgefallen man sollte das spi schon 
voll aufdrehen (8MHz) bei 100 KHz SPI Clk Flacken die LED's

Autor: Falk Brunner (falk)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
@  Nova (Gast)

>auf dem folien leiter und mir ist aufgefallen man sollte das spi schon
>voll aufdrehen (8MHz) bei 100 KHz SPI Clk Flacken die LED's

Dann machst du was falsch. Die LED-Ansteuerung ist unabhängig von der 
SPI-Geschwindigkeit.

MFG
Falk

Autor: Nova (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
da ist auch noch ein fehler
if (byte_in & 0x0200) byte_out |= mask_out;     // Prüfe Bit #12, wenn ja in den Ausgangsd

das muss "glaube ich" so aussehen
if (byte_in & 0x0800) byte_out |= mask_out;     // Prüfe Bit #12, wenn ja in den Ausgangsd

Autor: Falk Brunner (falk)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
Stimmt, kleiner Aufmerksamkeitstest ;-)

Autor: Nova (Gast)
Datum:

Diesen Beitrag bewerten:
lesenswert
nicht lesenswert
ja ok^^
in zwichen bin ich da auch durchgestiegen^^
Ps.: geile Variante total einfach, multifunktional einsetz bar, SAU 
schnell, und ich bin nicht draufgekommen -_- ....

ps kennsich wer mit controllerlosen displays aus?
Beitrag "GLCD Interface"

kann mir da wer weiter helfen?

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




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 erkennst du die Nutzungsbedingungen an.

webmaster@mikrocontroller.netImpressumNutzungsbedingungenWerbung auf Mikrocontroller.net