www.mikrocontroller.net

Forum: Compiler & IDEs LCD+Optimierung


Autor: Jochen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe angefangen für mein LCD Funktionen zu schreiben:
#include <avr/io.h>
#include <util/delay.h>

// RS    = PG2
// R/W    = PG0
// E    = PG1
// D0-D7  = PC0-PC7

void lcdSend(char data, int RS) {
  if(RS) {
    PORTG |= (1<<PG2);
  } else {
    PORTG &= ~(1<<PG2);
  }
  PORTG &= ~(1<<PG0);
  _delay_us(1);
  PORTG |= (1<<PG1);
  PORTC = data;
  _delay_us(1);
  PORTG &= ~(1<<PG1);
  _delay_us(1);
}

int main() {
  DDRC = 0xFF;
  DDRG = 0x07;
  _delay_ms(100);
  lcdSend(0x38,0);
  lcdSend(0x0F,0);
  lcdSend(0x01,0);
  lcdSend(0x06,0);
  lcdSend('H',1);
  lcdSend('a',1);
  lcdSend('l',1);
  lcdSend('l',1);
  lcdSend('o',1);
  lcdSend('!',1);
  while(1);
  return 1;
}
Das LCD gibt auch einwandfrei "Hallo!" aus. Aber nur solange ich -O0 
benutze sobald ich eine Optimierung aktiviere funktioniert es nicht 
mehr. Ich vermute, dass es wohl irgendwie am Timing liegt und die 
Optimierung mir die Delays raus wirft oder irgendso was in der Art. Da 
ich mir die _delay_xx() Funktionen nicht aus den Fingern gesaugt habe, 
und sie schon bei WinAVR/AVRStudio dabei waren gehe ich stark davon aus, 
dass diese eigentlich zuverlässig funktionieren sollten.
F_CPU habe ich auch richtig gesetzt.

Komisch ist auch, dass wenn ich es debugge und 
http://www.helmix.at/hapsim/ dabei laufen habe es mit Run NICHT 
funktioniert aber sehr wohl mit AutoStep wohl auf der Seite extra steht, 
dass auf das Timing keine Rücksicht genommen wird.

Hm was kann ich noch angeben...
AVRStudio 4.13 b528
WinAVR puh... 20070122
ATMega128L

So ich hoffe, ich hab alles angegeben und nichts vergessen und ihr könnt 
mir bei dem Problem weiter helfen.

MfG,
Jochen

Autor: Wolfram (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich kann nicht nachvollziehen was du in deiner lcdSend routine machst.
Normaler weise geht das so: lege die Daten an , warten ,enable mit Read 
oder write, warten, disable

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

Bewertung
0 lesenswert
nicht lesenswert
Es liegt mit ziemlicher Sicherheit am Tinming.
Dazu musst du wissen, dass die _dely_xx Funktionen
ihre Zeiten nur dann einhalten, wenn die Optimierung
eingeschaltet ist. Ist sie ausgeschaltet, so haben diese
Funktionen ein Vielfaches ihrer normalen Laufzeit.

Und wenn ich mir deine Initialisierungsfunktionen so
ansehe: Die geforderten Zeiten sind um einiges höher.
Nachdem du ein Komando zum LCD geschickt hast, musst du
dem LCD Zeit geben, dieses Kommando auch zu verarbeiten.
Mach da mal 30 oder 40 ms Pause nach einem Kommando
rein.

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ohne zusätzliche oder längere delays wird es wohl nicht gehen.

Schau in das Datenblatt des LCD's, wie das Timing auszusehen hat, und 
vergleiche das mit deinem (Assembler)-Code (Zyklen zählen). Gerade die 
Bit-Befehle wie "PORTG &= ~(1<<PG0);" dampft die Optimierung von 
mehreren auf einen Takt ein, und auch im Funktionsaufruf wird einiges 
eingespart.

Hat dein LCD ein busy-flag? Wenn ja, warum wohl?

Oliver

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Oliver

>Schau in das Datenblatt des LCD's, wie das Timing auszusehen hat, und
>vergleiche das mit deinem (Assembler)-Code (Zyklen zählen). Gerade di
Sooo tief muss man nicht im Schlamm wühlen. gerade die _delay_us() ist 
schon wasserdicht.

e
Bit-Befehle wie "PORTG &= ~(1<<PG0);" dampft die Optimierung von
mehreren auf einen Takt ein, und auch im Funktionsaufruf wird einiges
eingespart.

Sein Problem ist die rein logische Abfolge. Nicht ins Datenblat 
geschaut? Die Initialisierung braucht Pausen im ms Bereich (15/5/1)

>Hat dein LCD ein busy-flag? Wenn ja, warum wohl?

Damit es Millionen von LCDs ungenutzt lassen und trotzdem gut 
funktionieren? Ein 40us Delay nach jedem Scheibkommando löst das 
Problem. Steht alles im Datenblatt.

@Jochen

Ich würde es mal so probieren.

// RS    = PG2
// R/W    = PG0
// E    = PG1
// D0-D7  = PC0-PC7

nicht als Kommentar hinschreiben sondern als define, macht den Code 
lesbar.

#define RS   PG2
#define R_W  PG0
#define E   PG1
// Kommentare sind auch in C Programmen sinnvoll und notwendig

void lcdSend(char data, int RS) {
  if(RS) {
    PORTG |= (1<<RS);  // Kommando
  } else {
    PORTG &= ~(1<<RS);  // Daten
  }
  PORTC = data;      // Daten ausgeben
  PORTG |= (1<<E);    // steigende Flanke von E
  _delay_us(1);
  PORTG &= ~(1<<PG1);  // fallende Flanke von E
  _delay_us(40);    // Wartezeit für Kommandoausführung
}

int main() {
  DDRC = 0xFF;
  DDRG = 0x07;

  PORTG &= ~(1<<R_W);  // R_W immer low, nur Schreibzugriffe

// Initialisierung
  _delay_ms(100);
  lcdSend(0x38,0);    // das muss dreimal ausgeführt werden
  _delay_ms(15);
  lcdSend(0x38,0);
  _delay_ms(1);
  lcdSend(0x38,0);
  lcdSend(0x0F,0);
  lcdSend(0x01,0);
  lcdSend(0x06,0);
// Ende der Initialisierung

  lcdSend('H',1);
  lcdSend('a',1);
  lcdSend('l',1);
  lcdSend('l',1);
  lcdSend('o',1);
  lcdSend('!',1);
  while(1);
  return 1;
}

MFG
Falk

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Karl heinz Buchegger

>Es liegt mit ziemlicher Sicherheit am Tinming.
>Dazu musst du wissen, dass die _dely_xx Funktionen
>ihre Zeiten nur dann einhalten, wenn die Optimierung
>eingeschaltet ist. Ist sie ausgeschaltet, so haben diese
>Funktionen ein Vielfaches ihrer normalen Laufzeit.

Das dürfe wohl kaum ein Problem sein. Langsames Ansteuern ist für das 
LCD kein Problem, zu schnelles schon.

MfG
Falk

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

Bewertung
0 lesenswert
nicht lesenswert
Falk wrote:
> @Karl heinz Buchegger
>
>>Es liegt mit ziemlicher Sicherheit am Tinming.
>>Dazu musst du wissen, dass die _dely_xx Funktionen
>>ihre Zeiten nur dann einhalten, wenn die Optimierung
>>eingeschaltet ist. Ist sie ausgeschaltet, so haben diese
>>Funktionen ein Vielfaches ihrer normalen Laufzeit.
>
> Das dürfe wohl kaum ein Problem sein. Langsames Ansteuern ist für das
> LCD kein Problem, zu schnelles schon.

Sein Problem war ja:
In einer Debug Version geht es, in einer Release nicht.
Debug: die Zeiten von den _delay_xx stimmen nicht, daher geht es
Release: die Zeiten von den _delay_xx stimmen, daher geht es nicht.


Mfg
Karl Heinz

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Karl heinz Buchegger

>Sein Problem war ja:
>In einer Debug Version geht es, in einer Release nicht.
>Debug: die Zeiten von den _delay_xx stimmen nicht

Das mag sein, aber dennoch sind lange Wartezeiten definitiv unkritisch!

>Release: die Zeiten von den _delay_xx stimmen, daher geht es nicht.

Es fehlen delays an der richtige Stelle.

MFG
Falk

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"Sooo tief muss man nicht im Schlamm wühlen."
Es bildet aber ungemein, daß mal gemacht zu haben. Danach sollten sich 
alle Fragen zu Timingproblemen mit LCD's für immer erledigt haben :-)

"Damit es Millionen von LCDs ungenutzt lassen und trotzdem gut
funktionieren? Ein 40us Delay nach jedem Scheibkommando löst das
Problem. Steht alles im Datenblatt."

Mehr sag ich doch gar nicht. Natürlich funktioniert das ohne Abfrage des 
busy-flags, nur muß man dem LCD eben die Zeit geben, den vorherigen 
Befehl abzuarbeiten.

Also, hier die Kurzfassung meines Beitrags:
RTFM

Oliver

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn mich nicht alles täuscht, werden Delays ohne Optimierung erst zur 
Laufzeit in float ausgerechnet.

Die können also durchaus 1000-fach länger sein.

Und der Code ist dann auch 10-mal größer.


Peter

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

Bewertung
0 lesenswert
nicht lesenswert
Falk wrote:
> @Karl heinz Buchegger
>
>>Sein Problem war ja:
>>In einer Debug Version geht es, in einer Release nicht.
>>Debug: die Zeiten von den _delay_xx stimmen nicht
>
> Das mag sein, aber dennoch sind lange Wartezeiten definitiv unkritisch!
>
>>Release: die Zeiten von den _delay_xx stimmen, daher geht es nicht.
>
> Es fehlen delays an der richtige Stelle.


OK.
In Zukunft erkläre ich einem Fragesteller nicht mehr
warum die Symptome so sind wie er sie beobachtet :-)

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Karl heinz Buchegger

>In Zukunft erkläre ich einem Fragesteller nicht mehr
>warum die Symptome so sind wie er sie beobachtet :-)

???
Bist du jetzt auch schon kritikunfähig?
Dein erster Absatz war unlogisch, der zweite was IMHO OK.
Das war alles was ich sagen wollte.

MFG
Falk


Autor: Jochen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

der Reihe nach:

Ich kann nicht nachvollziehen was du in deiner lcdSend routine machst.
Normaler weise geht das so: lege die Daten an , warten ,enable mit Read
oder write, warten, disable

Ich habe mich (meiner Meinung nach) dabei an das Datenblatt gehalten:
http://www.lcd-module.de/deu/pdf/doma/4_20.pdf

Auf Seite 6 das Bild Write Operation:
Dort geht eindeutig R/S und RW als erstes gesetzt. Danach soll ich t_AS, 
also mindestens 140ns, warten. Danach E high. Danach D0-D7 setzen und 
zwischen Setzen und E low müssen t_DSW >= 195ns vergehen. Also 
dazwischen noch 1us. Und zum Schluss noch eine 1us warten, damit ich 
t_CYCLE >= 1000ns garantiert erfülle.

@Karl heinz Buchegger:
arg jetzt wo du es sagst. Hab die max. Execution Times auf Seite 4 
verbummelt.

@Falk:
Das mit dem ersetzen war mir klar. Ich wollte es nur mal grob zum Laufen 
bekommen und dann später die ganzen Ersetzungen einbauen.
Trotzdem danke für den Rat.

// das muss dreimal ausgeführt werden

Laut Initialisierungbeispiel auf Seite 4 eben nicht.

@Oliver:
Ich hoffe du hast bei den obigen Zeilen gesehen, dass ich mich sehr wohl 
mit dem FM auseinander gesetzt habe und mir darüber Gedanken gemacht 
habe. Man kann immer mal etwas übersehen.

Ich werde jetzt mal sehen, wie es mit _delay_ms(40) in der letzten Zeile 
von lcdSend(); aussieht.
Oder ich teile die 40ms auf die einzelnen delays auf.
Wenn es danach immer noch nicht klappen sollte schau ich mir wohl mal 
ein anderes LCD-Datenblatt an bei dem auch der HD44780 verwendet wird. 
Vielleicht stehen dort andere Angaben, die ich versuchen kann.

Nochmal danke an alle, die sich die Zeit genommen haben sich den Thread 
anzuschauen und ihre Meinung gepostet haben.

Autor: Falk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Jochen

Auf Seite 6 das Bild Write Operation:
>Dort geht eindeutig R/S und RW als erstes gesetzt. Danach soll ich t_AS,
>also mindestens 140ns, warten. Danach E high. Danach D0-D7 setzen und
>zwischen Setzen und E low müssen t_DSW >= 195ns vergehen. Also
>dazwischen noch 1us. Und zum Schluss noch eine 1us warten, damit ich
>t_CYCLE >= 1000ns garantiert erfülle.

Ist erstmal korrekt, allerdings kann man das sinvoll vereinfachen.

RS, RW, D0-7 setzen
140ns warten
E auf 1
mind 450 ns warten
E auf 0

Die minimale Zykluszeit von 1us kommt automatisch zustande da deine 
Routine incl call/retrun einiges an Zeit braucht.

>// das muss dreimal ausgeführt werden

>Laut Initialisierungbeispiel auf Seite 4 eben nicht.

In einem anderen Datenblatt wird aber dreimal gefordert, und eben auch 
mit den Pausen dazwischen.

>Ich werde jetzt mal sehen, wie es mit _delay_ms(40) in der letzten Zeile
>von lcdSend(); aussieht.

_delay_us(40), MIKROsekunden, nicht Millisekunden!

MFG
Falk

Autor: Jochen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Ich werde jetzt mal sehen, wie es mit _delay_ms(40) in der letzten Zeile
>von lcdSend(); aussieht.

_delay_us(40), MIKROsekunden, nicht Millisekunden!


Meinte ich auch... naja eigentlich meinte ich _delay_ms(2) um auch 
sicher die "Clear Display" und "Cursor at Home" ausgeführt werden.


Habe mir mittlerweile aber auch eine funktionierende lcdIsBusy() 
Funktion geschrieben.

Vielen Dank nochmals an alle.

Autor: Daniel Held (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Falk: hättest Du den Beitrag von Karl-Heinz richtig gelesen und 
verstanden wäre der Thread einige Beiträge kürzer. Ihr sagt im Prinzip 
das gleiche nur das karl-Heinz noch das Beobachtete erklärt.
(Im Debug: delays dauern länger = funktioniert
ohne Debug: delays sind wie programmiert = zu kurz = geht nicht)

Falk wrote:
> @Karl heinz Buchegger
>
>>Sein Problem war ja:
>>In einer Debug Version geht es, in einer Release nicht.
>>Debug: die Zeiten von den _delay_xx stimmen nicht
>
> Das mag sein, aber dennoch sind lange Wartezeiten definitiv unkritisch!
>
>>Release: die Zeiten von den _delay_xx stimmen, daher geht es nicht.
>
> Es fehlen delays an der richtige Stelle.


OK.
In Zukunft erkläre ich einem Fragesteller nicht mehr
warum die Symptome so sind wie er sie beobachtet :-)

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.