Forum: Compiler & IDEs Probleme win WinAVR 20081205


von UBoot-Stocki (Gast)


Lesenswert?

Hi,

ich habe in meinem Labor nun einen neuen PC für meine 
Programmierarbeiten. Im Zuge der Installation habe ich mir die neueste 
WinAVR-Version vom 5.12.2008 gezogen.

Allerdings habe ich so meine Probleme damit, einen Lauffähigen Code zu 
erzeugen. Ohne jetzt ins Detail gehen zu wollen:

Nutzt jemand schon die neue Version und ist damit zufrieden ? Sind 
bereits Bugs bekannt ?

Gruß

Andreas

von Marius W. (mw1987)


Lesenswert?

Also bei mir funktioniert die Version einwandfrei. Hab bisher noch keine 
Bugs gefunden.

Wenn du uns nicht verrätst, ob es ne Fehlermeldung gibt und welche, dann 
kann dir auch nicht geholfen werden.

MfG
Marius

von UBoot-Stocki (Gast)


Lesenswert?

Hi,

bin voller Vezweiflung nun auf die Version WinAVR-20080610 
zurückgegangen und siehe da: ES FUNKTIONIERT.

Mit der neuen Version (Dezember 2008) kann ich mein Programm zwar 
compilieren (alles "Standard" mit MAKE-File aus meinem Programm-VZ vom 
September 2007) und dann mittels Ponyprog auf den Controller beamen aber 
es läuft nicht :-( Auf dem LCD erscheinen nur wirre Zeichen - das 
Prgramm reagiert überhaupt nicht.

Wenn ich exakt das selbe mit der Oktober-Version von WinAVR mache mit 
exakt dem selben MAKE-File läuft alles genauso ab nur dass das LCD das 
zeigt was es zeigen soll und mein Programm von Controller ausgeführt 
wird.

Was nun ?

Zunächst kann ich mit der Oktober-Version gut leben - nur wie sucht man 
einen solchen Fehler ???

Gruß

Andreas

von Benedikt K. (benedikt)


Lesenswert?

UBoot-Stocki wrote:
> Auf dem LCD erscheinen nur wirre Zeichen - das
> Prgramm reagiert überhaupt nicht.

Das deutet auf ein Timingproblem oder sonst einen gemeinen Fehler in der 
Software hin (Stacküberlauf, ein fehlendes volatile oder ähnliches). Es 
war quasi Zufall dass die Software lief.

von UBoot-Stocki (Gast)


Lesenswert?

Hi,

schon klar - Wobei die Copilerausgabe sehr gut aussieht:
1
> "make.exe" all
2
avr-gcc -g -Wall -O2 -mmcu=atmega8    -c -o LCD1.o LCD1.c
3
avr-gcc -g -Wall -O2 -mmcu=atmega8  -Wl,-Map,LCD1.map -o LCD1.elf LCD1.o 
4
avr-objdump -h -S LCD1.elf > LCD1.lst
5
avr-objcopy -j .text -j .data -O ihex LCD1.elf LCD1.hex
6
avr-objcopy -j .text -j .data -O binary LCD1.elf LCD1.bin
7
avr-objcopy -j .text -j .data -O srec LCD1.elf LCD1.srec
8
avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O ihex LCD1.elf LCD1_eeprom.hex \
9
  || { echo empty LCD1_eeprom.hex not generated; exit 0; }
10
c:\Programme\WinAVR-20080610\bin\avr-objcopy.exe: --change-section-lma .eeprom=0x00000000 never used
11
avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O binary LCD1.elf LCD1_eeprom.bin \
12
  || { echo empty LCD1_eeprom.bin not generated; exit 0; }
13
c:\Programme\WinAVR-20080610\bin\avr-objcopy.exe: --change-section-lma .eeprom=0x00000000 never used
14
avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O srec LCD1.elf LCD1_eeprom.srec \
15
  || { echo empty LCD1_eeprom.srec not generated; exit 0; }
16
c:\Programme\WinAVR-20080610\bin\avr-objcopy.exe: --change-section-lma .eeprom=0x00000000 never used
17
18
> Process Exit Code: 0
19
> Time Taken: 00:02

-Wall sollte doch gut sein ?

Gruß

Ein verwirrter Andreas

von Oliver (Gast)


Lesenswert?

>wie sucht man einen solchen Fehler ???

Indem du mal den sourcecode hier postest.

Oliver

von UBoot-Stocki (Gast)


Angehängte Dateien:

Lesenswert?

Alles klar,

Ihr wolltet es so ... (siehe Anhang)

Übrigens bringt -Wextra auch nix neues ....

Gruß

Andreas

von UBoot-Stocki (Gast)


Lesenswert?

Ich sollte vielleicht noch bemerken, dass das Programm seit September 
2007 bei mir "produktiv" im einsatz ist. Ich möchte nun einige 
Funktionen überarbeiten, da die Benutzung und Menüführung etwas 
"unpraktisch" ist.

Diese Programm ist/war übrigens auch die Grundlage für meine 
Rolladensteuerung (Beitrag "Komfortable Rolladensteuerung V1.0")

Gruß

Andreas

von Benedikt K. (benedikt)


Lesenswert?

Wie vermutet: Die LCD Init ist schonmal ziemlich falsch, du verletzt da 
sehr viele Timings.
1
 PORTD = 0x03; // muss 3mal hintereinander gesendet werden zur Initialisierung 
2
  lcd_enable();
3
  PORTD = 0x03;
4
  lcd_enable();
5
  PORTD = 0x03;
6
  lcd_enable();
7
  PORTD = 0x02; // 4bit-Modus einstellen  
8
  lcd_enable();
9
  lcd_busy_wait();
10
  lcd_send(0x28,1);  // 4Bit / 2 Zeilen / 5x8
Schau mal die Init im Datenblatt an, da werden in diesem Codeteil einige 
Pausen gefordert.

in void lcd_busy_wait(void)
ist dieser Teil auch nicht ganz nach Datenblatt:
1
  uint8_t i=1;
2
  
3
  DDRD = 0xF0;
4
  PORTD &= ~(1<<PD4); // PD4 = RS-Leitung 0
5
  PORTD |=  (1<<PD6); // PD6 = R/W-Leitung 1
6
  PORTD |=  (1<<PD5); // enable 1
7
  while(i!=0) {
8
    i=PIND << 4; // liest die ersten 4 BIT ein
9
    i=(PIND & (1<<PIND3)); // Fragt PD3 auf 1 ab
10
  }
11
  PORTD &= ~(1<<PD5); // enable 0
12
  PORTD &= ~(1<<PD6); //R/W-Leitung 0
13
  DDRD = 0xFF;D3)); // Fragt PD3 auf 1 ab
Diese Zeile ist sinnlos, da in der nächsten Zeile i überschrieben wird:
    i=PIND << 4; // liest die ersten 4 BIT ein

Weiterhin führst du beim Busy Lesen immer noch einen Transfer aus, 
obwohl das Datenblatt immer 2 Transfers fordert, damit ein volles Byte 
übertragen wird.
Mich wundert es, dass dieser Code bisher lief...

PS: Die busy Abfrage packt man sinnvollerweise vor die Senderoutine, 
denn dann kann der µC während das Display beschäftigt ist andere Dinge 
erledigen, und wenn das lange genug dauert, dann ist gar keine Wartezeit 
erforderlich.

von UBoot-Stocki (Gast)


Lesenswert?

Hi,

zur Initialisierung kann ich jetzt auf die schnelle nichts sagen - muss 
ich mir ansehen.

Bei der Routine lcd_busy_wait(void) bin ich ziemlich sicher, dass das so 
stimmt. Allein schon aus dem Grund, dass es NUR so funktioniert. Der 
Inhalt von "i" in
1
i=PIND << 4; // liest die ersten 4 BIT ein
spielt keine Rolle, da es nur um das Lesen an sich geht. Hier findet 
auch das von Dir erwähnte 1. Lesen statt. Die wichtige Zeile ist
1
i=(PIND & (1<<PIND3)); // Fragt PD3 auf 1 ab
da hier in der zweiten Operation das BIT gelesen wir. Beachte bitte es 
handelt sich hier um den 4-BIT-Modus.

Egal ob nun die Timings stimmen oder nicht - Warum wird der Code 
übersetzt mit gcc 5.12.2008 falsch ausgeführt (selbst wenn das LCD nicht 
funktioniert müssten doch die Tasten und die damit verbundenen 
Funktionen für die Hintergrundbeleuchtung laufen) und mit gcc 6.10.2008 
funzt es einwandfrei ???

Das kann nicht  an falschen LCD-Timings liegen ?

Wer hat da eine Idee ?

Gruß

Andreas

von Benedikt K. (benedikt)


Angehängte Dateien:

Lesenswert?

UBoot-Stocki wrote:
> Allein schon aus dem Grund, dass es NUR so funktioniert.

Das kann an den restlichen Fehlern liegen.

> Der
> Inhalt von "i" in
>
1
> i=PIND << 4; // liest die ersten 4 BIT ein
2
>
> spielt keine Rolle, da es nur um das Lesen an sich geht.

Das Lesen ist schlicht und einfach sinnlos, da das LCD davon nichts 
mitbekommt. Der einzige Nutzen davon ist eine Pause. 1-2 nops erfüllen 
den selben Zweck.

> Hier findet auch das von Dir erwähnte 1. Lesen statt.

Nein. Denn dazu müsstest du enable takten, was du aber nicht machst.

> Die wichtige Zeile ist
>
1
> i=(PIND & (1<<PIND3)); // Fragt PD3 auf 1 ab
2
>
> da hier in der zweiten Operation das BIT gelesen wir. Beachte bitte es
> handelt sich hier um den 4-BIT-Modus.

Ja, sag ich doch. Aber um dein Argument, dass es sich um den 2. Transfer 
handelt, weiter zu entkräften: Das Busy Bit liegt im oberen Nibble, und 
das wird zuerst übertragen.

> Das kann nicht  an falschen LCD-Timings liegen ?

Doch. Wenn er z.B. bei der komplett falschen Busy Abfrage hängen bleibt, 
dann schon.
Schau dir mal den angehängten Ausschnitt aus dem Datenblatt an, der 
sieht "leicht" anders aus als das was dein Code macht.

von Johann L. (gjlayde) Benutzerseite


Angehängte Dateien:

Lesenswert?

Wenn ich es recht sehe, funktioniert keine der beiden Versionen wie sie 
soll, denn keine passt in den Flash.

Dazu ein Blick ins mapfile wagen (.text+.data ist größer als 8kB)

Bei 0610 waren's nur 8 Byte zu viel, also wurden nicht so viele Daten 
falsch initialisiert wie in 1205.

20080610
1
0x00002008                __data_load_end

20081205
1
0x0000204a                __data_load_end

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Tipp: versuch mal Optimierungsstufe -Os

von Börnie (Gast)


Lesenswert?

Der Tipp mit der Optimierungsstufe ist gut. Ich würde es jedoch mit eher 
mit "-O0" versuchen.
Folgender Code z.B. läuft nur korrekt mit "-O0" bei jeder anderen 
Optimierungsstufe werden die Schleifen wegoptimiert. Logisch, die tun ja 
auch nichts ausser den Programmablauf verzögern aber manchmal ist es 
jedoch notwendig.
int main()       //* Blinker *********
{
        int    n;
  DDRB = 0x08;
  while(1)
  {
    PORTB = (0x001 << PB3);
    for (n = 1; n < 3000; n++);
    PORTB = 0;
    for (n = 1; n < 3000; n++);
  }
  return 0;
}

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Börnie wrote:
> Der Tipp mit der Optimierungsstufe ist gut. Ich würde es jedoch mit eher
> mit "-O0" versuchen.

Wenn das Programm mit -O2 bereits nicht in den den µC passt, dann schon 
garnicht mit -O0.

Falls es denn -O2 sei soll -- was jedoch m.E. eh nicht empfehlenswert 
ist, für AVR abgezeigt ist -Os --, dann sollte man die für avr-gcc 4.x 
geboteten Optionen wie -fno-inline-small-functions etc. setzten. Damit 
passt's auch rein.

Mit -O0 lässt sich noch nichtmal ein hex-File erzeugen: ld-Fehler weil 
.text überläuft.

von Oliver (Gast)


Lesenswert?

>Der Tipp mit der Optimierungsstufe ist gut.

Ist er.

>Ich würde es jedoch mit eher mit "-O0" versuchen.

Nur, wenn man unbedingt selbstgezimmerte Verzögerungsschleifen mit 
undefinierter Dauer braucht. Wobei, auch die gehen "optimierungssicher" 
mit
1
 for (volatile int n=0;n<30000;n++);

Für Verzögerungen mit Rechenzeitvernichtung gibt es in der avrlib 
entsprechende Funktionen, die nicht "wegoptimiert" werden. Ernsthafte 
Programme, die nicht nur eine LED blinken lassen, passen ohne 
Größenoptimierung kaum in einen normalen AVR, und bei denen löst man das 
Blinken nebenher mit einem Timerinterrupt.

Oliver

von UBoot-Stocki (Gast)


Lesenswert?

Ich habe mir in den letzten Stunden die Unterlagen zu meinem alten 
Projekt angesehen. Die Initialisierungs-Routine stammt 1:1 aus dem 
Tutorial hier aus dem Forum. Zum Glück habe ich noch einen alten 
Ausdruck vom 29.5.2007 gefunden. Heute ist der Code im Tutorial anders!

Ich halte Euch auf dem Laufenden wie es weiter geht ...

Gruß

Andreas

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

UBoot-Stocki wrote:

> Ich halte Euch auf dem Laufenden wie es weiter geht ...

Die Lösung warum dein Zeug abschmiert steht oben. Lesen musst du aber 
schon selber ;-)

von UBoot-Stocki (Gast)


Lesenswert?

Hi,

habe jetzt folgende Initialisierungsroutine:
1
void lcd_init(void) // Muss ganz am Anfang des Programms aufgerufen werden.
2
{
3
  uint8_t i;
4
5
  PORTD = 0x03; // Muss zur Initialisierung 3x ausgeführt werden
6
  
7
  i = 0;
8
  while(i++ <= 25)
9
    _delay_ms(1);  // Warten
10
  lcd_enable();
11
  
12
  i = 0;
13
  while(i++ <= 5)
14
    _delay_ms(1);  // Warten
15
  lcd_enable();
16
  
17
  i = 0;
18
  while(i++ <= 1)
19
    _delay_ms(1);  // Warten
20
  lcd_enable();
21
  
22
  PORTD = 0x02; // 4bit-Modus einstellen  
23
  lcd_enable();
24
  lcd_busy_wait();
25
  
26
  lcd_send(0x28,1);  // 4Bit / 2 Zeilen / 5x8        
27
  
28
  lcd_send(0x0C,1); // Display ein / Cursor aus / kein Blinken        
29
  
30
  lcd_send(0x04,1);  // inkrement / kein Scrollen
31
}

und folgendes busy-wait
1
void lcd_busy_wait(void) // wartet bis lcd fertig ist
2
{
3
  uint8_t i=1;
4
  
5
  DDRD = 0xF0;
6
  PORTD &= ~(1<<PD4); // PD4 = RS-Leitung 0
7
  PORTD |=  (1<<PD6); // PD6 = R/W-Leitung 1
8
  
9
  while(i!=0) {
10
    PORTD |=  (1<<PD5); // enable 1
11
    asm("nop");  
12
    asm("nop");        
13
    i=(PIND & (1<<PIND3)); // Fragt PD3 auf 1 ab
14
    PORTD &= ~(1<<PD5); // enable 0
15
        
16
    lcd_enable(); // Fragt 2. Nibble ab
17
  }
18
  
19
  PORTD &= ~(1<<PD6); // R/W-Leitung 0
20
  DDRD = 0xFF; 
21
}

Bitte gebt Feedback ob das jetzt passt ...

Bzgl. der Optimierung habe ich jetzt "-Os -fno-inline-small-functions" 
verwendet.
1
> "make.exe" all
2
avr-gcc -g -Wextra -Os -fno-inline-small-functions -mmcu=atmega8    -c -o LCD1.o LCD1.c
3
avr-gcc -g -Wextra -Os -fno-inline-small-functions -mmcu=atmega8  -Wl,-Map,LCD1.map -o LCD1.elf LCD1.o 
4
avr-objdump -h -S LCD1.elf > LCD1.lst
5
avr-objcopy -j .text -j .data -O ihex LCD1.elf LCD1.hex
6
avr-objcopy -j .text -j .data -O binary LCD1.elf LCD1.bin
7
avr-objcopy -j .text -j .data -O srec LCD1.elf LCD1.srec
8
avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O ihex LCD1.elf LCD1_eeprom.hex \
9
  || { echo empty LCD1_eeprom.hex not generated; exit 0; }
10
c:\Programme\WinAVR-20080610\bin\avr-objcopy.exe: --change-section-lma .eeprom=0x00000000 never used
11
avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O binary LCD1.elf LCD1_eeprom.bin \
12
  || { echo empty LCD1_eeprom.bin not generated; exit 0; }
13
c:\Programme\WinAVR-20080610\bin\avr-objcopy.exe: --change-section-lma .eeprom=0x00000000 never used
14
avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O srec LCD1.elf LCD1_eeprom.srec \
15
  || { echo empty LCD1_eeprom.srec not generated; exit 0; }
16
c:\Programme\WinAVR-20080610\bin\avr-objcopy.exe: --change-section-lma .eeprom=0x00000000 never used
17
18
> Process Exit Code: 0
19
> Time Taken: 00:01

Es ist tatsächlich so, dass die Oktober-Version einen größeren Code 
generiert als die in 2007 verwendete (keine Ahnung mehr welche das war 
...)

Morgen teste ich die aktuelle ...

Gruß und Danke für die Tipps

Andreas

von Simon K. (simon) Benutzerseite


Lesenswert?

UBoot-Stocki wrote:
>   i = 0;
>   while(i++ <= 25)
>     _delay_ms(1);  // Warten

Warum nicht _delay_ms(25)?

von UBoot-Stocki (Gast)


Lesenswert?

Hi,

"Warum nicht _delay_ms(25)?"

Wäre doch zu einfach ;-)

Im Ernst: Ich habe das "auf die Schnelle" gemacht. Werde da noch 
Anpassungen machen ...

Gruß

Andreas

von Benedikt K. (benedikt)


Lesenswert?

UBoot-Stocki wrote:

> habe jetzt folgende Initialisierungsroutine:

Sieht gut aus, sollte funktionieren. Zumindest stimmt jetzt alles mit 
dem Datenblatt überein. Dieser Code sollte zuverlässig mit allen 44780 
kompatiblem LCDs funktionieren.

von UBoot-Stocki (Gast)


Lesenswert?

Hi,

alles klar - Problem gelöst.

Nochmals vielen Dank inbesondere an benedikt und gjlayde aber natürlich 
auch an alle Anderen.

Die neue Version läuft, mein Code läuft und es passt alles in den 
Controller!

Eine Frage bleibt: Wie sind denn die "Empfohlenen" Optimierungsoptionen 
für ein AVR-Projekt in Bezog auf die Codegröße ???

Gruß

andreas

von Benedikt K. (benedikt)


Lesenswert?

UBoot-Stocki wrote:

> Eine Frage bleibt: Wie sind denn die "Empfohlenen" Optimierungsoptionen
> für ein AVR-Projekt in Bezog auf die Codegröße ???

-Os erzeugt fast immer den kleinsten Code, teilweise optimiert er aber 
Sachen zu stark (z.B. /16 wird über eine Division gerechnet und nicht 
über eine Schiebeoperation. Ein Funktionsaufruf ist Platzmäßig eben 
besser als eine Schiebeoperation, wenn die Divisionsroutine sowieso 
schon eingebunden ist.) Wenn ausreichen Platz zur Verfügung steht ist 
-O2 daher meine Standardwahl.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

UBoot-Stocki schrob:

> Eine Frage bleibt: Wie sind denn die "Empfohlenen" Optimierungsoptionen
> für ein AVR-Projekt in Bezog auf die Codegröße ???

Auf jeden Fall
1
-Os

Die Laufzeit wird damit nur unmerklich schlechter als mit -O2, während 
die Codegröße deutlich abnimmt. Bei -O2 werten teilweise Basic Blocks 
kopiert, um Sprünge zu sparen, was aber mächtig Code kostet. Von -O3 ist 
generell abzuraten. -O1 wenn man optimieren möchte/muss, aber noch 
einigermassen gut debuggen können möchte.

Wertere Optionen die du antesten kannst sind
1
-fno-inline-small-functions
2
-fno-split-wide-types
3
-fno-tree-scev-cprop

Und last not least besteht die Möglichkeit ältere Versionen von avr-gcc 
zu versuchen. Ich verwende standardmässig den 3.4.6, der macht in meinen 
Projekten rund 10% kleineren Code. Bei deinem Projekt ist die Codegröße 
so wie bei 4.3.2, was darauf hindeutet, daß du weitere 10% an Code 
sparen kannst, wenn du etwas geschickter codierst.

Benedikt K. schrob:
> -Os erzeugt fast immer den kleinsten Code, teilweise optimiert er aber
> Sachen zu stark (z.B. /16 wird über eine Division gerechnet und nicht
> über eine Schiebeoperation. Ein Funktionsaufruf ist Platzmäßig eben
> besser als eine Schiebeoperation, wenn die Divisionsroutine sowieso
> schon eingebunden ist.) Wenn ausreichen Platz zur Verfügung steht ist
> -O2 daher meine Standardwahl.

Das dürfte ein bekanntes Problem sein, siehe

http://gcc.gnu.org/ml/gcc/2008-12/msg00329.html
http://gcc.gnu.org/ml/gcc-help/2008-12/msg00232.html

sowie die Antworten darauf.

von Wilhelm S. (wst)


Lesenswert?

Hallo,

Dem Thema entsprechend hänge ich mich hier gleich an.

Mit der neuen GCC-Version funktionieren die Stringfunktionen nicht mehr.
Z.B.

uint16_t uword = 12345;
char foo_string[10];

sprintf(foo_string, "%05u", uword);
ausgabe(foo_string);

Die sprintf führt zum Neustart (Reset) des ATmega128.



char foo_string[10];

strcpy(foo_string, "12345");
ausgabe(foo_string);

Nach der strcpy beinhaltet der string sechs byte mit jeweils 0xFF.

Bitte antwortet nur wenn ihr die Funktionen auch tatsächlich in einem 
ATmega128 laufen lassen könnt und nicht nur in einem Simulator. Die 
angeführten Beispiele laufen z.B. mit WinAVR 20080610 und allen anderen 
Vorgängerversionen einwandfrei. Es liegt also nicht am Kode sondern an 
der Übersetzung. In wie weit andere Stringfunktionen ebenfalls betroffen 
sind kann ich derzeit nicht sagen weil ich wegen Zeitdrucks jetzt mit 
der 20080610 Version weiterarbeite und keine Zeit für Experimente habe.

Hier noch der Makeoutput um Fragen bezüglich Meldungen und Einstellungen 
gleich vorweg zu beantworten:

-------- begin --------
avr-gcc (WinAVR 20081205) 4.3.2
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is 
NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR 
PURPOSE.


Size before:
AVR Memory Usage
----------------
Device: atmega128

Program:    9616 bytes (7.3% Full)
(.text + .data + .bootloader)

Data:        993 bytes (24.2% Full)
(.data + .bss + .noinit)

EEPROM:        1 bytes (0.0% Full)
(.eeprom)




Compiling C: E2000_Flughaven.c
avr-gcc -c -mmcu=atmega128 -I. -gdwarf-2 -DF_CPU=7372800UL -O0 
-funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall 
-Wstrict-prototypes -Wa,-adhlns=./E2000_Flughaven.lst  -std=gnu99 
-Wundef -MMD -MP -MF .dep/E2000_Flughaven.o.d E2000_Flughaven.c -o 
E2000_Flughaven.o

Linking: E2000_Flughaven.elf
avr-gcc -mmcu=atmega128 -I. -gdwarf-2 -DF_CPU=7372800UL -O0 
-funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall 
-Wstrict-prototypes -Wa,-adhlns=E2000_Flughaven.o  -std=gnu99 -Wundef 
-MMD -MP -MF .dep/E2000_Flughaven.elf.d E2000_Flughaven.o --output 
E2000_Flughaven.elf -Wl,-Map=E2000_Flughaven.map,--cref 
-Wl,-u,vfprintf -lprintf_flt  -lm

Creating load file for Flash: E2000_Flughaven.hex
avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock E2000_Flughaven.elf 
E2000_Flughaven.hex

Creating load file for EEPROM: E2000_Flughaven.eep
avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" \
  --change-section-lma .eeprom=0 --no-change-warnings -O ihex 
E2000_Flughaven.elf E2000_Flughaven.eep || exit 0

Creating Extended Listing: E2000_Flughaven.lss
avr-objdump -h -S -z E2000_Flughaven.elf > E2000_Flughaven.lss

Creating Symbol Table: E2000_Flughaven.sym
avr-nm -n E2000_Flughaven.elf > E2000_Flughaven.sym

Size after:
AVR Memory Usage
----------------
Device: atmega128

Program:    9666 bytes (7.4% Full)
(.text + .data + .bootloader)

Data:        999 bytes (24.4% Full)
(.data + .bss + .noinit)

EEPROM:        1 bytes (0.0% Full)
(.eeprom)



srec_cat E2000_Flughaven.hex -Intel -Output E2000_Flughaven.srec 
-Motorola -Line_Length 142
-------- end --------

von Benedikt K. (benedikt)


Lesenswert?

Könntest du mal die erstellte .elf Datei von dem Projekt posten?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Du verwendest den EEPROM. Bist du sicher, daß nicht ein Silicon-Bug 
zuschlägt? Die AVR-Tools kümmern sich nicht um Silicon-Bugs.
1
6. Reading EEPROM by using ST or STS to set EERE bit triggers 
2
   unexpected interrupt request.

Da keine ISR implementiert ist gibt's also u.U. nen Reset wenn du aufn 
EEPROM zugreifst

von Wilhelm S. (wst)


Lesenswert?

Sorry, ich habe bereits deinstalliert und arbeite wieder mit der 
20080610. Das Problem läuft aber nicht davon und nach dem 12.1. nehme 
ich mir etwas Zeit und installiere 20081205 erneut.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Du kannst mehrere AVR-Toolchains parallel installieren.

Einfach die Pfadvariable anpassen oder die Tools mal mit absoluten 
Pfaden aufrufen wenn man ne andere Version antesten will.

von Wilhelm S. (wst)


Lesenswert?

Nein in diesem Projekt wird kein EEProm verwendet. Den EEProm-Bug gabs 
auch nur in der Zeit zwischen nach 2006xxxx und 20080610. War ja auch 
ich der den schmerzlich bemerkt hat. Der wurde aber dann auch durch 
Austausch der Headerdatei umschifft. Ob das nun wieder ein Thema wird 
werde ich erst später mir mal ansehen. Heute habe ich nur festgestellt 
dass die beiden Stringfunktionen nicht mehr funktionieren.

von Robert K. (molch) Benutzerseite


Lesenswert?

Hi,

bitte entschuldigt, dass ich den Thread nochmal rauskrame. Ich nutze 
ebenfalls die Version "WinAVR 20081205".
Beim Compilieren kommen keine Fehler jedoch zeigt das Programm seltsam 
Erscheinungen. Ein Blick in das list-file brachte die "Erleuchtung". Bei 
Verwendung einer Optimierungsstufe (-O1..-Os) wird ein "doppelter" ASM 
Code erzeugt. Im Simulator funktioniert der Code wie gewollt, nur real 
eben nicht.

Hier das Code-Fragment in C:
1
uint8_t main (void) {
2
3
  uart0_init();
4
  port_init();
5
  timer0_init();
6
  timer1_init();
7
  sei();
8
  PORTD = (1<<PD5);
9
10
  while(1){  // Endlosschleife
11
12
    // neue PWM Daten
13
    
14
    if (uart0_rx_is_buffer_empty() == NO){
15
      
16
      uint8_t PWM_value;
17
      PORTD ^= (1<<PD6);                  // LED rot toggle
18
      PWM_value = uart0_rx_getchar();
19
      uart0_tx_putchar(PWM_value);
20
      
21
      if ( (PWM_value >= 0) && (PWM_value <= 100) ){
22
        OCR1A = PWM_value*0xFF/100; 
23
      }
24
    }
25
    
26
       
27
  }
28
29
  // wird nie erreicht
30
  return 0;                 
31
}


Und hier das Resultat im list-file:
Ab Adresse ca beginnt der Inhalt der Endloschleife. Dieser Code ist auch 
schon falsch da keinerlei togglen der LED an dieser Stelle erfolgt 
(PORTD 0x12 wird nicht zum XOR verknüpfen ausgelesen). Ab e0 wird ein 
"doppelter" Code wiederholt. Diesmal beginnt er jedoch korrekt mit dem 
LED Toggle.
1
uint8_t main (void) {
2
  b2:  df 92         push  r13
3
  b4:  ef 92         push  r14
4
  b6:  ff 92         push  r15
5
  b8:  0f 93         push  r16
6
  ba:  1f 93         push  r17
7
  bc:  cf 93         push  r28
8
  be:  df 93         push  r29
9
10
  uart0_init();
11
  c0:  26 d0         rcall  .+76       ; 0x10e <uart0_init>
12
  port_init();
13
  c2:  cd df         rcall  .-102      ; 0x5e <port_init>
14
  timer0_init();
15
  timer1_init();
16
  c4:  e8 df         rcall  .-48       ; 0x96 <timer1_init>
17
  sei();
18
  c6:  78 94         sei
19
  PORTD = (1<<PD5);
20
  c8:  80 e2         ldi  r24, 0x20  ; 32
21
  ca:  82 bb         out  0x12, r24  ; 18
22
    // neue PWM Daten
23
    
24
    if (uart0_rx_is_buffer_empty() == NO){
25
      
26
      uint8_t PWM_value;
27
      PORTD ^= (1<<PD6);                  // LED rot toggle
28
  cc:  c2 e3         ldi  r28, 0x32  ; 50
29
  ce:  d0 e0         ldi  r29, 0x00  ; 0
30
  d0:  00 e4         ldi  r16, 0x40  ; 64
31
      PWM_value = uart0_rx_getchar();
32
      uart0_tx_putchar(PWM_value);
33
      
34
      if ( (PWM_value >= 0) && (PWM_value <= 100) ){
35
        OCR1A = PWM_value*0xFF/100; 
36
  d2:  dd 24         eor  r13, r13
37
  d4:  da 94         dec  r13
38
  d6:  0f 2e         mov  r0, r31
39
  d8:  fa e4         ldi  r31, 0x4A  ; 74
40
  da:  ef 2e         mov  r14, r31
41
  dc:  ff 24         eor  r15, r15
42
  de:  f0 2d         mov  r31, r0
43
44
  while(1){  // Endlosschleife
45
46
    // neue PWM Daten
47
    
48
    if (uart0_rx_is_buffer_empty() == NO){
49
  e0:  4e d0         rcall  .+156      ; 0x17e <uart0_rx_is_buffer_empty>
50
  e2:  88 23         and  r24, r24
51
  e4:  e9 f7         brne  .-6        ; 0xe0 <main+0x2e>
52
      
53
      uint8_t PWM_value;
54
      PORTD ^= (1<<PD6);                  // LED rot toggle
55
  e6:  88 81         ld  r24, Y
56
  e8:  80 27         eor  r24, r16
57
  ea:  88 83         st  Y, r24
58
      PWM_value = uart0_rx_getchar();
59
  ec:  52 d0         rcall  .+164      ; 0x192 <uart0_rx_getchar>
60
  ee:  18 2f         mov  r17, r24
61
      uart0_tx_putchar(PWM_value);
62
  f0:  71 d0         rcall  .+226      ; 0x1d4 <uart0_tx_putchar>
63
      
64
      if ( (PWM_value >= 0) && (PWM_value <= 100) ){
65
  f2:  15 36         cpi  r17, 0x65  ; 101
66
  f4:  a8 f7         brcc  .-22       ; 0xe0 <main+0x2e>
67
        OCR1A = PWM_value*0xFF/100; 
68
  f6:  1d 9d         mul  r17, r13
69
  f8:  c0 01         movw  r24, r0
70
  fa:  11 24         eor  r1, r1
71
  fc:  64 e6         ldi  r22, 0x64  ; 100
72
  fe:  70 e0         ldi  r23, 0x00  ; 0
73
 100:  bd d0         rcall  .+378      ; 0x27c <__divmodhi4>
74
 102:  86 2f         mov  r24, r22
75
 104:  97 2f         mov  r25, r23
76
 106:  f7 01         movw  r30, r14
77
 108:  91 83         std  Z+1, r25  ; 0x01
78
 10a:  80 83         st  Z, r24
79
 10c:  e9 cf         rjmp  .-46       ; 0xe0 <main+0x2e>

Ich werde in den nächsten Tagen mal eine Vorgängerversion testen. Bis 
dahin seht dies einfach als Information. Leider fehlt mir im Moment die 
Zeit sämtliche Bugreports etc. für diese WinAVR Version zu durchforsten 
deswegen kann ich nicht sagen ob dieser Fehler bereits bekannt ist.

MfG
Robert

von (prx) A. K. (prx)


Lesenswert?

Du lässt dich zu sehr von den eingestreuten Zitaten über die 
C-Statements kirre machen. Statt dessen hättest du mal versuchen sollen, 
den erzeugten Code zu untersuchen.

Jenseits von -O0 ist ist durchaus üblich, dass der Compiler den Code 
eines Statements in mehrere Codeblöcke zerschnippelt und sie auf sehr 
unterschiedliche Stelle verteilt. Diese aber jeweils mit dem gleichen 
C-Statement garniert, so dass die gleiche Zeile vom Quellcode mehrfach 
auftaucht.

Nach Bugreports zu suchen ist müssig, denn der erzeugte Code ist 
korrekt.

> Ab Adresse ca beginnt der Inhalt der Endloschleife.

Nein, die beginnt bei 0xE0. Das Zeug davor intialisiert nur ein paar 
Register, die u.U. in den im Kommentar angegebenen Statements verwendet 
werden (oder auch garnicht).

> Dieser Code ist auch
> schon falsch da keinerlei togglen der LED an dieser Stelle erfolgt

Im Code auch nicht.

> Ab e0 wird ein "doppelter" Code wiederholt.

Nein. Es werden nur ein paar Quellcodezeilen wiederholt. Der Code dazu 
ist verschieden.

von (prx) A. K. (prx)


Lesenswert?

Apropos: Wenn der gleiche Code im Simulator funktioniert, auf realer 
Hardware jedoch nicht, dann kann man das als deutlichen Hinweis auf 
Zeitprobleme verstehen. Dem Compiler ist es doch völlig schnuppe ob die 
Hardware echt ist oder simulert.

von (prx) A. K. (prx)


Lesenswert?

Beispiel:

Die Zeile
    PORTD ^= (1<<PD6);                  // LED rot toggle
besteht insgesamt aus zwei verteilten Codeblöcken, einmal
  cc:  c2 e3         ldi  r28, 0x32  ; 50
  ce:  d0 e0         ldi  r29, 0x00  ; 0
  d0:  00 e4         ldi  r16, 0x40  ; 64
als Initialisierung vor der Schleife, und dann
  e6:  88 81         ld  r24, Y
  e8:  80 27         eor  r24, r16
  ea:  88 83         st  Y, r24
als toggle Operation in der Schleife.

Man kann nun drüber streiten, ob das wirklich als Optimierung zu 
verstehen ist, weil dieser Code summarum langsamer und länger ist als 
eine weniger agressiv optimierte Version. Aber korrekt ist es.

von Robert K. (molch) Benutzerseite


Lesenswert?

Servus,
danke für die ausführliche Erklärung. Du hast natürlich recht, hätte ich 
noch genauer hingesehen wärs mir vllt. auch aufgefallen.
Leider bekomm ich mein Programm aber mit dem WinAVR trotzdem nicht zum 
laufen. Habe den Code mit dem ICC AVR v7 von Imagecraft übersetzt und 
damit läuft es. Dummerweise kann ich auch keinen logischen Fehler 
entdecken. Ich verweise nochmal auf mein C Codesegment hier 
Beitrag "Re: Probleme win WinAVR 20081205".

Das Programm begibt sich in jedem Durchlauf in die erste If-Verzweigung 
obwohl die Bedingung eigentlich nicht erfüllt sein dürfte. Naja, mal 
sehen ob ich noch dahinter komme was da falsch läuft.

Grüße und danke nochmals.

von Stefan E. (sternst)


Lesenswert?

Robert K. wrote:

> Das Programm begibt sich in jedem Durchlauf in die erste If-Verzweigung
> obwohl die Bedingung eigentlich nicht erfüllt sein dürfte.

Meinst du mit "erste If-Verzweigung" dies?
1
if (uart0_rx_is_buffer_empty() == NO){


uart0_rx_is_buffer_empty liefert also nicht das erwartete Ergebnis. Was 
glaubst du soll irgendjemand hier dazu sagen, wenn wir den "Inhalt" 
dieser Funktion nicht kennen?

von Robert K. (molch) Benutzerseite


Lesenswert?

Hi,
ich steig einfach nich dahinter warum der Controller nich das macht was 
er soll. Es scheitert schon an dem einfachen LED-toggle. Hab alle UART 
Funktionen entfernt, compiliert mit 3 WinAVR Versionen (aus AVR-Studio 
4.15 Build 623). Schau mal bitte einer drüber ob er nen Fehler findet, 
so langsam neige ich dazu auch privat auf nen anderen Compiler 
umzusteigen, mit dem Imagecraft ICC AVR 7 klappts ohne Probleme. Habe 
irgendwie die Vermutung das es an den Interrupts liegt.
Die Ausgabe des PWM Signals funzt dagegen wie sie soll auch beim WinAVR 
(Frequenz und Tastverhältnis mit Oszi überprüft)

thx and greetz, molch

edit 1: Nur eine Warnung beim compilieren das der Rückgabetyp von main 
nicht int ist, denke daran sollte es nich liegen. Sonst keine 
Fehlermeldungen.
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdint.h>
4
5
//#include "uart.h"
6
7
8
//uint8_t *ptr_fed = uart0_rx_buffer;
9
10
uint16_t life_LED_counter;
11
12
13
void port_init(void){
14
15
  DDRB  = (1<<DDB1);
16
  PORTB = 0x00;
17
  DDRC  = 0x00;
18
  PORTC = 0x00;
19
  DDRD  = (1<<DDD6) | (1<<DDD5);
20
  PORTD = 0x00;
21
  
22
}
23
24
25
ISR(TIMER1_OVF_vect){
26
27
  life_LED_counter++;
28
29
}
30
31
/*
32
void timer0_init(void){
33
  
34
35
}
36
*/
37
38
void timer1_init(void){
39
40
  // Set OC1A on Compare Match when upcounting.
41
  // Clear OC1A on Compare Match when counting down. PWM inverted at OC1A
42
  TCCR1A = (1<<COM1A1) | (1<<COM1A0);
43
  
44
  // WGM Mode 8 -> Phase and frequency correct PWM
45
  // CS10..CS12 für Clocksource, 0 gestoppt, 1..5 Prescaler 1, 8, 64, 256, 1024
46
  TCCR1B = (1<<WGM13) | (1<<CS10);
47
  
48
  TIMSK = (1<<TICIE1) | (1<<TOIE1);
49
  
50
  ICR1H = 0x00;              // für TOP-Wert, bestimmt PWM Frequenz und Auflösung 
51
  ICR1L = 0xff;
52
  OCR1A = 0x80;              // bestimmt Tastverhältnis
53
}
54
55
56
57
uint8_t main (void) {
58
59
  //uart0_init();
60
  port_init();
61
  //timer0_init();
62
  timer1_init();
63
  sei();
64
  //uart0_tx_putchar('O');
65
  //uart0_tx_putchar('K');
66
  PORTD = (1<<PD5);
67
68
  while(1){                                // Endlosschleife
69
70
    // neue PWM Daten
71
    
72
    if (life_LED_counter >= 2000){
73
      life_LED_counter = 0;
74
      PORTD ^= (1<<PD5);
75
    }
76
/*
77
    if (uart0_rx_is_buffer_empty() == NO){
78
      
79
      uint16_t PWM_value;
80
      PORTD ^= (1<<PD6);                  // LED rot toggle
81
      PWM_value = uart0_rx_getchar();
82
      uart0_tx_putchar(PWM_value);
83
      
84
      if ( (PWM_value >= 0) && (PWM_value <= 100) ){
85
        OCR1A = PWM_value*0xFF/100; 
86
      }
87
    }
88
*/    
89
       
90
  }    // while(1)
91
92
  // wird nie erreicht
93
}

von Simon K. (simon) Benutzerseite


Lesenswert?

volatile uint16_t life_LED_counter;

statt

uint16_t life_LED_counter;

Außerdem musst du in der Main loop darauf achten, dass du den Wert 
atomar behandelst.
und vor allem(!) Unter Interruptsperre wieder zurücksetzt.
Da kann der Compiler aber auch nichts für, wenn du fehlerhaften Code 
schreibst.

Lesen: http://www.mikrocontroller.net/articles/Interrupt

von Robert K. (molch) Benutzerseite


Lesenswert?

Variable auf volatile gesetzt, Interrupts für die Zeit der Ausführung 
global blockiert für "atomaren" bzw. ungestörten Zugriff. Was genau 
meinst du mit Unter Interruptsperre zurücksetzen, der Timeroverflowint. 
returnt mit nem reti, das sollte meines Wissen diesen Interrupt wieder 
freigeben.

edit: ...und die LED wird zwar einmal angeschalten vor der while 
Schleife aber in dieser tut sich nix mehr.
1
cli();
2
if (life_LED_counter >= 2000){
3
life_LED_counter = 0;
4
PORTD ^= (1<<PD5);
5
}
6
sei();

von Oliver (Gast)


Lesenswert?

>edit: ...und die LED wird zwar einmal angeschalten vor der while
>Schleife aber in dieser tut sich nix mehr.

Selbst bei 16MHz dauert es 8 Sekunden, bis die LED aus geht. Bei 1MHz 
sind es mehr als 2 Minuten. Hast du auch lange genug gewartet?

Oliver

von Robert K. (molch) Benutzerseite


Lesenswert?

@Olli:

Timer1 16Bit, Phase & Frequency correct PWM, TOP-Wert im ICR1 mit 255 
initialisiert, Formel laut Datenblatt:

"Genau" das mess ich auch mit dem Oszi für die PWM.
Der Timeroverflow erfolgt dann also etwa aller 500µs = 0,5ms, mit meinem 
Zwischenzähler "life_LED_counter" teil ich die Frequenz um den Faktor 
2000 nach unten -> 1 Hz -> 0,5s bis ein Zustandswechsel an der LED 
erkennbar ist.
Wie kommst du auf 2 Minuten?

Grüße

von Robert K. (molch) Benutzerseite


Lesenswert?

Robert K. wrote:

>
>
>

...muss natürlich...
... heissen. Also nich 1960 KHz sondern 1960 Hz.

Rest des Abschnitts stimmt.

Auf die 2 Minuten kommst du sicherlich wenn du TOP = 65535 setzt, aber 
das tu ich hier ja nicht.

Wie lange ist die Edit-Funktion für eigene Beiträge aktiv?

Grüße

von Robert K. (molch) Benutzerseite


Lesenswert?

Hi,

ich darf verkünden Problem gelöst.
Der Grund ist das verschiedene Interrupthandling der beiden von mir 
verwendten Compiler (ICC und GCC). Der WinAVR erstellt ein Tabelle mit 
den Interrupt Adressen am Anfang des Listfiles und da sind alle 
Interrupte denen keine ISR zugeordnet ist mit der Sprungmarke 0x5c 
<__bad_interrupt> gekennzeichnet. An dieser wird dann zum Resetvektor 
zurückgesprungen.

Da mein Timer1 Capture Event Int. erlaubt war (
1
TIMSK = (1<<TICIE1) | (1<<TOIE1);
) aber keine zugehörige ISR existierte erfolgte bei jedem Capture Event 
ein Reset.

Was mich dennoch stutzig macht ist, dass das PWM-Signal korrekt aussah.
Die Erzeugung der PWM wird ja dann beim TOP-Wert des Timers durch den 
Reset unterbrochen und damit eigentlich eine halbe Periode zu früh was 
die doppelte Frequenz zur Folge hätte. Kann sein, dass das durch das 
Tastverhältnis von 50% und den Phase6 Frequency Correct Mode überhaupt 
nicht auffiel, aber das untersuch ich jetz erstmal nich. Jetz seh ich zu 
das ich in dem Programm mal weiterkomm.

Grüße und danke an die Helfenden, auch wenn keiner von euch den Fehler 
gefunden hat :P joke

Bis zum nächsten Problem, Robert

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.