Forum: Mikrocontroller und Digitale Elektronik Grafikdisplay, Probleme mit Timer Interrupt


von Chris (Gast)


Lesenswert?

Hallo allerseits,

Habe jetzt das Display zum laufen bekommen,
nachdem mir zwischendrinn die Festplatte verreckt war und dadurch auch
alle Projektdaten flöten gegangen sind.
Habe mir jetzt alle nötigen funktionen zusammengeklimpert die ich für
zwei Textgrößen incl. invertierung brauche.

Jetzt habe ich momentan die Funktion zum beschreiben des Display in:
1
int main(void)
2
{
3
4
    while(1)
5
    {
6
      WDH3224_LOAD_STACK(); //Von Dis.Stack --> auf Display
7
    }
8
}
9
10
ISR(TIMER0_OVF_vect)
11
{  
12
  WDH3224_CONTROL_PORT ^=(1<<WDH3224_M); //M-Pin toggle ca. 400Hz  
13
}
14
15
ISR(TIMER1_COMPA_vect)
16
{
17
  cli();
18
  //WDH3224_LOAD_STACK();
19
  TCNT1 = 0;
20
  OCR1A   = 32767;  //TimerCounter1 Compare Register laden 
21
                          //32767/(F_CPU(8MHz)/Prescaler(8)) = 0,032s
22
  sei();
23
}

Sobald ich jetzt WDH3224_LOAD_STACK() in eine ISR verschiebe
funktioniert das ganze nicht mehr obwohl ich die ISR durch cli() und
sei() verriegel,
so das diese nicht unterbrochen wird. Das die Interrupts abgeschaltet
werden kann man an M gut erkennen, da dort immer wieder für 30ms
unterbrechungen drin sind. Woran kann das liegen? Ich möchte ja nicht
die while(1) Schleife komplett durchlaufen und dann erst das Display
refreshen da das evtl schon zu lang sein kann wenn ich z.B. meine
SD-Card auslese.

Vlt. hat ja jemand eine Idee an was es liegen kann.
hier noch mal die wichtigsten Funktionen fürs Display:
1
unsigned  char LCD_STACK[240][40]= {};
2
void WDH3224_INIT()  //alle nötigen Register für PORTs und Timer setzen
3
{
4
  WDH3224_CONTROL_DDR |= (1<<PC0) | (1<<PC1) 
5
                               |(1<<PC2)|(1<<PC3) | (1<<PC4);
6
  WDH3224_DATA_DDR  |= 0x0F;
7
  
8
  WDH3224_DISPOFF_SET_HIGH;
9
  WDH3224_FRAME_SET_LOW;
10
  WDH3224_M_SET_LOW;
11
  WDH3224_LOAD_SET_LOW;
12
  WDH3224_CLOCK_SET_HIGH;
13
  
14
  //Timer starten und Interrupt erlauben
15
  SREG   |= 0x80;    //Interrup global freigeben
16
  TCCR1B |= 0x02;    //Timer starte, Vorteiler auf 1
17
  TCCR0B |= 0x03;    //Timer starten, Vorteiler 64
18
  TIMSK0 |= 0x01;    //TimerCounter Interrupt Overflow Enable
19
  TIMSK1 |= 0x02;    //TimerCounter CompareA Interrupt Enable
20
  OCR1A   = 32760;  //TimerCounter1 Compare Register laden 32767/(F_CPU/Prescaler) = 0,032 S / 32mS
21
  
22
}
23
void WDH3224_LOAD_STACK()
24
{
25
  
26
  WDH3224_FRAME_SET_HIGH;
27
  
28
  WDH3224_LOAD_SET_HIGH;
29
  WDH3224_M_SET_HIGH;
30
  WDH3224_LOAD_SET_LOW;
31
  
32
  for(int i=0;i<40;i++)      //da das Array aus [240][40] besteht bis 40 zählen
33
  {
34
    WDH3224_CLOCK_SET_HIGH;
35
    WDH3224_DATA_PORT = LCD_STACK[0][i] >> 4;  //da 4 Bit Bus, Bit shift um MSB zu bekommen
36
    WDH3224_CLOCK_SET_LOW;            //Daten laden
37
    
38
    WDH3224_CLOCK_SET_HIGH;
39
    WDH3224_DATA_PORT = LCD_STACK[0][i];  // kein Bit shift für LSB
40
    WDH3224_CLOCK_SET_LOW;            //Daten laden
41
  }
42
  
43
  WDH3224_FRAME_SET_LOW;
44
  
45
  for (int n=1;n<240;n++)  //nun das ganze für die übrigen 239 Zeilen
46
  {
47
    WDH3224_LOAD_SET_HIGH;
48
    WDH3224_LOAD_SET_LOW;
49
    
50
    for (int i=0;i<40;i++)
51
    {
52
      WDH3224_CLOCK_SET_HIGH;
53
      WDH3224_DATA_PORT = LCD_STACK[n][i] >> 4;
54
      WDH3224_CLOCK_SET_LOW;
55
      
56
      WDH3224_CLOCK_SET_HIGH;
57
      WDH3224_DATA_PORT = LCD_STACK[n][i];
58
      WDH3224_CLOCK_SET_LOW;
59
    }
60
  }
61
  
62
  WDH3224_M_SET_LOW;
63
  
64
}
LG Chris

von Na Sowas (Gast)


Lesenswert?

Ine ganz schlechte Idee,  vom Main und von der Interuptroutine auf das 
Display zuzugreifen. So wird das nie was. Ich nicht von der 
Interruptroutine auf den Display zugreifen. Eher im Timer ein Flag 
setzen und im Main darauf reagieren.

von Chris (Gast)


Lesenswert?

Das Problem ist eben, das das Display keinen eigenen Controller hat, und 
ich das alles machen muss darum müssen die Daten spätestens alle 30ms 
aufs Display geladen werden, sonst fängt das Bild an zu verblassen. Und 
wenn ich jetzt meine SD-Card auslese kann das avtl. länger als 30ms 
dauern. Darum wollte ich das ganze jetzt in einen TimerInterrupt packen.

LG

von Na Sowas (Gast)


Lesenswert?

Eine interruptroutine wird eh nicht unterbrochen, ein cli/sei ist 
unnoetig. Man kann's auch im main mit der passenden wiederholrate 
anzeigen

von Chris (Gast)


Lesenswert?

allerdings wundert mich dann, dass das in der while(1) funktioniert und 
sobald ich es über einen interrupt aufraufe nicht...

von Sascha W. (sascha-w)


Lesenswert?

Hallo,

wie lange dauert denn die Ausgabe des kompetten Displayinhalts? 
Warscheinlich länger als die 32ms des Timers!

Im übrigen ist es an dieser Stelle besser in der ISR nicht den Inhalt 
des kompletten Displays auszugeben, sondern immer eine Zeile und die ISR 
mit entsprechend höherer Frequenz laufen zu lassen. Bei Dir werden ja 
alle Zeilen nur für einen Bruchteil der Gesamtframerate angezeigt, die 
letzte Zeile dafür 30ms lang.

Sascha

von Chris (Gast)


Lesenswert?

die dauer hatte ich gestern gemessen und lag so bei ca. 10ms von einem 
FLM (First Line Mark)zum nächsten. Demnach müssten zwischen den 
Interrupts 20ms Pause sein.

LG

von Sascha W. (sascha-w)


Lesenswert?

was genau zeigt denn dein Display an wenn es nicht geht?
UND wenn du in Main und in der ISR auf das Array zugreifst solltest du 
es volatile machen.

Sascha

von Chris (Gast)


Lesenswert?

nichts, das Display zeigt einfach nichts an.
Habe alle Funktionen von WDH3224_ in einer externen Header untergebracht 
(WDH3224.h) die Unteren Funktionen sind aus dieser rauskopiert.
Muss ich dann das Array trotzdem noch volatile machen?

LG

von Sascha W. (sascha-w)


Lesenswert?

Chris schrieb:
> nichts, das Display zeigt einfach nichts an.
> Habe alle Funktionen von WDH3224_ in einer externen Header untergebracht
> (WDH3224.h) die Unteren Funktionen sind aus dieser rauskopiert.
> Muss ich dann das Array trotzdem noch volatile machen?
wo und in welcher Datei dein Quellcode steht hat doch keinen Einfluss 
auf die Verarbeitung des Programms als Gesamtes. Deshalb muss das 
volatile trotzdem hin.
Werden den die Steuersignale [FLM/CLK] ausgegeben?
Was hast du überhaupt für einen Controller, und mit welchem Takt läuft 
der?
Deinw Timerkonfig und die Frequenzen passen irgendwie nicht mit deinen 
Kommentaren zusammen.
Den Timer1 konf. du am besten mal im CTC-Mode, dann kannst du dir das 
Rückstellen von TCNT1 schon mal sparen! Und was soll das schreiben von 
OCR1A in der ISR?

Sascha

von Chris (Gast)


Lesenswert?

Hallo Sascha,

Habe in der ISR Variante FLM und CLK ehrlichgesagt noch gar nicht 
nachgemessen, aber das wäre definitiv schon mal ein anhaltspunkt 
gewesen.
Habe einen ATMega1284, mit internen 8MHz. Habe ihn am Freitag mit einem 
Externen Oszilator beschaltet, der 12MHz liefert, da ich dachte das vlt. 
8Mhz schon zu langsam wären, aber daran lag es nicht. Ich Tippe aber mal 
auf deine Idee mit dem volatile vorm Array, kanns aber im Moment leider 
nicht ausprobieren, wird aber Morgen sofort gemacht.

LG Chris

von Sascha W. (sascha-w)


Lesenswert?

ok,
was ich aber noch als Problem sehe, ist die lange Pause, in der nur die 
letzte Zeile angezeigt wird, die bis zum nächsten Interrupt vergeht.
Wenn die Ausgabe der 240 Zeilen ca. 10ms dauert, dann wird Zeile 1-239 
für je
10ms/240=42us angezeigt, während Zeile 240 für die restlichen 20ms zu 
sehen ist. Da glaube ich kaum das da noch Kontrast übrigbleibt!
Mit der Ausgabe in Main erfolgt ja sofort nach der Zeile 240 wieder 
Zeile 1 und da geht das natürlich.
Du musst den Timer mit der Framerate * 240 laufen lassen
30Hz * 240 = 7.2kHz -> ca. 140us und innerhalb der ISR dann die 40Byte 
einer Zeile ausgeben, dann verteilt sich die Leuchtdauer aller Pixel 
gleichmäßig über die gesamte Framezeit.

Sascha

von Chris (Gast)


Lesenswert?

Chris schrieb:
>
>if(n>240)n=0;
>if(i>40)i=0;
>if(n==0)      //da das Array aus [240][40] besteht bis 40 zählen
>   {
>     WDH3224_FRAME_SET_HIGH;
>     WDH3224_CLOCK_SET_HIGH;
>     WDH3224_DATA_PORT = LCD_STACK[0][i] >> 4;  //da 4 Bit Bus, Bit shift um MSB 
zu bekommen
>     WDH3224_CLOCK_SET_LOW;            //Daten laden
>
>     WDH3224_CLOCK_SET_HIGH;
>     WDH3224_DATA_PORT = LCD_STACK[0][i];  // kein Bit shift für LSB
>     WDH3224_CLOCK_SET_LOW;            //Daten laden
>     WDH3224_FRAME_SET_LOW;
>   }
>
>
>
>   if(n>0)  //nun das ganze für die übrigen 239 Zeilen
>   {
>     WDH3224_LOAD_SET_HIGH;
>     WDH3224_LOAD_SET_LOW;
>
>
>
>       WDH3224_CLOCK_SET_HIGH;
>       WDH3224_DATA_PORT = LCD_STACK[n][i] >> 4;
>       WDH3224_CLOCK_SET_LOW;
>
>       WDH3224_CLOCK_SET_HIGH;
>       WDH3224_DATA_PORT = LCD_STACK[n][i];
>       WDH3224_CLOCK_SET_LOW;
>    }
>    if(i>40)n++;
>    i++;

OK ich baue also hier die for schleifen raus und lasse i+n durch die ISR 
hochzählen und sollte diese dann ihren Maximalwert erreichen, setze ich 
sie wieder 0.

Die 7.2kHz sollte ich ja mit Timer1 Locker hinbekommen.

Interruptfrquent müsste ja wie folgt aussehen 
(F_CPU(12MHz)/Prescaler(1))/OCR1A(63869)= 7198,56

Bzw. bei F_CPU= 8MHz, Precaler= 1,OCR1A = 64425 ist F= 7200.72Hz

LG Chris

von Sascha W. (sascha-w)


Lesenswert?

Chris schrieb:
> Die 7.2kHz sollte ich ja mit Timer1 Locker hinbekommen.
jo, währe sogar mit einem 8Bit'er möglich
> Interruptfrquent müsste ja wie folgt aussehen
> (F_CPU(12MHz)/Prescaler(1))/OCR1A(63869)= 7198,56
>
> Bzw. bei F_CPU= 8MHz, Precaler= 1,OCR1A = 64425 ist F= 7200.72Hz
ja,
aber nimm ruhig mal den CTC-Mode, dann ist OCR=1667 und der Zähler wird 
bei erreichen dieses Wertes automatisch wieder auf Null gestellt.


Sascha

von Chris (Gast)


Lesenswert?

Ok soweit läuft das jetzt auch in der ISR.
Allerdings haut das mit den Zeiten nicht so ganz hin.
Habe jetzt ewig mit den Zeiten gespielt, bekomme aber das Bild nicht 
flimmerfrei.

Code habe ich wie folgt abgeändert:
1
  if(zeile>239)zeile=0;
2
  //WDH3224_M_SET_HIGH;
3
  if(zeile==0)      //da das Array aus [240][40] besteht bis 40 zählen
4
     {  
5
          WDH3224_FRAME_SET_HIGH;
6
       WDH3224_LOAD_SET_HIGH;
7
          
8
         WDH3224_LOAD_SET_LOW;
9
         
10
       
11
       for (unsigned int i=0;i<40;i++)
12
       {
13
         WDH3224_CLOCK_SET_HIGH;
14
         WDH3224_DATA_PORT = LCD_STACK[0][i] >> 4;  //da 4 Bit Bus, Bit shift um MSB zu bekommen
15
         WDH3224_CLOCK_SET_LOW;            //Daten laden
16
    
17
           WDH3224_CLOCK_SET_HIGH;
18
           WDH3224_DATA_PORT = LCD_STACK[0][i];    // kein Bit shift für LSB
19
         WDH3224_CLOCK_SET_LOW;            //Daten laden
20
       }
21
         
22
       
23
         WDH3224_FRAME_SET_LOW;
24
     }
25
  
26
  
27
  
28
     if(zeile>0)  //nun das ganze für die übrigen 239 Zeilen
29
     {
30
         WDH3224_LOAD_SET_HIGH;
31
         WDH3224_LOAD_SET_LOW;
32
    
33
    
34
      for(unsigned int i=0;i<40;i++)
35
      {
36
        WDH3224_CLOCK_SET_HIGH;
37
        WDH3224_DATA_PORT = LCD_STACK[zeile][i] >> 4;
38
        WDH3224_CLOCK_SET_LOW;
39
    
40
        WDH3224_CLOCK_SET_HIGH;
41
        WDH3224_DATA_PORT = LCD_STACK[zeile][i];
42
        WDH3224_CLOCK_SET_LOW;
43
      }    
44
      }
45
    
46
      zeile++;
47
      //WDH3224_M_SET_LOW;

Und die ISRs sehen jetzt so aus:
1
ISR(TIMER0_OVF_vect)
2
{  
3
  WDH3224_CONTROL_PORT ^=(1<<WDH3224_M);  
4
}
5
6
ISR(TIMER1_COMPA_vect)
7
{
8
  
9
  WDH3224_LOAD_STACK();
10
  TCNT1=0;  
11
}

Register:
1
 OCR1A   = 300;    //TimerCounter1 Compare Register laden 
2
TCCR1B |= (1<<CS10);//Timer starten, Vorteiler auf 1

von Sascha W. (sascha-w)


Lesenswert?

Chris schrieb:
> Ok soweit läuft das jetzt auch in der ISR.
> Allerdings haut das mit den Zeiten nicht so ganz hin.
> Habe jetzt ewig mit den Zeiten gespielt, bekomme aber das Bild nicht
> flimmerfrei.

> Register:
1
 OCR1A   = 300;    //TimerCounter1 Compare Register laden
2
TCCR1B |= (1<<CS10);//Timer starten, Vorteiler auf 1
das währen ja 40kHz und nicht 7.2kHz

nimm mal (bei 12MHz):
1
OCR1A   = 208
2
TCCR1B  = (1<<WGM12)|(2<<CS10)   ;CTC_Mode, Teiler 8
3
TIMSK1  = (1<<OCIE1A)
4
5
ISR(TIMER1_COMPA_vect)
6
{
7
  WDH3224_LOAD_STACK(); am Besten den Code gleich hier einfügen
8
}

mit WDH3224_LOAD_SET_** sollten eigentlich am Ende der Ausgabe der 
Zeilendaten diese übernommen werden, so wie du das jetzt hast werden die 
reingeschobenen Daten erst mit der nächsten Zeile gelatcht - sollte aber 
eigentlich auch gehen.


Sascha

von Chris (Gast)


Lesenswert?

Hallo Sascha,

habe mal deine Änderungen 1:1 übernommen und das ganze ist eigentlich 
nur noch schlimmer geworden, der Bildaufbau ist super träge und das 
flimmern sogar noch stärker.

Sascha Weber schrieb:
> mit WDH3224_LOAD_SET_** sollten eigentlich am Ende der Ausgabe der
>
> Zeilendaten diese übernommen werden

irgendwie müssen doch die anliegenden Daten übernommen werden..?

LG Chris

von Sascha W. (sascha-w)


Lesenswert?

Chris schrieb:
> Hallo Sascha,
>
> habe mal deine Änderungen 1:1 übernommen und das ganze ist eigentlich
> nur noch schlimmer geworden, der Bildaufbau ist super träge und das
> flimmern sogar noch stärker.
hmm

hast du evl. noch die CKDIV8 Fuse drin? Kannst du an FLM messen was du 
dort für eine Frequenz hast?

Von was sprichst du bei Bildaufbau, wird irgendwas veränderliches in den 
Bildpuffer geschrieben?

Mit 30Hz Framerate @12MHz wird auf alle Fälle mehr als 50% der 
Rechleistung schon für die Bildausgabe gebraucht. Müsste man mal 
anschauen, ob sich die Ausgabeschleifen noch optimieren lassen.

> irgendwie müssen doch die anliegenden Daten übernommen werden..?
ohne mir jetzt das Datenblatt deines Displays angeschaut zu haben, 
werden die Daten mit CLK reingeschoben, und am Ende mit einem Impuls an 
LP übernommen.

Sascha

von Chris (Gast)


Lesenswert?

Sascha Weber schrieb:
> ohne mir jetzt das Datenblatt deines Displays angeschaut zu haben

habe ich auch nicht ;) konnte keins finden welches direkt für mein 
Display ist. Habe mir dann hier über die Suche alle möglichen anderen 
Datenblätter gesucht, bis ich eines hatte, wo das Timingdiagram 
verständlich genug für mich war :) und habe dann nach diesem meinen 
Software geschrieben.

Sascha Weber schrieb:
> hast du evl. noch die CKDIV8 Fuse drin?

Habe ich nicht drin, passiert mir aber ständig und ich such jedes mal 
wieder den Fehler ;)

Sascha Weber schrieb:
> Kannst du an FLM messen was du
> dort für eine Frequenz hast?

werde ich mal machen!

Sascha Weber schrieb:
> Von was sprichst du bei Bildaufbau, wird irgendwas veränderliches in den
> Bildpuffer geschrieben?

Ich kann zusehen wie langsam die Buchstaben erscheinen...
Ja, sonst wäre das langweilig wenn an der anzeige nichts passiert ;)
Es werden (sollen, denn hier Kämpfe ich auch noch dran, auf dem 
Testboard gehts im Gerät selber nicht) Daten von einer SD-Card in 
abhängigkeit einer gemessenen Leitung angezeigtwerden.

LG Chris

von Chris (Gast)


Angehängte Dateien:

Lesenswert?

Moin Moin,

hab dir mal die Bilder der gemessenen Signale angehängt.

von Chris (Gast)


Lesenswert?

Hallo Sascha,

habe das flimmern jetzt weg.
Habe den ganzen tag rumgespielt und hatte zum Schluss das Gefühl, das 
der Controller zu langsam ist. Da ich an FLM 17,5Hz gemessen habe habe 
ich jetzt mal anstatt 12MHz; 24MHz Takt angelegt und siehe da FLM hat 
jetz 35Hz und es gibt kein flimmern mehr. Hatte das zuvor schon über die 
Software versucht, aber das hat nicht so recht funktioniert.

Jetzt kämpfe ich nur noch mit der SD-Card und dem FT232 der immer nur 
sporadich was sendet aber wenn, dann ist es richtig.

LG Chris

von Sascha W. (sascha-w)


Lesenswert?

Chris schrieb:
> Hallo Sascha,
>
> habe das flimmern jetzt weg.
> Habe den ganzen tag rumgespielt und hatte zum Schluss das Gefühl, das
> der Controller zu langsam ist. Da ich an FLM 17,5Hz gemessen habe habe
> ich jetzt mal anstatt 12MHz; 24MHz Takt angelegt und siehe da FLM hat
> jetz 35Hz und es gibt kein flimmern mehr.
hast du da jetzt den OCR-Wert halbiert?

> Jetzt kämpfe ich nur noch mit der SD-Card und dem FT232 der immer nur
> sporadich was sendet aber wenn, dann ist es richtig.
da hat dein Controller ja ordentlich was zu tun.

Sascha

von Chris (Gast)


Lesenswert?

Sascha Weber schrieb:
> hast du da jetzt den OCR-Wert halbiert?

jaein... ich habe bestimmt 45-60min damit verbracht den OCR wert in 
sämtliche richtungen zu veränder, von sehr langsam OCR = 60000 zu sehr 
schnell OCR = 50. Habe auch den CTC mode (1<<WGM12) wieder aktiviert und 
hatte mich dann irgendwo bei OCR = 2850 eingependelt. Alles was 
langsamer wahr brachte mir dicke horizontale, von oben nach unten 
laufende Streifen. Alles was schneller war beschehrte mir Armeisenkrieg 
und irgendwann ein schwarzes Bild. Als ich dann einem Kollegen sagte das 
ich glaube der Prozessor packt das in der Zeit nicht mehr meinte der nur 
F_CPU erhöhen.
Zum Glück habe ich CBUS0 des FT232 an XTAL1 des AVR so das ich ziemlich 
einfach von 12 auf 24MHz wechseln konnte. Nach dem einem Reset zum 
übernehmen der werte, dachte ich erst oh misst das hat auch wieder nicht 
geklappt, da ich nur den vorgeladenen Display-Stack sehen konnte ohne 
irgendwelche Änderungen. Irgendwann hat dann das Display kurz gezuckt 
und es war ein eins A flimmerfreies Bild zu sehen wie es sein sollte.

Sascha Weber schrieb:
> da hat dein Controller ja ordentlich was zu tun.

auf jeden Fall und das ist noch nicht alles.
Dazu wollen noch einige Schieberegister bedient werden und ein ADC

Bis hier her schon mal vielen vieln Damk für die tolle Hilfe
Chris

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.